use super::{bit_string, boolean, integer, null, oid, real};
use crate::error::ErrorCode;
use crate::length::Encoding;
use alloc::string::String;
fn decimal(value: super::Oid<'_>) -> String {
let execution = crate::test_memory();
value
.text(&execution)
.unwrap()
.as_str(&execution)
.unwrap()
.into()
}
#[test]
fn identifiers_render_as_the_dotted_form_they_encode() {
for (bytes, dotted) in [
(&[0x55, 0x1d, 0x13][..], "2.5.29.19"),
(&[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d][..], "1.2.840.113549"),
(&[0x28, 0x03][..], "1.0.3"),
(&[0x06][..], "0.6"),
(&[0x88, 0x37][..], "2.999"),
] {
let parsed = oid(bytes).unwrap();
assert_eq!(decimal(parsed), dotted, "{bytes:02x?}");
assert_eq!(parsed.as_bytes(), bytes);
}
}
#[test]
fn identifiers_that_cannot_be_read_are_refused() {
for bytes in [&[][..], &[0x2a, 0x86][..], &[0x2a, 0x80, 0x01][..]] {
assert_eq!(
oid(bytes).unwrap_err(),
ErrorCode::MalformedOid,
"{bytes:02x?}"
);
}
}
#[test]
fn an_arc_that_fits_sixty_four_bits_is_read_whatever_its_group_count() {
let bytes = [
0x2a, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
];
let parsed = oid(&bytes).unwrap();
assert_eq!(parsed.arcs().nth(2).unwrap().as_u64(), Some(1u64 << 63));
assert_eq!(decimal(parsed), "1.2.9223372036854775808");
}
#[test]
fn the_first_pair_carries_its_eighty_arc_offset() {
let mut combined = u128::from(u64::MAX) + 80;
let mut groups = alloc::vec::Vec::new();
while combined > 0 {
groups.push(u8::try_from(combined & 0x7f).unwrap());
combined >>= 7;
}
groups.reverse();
let last = groups.len() - 1;
for group in &mut groups[..last] {
*group |= 0x80;
}
let parsed = oid(&groups).unwrap();
let arcs: alloc::vec::Vec<Option<u64>> = parsed.arcs().map(super::Arc::as_u64).collect();
assert_eq!(arcs, [Some(2), Some(u64::MAX)]);
let mut combined = u128::from(u64::MAX) + 81;
let mut groups = alloc::vec::Vec::new();
while combined > 0 {
groups.push(u8::try_from(combined & 0x7f).unwrap());
combined >>= 7;
}
groups.reverse();
let last = groups.len() - 1;
for group in &mut groups[..last] {
*group |= 0x80;
}
let parsed = oid(&groups).unwrap();
assert_eq!(parsed.arcs().nth(1).unwrap().as_u64(), None);
assert_eq!(decimal(parsed), "2.18446744073709551616");
}
#[test]
fn an_arc_wider_than_this_reader_is_still_read() {
let bytes = [
0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
];
let parsed = oid(&bytes).unwrap();
assert_eq!(parsed.arcs().nth(2).unwrap().as_u64(), None);
assert_eq!(decimal(parsed), "1.2.1180591620717411303423");
}
#[test]
fn integers_keep_their_bytes_and_convert_on_request() {
let serial = integer(&[0x00, 0xd8, 0x1c, 0x4d]).unwrap();
assert_eq!(serial.as_u64(), Some(0x00d8_1c4d));
assert!(!serial.is_negative());
assert_eq!(serial.as_bytes(), &[0x00, 0xd8, 0x1c, 0x4d]);
let negative = integer(&[0x80]).unwrap();
assert!(negative.is_negative());
assert_eq!(negative.as_i64(), Some(-128));
assert_eq!(negative.as_u64(), None);
assert_eq!(integer(&[0x00]).unwrap().as_u64(), Some(0));
assert_eq!(integer(&[0x7f]).unwrap().as_i64(), Some(127));
assert_eq!(integer(&[0xff]).unwrap().as_i64(), Some(-1));
let wide = integer(&[0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]).unwrap();
assert_eq!(wide.as_u64(), Some(u64::MAX));
assert_eq!(wide.as_i64(), None);
}
#[test]
fn integers_written_a_byte_longer_than_needed_are_refused() {
assert_eq!(integer(&[]).unwrap_err(), ErrorCode::IntegerEmpty);
assert_eq!(
integer(&[0x00, 0x7f]).unwrap_err(),
ErrorCode::IntegerNotMinimal
);
assert_eq!(
integer(&[0xff, 0x80]).unwrap_err(),
ErrorCode::IntegerNotMinimal
);
assert!(integer(&[0x00, 0x80]).is_ok());
assert!(integer(&[0xff, 0x7f]).is_ok());
}
#[test]
fn a_bit_string_addresses_bits_rather_than_bytes() {
let usage = bit_string(&[0x02, 0x84], Encoding::Der).unwrap();
assert_eq!(usage.len(), 6);
assert!(usage.bit(0));
assert!(!usage.bit(1));
assert!(usage.bit(5));
assert!(!usage.bit(6));
assert!(!usage.bit(64));
assert_eq!(usage.octets(), None);
let whole = bit_string(&[0x00, 0xde, 0xad], Encoding::Der).unwrap();
assert_eq!(whole.octets(), Some(&[0xde, 0xad][..]));
assert_eq!(whole.len(), 16);
let empty = bit_string(&[0x00], Encoding::Der).unwrap();
assert!(empty.is_empty());
assert_eq!(empty.len(), 0);
assert!(!empty.bit(0));
}
#[test]
fn bit_strings_that_could_hide_bytes_in_the_padding_are_refused() {
assert_eq!(
bit_string(&[], Encoding::Der).unwrap_err(),
ErrorCode::MalformedBitString
);
assert_eq!(
bit_string(&[0x08, 0xff], Encoding::Der).unwrap_err(),
ErrorCode::MalformedBitString
);
assert_eq!(
bit_string(&[0x01], Encoding::Der).unwrap_err(),
ErrorCode::MalformedBitString
);
assert_eq!(
bit_string(&[0x04, 0x8f], Encoding::Der).unwrap_err(),
ErrorCode::MalformedBitString
);
assert!(bit_string(&[0x04, 0x8f], Encoding::Ber).is_ok());
}
#[test]
fn a_boolean_has_one_spelling_under_der_and_several_under_ber() {
assert_eq!(boolean(&[0x00], Encoding::Der), Ok(false));
assert_eq!(boolean(&[0xff], Encoding::Der), Ok(true));
assert_eq!(
boolean(&[0x01], Encoding::Der).unwrap_err(),
ErrorCode::MalformedBoolean
);
assert_eq!(boolean(&[0x01], Encoding::Ber), Ok(true));
for encoding in [Encoding::Der, Encoding::Ber] {
assert_eq!(
boolean(&[], encoding).unwrap_err(),
ErrorCode::MalformedBoolean
);
assert_eq!(
boolean(&[0x00, 0x00], encoding).unwrap_err(),
ErrorCode::MalformedBoolean
);
}
}
#[test]
fn a_null_carries_nothing() {
assert_eq!(null(&[]), Ok(()));
assert_eq!(null(&[0x00]).unwrap_err(), ErrorCode::MalformedNull);
}
#[test]
#[should_panic(expected = "not a well formed object identifier")]
fn a_constant_with_a_padded_arc_is_refused_at_construction() {
let _ = super::Oid::from_bytes(&[0x2a, 0x80, 0x01]);
}
#[test]
#[should_panic(expected = "not a well formed object identifier")]
fn a_constant_ending_mid_arc_is_refused_at_construction() {
let _ = super::Oid::from_bytes(&[0x2a, 0x86]);
}
#[test]
fn a_constant_naming_a_wide_arc_is_built() {
let wide = super::Oid::from_bytes(&[
0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
]);
assert_eq!(decimal(wide), "1.2.1180591620717411303423");
}
#[test]
fn an_arc_wider_than_sixty_four_bits_is_read_and_printed() {
let mut bytes = alloc::vec![0x2a, 0x81];
bytes.extend(core::iter::repeat_n(0x80, 9));
bytes.push(0x00);
let parsed = oid(&bytes).unwrap();
assert_eq!(decimal(parsed), "1.2.1180591620717411303424");
assert_eq!(parsed.arcs().nth(2).unwrap().as_u64(), None);
assert_eq!(parsed.arcs().next().unwrap().as_u64(), Some(1));
}
#[test]
fn an_arc_past_the_accumulator_keeps_its_own_value() {
let mut bytes = alloc::vec![0x2a, 0x81];
bytes.extend(core::iter::repeat_n(0x80, 18));
bytes.push(0x01);
let parsed = oid(&bytes).unwrap();
assert_eq!(parsed.arcs().nth(2).unwrap().as_u64(), None);
assert_eq!(
decimal(parsed),
"1.2.10889035741470030830827987437816582766593"
);
}
fn reference_decimal(groups: impl Iterator<Item = u8>, offset: u8) -> String {
let mut digits = alloc::vec![0u8];
for group in groups {
let mut carry = u16::from(group & 0x7f);
for digit in &mut digits {
let value = u16::from(*digit) * 128 + carry;
*digit = u8::try_from(value % 10).unwrap();
carry = value / 10;
}
while carry > 0 {
digits.push(u8::try_from(carry % 10).unwrap());
carry /= 10;
}
}
let mut owed = offset;
for digit in &mut digits {
let next = owed / 10;
let remainder = owed % 10;
if *digit >= remainder {
*digit -= remainder;
owed = next;
} else {
*digit = *digit + 10 - remainder;
owed = next + 1;
}
if owed == 0 {
break;
}
}
assert_eq!(owed, 0);
while digits.len() > 1 && digits.last() == Some(&0) {
digits.pop();
}
digits
.into_iter()
.rev()
.map(|digit| char::from(b'0' + digit))
.collect()
}
#[test]
fn a_wide_arc_takes_the_joint_offset_off_before_it_is_written() {
let mut bytes = alloc::vec![0x81];
bytes.extend(core::iter::repeat_n(0x80, 598));
bytes.push(0x00);
let rendered = decimal(oid(&bytes).unwrap());
let expected = reference_decimal(bytes.iter().copied(), 80);
assert_eq!(rendered.strip_prefix("2."), Some(expected.as_str()));
}
#[test]
fn a_very_wide_arc_is_exact_or_returns_a_resource_error() {
for groups in [512, 4001] {
let mut bytes = alloc::vec![0x2a];
bytes.extend(core::iter::repeat_n(0xff, groups - 1));
bytes.push(0x7f);
let rendered = decimal(oid(&bytes).unwrap());
let expected = reference_decimal(bytes[1..].iter().copied(), 0);
assert_eq!(rendered.strip_prefix("1.2."), Some(expected.as_str()));
}
let mut bytes = alloc::vec![0x2a];
bytes.extend(core::iter::repeat_n(0x81, 512));
bytes.push(0x02);
let rendered = decimal(oid(&bytes).unwrap());
let expected = reference_decimal(bytes[1..].iter().copied(), 0);
assert_eq!(rendered.strip_prefix("1.2."), Some(expected.as_str()));
let mut bytes = alloc::vec![0x2a];
bytes.extend(core::iter::repeat_n(0xff, 40000));
bytes.push(0x7f);
let execution = crate::memory::Memory::new(alloc::sync::Arc::new(
crate::memory::MemoryAccount::new(100_000, 200_000),
));
assert_eq!(
oid(&bytes).unwrap().text(&execution).unwrap_err(),
crate::memory::MemoryError::WorkExceeded,
);
assert_eq!(execution.used(), 0);
}
#[test]
fn a_real_exponent_is_written_in_the_shortest_form_that_holds_it() {
for contents in [
&[0x83, 0x01, 0x01, 0x01][..],
&[0x83, 0x02, 0x01, 0x00, 0x01],
&[0x83, 0x03, 0x01, 0x00, 0x00, 0x01],
] {
assert!(real(contents, Encoding::Ber).is_ok(), "{contents:02x?}");
assert_eq!(
real(contents, Encoding::Der).unwrap_err(),
ErrorCode::MalformedReal,
"{contents:02x?}"
);
}
let long = [0x83, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01];
for encoding in [Encoding::Ber, Encoding::Der] {
assert!(real(&long, encoding).is_ok());
}
for contents in [
&[0x80, 0x01, 0x01][..],
&[0x81, 0x01, 0x00, 0x01],
&[0x82, 0x01, 0x00, 0x00, 0x01],
] {
assert!(real(contents, Encoding::Der).is_ok(), "{contents:02x?}");
}
}
#[test]
fn the_two_encodings_write_a_real_differently() {
for contents in [
&[0xa0, 0x01, 0x01][..],
&[0x88, 0x01, 0x01],
&[0x80, 0x01, 0x02],
] {
assert!(real(contents, Encoding::Ber).is_ok(), "{contents:02x?}");
assert_eq!(
real(contents, Encoding::Der).unwrap_err(),
ErrorCode::MalformedReal,
"{contents:02x?}"
);
}
for contents in [&b"\x011.0"[..], b"\x02 1.0"] {
assert!(real(contents, Encoding::Ber).is_ok(), "{contents:02x?}");
assert_eq!(
real(contents, Encoding::Der).unwrap_err(),
ErrorCode::MalformedReal,
"{contents:02x?}"
);
}
for contents in [&[0xb0, 0x01, 0x01][..], &[0x00], &[0x44]] {
for encoding in [Encoding::Ber, Encoding::Der] {
assert_eq!(
real(contents, encoding).unwrap_err(),
ErrorCode::MalformedReal,
"{contents:02x?}"
);
}
}
for contents in [&[][..], &[0x40], &[0x43], &[0x80, 0x01, 0x01]] {
for encoding in [Encoding::Ber, Encoding::Der] {
assert!(real(contents, encoding).is_ok(), "{contents:02x?}");
}
}
}