use ldap_client_ber::tag::{INTEGER, OCTET_STRING, Tag};
use ldap_client_ber::{BerError, BerReader, BerWriter};
#[test]
fn integer_zero() {
let mut w = BerWriter::new();
w.write_integer(0);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), 0);
}
#[test]
fn integer_positive_small() {
let mut w = BerWriter::new();
w.write_integer(127);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), 127);
}
#[test]
fn integer_positive_128() {
let mut w = BerWriter::new();
w.write_integer(128);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), 128);
}
#[test]
fn integer_negative() {
let mut w = BerWriter::new();
w.write_integer(-1);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), -1);
}
#[test]
fn integer_negative_128() {
let mut w = BerWriter::new();
w.write_integer(-128);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), -128);
}
#[test]
fn integer_negative_129() {
let mut w = BerWriter::new();
w.write_integer(-129);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), -129);
}
#[test]
fn integer_max() {
let mut w = BerWriter::new();
w.write_integer(i64::MAX);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), i64::MAX);
}
#[test]
fn integer_min() {
let mut w = BerWriter::new();
w.write_integer(i64::MIN);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), i64::MIN);
}
#[test]
fn boolean_true() {
let mut w = BerWriter::new();
w.write_boolean(true);
let mut r = BerReader::new(w.as_bytes());
assert!(r.read_boolean().unwrap());
}
#[test]
fn boolean_false() {
let mut w = BerWriter::new();
w.write_boolean(false);
let mut r = BerReader::new(w.as_bytes());
assert!(!r.read_boolean().unwrap());
}
#[test]
fn octet_string_empty() {
let mut w = BerWriter::new();
w.write_bytes(&[]);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_octet_string().unwrap(), b"");
}
#[test]
fn octet_string_hello() {
let mut w = BerWriter::new();
w.write_bytes(b"hello");
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_octet_string().unwrap(), b"hello");
}
#[test]
fn octet_string_binary() {
let data: Vec<u8> = (0..=255).collect();
let mut w = BerWriter::new();
w.write_bytes(&data);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_octet_string().unwrap(), &data[..]);
}
#[test]
fn enumerated_roundtrip() {
for val in [0, 1, 2, 10, 49, 80, -1] {
let mut w = BerWriter::new();
w.write_enumerated(val);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_enumerated().unwrap(), val);
}
}
#[test]
fn sequence_of_integers() {
let mut w = BerWriter::new();
w.write_sequence(Tag::sequence(), |inner| {
inner.write_integer(1);
inner.write_integer(2);
inner.write_integer(3);
});
let mut r = BerReader::new(w.as_bytes());
r.read_sequence(Tag::sequence(), |inner| {
assert_eq!(inner.read_integer()?, 1);
assert_eq!(inner.read_integer()?, 2);
assert_eq!(inner.read_integer()?, 3);
Ok(())
})
.unwrap();
}
#[test]
fn nested_sequences() {
let mut w = BerWriter::new();
w.write_sequence(Tag::sequence(), |outer| {
outer.write_integer(42);
outer.write_sequence(Tag::sequence(), |inner| {
inner.write_bytes(b"nested");
});
});
let mut r = BerReader::new(w.as_bytes());
r.read_sequence(Tag::sequence(), |outer| {
assert_eq!(outer.read_integer()?, 42);
outer.read_sequence(Tag::sequence(), |inner| {
assert_eq!(inner.read_octet_string()?, b"nested");
Ok(())
})
})
.unwrap();
}
#[test]
fn empty_sequence() {
let mut w = BerWriter::new();
w.write_sequence(Tag::sequence(), |_| {});
let mut r = BerReader::new(w.as_bytes());
r.read_sequence(Tag::sequence(), |inner| {
assert!(inner.is_empty());
Ok(())
})
.unwrap();
}
#[test]
fn context_tagged_octet_string() {
let mut w = BerWriter::new();
w.write_octet_string(Tag::context(0), b"password");
let mut r = BerReader::new(w.as_bytes());
let data = r.read_tagged_implicit_octet_string(0).unwrap();
assert_eq!(data, b"password");
}
#[test]
fn context_constructed() {
let mut w = BerWriter::new();
w.write_sequence(Tag::context_constructed(3), |inner| {
inner.write_string(Tag::universal(OCTET_STRING), "EXTERNAL");
});
let mut r = BerReader::new(w.as_bytes());
r.read_sequence(Tag::context_constructed(3), |inner| {
assert_eq!(inner.read_octet_string()?, b"EXTERNAL");
Ok(())
})
.unwrap();
}
#[test]
fn application_tagged_sequence() {
let mut w = BerWriter::new();
w.write_sequence(Tag::application(0), |inner| {
inner.write_integer(3);
inner.write_bytes(b"cn=admin");
inner.write_octet_string(Tag::context(0), b"secret");
});
let mut r = BerReader::new(w.as_bytes());
r.read_sequence(Tag::application(0), |inner| {
assert_eq!(inner.read_integer()?, 3);
assert_eq!(inner.read_octet_string()?, b"cn=admin");
let pw = inner.read_tagged_implicit_octet_string(0)?;
assert_eq!(pw, b"secret");
Ok(())
})
.unwrap();
}
#[test]
fn tag_encode_low_number() {
let tag = Tag::universal(INTEGER);
assert_eq!(tag.encode(), vec![0x02]);
}
#[test]
fn tag_encode_sequence() {
let tag = Tag::sequence();
assert_eq!(tag.encode(), vec![0x30]);
}
#[test]
fn tag_encode_context_0() {
let tag = Tag::context(0);
assert_eq!(tag.encode(), vec![0x80]);
}
#[test]
fn tag_encode_application_0_constructed() {
let tag = Tag::application(0);
assert_eq!(tag.encode(), vec![0x60]);
}
#[test]
fn tag_encode_high_number() {
let tag = Tag::application(31);
assert_eq!(tag.encode(), vec![0x7F, 31]);
}
#[test]
fn tag_encode_application_23() {
let tag = Tag::application(23);
assert_eq!(tag.encode(), vec![0x77]);
}
#[test]
fn truncated_input() {
let r = BerReader::new(&[]).read_integer();
assert!(matches!(r, Err(BerError::Truncated { .. })));
}
#[test]
fn wrong_tag() {
let mut w = BerWriter::new();
w.write_boolean(true);
let mut r = BerReader::new(w.as_bytes());
let err = r.read_integer().unwrap_err();
assert!(matches!(err, BerError::UnexpectedTag { .. }));
}
#[test]
fn constructed_octet_string_rejected() {
let data = [0x24, 0x02, 0x04, 0x00];
let mut r = BerReader::new(&data);
let err = r.read_octet_string().unwrap_err();
assert!(matches!(err, BerError::ConstructedPrimitive));
}
#[test]
fn indefinite_length_rejected() {
let data = [0x30, 0x80]; let mut r = BerReader::new(&data);
let err = r.read_sequence(Tag::sequence(), |_| Ok(())).unwrap_err();
assert!(matches!(err, BerError::IndefiniteLength));
}
#[test]
fn recursion_limit_enforced() {
fn nest(w: &mut BerWriter, depth: u16) {
if depth == 0 {
w.write_integer(42);
} else {
w.write_sequence(Tag::sequence(), |inner| nest(inner, depth - 1));
}
}
let mut w = BerWriter::new();
nest(&mut w, 35);
fn unnest(r: &mut BerReader<'_>, depth: u16) -> Result<i64, BerError> {
if depth == 0 {
r.read_integer()
} else {
r.read_sequence(Tag::sequence(), |inner| unnest(inner, depth - 1))
}
}
let mut r = BerReader::new(w.as_bytes()).with_max_depth(32);
let err = unnest(&mut r, 35).unwrap_err();
assert!(matches!(err, BerError::RecursionLimit { max: 32 }));
}
#[test]
fn element_too_large_rejected() {
let data = [0x04, 0x83, 0x10, 0x00, 0x00, 0x00]; let mut r = BerReader::new(&data).with_max_element_size(1024);
let err = r.read_element().unwrap_err();
assert!(matches!(err, BerError::ElementTooLarge { .. }));
}
#[test]
fn length_exceeds_buffer() {
let data = [0x04, 0x64, 0x00, 0x00, 0x00];
let mut r = BerReader::new(&data);
let err = r.read_element().unwrap_err();
assert!(matches!(err, BerError::Truncated { .. }));
}
#[test]
fn peek_tag_without_consuming() {
let mut w = BerWriter::new();
w.write_integer(99);
let r = BerReader::new(w.as_bytes());
let tag = r.peek_tag().unwrap();
assert_eq!(tag, Tag::universal(INTEGER));
let mut r = r;
assert_eq!(r.read_integer().unwrap(), 99);
}
#[test]
fn writer_clear_reuse() {
let mut w = BerWriter::with_capacity(64);
w.write_integer(1);
assert!(!w.as_bytes().is_empty());
w.clear();
assert!(w.as_bytes().is_empty());
w.write_integer(2);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), 2);
}
#[test]
fn multiple_elements() {
let mut w = BerWriter::new();
w.write_integer(1);
w.write_boolean(true);
w.write_bytes(b"test");
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_integer().unwrap(), 1);
assert!(r.read_boolean().unwrap());
assert_eq!(r.read_octet_string().unwrap(), b"test");
assert!(r.is_empty());
}
#[test]
fn long_form_length() {
let data = vec![0xAA; 200];
let mut w = BerWriter::new();
w.write_bytes(&data);
let mut r = BerReader::new(w.as_bytes());
assert_eq!(r.read_octet_string().unwrap(), &data[..]);
}
#[test]
fn read_sequence_lax_allows_trailing_data() {
let mut w = BerWriter::new();
w.write_sequence(Tag::sequence(), |inner| {
inner.write_integer(1);
inner.write_integer(2);
inner.write_integer(3);
});
let mut r = BerReader::new(w.as_bytes());
let val = r
.read_sequence_lax(Tag::sequence(), |inner| {
let first = inner.read_integer()?;
Ok(first)
})
.unwrap();
assert_eq!(val, 1);
}
#[test]
fn read_sequence_rejects_trailing_data() {
let mut w = BerWriter::new();
w.write_sequence(Tag::sequence(), |inner| {
inner.write_integer(1);
inner.write_integer(2);
});
let mut r = BerReader::new(w.as_bytes());
let err = r
.read_sequence(Tag::sequence(), |inner| {
inner.read_integer()?;
Ok(())
})
.unwrap_err();
assert!(matches!(err, BerError::TrailingData { .. }));
}
#[test]
fn high_tag_number_roundtrip() {
let mut w = BerWriter::new();
w.write_octet_string(Tag::context(128), b"high-tag");
let mut r = BerReader::new(w.as_bytes());
let data = r.read_tagged_implicit_octet_string(128).unwrap();
assert_eq!(data, b"high-tag");
}
#[test]
fn tag_overflow_rejected() {
let data = [0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x01, 0x00];
let mut r = BerReader::new(&data);
let err = r.read_element().unwrap_err();
assert!(matches!(err, BerError::TagOverflow));
}
#[test]
fn null_encoding() {
let mut w = BerWriter::new();
w.write_null();
let bytes = w.as_bytes();
assert_eq!(bytes, &[0x05, 0x00]);
}