#![cfg(feature = "num-bigint")]
use dcbor::prelude::*;
use num_bigint::{BigInt, BigUint};
#[test]
fn rfc8949_test_vector_2_pow_64() {
let expected_hex = "c249010000000000000000";
let expected_value = BigUint::from(u64::MAX) + 1u32;
let cbor = CBOR::from(expected_value.clone());
assert_eq!(hex::encode(cbor.to_cbor_data()), expected_hex);
let decoded_cbor = CBOR::try_from_hex(expected_hex).unwrap();
let decoded: BigUint = decoded_cbor.try_into().unwrap();
assert_eq!(decoded, expected_value);
}
#[test]
fn rfc8949_test_vector_neg_2_pow_64_minus_1() {
let expected_hex = "c349010000000000000000";
let big_2_64: BigInt = BigInt::from(1) << 64;
let sum: BigInt = big_2_64 + 1;
let expected_value = -sum;
let cbor = CBOR::from(expected_value.clone());
assert_eq!(hex::encode(cbor.to_cbor_data()), expected_hex);
let decoded_cbor = CBOR::try_from_hex(expected_hex).unwrap();
let decoded: BigInt = decoded_cbor.try_into().unwrap();
assert_eq!(decoded, expected_value);
}
#[test]
fn rfc8949_example_bignum_encoding() {
let value = BigUint::from(1u128) << 64;
let cbor = CBOR::from(value);
let bytes = cbor.to_cbor_data();
assert_eq!(bytes[0], 0xc2);
assert_eq!(bytes[1], 0x49);
assert_eq!(
&bytes[2..],
&[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
);
}
#[test]
fn biguint_roundtrip_zero() {
let big = BigUint::from(0u32);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'')");
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn biguint_roundtrip_one() {
let big = BigUint::from(1u32);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'01')");
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn biguint_roundtrip_255() {
let big = BigUint::from(255u32);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'ff')");
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn biguint_roundtrip_256() {
let big = BigUint::from(256u32);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'0100')");
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn biguint_roundtrip_u64_max() {
let big = BigUint::from(u64::MAX);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'ffffffffffffffff')");
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn biguint_roundtrip_over_u64() {
let big = BigUint::from(u64::MAX) + 1u32;
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic_flat(), "2(h'010000000000000000')");
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn biguint_roundtrip_large() {
let big: BigUint = BigUint::from(1u32) << 200;
let cbor = CBOR::from(big.clone());
let decoded: BigUint = cbor.clone().try_into().unwrap();
assert_eq!(decoded, big);
assert!(cbor.diagnostic_flat().starts_with("2(h'"));
}
#[test]
fn bigint_roundtrip_zero() {
let big = BigInt::from(0);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_positive_one() {
let big = BigInt::from(1);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'01')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_positive_256() {
let big = BigInt::from(256);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "2(h'0100')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_negative_one() {
let big = BigInt::from(-1);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "3(h'00')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_negative_two() {
let big = BigInt::from(-2);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "3(h'01')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_negative_256() {
let big = BigInt::from(-256);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "3(h'ff')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_negative_257() {
let big = BigInt::from(-257);
let cbor = CBOR::from(big.clone());
assert_eq!(cbor.diagnostic(), "3(h'0100')");
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, big);
}
#[test]
fn bigint_roundtrip_large_positive() {
let big: BigInt = BigInt::from(1) << 200;
let cbor = CBOR::from(big.clone());
let decoded: BigInt = cbor.clone().try_into().unwrap();
assert_eq!(decoded, big);
assert!(cbor.diagnostic_flat().starts_with("2(h'"));
}
#[test]
fn bigint_roundtrip_large_negative() {
let shifted: BigInt = BigInt::from(1) << 200;
let big = -shifted;
let cbor = CBOR::from(big.clone());
let decoded: BigInt = cbor.clone().try_into().unwrap();
assert_eq!(decoded, big);
assert!(cbor.diagnostic_flat().starts_with("3(h'"));
}
#[test]
fn decode_plain_unsigned_to_biguint() {
let cbor = CBOR::from(12345u64);
let big: BigUint = cbor.try_into().unwrap();
assert_eq!(big, BigUint::from(12345u64));
}
#[test]
fn decode_plain_unsigned_to_bigint() {
let cbor = CBOR::from(12345u64);
let big: BigInt = cbor.try_into().unwrap();
assert_eq!(big, BigInt::from(12345));
}
#[test]
fn decode_plain_negative_to_bigint() {
let cbor = CBOR::from(-12345i64);
let big: BigInt = cbor.try_into().unwrap();
assert_eq!(big, BigInt::from(-12345));
}
#[test]
fn decode_plain_max_u64_to_biguint() {
let cbor = CBOR::from(u64::MAX);
let big: BigUint = cbor.try_into().unwrap();
assert_eq!(big, BigUint::from(u64::MAX));
}
#[test]
fn decode_plain_min_i64_to_bigint() {
let cbor = CBOR::from(i64::MIN);
let big: BigInt = cbor.try_into().unwrap();
assert_eq!(big, BigInt::from(i64::MIN));
}
#[test]
fn decode_plain_negative_to_biguint_fails() {
let cbor = CBOR::from(-1i64);
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_tag3_to_biguint_fails() {
let big = BigInt::from(-1);
let cbor = CBOR::from(big);
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_large_negative_bigint_to_biguint_fails() {
let shifted: BigInt = BigInt::from(1) << 200;
let big = -shifted;
let cbor = CBOR::from(big);
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_float_to_biguint_fails() {
let cbor = CBOR::from(1.5f64);
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_float_to_bigint_fails() {
let cbor = CBOR::from(1.5f64);
let result: Result<BigInt, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_integral_float_to_biguint_succeeds() {
let cbor = CBOR::from(42.0f64);
assert_eq!(cbor.diagnostic(), "42");
let result: BigUint = cbor.try_into().unwrap();
assert_eq!(result, BigUint::from(42u32));
}
#[test]
fn decode_integral_float_to_bigint_succeeds() {
let cbor = CBOR::from(42.0f64);
let result: BigInt = cbor.try_into().unwrap();
assert_eq!(result, BigInt::from(42));
}
#[test]
fn decode_negative_float_to_bigint_fails() {
let cbor = CBOR::from(-1.5f64);
let result: Result<BigInt, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_string_to_biguint_fails() {
let cbor = CBOR::from("hello");
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_string_to_bigint_fails() {
let cbor = CBOR::from("hello");
let result: Result<BigInt, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_array_to_biguint_fails() {
let cbor: CBOR = vec![1u64, 2, 3].into();
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_bytestring_to_biguint_fails() {
let cbor = CBOR::to_byte_string([1u8, 2, 3]);
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_wrong_tag_to_biguint_fails() {
let cbor = CBOR::to_tagged_value(42u64, CBOR::to_byte_string([1u8]));
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_tag2_with_leading_zero_fails() {
let cbor = CBOR::to_tagged_value(2u64, CBOR::to_byte_string([0u8, 1u8]));
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_tag2_with_leading_zeros_fails() {
let cbor =
CBOR::to_tagged_value(2u64, CBOR::to_byte_string([0u8, 0u8, 1u8]));
let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_tag3_with_leading_zero_fails() {
let cbor = CBOR::to_tagged_value(3u64, CBOR::to_byte_string([0u8, 1u8]));
let result: Result<BigInt, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_tag3_empty_byte_string_fails() {
let cbor = CBOR::to_tagged_value(3u64, CBOR::to_byte_string([]));
let result: Result<BigInt, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_tag2_empty_is_zero() {
let cbor = CBOR::to_tagged_value(2u64, CBOR::to_byte_string([]));
let big: BigUint = cbor.clone().try_into().unwrap();
assert_eq!(big, BigUint::from(0u32));
let big_int: BigInt = cbor.try_into().unwrap();
assert_eq!(big_int, BigInt::from(0));
}
#[test]
fn decode_tag3_single_zero_is_negative_one() {
let cbor = CBOR::to_tagged_value(3u64, CBOR::to_byte_string([0u8]));
let big: BigInt = cbor.try_into().unwrap();
assert_eq!(big, BigInt::from(-1));
}
#[test]
fn from_ref_biguint() {
let big = BigUint::from(256u32);
let cbor = CBOR::from(&big);
assert_eq!(cbor.diagnostic(), "2(h'0100')");
}
#[test]
fn from_ref_bigint() {
let big = BigInt::from(-256);
let cbor = CBOR::from(&big);
assert_eq!(cbor.diagnostic(), "3(h'ff')");
}
#[test]
fn bigint_around_i64_bounds() {
let i64_max = BigInt::from(i64::MAX);
let cbor = CBOR::from(i64_max.clone());
assert!(cbor.diagnostic().starts_with("2(h'"));
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, i64_max);
let i64_min = BigInt::from(i64::MIN);
let cbor = CBOR::from(i64_min.clone());
assert!(cbor.diagnostic().starts_with("3(h'"));
let decoded: BigInt = cbor.try_into().unwrap();
assert_eq!(decoded, i64_min);
}
#[test]
fn biguint_around_u64_bounds() {
let u64_max = BigUint::from(u64::MAX);
let cbor = CBOR::from(u64_max.clone());
assert!(cbor.diagnostic().starts_with("2(h'"));
let decoded: BigUint = cbor.try_into().unwrap();
assert_eq!(decoded, u64_max);
}
#[test]
fn rfc8949_preferred_serialization_zero() {
let zero = BigUint::from(0u32);
let cbor = CBOR::from(zero);
assert_eq!(cbor.diagnostic(), "2(h'')");
assert_eq!(hex::encode(cbor.to_cbor_data()), "c240");
}
#[test]
fn rfc8949_noncanonical_leading_zeros_rejected() {
let cbor = CBOR::try_from_hex("c24100").unwrap(); let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
let cbor = CBOR::try_from_hex("c2420001").unwrap(); let result: Result<BigUint, _> = cbor.try_into();
assert!(result.is_err());
}
#[test]
fn decode_from_hex_positive_bignum() {
let cbor = CBOR::try_from_hex("c2420100").unwrap();
let big: BigUint = cbor.try_into().unwrap();
assert_eq!(big, BigUint::from(256u32));
}
#[test]
fn decode_from_hex_negative_bignum() {
let cbor = CBOR::try_from_hex("c34100").unwrap();
let big: BigInt = cbor.try_into().unwrap();
assert_eq!(big, BigInt::from(-1));
let cbor = CBOR::try_from_hex("c341ff").unwrap();
let big: BigInt = cbor.try_into().unwrap();
assert_eq!(big, BigInt::from(-256));
}
#[test]
fn encoding_length_efficiency() {
let one = BigUint::from(1u32);
let cbor = CBOR::from(one);
assert_eq!(cbor.to_cbor_data().len(), 3);
let big = BigUint::from(1u128) << 64;
let cbor = CBOR::from(big);
assert_eq!(cbor.to_cbor_data().len(), 11);
}
#[test]
fn summarizer_positive_bignum() {
dcbor::register_tags();
let big = BigUint::from(256u32);
let cbor = CBOR::from(big);
let opts = DiagFormatOpts::default()
.summarize(true)
.tags(TagsStoreOpt::Global);
let diag = cbor.diagnostic_opt(&opts);
assert_eq!(diag, "bignum(256)");
}
#[test]
fn summarizer_negative_bignum() {
dcbor::register_tags();
let big = BigInt::from(-256);
let cbor = CBOR::from(big);
let opts = DiagFormatOpts::default()
.summarize(true)
.tags(TagsStoreOpt::Global);
let diag = cbor.diagnostic_opt(&opts);
assert_eq!(diag, "bignum(-256)");
}
#[test]
fn summarizer_zero() {
dcbor::register_tags();
let big = BigUint::from(0u32);
let cbor = CBOR::from(big);
let opts = DiagFormatOpts::default()
.summarize(true)
.tags(TagsStoreOpt::Global);
let diag = cbor.diagnostic_opt(&opts);
assert_eq!(diag, "bignum(0)");
}
#[test]
fn summarizer_negative_one() {
dcbor::register_tags();
let big = BigInt::from(-1);
let cbor = CBOR::from(big);
let opts = DiagFormatOpts::default()
.summarize(true)
.tags(TagsStoreOpt::Global);
let diag = cbor.diagnostic_opt(&opts);
assert_eq!(diag, "bignum(-1)");
}
#[test]
fn summarizer_large_positive() {
dcbor::register_tags();
let big = BigUint::from(1u128) << 64;
let cbor = CBOR::from(big);
let opts = DiagFormatOpts::default()
.summarize(true)
.tags(TagsStoreOpt::Global);
let diag = cbor.diagnostic_opt(&opts);
assert_eq!(diag, "bignum(18446744073709551616)");
}
#[test]
fn summarizer_large_negative() {
dcbor::register_tags();
let big_2_64: BigInt = BigInt::from(1) << 64;
let sum: BigInt = big_2_64 + 1;
let big = -sum;
let cbor = CBOR::from(big);
let opts = DiagFormatOpts::default()
.summarize(true)
.tags(TagsStoreOpt::Global);
let diag = cbor.diagnostic_opt(&opts);
assert_eq!(diag, "bignum(-18446744073709551617)");
}