use crate::{DecodeOptions, Error, Format, IoError, Value};
#[test]
fn default_decodes_simple_value() {
let v = DecodeOptions::new().decode(&[0x18, 42]).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn default_matches_value_decode() {
let bytes = [0x82, 0x01, 0x02];
let via_options = DecodeOptions::new().decode(&bytes).unwrap();
let via_value = Value::decode(&bytes).unwrap();
assert_eq!(via_options, via_value);
}
#[test]
fn default_trait_equals_new() {
let a = DecodeOptions::default().decode(&[0x00]).unwrap();
let b = DecodeOptions::new().decode(&[0x00]).unwrap();
assert_eq!(a, b);
}
#[test]
fn hex_decode_matches_binary() {
let hex = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
let bin = DecodeOptions::new().decode(&[0x18, 0x2a]).unwrap();
assert_eq!(hex, bin);
}
#[test]
fn hex_uppercase_accepted() {
let v = DecodeOptions::new().format(Format::Hex).decode("182A").unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn hex_invalid_returns_error() {
let err = DecodeOptions::new().format(Format::Hex).decode("18zz").unwrap_err();
assert_eq!(err, Error::InvalidHex);
}
#[test]
fn hex_off_treats_input_as_binary() {
let v = DecodeOptions::new().decode("1").unwrap();
assert_eq!(v.to_i32().unwrap(), -18);
}
#[test]
fn value_decode_hex_matches_options() {
let via_value = Value::decode_hex("182a").unwrap();
let via_options = DecodeOptions::new().format(Format::Hex).decode("182a").unwrap();
assert_eq!(via_value, via_options);
}
#[test]
fn recursion_limit_zero_rejects_array() {
let err = DecodeOptions::new()
.recursion_limit(0)
.decode(&[0x81, 0x00])
.unwrap_err();
assert_eq!(err, Error::NestingTooDeep);
}
#[test]
fn recursion_limit_one_allows_single_level() {
let v = DecodeOptions::new().recursion_limit(1).decode(&[0x81, 0x00]).unwrap();
assert_eq!(v.len(), Some(1));
}
#[test]
fn recursion_limit_one_rejects_two_levels() {
let err = DecodeOptions::new()
.recursion_limit(1)
.decode(&[0x81, 0x81, 0x00])
.unwrap_err();
assert_eq!(err, Error::NestingTooDeep);
}
#[test]
fn recursion_limit_raised_above_default() {
let mut bytes = vec![0x81; 300];
bytes.push(0xf6);
assert!(DecodeOptions::new().recursion_limit(300).decode(&bytes).is_ok());
}
#[test]
fn recursion_limit_applies_to_tags() {
let bytes = [0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xf6];
let err = DecodeOptions::new().recursion_limit(1).decode(&bytes).unwrap_err();
assert_eq!(err, Error::NestingTooDeep);
}
#[test]
fn length_limit_rejects_oversized_text() {
let err = DecodeOptions::new().length_limit(4).decode(b"\x65hello").unwrap_err();
assert_eq!(err, Error::LengthTooLarge);
}
#[test]
fn length_limit_rejects_oversized_byte_string() {
let err = DecodeOptions::new()
.length_limit(4)
.decode(&[0x45, 1, 2, 3, 4, 5])
.unwrap_err();
assert_eq!(err, Error::LengthTooLarge);
}
#[test]
fn length_limit_rejects_oversized_array() {
let err = DecodeOptions::new()
.length_limit(2)
.decode(&[0x83, 0x01, 0x02, 0x03])
.unwrap_err();
assert_eq!(err, Error::LengthTooLarge);
}
#[test]
fn length_limit_rejects_oversized_map() {
let err = DecodeOptions::new()
.length_limit(1)
.decode(&[0xa2, 0x00, 0x00, 0x01, 0x00])
.unwrap_err();
assert_eq!(err, Error::LengthTooLarge);
}
#[test]
fn length_limit_at_boundary_accepts() {
let v = DecodeOptions::new().length_limit(5).decode(b"\x65hello").unwrap();
assert_eq!(v.as_str().unwrap(), "hello");
}
#[test]
fn length_limit_raised_above_default() {
let v = DecodeOptions::new()
.length_limit(u64::MAX)
.decode(&[0x84, 0x01, 0x02, 0x03, 0x04])
.unwrap();
assert_eq!(v.len(), Some(4));
}
#[test]
fn oom_mitigation_zero_still_decodes() {
let v = DecodeOptions::new()
.oom_mitigation(0)
.decode(&[0x83, 0x01, 0x02, 0x03])
.unwrap();
assert_eq!(v.len(), Some(3));
}
#[test]
fn oom_mitigation_does_not_constrain_correctness() {
let bytes = [0x82, 0x82, 0x01, 0x02, 0x82, 0x03, 0x04];
let v = DecodeOptions::new().oom_mitigation(8).decode(&bytes).unwrap();
assert_eq!(v.len(), Some(2));
}
#[test]
fn read_from_binary() {
let bytes: &[u8] = &[0x18, 42];
let v = DecodeOptions::new().read_from(bytes).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn read_from_hex() {
let hex: &[u8] = b"182a";
let v = DecodeOptions::new().format(Format::Hex).read_from(hex).unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn read_from_propagates_data_error() {
let bytes: &[u8] = &[0x18, 0x00];
let err = DecodeOptions::new().read_from(bytes).unwrap_err();
assert!(matches!(err, IoError::Data(Error::NonDeterministic)));
}
#[test]
fn read_from_propagates_eof() {
let bytes: &[u8] = &[0x18];
let err = DecodeOptions::new().read_from(bytes).unwrap_err();
assert!(matches!(err, IoError::Data(Error::UnexpectedEof)));
}
#[test]
fn read_from_recursion_limit_applies() {
let bytes: &[u8] = &[0x81, 0x81, 0x00];
let err = DecodeOptions::new().recursion_limit(1).read_from(bytes).unwrap_err();
assert!(matches!(err, IoError::Data(Error::NestingTooDeep)));
}
#[test]
fn value_read_from_matches_options() {
let bytes: &[u8] = &[0x18, 42];
let via_value = Value::read_from(bytes).unwrap();
let bytes2: &[u8] = &[0x18, 42];
let via_options = DecodeOptions::new().read_from(bytes2).unwrap();
assert_eq!(via_value, via_options);
}
#[test]
fn value_read_hex_from_matches_options() {
let hex1: &[u8] = b"182a";
let via_value = Value::read_hex_from(hex1).unwrap();
let hex2: &[u8] = b"182a";
let via_options = DecodeOptions::new().format(Format::Hex).read_from(hex2).unwrap();
assert_eq!(via_value, via_options);
}
#[test]
fn builder_chain_on_fresh_value() {
let v = DecodeOptions::new()
.format(Format::Hex)
.recursion_limit(8)
.length_limit(64)
.oom_mitigation(1024)
.decode("182a")
.unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn builder_reused_across_decodes() {
let opts = DecodeOptions::new().recursion_limit(4).length_limit(16);
assert!(opts.decode(&[0x18, 42]).is_ok());
assert!(opts.decode(&[0x81, 0x00]).is_ok());
}
#[test]
fn decode_binary_rejects_trailing_byte() {
let err = DecodeOptions::new().decode(&[0x00, 0x00]).unwrap_err();
assert_eq!(err, Error::InvalidFormat);
}
#[test]
fn decode_hex_rejects_trailing_digits() {
let err = DecodeOptions::new().format(Format::Hex).decode("0000").unwrap_err();
assert_eq!(err, Error::InvalidFormat);
}
#[test]
fn decode_diagnostic_rejects_trailing_value() {
let err = DecodeOptions::new()
.format(Format::Diagnostic)
.decode("1 2")
.unwrap_err();
assert_eq!(err, Error::InvalidFormat);
}
#[test]
fn decode_diagnostic_accepts_trailing_whitespace_and_comments() {
let v = DecodeOptions::new()
.format(Format::Diagnostic)
.decode("42 # trailing line comment\n / block / \n")
.unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn decode_owned_binary_rejects_trailing_byte() {
let err = DecodeOptions::new().decode_owned(&[0x00, 0x00][..]).unwrap_err();
assert_eq!(err, Error::InvalidFormat);
}
#[test]
fn decode_owned_hex_rejects_trailing_digits() {
let err = DecodeOptions::new()
.format(Format::Hex)
.decode_owned("0000")
.unwrap_err();
assert_eq!(err, Error::InvalidFormat);
}
#[test]
fn decode_owned_diagnostic_rejects_trailing_value() {
let err = DecodeOptions::new()
.format(Format::Diagnostic)
.decode_owned("1 2")
.unwrap_err();
assert_eq!(err, Error::InvalidFormat);
}
#[test]
fn decode_owned_diagnostic_accepts_trailing_whitespace_and_comments() {
let v = DecodeOptions::new()
.format(Format::Diagnostic)
.decode_owned("42 # trailing line comment\n / block / \n")
.unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn diagnostic_decode_integer() {
let v = DecodeOptions::new().format(Format::Diagnostic).decode("42").unwrap();
assert_eq!(v.to_u32().unwrap(), 42);
}
#[test]
fn diagnostic_decode_nested() {
let v = DecodeOptions::new()
.format(Format::Diagnostic)
.decode(r#"{"a": [1, 2, 3]}"#)
.unwrap();
assert_eq!(v["a"].len(), Some(3));
}
#[test]
fn diagnostic_recursion_limit_applies() {
let err = DecodeOptions::new()
.format(Format::Diagnostic)
.recursion_limit(1)
.decode("[[1]]")
.unwrap_err();
assert_eq!(err, Error::NestingTooDeep);
}
#[test]
fn read_from_diagnostic_consumes_trailing_comma() {
let mut input: &[u8] = b"1, 2";
let opts = DecodeOptions::new().format(Format::Diagnostic);
let a = opts.read_from(&mut input).unwrap();
let b = opts.read_from(&mut input).unwrap();
assert_eq!(a.to_u32().unwrap(), 1);
assert_eq!(b.to_u32().unwrap(), 2);
}
#[test]
fn read_from_diagnostic_allows_trailing_whitespace_and_comments() {
let mut input: &[u8] = b"1 # after one\n, 2 / then two /";
let opts = DecodeOptions::new().format(Format::Diagnostic);
let a = opts.read_from(&mut input).unwrap();
let b = opts.read_from(&mut input).unwrap();
assert_eq!(a.to_u32().unwrap(), 1);
assert_eq!(b.to_u32().unwrap(), 2);
}
#[test]
fn read_from_diagnostic_rejects_unexpected_token_between_items() {
let mut input: &[u8] = b"1 ; 2";
let opts = DecodeOptions::new().format(Format::Diagnostic);
let err = opts.read_from(&mut input).unwrap_err();
assert!(matches!(err, IoError::Data(Error::InvalidFormat)));
}
#[test]
fn decoder_binary_yields_all_items() {
let items: Vec<_> = DecodeOptions::new()
.sequence_decoder(&[0x01, 0x02, 0x03])
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 3);
assert_eq!(items[0].to_u32().unwrap(), 1);
assert_eq!(items[2].to_u32().unwrap(), 3);
}
#[test]
fn decoder_hex_yields_all_items() {
let items: Vec<_> = DecodeOptions::new()
.format(Format::Hex)
.sequence_decoder(b"010203")
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn decoder_diagnostic_yields_all_items() {
let opts = DecodeOptions::new().format(Format::Diagnostic);
let items: Vec<_> = opts.sequence_decoder(b"1, 2, 3").collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn decoder_diagnostic_accepts_trailing_comma() {
let opts = DecodeOptions::new().format(Format::Diagnostic);
let items: Vec<_> = opts.sequence_decoder(b"1, 2, 3,").collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn decoder_empty_input_is_empty_iterator() {
let mut d = DecodeOptions::new().sequence_decoder(&[]);
assert!(d.next().is_none());
}
#[test]
fn decoder_diagnostic_empty_input_is_empty_iterator() {
let opts = DecodeOptions::new().format(Format::Diagnostic);
let mut d = opts.sequence_decoder(b"");
assert!(d.next().is_none());
}
#[test]
fn decoder_diagnostic_whitespace_only_is_empty_iterator() {
let opts = DecodeOptions::new().format(Format::Diagnostic);
let mut d = opts.sequence_decoder(b" # nothing here\n / blank / ");
assert!(d.next().is_none());
}
#[test]
fn decoder_binary_reports_truncated_tail() {
let mut d = DecodeOptions::new().sequence_decoder(&[0x01, 0x18]);
assert_eq!(d.next().unwrap().unwrap().to_u32().unwrap(), 1);
let err = d.next().unwrap().unwrap_err();
assert_eq!(err, Error::UnexpectedEof);
}
#[test]
fn sequence_reader_binary_yields_all_items() {
let bytes: &[u8] = &[0x01, 0x02, 0x03];
let items: Vec<_> = DecodeOptions::new()
.sequence_reader(bytes)
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn sequence_reader_hex_yields_all_items() {
let hex: &[u8] = b"010203";
let items: Vec<_> = DecodeOptions::new()
.format(Format::Hex)
.sequence_reader(hex)
.collect::<Result<_, _>>()
.unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn sequence_reader_diagnostic_yields_all_items() {
let opts = DecodeOptions::new().format(Format::Diagnostic);
let diag: &[u8] = b"1, 2, 3,";
let items: Vec<_> = opts.sequence_reader(diag).collect::<Result<_, _>>().unwrap();
assert_eq!(items.len(), 3);
}
#[test]
fn sequence_reader_empty_binary_is_empty() {
let bytes: &[u8] = &[];
let mut s = DecodeOptions::new().sequence_reader(bytes);
assert!(s.next().is_none());
}
#[test]
fn sequence_reader_binary_reports_truncation() {
let bytes: &[u8] = &[0x01, 0x18];
let mut s = DecodeOptions::new().sequence_reader(bytes);
assert!(s.next().unwrap().is_ok());
let err = s.next().unwrap().unwrap_err();
assert!(matches!(err, IoError::Data(Error::UnexpectedEof)));
}