use tinyklv::dec::binary as decb;
use tinyklv::enc::binary as encb;
use tinyklv::prelude::*;
#[derive(Klv, Debug, PartialEq)]
#[klv(
stream = &[u8],
key(dec = decb::u8, enc = encb::u8),
len(dec = decb::u8_as_usize, enc = encb::u8_from_usize),
)]
struct Pair {
#[klv(key = 0x01, dec = decb::u8, enc = *encb::u8)]
a: u8,
#[klv(key = 0x02, dec = decb::u8, enc = *encb::u8)]
b: u8,
}
#[test]
fn decode_partial_complete_input_emits_needmore_with_full_partial() {
let v = Pair { a: 3, b: 4 };
let encoded = v.encode_value();
let mut cursor: &[u8] = encoded.as_slice();
let p = match Pair::decode_partial(&mut cursor) {
Ok(Packet::NeedMore(p)) => p,
other => panic!("expected NeedMore, got {}", kind(&other)),
};
assert!(
cursor.is_empty(),
"cursor must advance past every consumed byte"
);
let got: Pair = p.try_into().expect("partial finalises cleanly");
assert_eq!(got, v);
}
#[test]
fn decode_partial_need_more_rewinds_cursor() {
let stream = [0x01u8, 0x05, 0xAA, 0xBB];
let mut cursor: &[u8] = &stream;
let before = cursor.len();
match Pair::decode_partial(&mut cursor) {
Ok(Packet::NeedMore(_)) => {}
other => panic!("expected NeedMore, got {}", kind(&other)),
}
assert_eq!(
cursor.len(),
before,
"cursor must be rewound to pre-attempt offset on NeedMore",
);
}
#[test]
fn decode_partial_short_len_is_recoverable() {
let stream = [0x01u8];
let mut cursor: &[u8] = &stream;
let before = cursor.len();
match Pair::decode_partial(&mut cursor) {
Ok(Packet::NeedMore(_)) => {}
other => panic!(
"expected NeedMore (recoverable truncation), got {}",
kind(&other)
),
}
assert_eq!(
cursor.len(),
before,
"cursor must be rewound on key+len truncation",
);
}
#[test]
fn decode_partial_missing_required_label_via_try_into() {
let stream = [0x01u8, 0x01, 0xAA];
let mut cursor: &[u8] = &stream;
let p = match Pair::decode_partial(&mut cursor) {
Ok(Packet::NeedMore(p)) => p,
other => panic!("expected NeedMore, got {}", kind(&other)),
};
let label: &'static str = <Pair as core::convert::TryFrom<_>>::try_from(p)
.expect_err("partial must fail finalisation: required `b` is missing");
assert!(
label.contains("Pair::b"),
"label must name the missing required field; got: {label}"
);
}
#[test]
fn decode_value_one_shot_missing_required() {
let stream = [0x01u8, 0x01, 0xAA];
let mut cursor: &[u8] = &stream;
let err = Pair::decode_value(&mut cursor)
.expect_err("decode_value must fail when required `b` missing");
let msg = format!("{err:?}");
assert!(
msg.contains("Pair::b"),
"ContextError must surface the static label naming the missing field; got: {msg}"
);
}
fn kind<T, P>(p: &Result<Packet<T, P>, &'static str>) -> &'static str
where
P: tinyklv::Partial<Final = T>,
{
match p {
Ok(Packet::Ready(_)) => "Ok(Ready)",
Ok(Packet::NeedMore(_)) => "Ok(NeedMore)",
Err(_) => "Err(label)",
}
}