From 88d0233c1f5f0b7e2eb4638b43ca525bfa17b1c3 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Fri, 2 Oct 2026 12:55:14 +0100 Subject: [PATCH 1/5] units: Add Target and Work to API tests `Target` and `Work` were moved into `units` but the API tests were not updated to cover them. `CommonTraits` is also missing `Sequence`. Add the missing types to the struct lists and the export checks. Assisted-by: Claude Opus 5.5 --- units/tests/api.rs | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/units/tests/api.rs b/units/tests/api.rs index 1e48741d69..91e9bf76b9 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -57,9 +57,11 @@ struct Structs { k: locktime::relative::NumberOf512Seconds, l: locktime::relative::NumberOfBlocks, m: pow::CompactTarget, - n: sequence::Sequence, - o: time::BlockTime, - p: weight::Weight, + n: pow::Target, + o: pow::Work, + p: sequence::Sequence, + q: time::BlockTime, + r: weight::Weight, } impl Structs { @@ -78,9 +80,11 @@ impl Structs { k: relative::NumberOf512Seconds::MAX, l: relative::NumberOfBlocks::MAX, m: pow::CompactTarget::from_consensus(u32::MAX), - n: sequence::Sequence::MAX, - o: BlockTime::from_u32(u32::MAX), - p: Weight::MAX, + n: pow::Target::MAX, + o: pow::Work::from_be_bytes([0xff; 32]), + p: sequence::Sequence::MAX, + q: BlockTime::from_u32(u32::MAX), + r: Weight::MAX, } } } @@ -114,8 +118,11 @@ struct CommonTraits { k: locktime::relative::NumberOf512Seconds, l: locktime::relative::NumberOfBlocks, m: pow::CompactTarget, - n: time::BlockTime, - o: weight::Weight, + n: pow::Target, + o: pow::Work, + p: sequence::Sequence, + q: time::BlockTime, + r: weight::Weight, } /// A struct that includes all types that implement `Default`. @@ -232,6 +239,10 @@ fn c_debug_nonempty() { assert!(!debug.is_empty()); let debug = format!("{:?}", t.b.p); assert!(!debug.is_empty()); + let debug = format!("{:?}", t.b.q); + assert!(!debug.is_empty()); + let debug = format!("{:?}", t.b.r); + assert!(!debug.is_empty()); } /// C-SEND-SYNC: Tests that all public types implement `Send` + `Sync`. @@ -380,7 +391,7 @@ fn p_consistent_exports_crate_modules() { fn p_consistent_exports_crate_types() { use bitcoin_units::{ Amount, BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval, BlockTime, - CompactTarget, FeeRate, NumOpResult, Sequence, SignedAmount, Weight, + CompactTarget, FeeRate, NumOpResult, Sequence, SignedAmount, Target, Weight, Work, }; } @@ -478,7 +489,7 @@ fn p_consistent_exports_result() { /// P-CONSISTENT-EXPORTS: Tests that all types can be imported from the `pow` module. #[test] fn p_consistent_exports_pow() { - use bitcoin_units::pow::CompactTarget; + use bitcoin_units::pow::{CompactTarget, Target, Work}; #[cfg(feature = "encoding")] use bitcoin_units::pow::{ CompactTargetDecoder, CompactTargetDecoderError, CompactTargetEncoder, @@ -552,9 +563,11 @@ impl<'a> Arbitrary<'a> for Structs { k: relative::NumberOf512Seconds::arbitrary(u)?, l: relative::NumberOfBlocks::arbitrary(u)?, m: pow::CompactTarget::from_consensus(u.int_in_range(0..=u32::MAX)?), - n: sequence::Sequence::arbitrary(u)?, - o: BlockTime::arbitrary(u)?, - p: Weight::arbitrary(u)?, + n: pow::Target::arbitrary(u)?, + o: pow::Work::arbitrary(u)?, + p: sequence::Sequence::arbitrary(u)?, + q: BlockTime::arbitrary(u)?, + r: Weight::arbitrary(u)?, }; Ok(a) } From ef3c7bfb3484a8227f580ef73f389d236e5847b8 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Fri, 2 Oct 2026 12:56:05 +0100 Subject: [PATCH 2/5] units: Add missing error types to API tests Several public error types are not in the `Errors` struct, so the API tests do not check their derives, `Send`, `Sync` or `Display`. The `CompactTargetDecoderError` is in `Errors` even though decoder errors are meant to be in `DecoderErrors`. Add the missing error types and move the decoder error. Assisted-by: Claude Opus 5.5 --- units/tests/api.rs | 60 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/units/tests/api.rs b/units/tests/api.rs index 91e9bf76b9..b7a5551f6d 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -140,6 +140,7 @@ struct Default { // These derives are the policy of `rust-bitcoin` not Rust API guidelines. #[derive(Debug, Clone, PartialEq, Eq)] // All public types implement Debug (C-DEBUG). struct Errors { + a: amount::error::BadPositionError, b: amount::error::InvalidCharacterError, c: amount::error::MissingDenominationError, d: amount::error::MissingDigitsError, @@ -154,17 +155,25 @@ struct Errors { #[cfg(feature = "serde")] m: fee_rate::serde::OverflowError, n: locktime::absolute::ConversionError, - o: locktime::absolute::ParseHeightError, - p: locktime::absolute::ParseTimeError, - q: locktime::relative::InvalidHeightError, - r: locktime::relative::InvalidTimeError, - s: locktime::relative::TimeOverflowError, - t: parse_int::ParseIntError, - u: parse_int::PrefixedHexError, - v: parse_int::UnprefixedHexError, - #[cfg(feature = "encoding")] - w: pow::CompactTargetDecoderError, - x: result::NumOpError, + o: locktime::absolute::IncompatibleHeightError, + p: locktime::absolute::IncompatibleTimeError, + q: locktime::absolute::ParseHeightError, + r: locktime::absolute::ParseTimeError, + s: locktime::relative::DisabledLockTimeError, + t: locktime::relative::IncompatibleHeightError, + u: locktime::relative::IncompatibleTimeError, + v: locktime::relative::InvalidHeightError, + w: locktime::relative::InvalidTimeError, + x: locktime::relative::IsSatisfiedByError, + y: locktime::relative::IsSatisfiedByHeightError, + z: locktime::relative::IsSatisfiedByTimeError, + aa: locktime::relative::TimeOverflowError, + ab: parse_int::ParseIntError, + ac: parse_int::PrefixedHexError, + ad: parse_int::UnprefixedHexError, + ae: pow::ParseTargetError, + af: pow::ParseWorkError, + ag: result::NumOpError, } /// A struct that includes all public decoder types. @@ -187,8 +196,9 @@ struct DecoderErrors { a: amount::error::AmountDecoderError, b: block::BlockHeightDecoderError, c: locktime::absolute::LockTimeDecoderError, - d: sequence::SequenceDecoderError, - e: time::BlockTimeDecoderError, + d: pow::CompactTargetDecoderError, + e: sequence::SequenceDecoderError, + f: time::BlockTimeDecoderError, } /// C-DEBUG-NONEMPTY: Tests that all public non-error types have non-empty Debug. @@ -267,6 +277,7 @@ fn c_good_err_display() { fn assert_display() {} + assert_display::(); assert_display::(); assert_display::(); assert_display::(); @@ -281,16 +292,26 @@ fn c_good_err_display() { #[cfg(feature = "serde")] assert_display::(); assert_display::(); + assert_display::(); + assert_display::(); assert_display::(); assert_display::(); + assert_display::(); + assert_display::(); + assert_display::(); assert_display::(); assert_display::(); + assert_display::(); + assert_display::(); + assert_display::(); assert_display::(); assert_display::(); assert_display::(); assert_display::(); #[cfg(feature = "encoding")] assert_display::(); + assert_display::(); + assert_display::(); assert_display::(); } @@ -465,12 +486,14 @@ fn p_consistent_exports_locktime_absolute() { #[test] fn p_consistent_exports_locktime_relative() { use bitcoin_units::locktime::relative::error::{ - DisabledLockTimeError as _, InvalidHeightError as _, InvalidTimeError as _, - TimeOverflowError as _, + DisabledLockTimeError as _, IncompatibleHeightError as _, IncompatibleTimeError as _, + InvalidHeightError as _, InvalidTimeError as _, IsSatisfiedByError as _, + IsSatisfiedByHeightError as _, IsSatisfiedByTimeError as _, TimeOverflowError as _, }; use bitcoin_units::locktime::relative::{ - DisabledLockTimeError, InvalidHeightError, InvalidTimeError, NumberOf512Seconds, - NumberOfBlocks, TimeOverflowError, + DisabledLockTimeError, IncompatibleHeightError, IncompatibleTimeError, InvalidHeightError, + InvalidTimeError, IsSatisfiedByError, IsSatisfiedByHeightError, IsSatisfiedByTimeError, + NumberOf512Seconds, NumberOfBlocks, TimeOverflowError, }; } @@ -489,7 +512,8 @@ fn p_consistent_exports_result() { /// P-CONSISTENT-EXPORTS: Tests that all types can be imported from the `pow` module. #[test] fn p_consistent_exports_pow() { - use bitcoin_units::pow::{CompactTarget, Target, Work}; + use bitcoin_units::pow::error::{ParseTargetError as _, ParseWorkError as _}; + use bitcoin_units::pow::{CompactTarget, ParseTargetError, ParseWorkError, Target, Work}; #[cfg(feature = "encoding")] use bitcoin_units::pow::{ CompactTargetDecoder, CompactTargetDecoderError, CompactTargetEncoder, From a518809aa108b16b8ab8cb5a5815161bba7facfd Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Fri, 2 Oct 2026 12:56:41 +0100 Subject: [PATCH 3/5] units: Check all serde types in API tests `c_serde` only checks some of the types that implement the serde traits. Add the remaining locktime, time and pow types. Assisted-by: Claude Opus 5.5 --- units/tests/api.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/units/tests/api.rs b/units/tests/api.rs index b7a5551f6d..5e26ff3836 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -333,10 +333,20 @@ fn c_object() { fn c_serde() { fn assert_serde serde::Deserialize<'de>>() {} + assert_serde::(); + assert_serde::(); + assert_serde::(); + assert_serde::(); + assert_serde::(); + assert_serde::(); assert_serde::(); assert_serde::(); assert_serde::(); assert_serde::(); + assert_serde::(); + assert_serde::(); + assert_serde::(); + assert_serde::(); assert_serde::(); assert_serde::(); } From 0631af0e3b114f88ed6ea99e2e894b709b046647 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Fri, 2 Oct 2026 19:49:27 +0100 Subject: [PATCH 4/5] units: Check decoder traits in API tests Decoder errors are listed in `DecoderErrors`, but `c_send_sync` only checks the general error aggregate, `Decoders` is not checked at all and `c_good_err_display` only covers one decoder error. Check `Send` and `Sync` for all decoders and decoder errors, and `Display` for all decoder errors, when encoding is enabled. Assisted-by: Claude Opus 5.5 --- units/tests/api.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/units/tests/api.rs b/units/tests/api.rs index 5e26ff3836..d3203c133d 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -268,6 +268,14 @@ fn c_send_sync() { // Error types should implement the Send and Sync traits (C-GOOD-ERR). assert_send::(); assert_sync::(); + + #[cfg(feature = "encoding")] + { + assert_send::(); + assert_sync::(); + assert_send::(); + assert_sync::(); + } } /// C-GOOD-ERR: Tests that all public error types implement Display. @@ -308,11 +316,19 @@ fn c_good_err_display() { assert_display::(); assert_display::(); assert_display::(); - #[cfg(feature = "encoding")] - assert_display::(); assert_display::(); assert_display::(); assert_display::(); + + #[cfg(feature = "encoding")] + { + assert_display::(); + assert_display::(); + assert_display::(); + assert_display::(); + assert_display::(); + assert_display::(); + } } /// C-OBJECT: Tests that traits are object-safe where appropriate. From 9a1fa36f05d15bd772801cf803da273bdb2434e0 Mon Sep 17 00:00:00 2001 From: "Jamil Lambert, PhD" Date: Fri, 2 Oct 2026 20:01:48 +0100 Subject: [PATCH 5/5] units: Check error types implement Error No API test checks that the public error types implement `std::error::Error`, so a missing impl would go unnoticed. Add a test that checks every public error type when std is enabled. Assisted-by: Claude Opus 5.5 --- units/tests/api.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/units/tests/api.rs b/units/tests/api.rs index d3203c133d..935d7f2ee1 100644 --- a/units/tests/api.rs +++ b/units/tests/api.rs @@ -331,6 +331,58 @@ fn c_good_err_display() { } } +/// C-GOOD-ERR: Tests that all public error types implement `std::error::Error`. +#[test] +#[cfg(feature = "std")] +fn c_good_err_error() { + fn assert_error() {} + + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + #[cfg(feature = "serde")] + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + + #[cfg(feature = "encoding")] + { + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + assert_error::(); + } +} + /// C-OBJECT: Tests that traits are object-safe where appropriate. #[test] fn c_object() {