Skip to content

Commit 1c40552

Browse files
committed
Merge rust-bitcoin#3777: Implement Arbitrary for units types
04dfe8d Add api test to check Arbitrary impls (Shing Him Ng) 678fc71 Implement Arbitrary for units types (Shing Him Ng) Pull request description: Implement Arbitrary for the rest of the types in `units`. Also moved the implementation in `FeeRate` right before the `tests` module Closes rust-bitcoin#3705 ACKs for top commit: apoelstra: ACK 04dfe8d; successfully ran local tests tcharding: ACK 04dfe8d Tree-SHA512: 156bd26d4de85d484711d476df1d2758805387125209f0307aa786dd1585ff9953dbe41b0864b00ae101419176647e3bde7994ed9257c18307d161463b1c8d2e
2 parents 989db7c + 04dfe8d commit 1c40552

File tree

7 files changed

+177
-8
lines changed

7 files changed

+177
-8
lines changed

api/units/all-features.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,14 @@ impl serde::ser::Serialize for bitcoin_units::locktime::relative::Time
624624
impl serde::ser::Serialize for bitcoin_units::weight::Weight
625625
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::Amount
626626
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::SignedAmount
627+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::amount::Denomination
628+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockHeight
629+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::block::BlockInterval
627630
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::fee_rate::FeeRate
631+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::Height
632+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::absolute::Time
633+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::relative::Height
634+
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::locktime::relative::Time
628635
impl<'a> arbitrary::Arbitrary<'a> for bitcoin_units::weight::Weight
629636
impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::Amount> for bitcoin_units::Amount
630637
impl<'a> core::iter::traits::accum::Sum<&'a bitcoin_units::SignedAmount> for bitcoin_units::SignedAmount
@@ -894,6 +901,7 @@ pub fn bitcoin_units::SignedAmount::unchecked_add(self, rhs: bitcoin_units::Sign
894901
pub fn bitcoin_units::SignedAmount::unchecked_sub(self, rhs: bitcoin_units::SignedAmount) -> bitcoin_units::SignedAmount
895902
pub fn bitcoin_units::SignedAmount::unsigned_abs(self) -> bitcoin_units::Amount
896903
pub fn bitcoin_units::amount::CheckedSum::checked_sum(self) -> core::option::Option<R>
904+
pub fn bitcoin_units::amount::Denomination::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
897905
pub fn bitcoin_units::amount::Denomination::clone(&self) -> bitcoin_units::amount::Denomination
898906
pub fn bitcoin_units::amount::Denomination::eq(&self, other: &bitcoin_units::amount::Denomination) -> bool
899907
pub fn bitcoin_units::amount::Denomination::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
@@ -981,6 +989,7 @@ pub fn bitcoin_units::amount::serde::as_str::opt::deserialize<'d, A: bitcoin_uni
981989
pub fn bitcoin_units::amount::serde::as_str::opt::serialize<A: bitcoin_units::amount::serde::SerdeAmountForOpt, S: serde::ser::Serializer>(a: &core::option::Option<A>, s: S) -> core::result::Result<<S as serde::ser::Serializer>::Ok, <S as serde::ser::Serializer>::Error>
982990
pub fn bitcoin_units::amount::serde::as_str::serialize<A: bitcoin_units::amount::serde::SerdeAmount, S: serde::ser::Serializer>(a: &A, s: S) -> core::result::Result<<S as serde::ser::Serializer>::Ok, <S as serde::ser::Serializer>::Error>
983991
pub fn bitcoin_units::block::BlockHeight::add(self, rhs: bitcoin_units::block::BlockInterval) -> Self::Output
992+
pub fn bitcoin_units::block::BlockHeight::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
984993
pub fn bitcoin_units::block::BlockHeight::clone(&self) -> bitcoin_units::block::BlockHeight
985994
pub fn bitcoin_units::block::BlockHeight::cmp(&self, other: &bitcoin_units::block::BlockHeight) -> core::cmp::Ordering
986995
pub fn bitcoin_units::block::BlockHeight::deserialize<__D>(__deserializer: __D) -> core::result::Result<Self, <__D as serde::de::Deserializer>::Error> where __D: serde::de::Deserializer<'de>
@@ -999,6 +1008,7 @@ pub fn bitcoin_units::block::BlockHeight::try_from(s: alloc::boxed::Box<str>) ->
9991008
pub fn bitcoin_units::block::BlockHeight::try_from(s: alloc::string::String) -> core::result::Result<Self, Self::Error>
10001009
pub fn bitcoin_units::block::BlockInterval::add(self, rhs: bitcoin_units::block::BlockInterval) -> Self::Output
10011010
pub fn bitcoin_units::block::BlockInterval::add_assign(&mut self, rhs: bitcoin_units::block::BlockInterval)
1011+
pub fn bitcoin_units::block::BlockInterval::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
10021012
pub fn bitcoin_units::block::BlockInterval::clone(&self) -> bitcoin_units::block::BlockInterval
10031013
pub fn bitcoin_units::block::BlockInterval::cmp(&self, other: &bitcoin_units::block::BlockInterval) -> core::cmp::Ordering
10041014
pub fn bitcoin_units::block::BlockInterval::default() -> bitcoin_units::block::BlockInterval
@@ -1052,6 +1062,7 @@ pub fn bitcoin_units::locktime::absolute::ConversionError::clone(&self) -> bitco
10521062
pub fn bitcoin_units::locktime::absolute::ConversionError::eq(&self, other: &bitcoin_units::locktime::absolute::ConversionError) -> bool
10531063
pub fn bitcoin_units::locktime::absolute::ConversionError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
10541064
pub fn bitcoin_units::locktime::absolute::ConversionError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
1065+
pub fn bitcoin_units::locktime::absolute::Height::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
10551066
pub fn bitcoin_units::locktime::absolute::Height::clone(&self) -> bitcoin_units::locktime::absolute::Height
10561067
pub fn bitcoin_units::locktime::absolute::Height::cmp(&self, other: &bitcoin_units::locktime::absolute::Height) -> core::cmp::Ordering
10571068
pub fn bitcoin_units::locktime::absolute::Height::deserialize<D>(deserializer: D) -> core::result::Result<Self, <D as serde::de::Deserializer>::Error> where D: serde::de::Deserializer<'de>
@@ -1074,6 +1085,7 @@ pub fn bitcoin_units::locktime::absolute::ParseTimeError::clone(&self) -> bitcoi
10741085
pub fn bitcoin_units::locktime::absolute::ParseTimeError::eq(&self, other: &bitcoin_units::locktime::absolute::ParseTimeError) -> bool
10751086
pub fn bitcoin_units::locktime::absolute::ParseTimeError::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
10761087
pub fn bitcoin_units::locktime::absolute::ParseTimeError::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
1088+
pub fn bitcoin_units::locktime::absolute::Time::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
10771089
pub fn bitcoin_units::locktime::absolute::Time::clone(&self) -> bitcoin_units::locktime::absolute::Time
10781090
pub fn bitcoin_units::locktime::absolute::Time::cmp(&self, other: &bitcoin_units::locktime::absolute::Time) -> core::cmp::Ordering
10791091
pub fn bitcoin_units::locktime::absolute::Time::deserialize<D>(deserializer: D) -> core::result::Result<Self, <D as serde::de::Deserializer>::Error> where D: serde::de::Deserializer<'de>
@@ -1087,6 +1099,7 @@ pub fn bitcoin_units::locktime::absolute::Time::serialize<S>(&self, serializer:
10871099
pub fn bitcoin_units::locktime::absolute::Time::try_from(s: &str) -> core::result::Result<Self, Self::Error>
10881100
pub fn bitcoin_units::locktime::absolute::Time::try_from(s: alloc::boxed::Box<str>) -> core::result::Result<Self, Self::Error>
10891101
pub fn bitcoin_units::locktime::absolute::Time::try_from(s: alloc::string::String) -> core::result::Result<Self, Self::Error>
1102+
pub fn bitcoin_units::locktime::relative::Height::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
10901103
pub fn bitcoin_units::locktime::relative::Height::clone(&self) -> bitcoin_units::locktime::relative::Height
10911104
pub fn bitcoin_units::locktime::relative::Height::cmp(&self, other: &bitcoin_units::locktime::relative::Height) -> core::cmp::Ordering
10921105
pub fn bitcoin_units::locktime::relative::Height::default() -> bitcoin_units::locktime::relative::Height
@@ -1102,6 +1115,7 @@ pub fn bitcoin_units::locktime::relative::Height::try_from(h: bitcoin_units::blo
11021115
pub fn bitcoin_units::locktime::relative::Height::try_from(s: &str) -> core::result::Result<Self, Self::Error>
11031116
pub fn bitcoin_units::locktime::relative::Height::try_from(s: alloc::boxed::Box<str>) -> core::result::Result<Self, Self::Error>
11041117
pub fn bitcoin_units::locktime::relative::Height::try_from(s: alloc::string::String) -> core::result::Result<Self, Self::Error>
1118+
pub fn bitcoin_units::locktime::relative::Time::arbitrary(u: &mut arbitrary::unstructured::Unstructured<'a>) -> arbitrary::error::Result<Self>
11051119
pub fn bitcoin_units::locktime::relative::Time::clone(&self) -> bitcoin_units::locktime::relative::Time
11061120
pub fn bitcoin_units::locktime::relative::Time::cmp(&self, other: &bitcoin_units::locktime::relative::Time) -> core::cmp::Ordering
11071121
pub fn bitcoin_units::locktime::relative::Time::default() -> bitcoin_units::locktime::relative::Time

units/src/amount/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ use core::cmp::Ordering;
2020
use core::fmt;
2121
use core::str::FromStr;
2222

23+
#[cfg(feature = "arbitrary")]
24+
use arbitrary::{Arbitrary, Unstructured};
25+
2326
use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner};
2427

2528
#[rustfmt::skip] // Keep public re-exports separate.
@@ -600,3 +603,18 @@ mod sealed {
600603
impl<T> Sealed<Amount> for T where T: Iterator<Item = Amount> {}
601604
impl<T> Sealed<SignedAmount> for T where T: Iterator<Item = SignedAmount> {}
602605
}
606+
607+
#[cfg(feature = "arbitrary")]
608+
impl<'a> Arbitrary<'a> for Denomination {
609+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
610+
let choice = u.int_in_range(0..=5)?;
611+
match choice {
612+
0 => Ok(Denomination::Bitcoin),
613+
1 => Ok(Denomination::CentiBitcoin),
614+
2 => Ok(Denomination::MilliBitcoin),
615+
3 => Ok(Denomination::MicroBitcoin),
616+
4 => Ok(Denomination::Bit),
617+
_ => Ok(Denomination::Satoshi),
618+
}
619+
}
620+
}

units/src/block.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
1414
use core::{fmt, ops};
1515

16+
#[cfg(feature = "arbitrary")]
17+
use arbitrary::{Arbitrary, Unstructured};
1618
#[cfg(feature = "serde")]
1719
use serde::{Deserialize, Serialize};
1820

@@ -248,6 +250,30 @@ impl<'a> core::iter::Sum<&'a BlockInterval> for BlockInterval {
248250
}
249251
}
250252

253+
#[cfg(feature = "arbitrary")]
254+
impl<'a> Arbitrary<'a> for BlockHeight {
255+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
256+
let choice = u.int_in_range(0..=2)?;
257+
match choice {
258+
0 => Ok(BlockHeight::MIN),
259+
1 => Ok(BlockHeight::MAX),
260+
_ => Ok(BlockHeight::from_u32(u32::arbitrary(u)?)),
261+
}
262+
}
263+
}
264+
265+
#[cfg(feature = "arbitrary")]
266+
impl<'a> Arbitrary<'a> for BlockInterval {
267+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
268+
let choice = u.int_in_range(0..=2)?;
269+
match choice {
270+
0 => Ok(BlockInterval::MIN),
271+
1 => Ok(BlockInterval::MAX),
272+
_ => Ok(BlockInterval::from_u32(u32::arbitrary(u)?)),
273+
}
274+
}
275+
}
276+
251277
#[cfg(test)]
252278
mod tests {
253279
use super::*;

units/src/fee_rate.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,6 @@ impl FeeRate {
161161
}
162162
}
163163

164-
#[cfg(feature = "arbitrary")]
165-
impl<'a> Arbitrary<'a> for FeeRate {
166-
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
167-
let f = u64::arbitrary(u)?;
168-
Ok(FeeRate(f))
169-
}
170-
}
171-
172164
/// Alternative will display the unit.
173165
impl fmt::Display for FeeRate {
174166
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -245,6 +237,20 @@ impl<'a> core::iter::Sum<&'a FeeRate> for FeeRate {
245237

246238
crate::impl_parse_str_from_int_infallible!(FeeRate, u64, from_sat_per_kwu);
247239

240+
#[cfg(feature = "arbitrary")]
241+
impl<'a> Arbitrary<'a> for FeeRate {
242+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
243+
let choice = u.int_in_range(0..=4)?;
244+
match choice {
245+
0 => Ok(FeeRate::MIN),
246+
1 => Ok(FeeRate::BROADCAST_MIN),
247+
2 => Ok(FeeRate::DUST),
248+
3 => Ok(FeeRate::MAX),
249+
_ => Ok(FeeRate(u64::arbitrary(u)?)),
250+
}
251+
}
252+
}
253+
248254
#[cfg(test)]
249255
mod tests {
250256
use super::*;

units/src/locktime/absolute.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
use core::fmt;
66

7+
#[cfg(feature = "arbitrary")]
8+
use arbitrary::{Arbitrary, Unstructured};
79
use internals::error::InputString;
810

911
use crate::parse::{self, ParseIntError};
@@ -386,6 +388,40 @@ impl From<ConversionError> for ParseError {
386388
fn from(value: ConversionError) -> Self { Self::Conversion(value.input.into()) }
387389
}
388390

391+
#[cfg(feature = "arbitrary")]
392+
impl<'a> Arbitrary<'a> for Height {
393+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
394+
let choice = u.int_in_range(0..=2)?;
395+
match choice {
396+
0 => Ok(Height::MIN),
397+
1 => Ok(Height::MAX),
398+
_ => {
399+
let min = Height::MIN.to_consensus_u32();
400+
let max = Height::MAX.to_consensus_u32();
401+
let h = u.int_in_range(min..=max)?;
402+
Ok(Height::from_consensus(h).unwrap())
403+
}
404+
}
405+
}
406+
}
407+
408+
#[cfg(feature = "arbitrary")]
409+
impl<'a> Arbitrary<'a> for Time {
410+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
411+
let choice = u.int_in_range(0..=2)?;
412+
match choice {
413+
0 => Ok(Time::MIN),
414+
1 => Ok(Time::MAX),
415+
_ => {
416+
let min = Time::MIN.to_consensus_u32();
417+
let max = Time::MAX.to_consensus_u32();
418+
let t = u.int_in_range(min..=max)?;
419+
Ok(Time::from_consensus(t).unwrap())
420+
}
421+
}
422+
}
423+
}
424+
389425
#[cfg(test)]
390426
mod tests {
391427
#[cfg(feature = "serde")]

units/src/locktime/relative.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
use core::fmt;
66

7+
#[cfg(feature = "arbitrary")]
8+
use arbitrary::{Arbitrary, Unstructured};
79
#[cfg(feature = "serde")]
810
use serde::{Deserialize, Serialize};
911

@@ -159,6 +161,32 @@ impl fmt::Display for TimeOverflowError {
159161
#[cfg(feature = "std")]
160162
impl std::error::Error for TimeOverflowError {}
161163

164+
#[cfg(feature = "arbitrary")]
165+
impl<'a> Arbitrary<'a> for Height {
166+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
167+
let choice = u.int_in_range(0..=2)?;
168+
169+
match choice {
170+
0 => Ok(Height::MIN),
171+
1 => Ok(Height::MAX),
172+
_ => Ok(Height::from_height(u16::arbitrary(u)?)),
173+
}
174+
}
175+
}
176+
177+
#[cfg(feature = "arbitrary")]
178+
impl<'a> Arbitrary<'a> for Time {
179+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
180+
let choice = u.int_in_range(0..=2)?;
181+
182+
match choice {
183+
0 => Ok(Time::MIN),
184+
1 => Ok(Time::MAX),
185+
_ => Ok(Time::from_512_second_intervals(u16::arbitrary(u)?)),
186+
}
187+
}
188+
}
189+
162190
#[cfg(test)]
163191
mod tests {
164192
use super::*;

units/tests/api.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use bitcoin_units::{
2525
amount, block, fee_rate, locktime, parse, weight, Amount, BlockHeight, BlockInterval, FeeRate,
2626
SignedAmount, Weight,
2727
};
28+
#[cfg(feature = "arbitrary")]
29+
use arbitrary::{Arbitrary, Unstructured};
2830

2931
/// A struct that includes all public non-error enums.
3032
#[derive(Debug)] // All public types implement Debug (C-DEBUG).
@@ -263,3 +265,42 @@ fn regression_default() {
263265
};
264266
assert_eq!(got, want);
265267
}
268+
269+
#[cfg(feature = "arbitrary")]
270+
impl<'a> Arbitrary<'a> for Types {
271+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
272+
let a = Types { a: Enums::arbitrary(u)?, b: Structs::arbitrary(u)? };
273+
Ok(a)
274+
}
275+
}
276+
277+
#[cfg(feature = "arbitrary")]
278+
impl<'a> Arbitrary<'a> for Structs {
279+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
280+
let a = Structs {
281+
a: Amount::arbitrary(u)?,
282+
// Skip the `Display` type.
283+
b: Amount::MAX.display_in(amount::Denomination::Bitcoin),
284+
c: SignedAmount::arbitrary(u)?,
285+
d: BlockHeight::arbitrary(u)?,
286+
e: BlockInterval::arbitrary(u)?,
287+
f: FeeRate::arbitrary(u)?,
288+
g: absolute::Height::arbitrary(u)?,
289+
h: absolute::Time::arbitrary(u)?,
290+
i: relative::Height::arbitrary(u)?,
291+
j: relative::Time::arbitrary(u)?,
292+
k: Weight::arbitrary(u)?,
293+
};
294+
Ok(a)
295+
}
296+
}
297+
298+
#[cfg(feature = "arbitrary")]
299+
impl<'a> Arbitrary<'a> for Enums {
300+
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
301+
let a = Enums {
302+
a: amount::Denomination::arbitrary(u)?,
303+
};
304+
Ok(a)
305+
}
306+
}

0 commit comments

Comments
 (0)