synvael/crates/net/src/tests/codec.rs

119 lines
3.6 KiB
Rust

// SPDX-License-Identifier: AGPL-3.0-only
use super::*;
use shared::protocol::{
ClientHello, ControlMessage, FeatureFlags, PROTOCOL_VERSION, PlayerIdentity,
};
/// Round-trips a set of boundary values through the varint codec, asserting both the decoded value and the exact byte length consumed.
#[test]
fn varint_round_trip_boundaries() -> Result<(), NetError> {
let cases = [
0,
1,
127,
128,
16_383,
16_384,
u64::from(u32::MAX),
u64::MAX,
];
for value in cases {
let mut buf = Vec::new();
write_varint(value, &mut buf);
let (decoded, consumed) = read_varint(&buf)?;
assert_eq!(decoded, value, "decoded value mismatch");
assert_eq!(
consumed,
buf.len(),
"consumed length must equal encoded length"
);
}
Ok(())
}
/// A frame encodes as `[varint payload length][payload]`, and decoding the prefix recovers exactly the payload byte count.
#[test]
fn encode_frame_prefixes_payload_length() -> Result<(), NetError> {
let msg = ControlMessage::ClientHello(ClientHello {
protocol_version: PROTOCOL_VERSION,
client_build: "synvael-client-0.1.0".to_string(),
player_identity: PlayerIdentity {
display_name: "Player1".to_string(),
},
installed_packs: Vec::new(),
requested_features: FeatureFlags(0),
});
let payload = postcard::to_stdvec(&msg)?;
let frame = encode_frame(&msg)?;
let (declared_len, prefix_bytes) = read_varint(&frame)?;
assert_eq!(
declared_len,
payload.len() as u64,
"prefix must equal payload length"
);
assert_eq!(
&frame[prefix_bytes..],
payload.as_slice(),
"payload bytes must follow the prefix unchanged"
);
Ok(())
}
/// Confirms the documented one/two-byte boundary encodings so a regression in the continuation logic is caught directly.
#[test]
fn varint_boundary_lengths() {
let mut buf = Vec::new();
write_varint(127, &mut buf);
assert_eq!(buf.len(), 1, "127 must encode in a single byte");
buf.clear();
write_varint(128, &mut buf);
assert_eq!(buf.len(), 2, "128 must encode in two bytes");
}
/// A varint whose final byte still sets the continuation bit is a truncated buffer and must error rather than panic.
#[test]
fn varint_truncated_is_error() {
// Two bytes both flagged as "continued", with no terminating byte.
let truncated = [0x80u8, 0x80u8];
assert!(
read_varint(&truncated).is_err(),
"truncated varint must return an error"
);
}
/// An encoding longer than the ten bytes a `u64` can occupy is rejected as overlong rather than silently accepted.
#[test]
fn varint_overlong_is_error() {
// Eleven continuation bytes followed by a terminator exceeds the u64 limit.
let overlong = [0x80u8; 11];
assert!(
read_varint(&overlong).is_err(),
"overlong varint must return an error"
);
}
/// A declared length within the cap is accepted; one exceeding it is rejected as `FrameTooLarge` before any allocation.
#[test]
fn frame_len_bound_is_enforced() {
assert_eq!(
check_frame_len(64, 128).ok(),
Some(64),
"a length within the cap is accepted"
);
assert_eq!(
check_frame_len(128, 128).ok(),
Some(128),
"a length equal to the cap is accepted"
);
assert!(
matches!(
check_frame_len(129, 128),
Err(NetError::FrameTooLarge { len: 129, max: 128 })
),
"a length over the cap must be rejected",
);
}