From 0ff9f8ba1e71f94da2b979ba27a8f9ac6c4ce033 Mon Sep 17 00:00:00 2001 From: Niklas Saari Date: Wed, 4 Sep 2024 23:58:37 +0300 Subject: [PATCH] More integer tests --- tests/integer.rs | 128 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 26 deletions(-) diff --git a/tests/integer.rs b/tests/integer.rs index ffe50de5..ca1dbe2a 100644 --- a/tests/integer.rs +++ b/tests/integer.rs @@ -1,3 +1,67 @@ +macro_rules! assert_integer_round_trip { + ($t:ty, $value:expr, $expected_unsigned:expr, $expected_signed:expr) => {{ + let value = <$t>::try_from($value).unwrap(); + + // Test unsigned bytes + let (unsigned_bytes, unsigned_needed) = value.to_unsigned_bytes_be(); + assert_eq!( + &unsigned_bytes.as_ref()[..unsigned_needed], + $expected_unsigned, + "Unsigned bytes mismatch for {}", + stringify!($value) + ); + + // Only test unsigned round-trip for non-negative values or unsigned types + #[allow(unused_comparisons)] + if $value >= 0 || stringify!($t).starts_with('u') { + assert_eq!( + <$t>::try_from_unsigned_bytes( + &unsigned_bytes.as_ref()[..unsigned_needed], + rasn::Codec::Oer + ) + .ok(), + Some(value), + "Round-trip failed for unsigned bytes of {}", + stringify!($value) + ); + } + + // Test signed bytes + let (signed_bytes, signed_needed) = value.to_signed_bytes_be(); + assert_eq!( + &signed_bytes.as_ref()[..signed_needed], + $expected_signed, + "Signed bytes mismatch for {}", + stringify!($value) + ); + + // Always test signed round-trip + assert_eq!( + <$t>::try_from_signed_bytes(&signed_bytes.as_ref()[..signed_needed], rasn::Codec::Oer) + .ok(), + Some(value), + "Round-trip failed for signed bytes of {}", + stringify!($value) + ); + // Round trip with Integer type should work for any type with all values + let integer = Integer::from($value); + let (bytes, needed) = integer.to_signed_bytes_be(); + assert_eq!( + Integer::try_from_signed_bytes(&bytes.as_ref()[..needed], rasn::Codec::Oer).ok(), + Some($value.into()), + "Round-trip failed for Integer({})", + stringify!($value) + ); + // Check that encoding matches the signed expected bytes for Integer type + assert_eq!( + &bytes.as_ref()[..needed], + $expected_signed, + "Signed bytes mismatch for Integer({})", + stringify!($value) + ); + }}; +} + macro_rules! test_integer_conversions_and_operations { ($($t:ident),*) => { #[cfg(test)] @@ -12,42 +76,54 @@ macro_rules! test_integer_conversions_and_operations { if min >= isize::MIN as i128 { assert!(matches!(min.into(), Integer::Primitive(_))); - } - else { + } else { assert!(matches!(min.into(), Integer::Variable(_))); } if max <= isize::MAX as u128 { assert!(matches!(max.into(), Integer::Primitive(_))); - }else { + } else { assert!(matches!(max.into(), Integer::Variable(_))); } - let value = 5 as $t; - let (unsigned_unsigned_bytes, needed) = value.to_unsigned_bytes_be(); - assert_eq!(&unsigned_unsigned_bytes.as_ref()[..needed], &[5]); - let (signed_unsigned_bytes, needed) = value.to_signed_bytes_be(); - assert_eq!(&signed_unsigned_bytes.as_ref()[..needed], &[5]); - let value = $t::try_from(128); - #[allow(irrefutable_let_patterns)] - if let Ok(number) = value { - let (unsigned_bytes, needed) = number.to_unsigned_bytes_be(); - assert_eq!(&unsigned_bytes.as_ref()[..needed], &[128]); - let (signed_bytes, needed) = number.to_signed_bytes_be(); - assert_eq!(&signed_bytes.as_ref()[..needed], &[0, 128]); + // Test positive values + assert_integer_round_trip!($t, 1, &[1], &[1]); + + // Test some signed maximum values, should be identical to unsigned + if <$t>::MAX as u128 >= i8::MAX as u128 { + assert_integer_round_trip!($t, i8::MAX as $t, &[127], &[127]); + } + // Even if the type is wider than 2 bytes, the value remains the same + if <$t>::MAX as u128 >= i16::MAX as u128 { + assert_integer_round_trip!($t, i16::MAX as $t, &[127, 255], &[127, 255]); + // 127 + 1 results to leading zero for signed types + assert_integer_round_trip!($t, 128, &[128], &[0, 128]); } - let value = $t::try_from(-5); - #[allow(irrefutable_let_patterns)] - if let Ok(number) = value { - // Signed bytes and unsigned bytes are the same for negative numbers - // However, when converting the actual integer, they mean different things - // 2's complement representation is ignored when converting unsigned bytes to whole number - // So "needed" includes all leading ones - let (unsigned_bytes, needed) = number.to_unsigned_bytes_be(); - assert_eq!(unsigned_bytes.as_ref()[..needed].last().unwrap(), &251); - let (signed_bytes, needed) = number.to_signed_bytes_be(); - assert_eq!(&signed_bytes.as_ref()[..needed], &[251]); + if <$t>::MAX as u128 >= i32::MAX as u128 { + assert_integer_round_trip!($t, i32::MAX as $t, &[127, 255, 255, 255], &[127, 255, 255, 255]); + // 32_767 + 1 results to leading zero for signed types + assert_integer_round_trip!($t, (i16::MAX as $t + 1), &[128, 0], &[0, 128, 0]); } + if <$t>::MAX as u128 >= i64::MAX as u128 { + assert_integer_round_trip!($t, i64::MAX as $t, &[127, 255, 255, 255, 255, 255, 255, 255], &[127, 255, 255, 255, 255, 255, 255, 255]); + } + + // Test negative values for signed types + match stringify!($t) { + "i8" => { + assert_integer_round_trip!($t, -1, &[255], &[255]); + }, + "i16" => { + assert_integer_round_trip!($t, -1, &[255, 255], &[255]); + }, + "i32" => { + assert_integer_round_trip!($t, -1, &[255, 255, 255, 255], &[255]); + }, + "i64" => { + assert_integer_round_trip!($t, -1, &[255, 255, 255, 255, 255, 255, 255, 255], &[255]); + }, + _ => {}, + } } )*