use super::*;
use crate::encoding::CompressionLevel;
use alloc::vec::Vec;
#[test]
fn captures_at_least_one_triple_on_repeating_pattern() {
let pattern: [u8; 16] = *b"PATTERN_1234_END";
let data: Vec<u8> = pattern.iter().copied().cycle().take(16 * 1024).collect();
let captured = compress_and_collect_sequences(&data, CompressionLevel::Level(3));
let seqs = &captured.sequences;
assert!(
!seqs.is_empty(),
"expected at least one Triple sequence on 16KB repeating pattern, got 0",
);
assert!(
seqs.iter().all(|s| s.block_idx == 0),
"16KB repeating pattern produced multi-block sequence stream: {:?}",
seqs.iter().map(|s| s.block_idx).collect::<Vec<_>>(),
);
for s in seqs {
assert!(s.of >= 1, "non-positive offset captured: {:?}", s);
assert!(s.ml >= 1, "non-positive match length captured: {:?}", s);
}
for (i, s) in seqs.iter().enumerate() {
assert_eq!(
s.seq_in_block, i as u32,
"seq_in_block discontinuity at idx {}: {:?}",
i, seqs,
);
}
assert_eq!(captured.block_tail_lengths.len(), 1);
let cumulative: u64 = seqs.iter().map(|s| s.ll as u64 + s.ml as u64).sum::<u64>()
+ captured.block_tail_lengths[0] as u64;
assert_eq!(
cumulative,
data.len() as u64,
"Σ(ll+ml) + tail must reconstruct the input length exactly: \
seqs sum + tail {} should == input {}",
cumulative,
data.len(),
);
}
#[test]
#[should_panic(expected = "raw/RLE block")]
fn rejects_incompressible_input_with_raw_on_wire_block() {
let mut state: u32 = 0x1234_5678;
let data: Vec<u8> = (0..1024)
.map(|_| {
state = state.wrapping_mul(1_664_525).wrapping_add(1_013_904_223);
(state >> 16) as u8
})
.collect();
let _ = compress_and_collect_sequences(&data, CompressionLevel::Level(3));
}
#[test]
#[should_panic(expected = "raw/RLE block")]
fn rejects_constant_run_with_rle_on_wire_block() {
let data: Vec<u8> = alloc::vec![b'A'; 16 * 1024];
let _ = compress_and_collect_sequences(&data, CompressionLevel::Level(3));
}
#[test]
fn captures_multi_block_tails_and_indices() {
let pattern: [u8; 16] = *b"PATTERN_1234_END";
let data: Vec<u8> = pattern.iter().copied().cycle().take(200 * 1024).collect();
let captured = compress_and_collect_sequences(&data, CompressionLevel::Level(3));
assert!(
captured.block_tail_lengths.len() >= 2,
"expected ≥2 block tail entries for 200 KiB input, got {}: {:?}",
captured.block_tail_lengths.len(),
captured.block_tail_lengths,
);
let cumulative: u64 = captured
.sequences
.iter()
.map(|s| s.ll as u64 + s.ml as u64)
.sum::<u64>()
+ captured
.block_tail_lengths
.iter()
.map(|t| *t as u64)
.sum::<u64>();
assert_eq!(
cumulative,
data.len() as u64,
"multi-block Σ(ll+ml)+Σ(tails) mismatch: got {}, want {} \
(blocks={}, triples={})",
cumulative,
data.len(),
captured.block_tail_lengths.len(),
captured.sequences.len(),
);
let num_blocks = captured.block_tail_lengths.len() as u32;
for s in &captured.sequences {
assert!(
s.block_idx < num_blocks,
"triple block_idx={} out of range (num_blocks={})",
s.block_idx,
num_blocks,
);
}
let mut max_seen: i64 = -1;
for s in &captured.sequences {
let idx = s.block_idx as i64;
assert!(
idx <= max_seen + 1,
"non-monotonic / gapped block_idx in triple stream: \
max_seen={max_seen}, observed={idx}",
);
if idx > max_seen {
max_seen = idx;
}
}
}
#[test]
#[should_panic(expected = "requires non-empty input")]
fn rejects_empty_input() {
let _ = compress_and_collect_sequences(&[], CompressionLevel::Level(3));
}
#[test]
#[should_panic(expected = "CompressionLevel::Uncompressed")]
fn rejects_uncompressed_level() {
let _ = compress_and_collect_sequences(
b"hello there general kenobi",
CompressionLevel::Uncompressed,
);
}
#[test]
#[should_panic(expected = "does not support post-split levels")]
fn rejects_post_split_numeric_level() {
let _ =
compress_and_collect_sequences(b"hello there general kenobi", CompressionLevel::Level(16));
}
#[test]
fn captures_through_best_preset() {
let pattern: [u8; 32] = {
let mut p = [0u8; 32];
for (i, b) in p.iter_mut().enumerate() {
*b = (i as u8).wrapping_mul(11).wrapping_add(3);
}
p
};
let data: Vec<u8> = pattern.iter().copied().cycle().take(32 * 1024).collect();
let captured = compress_and_collect_sequences(&data, CompressionLevel::Best);
let cumulative: u64 = captured
.sequences
.iter()
.map(|s| s.ll as u64 + s.ml as u64)
.sum::<u64>()
+ captured
.block_tail_lengths
.iter()
.map(|t| *t as u64)
.sum::<u64>();
assert_eq!(cumulative, data.len() as u64);
}
#[test]
fn captures_through_pre_split_level_15() {
let pattern: [u8; 16] = *b"PATTERN_1234_END";
let data: Vec<u8> = pattern.iter().copied().cycle().take(32 * 1024).collect();
let captured = compress_and_collect_sequences(&data, CompressionLevel::Level(15));
let cumulative: u64 = captured
.sequences
.iter()
.map(|s| s.ll as u64 + s.ml as u64)
.sum::<u64>()
+ captured
.block_tail_lengths
.iter()
.map(|t| *t as u64)
.sum::<u64>();
assert_eq!(cumulative, data.len() as u64);
}