use super::*;
#[cfg(test)]
use crate::encoding::CompressionLevel;
#[cfg(test)]
use crate::encoding::Matcher;
#[cfg(test)]
use crate::encoding::dfast::DfastMatchGenerator;
#[cfg(test)]
use crate::encoding::match_generator::MatchGeneratorDriver;
use crate::encoding::test_support::BlockReplay;
use alloc::vec::Vec;
#[test]
fn dfast_matches_roundtrip_multi_block_pattern() {
let pattern = [9, 21, 44, 184, 19, 96, 171, 109, 141, 251];
let first_block: Vec<u8> = pattern.iter().copied().cycle().take(128 * 1024).collect();
let second_block: Vec<u8> = pattern.iter().copied().cycle().take(128 * 1024).collect();
let mut matcher = DfastMatchGenerator::new(1 << 22);
matcher.commit_input(&first_block);
let mut history = Vec::new();
let mut replay = BlockReplay::new(&first_block);
matcher.start_matching(|seq| replay.apply(&mut history, seq));
assert_eq!(history, first_block);
matcher.commit_input(&second_block);
let prefix_len = history.len();
let mut replay = BlockReplay::new(&second_block);
matcher.start_matching(|seq| replay.apply(&mut history, seq));
assert_eq!(&history[prefix_len..], second_block.as_slice());
}
#[test]
fn dfast_accepts_exact_five_byte_match() {
let mut data = Vec::new();
data.push(b'Z'); data.extend_from_slice(b"ABCDE"); data.extend_from_slice(b"!!!!!!!!!!!!!!!!!!!!!!!"); data.extend_from_slice(b"ABCDE"); data.push(b'F'); data.extend_from_slice(b"GHIJKLMNOPQRSTUVWXYZ"); assert_eq!(data.len(), 55);
let mut matcher = DfastMatchGenerator::new(1 << 22);
matcher.commit_input(&data);
let mut saw_five_byte_match = false;
let mut saw_longer_match = false;
matcher.start_matching(|seq| {
if let Sequence::Triple {
offset, match_len, ..
} = seq
{
if offset == 28 && match_len == 5 {
saw_five_byte_match = true;
} else if offset == 28 && match_len > 5 {
saw_longer_match = true;
}
}
});
assert!(
saw_five_byte_match,
"dfast must accept the exact-5-byte match — a 6-byte floor would skip it"
);
assert!(
!saw_longer_match,
"fixture pinned to length 5 — byte 33 ('F') must terminate the extension"
);
}
#[test]
fn driver_switches_backends_and_initializes_dfast_via_reset() {
let mut driver = MatchGeneratorDriver::new(32, 2);
driver.reset(CompressionLevel::Default);
assert_eq!(
driver.active_backend(),
crate::encoding::strategy::BackendTag::Dfast
);
assert_eq!(driver.window_size(), (1u64 << 21));
driver.commit_input(b"abcabcabcabc");
assert_eq!(driver.get_last_space(), b"abcabcabcabc");
driver.skip_matching_with_hint(None);
driver.commit_input(b"abcabcabcabc");
let mut reconstructed = b"abcabcabcabc".to_vec();
let mut replay = BlockReplay::new(b"abcabcabcabc");
driver.start_matching(|seq| replay.apply(&mut reconstructed, seq));
assert_eq!(reconstructed, b"abcabcabcabcabcabcabcabc");
driver.reset(CompressionLevel::Fastest);
assert_eq!(driver.window_size(), (1u64 << 19));
}
#[test]
fn driver_level5_selects_row_backend() {
let mut driver = MatchGeneratorDriver::new(32, 2);
driver.reset(CompressionLevel::Level(5));
assert_eq!(
driver.active_backend(),
crate::encoding::strategy::BackendTag::Row
);
assert_eq!(
driver.parse,
crate::encoding::strategy::ParseMode::Greedy,
"L5 must route to start_matching_greedy (parse == Greedy)",
);
assert_eq!(
driver.row_matcher().lazy_depth,
0,
"row matcher lazy_depth must mirror the greedy parse mode",
);
}
#[test]
fn driver_level4_greedy_round_trip_single_slice() {
let mut driver = MatchGeneratorDriver::new(64, 2);
driver.reset(CompressionLevel::Level(4));
let input = b"abcdefgh_abcdefgh_abcdefgh_abcdefgh";
driver.commit_input(input);
let mut reconstructed: Vec<u8> = Vec::new();
let mut saw_triple = false;
let mut replay = BlockReplay::new(input);
driver.start_matching(|seq| {
saw_triple |= matches!(seq, Sequence::Triple { .. });
replay.apply(&mut reconstructed, seq);
});
assert_eq!(
reconstructed,
input.to_vec(),
"L4 greedy parse failed to reconstruct repeating-pattern input",
);
assert!(
saw_triple,
"L4 greedy parse on a repeating pattern must emit at least one match (Triple)",
);
}
#[test]
fn driver_level4_greedy_round_trip_cross_slice() {
let mut driver = MatchGeneratorDriver::new(32, 4);
driver.reset(CompressionLevel::Level(4));
let chunk = b"the quick brown fox jumps over!!";
assert_eq!(chunk.len(), 32);
driver.commit_input(chunk);
let mut first_recon: Vec<u8> = Vec::new();
let mut replay = BlockReplay::new(chunk);
driver.start_matching(|seq| replay.apply(&mut first_recon, seq));
assert_eq!(
first_recon,
chunk.to_vec(),
"first slice failed to round-trip"
);
driver.commit_input(chunk);
let mut full = first_recon.clone();
let mut saw_cross_slice_match = false;
let mut replay = BlockReplay::new(chunk);
driver.start_matching(|seq| {
if let Sequence::Triple { offset, .. } = seq
&& offset >= chunk.len()
{
saw_cross_slice_match = true;
}
replay.apply(&mut full, seq);
});
let mut expected = chunk.to_vec();
expected.extend_from_slice(chunk);
assert_eq!(
full, expected,
"cross-slice L4 greedy parse failed to reconstruct"
);
assert!(
saw_cross_slice_match,
"L4 greedy parse must match across slice boundaries (history is shared)",
);
}