use super::StreamingDecoder;
use crate::io::Read;
#[cfg(feature = "hash")]
#[test]
fn read_delivering_bytes_defers_checksum_error_to_next_call() {
use crate::decoding::ContentChecksum;
use crate::encoding::{CompressionLevel, FrameCompressor};
use crate::io::ErrorKind;
use alloc::vec;
use alloc::vec::Vec;
let payload: Vec<u8> = (0..8192u32).map(|i| (i & 0xFF) as u8).collect();
let mut compressor = FrameCompressor::new(CompressionLevel::Default);
compressor.set_content_checksum(true);
compressor.set_source(payload.as_slice());
let mut compressed = Vec::new();
compressor.set_drain(&mut compressed);
compressor.compress();
let last = compressed.len() - 1;
compressed[last] ^= 0xFF;
let mut decoder = StreamingDecoder::new(compressed.as_slice()).unwrap();
decoder
.decoder
.set_content_checksum(ContentChecksum::Verify);
let mut buf = vec![0u8; payload.len() + 4096];
let n = decoder
.read(&mut buf)
.expect("a read that delivered bytes must not return the checksum Err");
assert_eq!(n, payload.len());
assert_eq!(&buf[..n], payload.as_slice());
let err = decoder
.read(&mut buf)
.expect_err("deferred checksum mismatch must surface on the terminating read");
assert_eq!(err.kind(), ErrorKind::Other);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_decode_in_place_matches_and_takes_direct_path() {
use crate::encoding::{CompressionLevel, FrameCompressor};
use alloc::vec::Vec;
let payload: Vec<u8> = (0..20_000u32)
.map(|i| (i.wrapping_mul(2654435761) >> 24) as u8)
.collect();
let mut compressor = FrameCompressor::new(CompressionLevel::Default);
compressor.set_source(payload.as_slice());
let mut compressed = Vec::new();
compressor.set_drain(&mut compressed);
compressor.compress();
let mut decoder = StreamingDecoder::new(compressed.as_slice()).unwrap();
let mut out = Vec::new();
let n = decoder.read_to_end(&mut out).unwrap();
assert_eq!(n, payload.len());
assert_eq!(out, payload);
assert_eq!(decoder.decoder.direct_frames(), 1);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_after_partial_read_is_complete() {
use crate::encoding::{CompressionLevel, FrameCompressor};
use alloc::vec;
use alloc::vec::Vec;
let payload: Vec<u8> = (0..20_000u32).map(|i| (i & 0xFF) as u8).collect();
let mut compressor = FrameCompressor::new(CompressionLevel::Default);
compressor.set_source(payload.as_slice());
let mut compressed = Vec::new();
compressor.set_drain(&mut compressed);
compressor.compress();
let mut decoder = StreamingDecoder::new(compressed.as_slice()).unwrap();
let mut head = vec![0u8; 4096];
let got = decoder.read(&mut head).unwrap();
assert!(got > 0 && got <= head.len());
let mut out = Vec::new();
out.extend_from_slice(&head[..got]);
decoder.read_to_end(&mut out).unwrap();
assert_eq!(out, payload);
assert_eq!(decoder.decoder.direct_frames(), 0);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_decodes_all_concatenated_frames() {
use crate::encoding::{CompressionLevel, compress_slice_to_vec};
use alloc::vec::Vec;
let a: Vec<u8> = (0..5000u32).map(|i| (i & 0xFF) as u8).collect();
let b: Vec<u8> = (0..3000u32)
.map(|i| ((i.wrapping_mul(7)) & 0xFF) as u8)
.collect();
let mut stream = compress_slice_to_vec(&a, CompressionLevel::Level(3));
stream.extend_from_slice(&compress_slice_to_vec(&b, CompressionLevel::Level(3)));
let mut decoder = StreamingDecoder::new(stream.as_slice()).unwrap();
let mut out = Vec::new();
decoder.read_to_end(&mut out).unwrap();
let mut expected = a.clone();
expected.extend_from_slice(&b);
assert_eq!(out, expected);
assert_eq!(decoder.decoder.direct_frames(), 2);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_after_partial_read_decodes_all_concatenated_frames() {
use crate::encoding::{CompressionLevel, compress_slice_to_vec};
use alloc::vec;
use alloc::vec::Vec;
let a: Vec<u8> = (0..6000u32).map(|i| (i & 0xFF) as u8).collect();
let b: Vec<u8> = (0..4000u32)
.map(|i| ((i.wrapping_mul(11)) & 0xFF) as u8)
.collect();
let mut stream = compress_slice_to_vec(&a, CompressionLevel::Level(3));
stream.extend_from_slice(&compress_slice_to_vec(&b, CompressionLevel::Level(3)));
let mut decoder = StreamingDecoder::new(stream.as_slice()).unwrap();
let mut head = vec![0u8; 2048];
let got = decoder.read(&mut head).unwrap();
assert!(got > 0 && got <= head.len());
let mut out = Vec::new();
out.extend_from_slice(&head[..got]);
decoder.read_to_end(&mut out).unwrap();
let mut expected = a.clone();
expected.extend_from_slice(&b);
assert_eq!(
out, expected,
"fallback path must decode frame 2 too, not stop at frame 1 EOF"
);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_concatenated_dict_frames_decode_with_dictionary() {
use crate::encoding::{CompressionLevel, FrameCompressor};
use alloc::vec::Vec;
let dict_raw = include_bytes!("../../../dict_tests/dictionary");
let compress_with_dict = |payload: &[u8]| -> Vec<u8> {
let mut compressor = FrameCompressor::new(CompressionLevel::Default);
compressor
.set_dictionary_from_bytes(dict_raw)
.expect("dict load");
compressor.set_source(payload);
let mut compressed = Vec::new();
compressor.set_drain(&mut compressed);
compressor.compress();
compressed
};
let a = b"first dictionary-compressed frame payload".to_vec();
let b = b"second dictionary-compressed frame payload".to_vec();
let mut stream = compress_with_dict(&a);
stream.extend_from_slice(&compress_with_dict(&b));
let mut decoder =
StreamingDecoder::new_with_dictionary_bytes(stream.as_slice(), dict_raw).unwrap();
let mut out = Vec::new();
decoder
.read_to_end(&mut out)
.expect("both dict frames must decode with the forced dictionary");
let mut expected = a.clone();
expected.extend_from_slice(&b);
assert_eq!(out, expected);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_truncates_output_on_direct_decode_error() {
use crate::encoding::{CompressionLevel, FrameCompressor};
use alloc::vec::Vec;
let payload: Vec<u8> = (0..5000u32).map(|i| (i & 0xFF) as u8).collect();
let mut compressor = FrameCompressor::new(CompressionLevel::Default);
compressor.set_source(payload.as_slice());
let mut compressed = Vec::new();
compressor.set_drain(&mut compressed);
compressor.compress();
compressed.truncate(compressed.len() - 40);
let mut decoder = StreamingDecoder::new(compressed.as_slice()).unwrap();
let mut out = b"SENTINEL".to_vec();
let result = decoder.read_to_end(&mut out);
assert!(result.is_err(), "truncated block must fail the decode");
assert_eq!(
out, b"SENTINEL",
"failed direct decode must not append non-decoded bytes to output"
);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_truncates_output_on_midframe_fallback_error() {
use crate::encoding::{CompressionLevel, CompressionParameters, FrameCompressor};
use alloc::vec;
use alloc::vec::Vec;
let payload: Vec<u8> = (0..320_000u32)
.map(|i| (i.wrapping_mul(2654435761) >> 24) as u8)
.collect();
let params = CompressionParameters::builder(CompressionLevel::Default)
.window_log(17)
.build()
.expect("window_log within bounds");
let mut compressor = FrameCompressor::new(CompressionLevel::Default);
compressor.set_parameters(¶ms);
compressor.set_source(payload.as_slice());
let mut compressed = Vec::new();
compressor.set_drain(&mut compressed);
compressor.compress();
compressed.truncate(compressed.len() - 40);
let mut decoder = StreamingDecoder::new(compressed.as_slice()).unwrap();
let mut head = vec![0u8; 4096];
let got = decoder.read(&mut head).unwrap();
assert!(got > 0);
let mut out = Vec::new();
out.extend_from_slice(&head[..got]);
let result = decoder.read_to_end(&mut out);
assert!(
result.is_err(),
"truncated current frame must fail the decode"
);
assert!(
out.len() <= payload.len(),
"failed fallback read must not leave a zero-filled tail (len {} > payload {})",
out.len(),
payload.len()
);
assert_eq!(
out.as_slice(),
&payload[..out.len()],
"decoded prefix must match the payload, with no appended non-decoded bytes"
);
}
#[cfg(feature = "std")]
#[test]
fn read_to_end_empty_frame_decodes_to_empty() {
use crate::encoding::{CompressionLevel, compress_slice_to_vec};
use alloc::vec::Vec;
let compressed = compress_slice_to_vec(&[], CompressionLevel::Level(3));
let mut decoder = StreamingDecoder::new(compressed.as_slice()).unwrap();
let mut out = Vec::new();
decoder.read_to_end(&mut out).unwrap();
assert!(out.is_empty());
}