#![allow(
clippy::approx_constant,
clippy::useless_vec,
clippy::len_zero,
clippy::unnecessary_cast,
clippy::redundant_closure,
clippy::too_many_arguments,
clippy::type_complexity,
clippy::needless_borrow,
clippy::enum_variant_names,
clippy::upper_case_acronyms,
clippy::inconsistent_digit_grouping,
clippy::unit_cmp,
clippy::assertions_on_constants,
clippy::iter_on_single_items,
clippy::expect_fun_call,
clippy::redundant_pattern_matching,
variant_size_differences,
clippy::absurd_extreme_comparisons,
clippy::nonminimal_bool,
clippy::for_kv_map,
clippy::needless_range_loop,
clippy::single_match,
clippy::collapsible_if,
clippy::needless_return,
clippy::redundant_clone,
clippy::map_entry,
clippy::match_single_binding,
clippy::bool_comparison,
clippy::derivable_impls,
clippy::manual_range_contains,
clippy::needless_borrows_for_generic_args,
clippy::manual_map,
clippy::vec_init_then_push,
clippy::identity_op,
clippy::manual_flatten,
clippy::single_char_pattern,
clippy::search_is_some,
clippy::option_map_unit_fn,
clippy::while_let_on_iterator,
clippy::clone_on_copy,
clippy::box_collection,
clippy::redundant_field_names,
clippy::ptr_arg,
clippy::large_enum_variant,
clippy::match_ref_pats,
clippy::needless_pass_by_value,
clippy::unused_unit,
clippy::let_and_return,
clippy::suspicious_else_formatting,
clippy::manual_strip,
clippy::match_like_matches_macro,
clippy::from_over_into,
clippy::wrong_self_convention,
clippy::inherent_to_string,
clippy::new_without_default,
clippy::unnecessary_wraps,
clippy::field_reassign_with_default,
clippy::manual_find,
clippy::unnecessary_lazy_evaluations,
clippy::should_implement_trait,
clippy::missing_safety_doc,
clippy::unusual_byte_groupings,
clippy::bool_assert_comparison,
clippy::zero_prefixed_literal,
clippy::await_holding_lock,
clippy::manual_saturating_arithmetic,
clippy::explicit_counter_loop,
clippy::needless_lifetimes,
clippy::single_component_path_imports,
clippy::uninlined_format_args,
clippy::iter_cloned_collect,
clippy::manual_str_repeat,
clippy::excessive_precision,
clippy::precedence,
clippy::unnecessary_literal_unwrap
)]
use oxicode::{
config, decode_from_slice, decode_from_slice_with_config, encode_to_vec,
encode_to_vec_with_config, Decode, Encode,
};
#[test]
fn test_empty_slice_decode_returns_error() {
let result = decode_from_slice::<u32>(&[]);
assert!(
result.is_err(),
"decoding empty slice should return an error"
);
}
#[test]
fn test_single_0xff_decode_u32_errors() {
let result = decode_from_slice::<u32>(&[0xFF]);
assert!(
result.is_err(),
"0xFF is not a valid varint tag for u32; should error"
);
}
#[test]
fn test_truncated_varint_two_ff_bytes_errors() {
let result = decode_from_slice::<u32>(&[0xFF, 0xFF]);
assert!(
result.is_err(),
"0xFF, 0xFF is not a valid varint for u32; should error"
);
}
#[test]
fn test_truncated_string_decode_returns_error() {
let s = String::from("hello world");
let mut encoded = encode_to_vec(&s).expect("encode string");
encoded.pop();
let result = decode_from_slice::<String>(&encoded);
assert!(result.is_err(), "truncated string encoding should error");
}
#[test]
fn test_truncated_vec_u32_decode_returns_error() {
let v: Vec<u32> = vec![1, 2, 3, 4, 5];
let mut encoded = encode_to_vec(&v).expect("encode vec");
let new_len = encoded.len().saturating_sub(4);
encoded.truncate(new_len);
let result = decode_from_slice::<Vec<u32>>(&encoded);
assert!(result.is_err(), "truncated Vec<u32> should error on decode");
}
#[test]
fn test_extra_trailing_bytes_do_not_prevent_valid_decode() {
let encoded = encode_to_vec(&42u32).expect("encode u32");
let mut padded = encoded.clone();
padded.extend_from_slice(&[0x00, 0x00, 0x00]);
let (value, consumed): (u32, _) =
decode_from_slice(&padded).expect("decode with trailing bytes");
assert_eq!(value, 42u32);
assert!(consumed < padded.len());
assert_eq!(consumed, encoded.len());
}
#[test]
fn test_limit_config_decode_within_limit_succeeds() {
let cfg = config::standard().with_limit::<128>();
let encoded = encode_to_vec_with_config(&99u8, cfg).expect("encode u8");
let (val, _): (u8, _) =
decode_from_slice_with_config(&encoded, cfg).expect("decode within limit");
assert_eq!(val, 99u8);
}
#[test]
fn test_limit_config_decode_exceeding_limit_returns_error() {
let s = String::from("this is a fairly long string that will exceed the tiny limit");
let encoded = encode_to_vec(&s).expect("encode string");
let tiny_cfg = config::standard().with_limit::<4>();
let result = decode_from_slice_with_config::<String, _>(&encoded, tiny_cfg);
assert!(result.is_err(), "decoding past byte limit should error");
}
#[test]
fn test_zero_bytes_cannot_decode_u32_zero() {
let result = decode_from_slice::<u32>(&[]);
assert!(result.is_err(), "cannot decode u32 from zero bytes");
}
#[test]
fn test_invalid_bool_byte_0x02_returns_error() {
let result = decode_from_slice::<bool>(&[0x02]);
assert!(result.is_err(), "0x02 is not a valid bool byte");
}
#[test]
fn test_bool_false_decodes_from_0x00() {
let (val, consumed): (bool, _) = decode_from_slice(&[0x00]).expect("decode bool false");
assert!(!val);
assert_eq!(consumed, 1);
}
#[test]
fn test_bool_true_decodes_from_0x01() {
let (val, consumed): (bool, _) = decode_from_slice(&[0x01]).expect("decode bool true");
assert!(val);
assert_eq!(consumed, 1);
}
#[test]
fn test_invalid_utf8_bytes_decode_string_returns_error() {
let bytes: &[u8] = &[0x01, 0x80];
let result = decode_from_slice::<String>(bytes);
assert!(
result.is_err(),
"invalid UTF-8 bytes should error on String decode"
);
}
#[derive(Debug, PartialEq, Encode, Decode)]
struct SimpleStruct {
x: u32,
y: u64,
z: bool,
}
#[test]
fn test_truncated_struct_decode_returns_error() {
let val = SimpleStruct {
x: 42,
y: 1234567890,
z: true,
};
let mut encoded = encode_to_vec(&val).expect("encode struct");
let new_len = encoded.len().saturating_sub(4);
encoded.truncate(new_len);
let result = decode_from_slice::<SimpleStruct>(&encoded);
assert!(result.is_err(), "truncated struct encoding should error");
}
#[derive(Debug, PartialEq, Encode, Decode)]
enum TinyEnum {
Alpha,
Beta,
}
#[test]
fn test_nonexistent_enum_discriminant_returns_error() {
let encoded = encode_to_vec(&TinyEnum::Alpha).expect("encode enum");
let mut tampered = encoded.clone();
tampered[0] = 200;
let result = decode_from_slice::<TinyEnum>(&tampered);
assert!(result.is_err(), "unknown enum discriminant should error");
}
#[test]
fn test_u32_max_value_roundtrip() {
let original = u32::MAX;
let encoded = encode_to_vec(&original).expect("encode u32::MAX");
let (decoded, consumed): (u32, _) = decode_from_slice(&encoded).expect("decode u32::MAX");
assert_eq!(decoded, original);
assert_eq!(consumed, encoded.len());
}
#[test]
fn test_decode_consumes_correct_byte_count_from_multi_value_slice() {
let enc_a = encode_to_vec(&10u32).expect("encode a");
let enc_b = encode_to_vec(&20u64).expect("encode b");
let mut combined = enc_a.clone();
combined.extend_from_slice(&enc_b);
let (val_a, consumed_a): (u32, _) = decode_from_slice(&combined).expect("decode first value");
assert_eq!(val_a, 10u32);
assert_eq!(consumed_a, enc_a.len());
let (val_b, consumed_b): (u64, _) =
decode_from_slice(&combined[consumed_a..]).expect("decode second value");
assert_eq!(val_b, 20u64);
assert_eq!(consumed_b, enc_b.len());
}
#[test]
fn test_multiple_sequential_decodes_accumulate_offsets() {
let values: Vec<u32> = vec![1, 2, 3, 4, 5];
let mut buffer: Vec<u8> = Vec::new();
for &v in &values {
let chunk = encode_to_vec(&v).expect("encode element");
buffer.extend_from_slice(&chunk);
}
let mut offset = 0usize;
for &expected in &values {
let (val, consumed): (u32, _) =
decode_from_slice(&buffer[offset..]).expect("sequential decode");
assert_eq!(val, expected);
offset += consumed;
}
assert_eq!(offset, buffer.len());
}
#[test]
fn test_large_sequence_length_with_small_limit_returns_error() {
let huge_len: u64 = 0x0001_0000_0000; let len_bytes = huge_len.to_le_bytes();
let mut fake_payload: Vec<u8> = vec![253]; fake_payload.extend_from_slice(&len_bytes);
let tiny_cfg = config::standard().with_limit::<16>();
let result = decode_from_slice_with_config::<Vec<u32>, _>(&fake_payload, tiny_cfg);
assert!(
result.is_err(),
"huge sequence with tiny limit should error"
);
}
#[test]
fn test_empty_vec_encodes_to_single_byte_and_roundtrips() {
let v: Vec<u32> = vec![];
let encoded = encode_to_vec(&v).expect("encode empty vec");
assert_eq!(
encoded.len(),
1,
"empty Vec should encode to exactly 1 byte"
);
assert_eq!(encoded[0], 0x00);
let (decoded, consumed): (Vec<u32>, _) = decode_from_slice(&encoded).expect("decode empty vec");
assert!(decoded.is_empty());
assert_eq!(consumed, 1);
}
#[test]
fn test_none_option_encodes_as_single_byte_0x00() {
let val: Option<u32> = None;
let encoded = encode_to_vec(&val).expect("encode None");
assert_eq!(encoded.len(), 1, "None should encode to exactly 1 byte");
assert_eq!(encoded[0], 0x00, "None discriminant must be 0x00");
}
#[test]
fn test_some_u32_max_first_byte_is_some_discriminant() {
let val: Option<u32> = Some(u32::MAX);
let encoded = encode_to_vec(&val).expect("encode Some(u32::MAX)");
assert!(
!encoded.is_empty(),
"Some(u32::MAX) encoding must not be empty"
);
assert_eq!(encoded[0], 0x01, "Some variant discriminant must be 0x01");
let (decoded, _): (Option<u32>, _) =
decode_from_slice(&encoded).expect("decode Some(u32::MAX)");
assert_eq!(decoded, Some(u32::MAX));
}