|
| 1 | +use std::sync::LazyLock; |
| 2 | + |
| 3 | +// All (negative) integers which are at or near a power of two to test |
| 4 | +// boundary conditions. We use strings so we can convert to any type using |
| 5 | +// parsing, while still being able to use the *position* in ORDERED_VALS for |
| 6 | +// comparisons. |
| 7 | +static ORDERED_VALS: LazyLock<Vec<String>> = LazyLock::new(|| { |
| 8 | + let mut pos_int_vals = Vec::new(); |
| 9 | + for exp in 0..=127 { |
| 10 | + let val = 1_u128 << exp; |
| 11 | + pos_int_vals.push(val.saturating_sub(2)); |
| 12 | + pos_int_vals.push(val.saturating_sub(1)); |
| 13 | + pos_int_vals.push(val); |
| 14 | + pos_int_vals.push(val.saturating_add(1)); |
| 15 | + pos_int_vals.push(val.saturating_add(2)); |
| 16 | + } |
| 17 | + pos_int_vals.sort(); |
| 18 | + pos_int_vals.dedup(); |
| 19 | + |
| 20 | + let mut pos_str_vals: Vec<_> = pos_int_vals.iter().map(|i| i.to_string()).collect(); |
| 21 | + |
| 22 | + // These are manual because the upper ones overflow even u128. |
| 23 | + pos_str_vals.push("340282366920938463463374607431768211454".to_owned()); // 2**128 - 2 |
| 24 | + pos_str_vals.push("340282366920938463463374607431768211455".to_owned()); // 2**128 - 1 |
| 25 | + pos_str_vals.push("340282366920938463463374607431768211456".to_owned()); // 2**128 |
| 26 | + pos_str_vals.push("340282366920938463463374607431768211457".to_owned()); // 2**128 + 1 |
| 27 | + pos_str_vals.push("340282366920938463463374607431768211458".to_owned()); // 2**128 + 2 |
| 28 | + |
| 29 | + let mut out = Vec::new(); |
| 30 | + for val in pos_str_vals[1..].iter().rev() { |
| 31 | + out.push(format!("-{val}")); |
| 32 | + } |
| 33 | + out.extend(pos_str_vals); |
| 34 | + out |
| 35 | +}); |
| 36 | + |
| 37 | +macro_rules! make_checked_cast_test { |
| 38 | + ($Src:ident as [$($Dst:ident),*]) => {$( |
| 39 | + #[test] |
| 40 | + #[allow(non_snake_case)] |
| 41 | + fn ${concat(test_checked_cast_, $Src, _to_, $Dst)}() { |
| 42 | + for val in ORDERED_VALS.iter() { |
| 43 | + if let Some(src) = val.parse::<$Src>().ok() { |
| 44 | + let dst: Option<$Dst> = val.parse().ok(); |
| 45 | + assert_eq!(src.checked_cast::<$Dst>(), dst); |
| 46 | + } |
| 47 | + } |
| 48 | + } |
| 49 | + )*} |
| 50 | +} |
| 51 | + |
| 52 | +macro_rules! make_bounded_cast_test { |
| 53 | + (|$src:ident| $raw:expr, $Src:ident as [$($Dst:ident),*]) => {$( |
| 54 | + #[test] |
| 55 | + #[allow(non_snake_case)] |
| 56 | + fn ${concat(test_bounded_cast_, $Src, _to_, $Dst)}() { |
| 57 | + let ord_idx = |s| ORDERED_VALS.iter().position(|v| *v == s).unwrap(); |
| 58 | + let dst_min_idx = ord_idx(<$Dst>::MIN.to_string()); |
| 59 | + let dst_max_idx = ord_idx(<$Dst>::MAX.to_string()); |
| 60 | + for (val_idx, val) in ORDERED_VALS.iter().enumerate() { |
| 61 | + if let Some($src) = val.parse::<$Src>().ok() { |
| 62 | + let dst: Option<$Dst> = val.parse().ok(); |
| 63 | + |
| 64 | + assert_eq!($src.wrapping_cast::<$Dst>(), $raw as $Dst); |
| 65 | + |
| 66 | + if val_idx > dst_max_idx { |
| 67 | + assert_eq!($src.saturating_cast::<$Dst>(), <$Dst>::MAX); |
| 68 | + } else if val_idx < dst_min_idx { |
| 69 | + assert_eq!($src.saturating_cast::<$Dst>(), <$Dst>::MIN); |
| 70 | + } else { |
| 71 | + assert_eq!($src.saturating_cast::<$Dst>(), dst.unwrap()); |
| 72 | + } |
| 73 | + } |
| 74 | + } |
| 75 | + } |
| 76 | + )*} |
| 77 | +} |
| 78 | + |
| 79 | +macro_rules! make_tests_for_src { |
| 80 | + (|$src:ident| $raw:expr, [$($Src:ident),*]) => {$( |
| 81 | + make_checked_cast_test!( $Src as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]); |
| 82 | + make_bounded_cast_test!(|$src| $raw, $Src as [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]); |
| 83 | + |
| 84 | + // NonZero types are not (yet) implemented. |
| 85 | + // make_checked_cast_test!($Src as [ |
| 86 | + // NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize, |
| 87 | + // NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize |
| 88 | + // ]); |
| 89 | + )*} |
| 90 | +} |
| 91 | + |
| 92 | +make_tests_for_src!(|x| x, [u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize]); |
| 93 | + |
| 94 | +// NonZero types are not (yet) implemented. |
| 95 | +// make_tests_for_src!( |
| 96 | +// |x| x.get(), |
| 97 | +// [ |
| 98 | +// NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize, |
| 99 | +// NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize |
| 100 | +// ] |
| 101 | +// ); |
0 commit comments