use std::io::{self, Read, Write};
use lzlib::{Level, Param};
struct PartialIo<I>(I);
impl<I: io::Read> io::Read for PartialIo<I> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0
.read(if buf.is_empty() { buf } else { &mut buf[0..1] })
}
}
impl<I: io::BufRead> io::BufRead for PartialIo<I> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.0
.fill_buf()
.map(|v| if v.is_empty() { v } else { &v[0..1] })
}
fn consume(&mut self, amt: usize) {
self.0.consume(amt)
}
}
impl<I: io::Write> io::Write for PartialIo<I> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(if buf.is_empty() { buf } else { &buf[0..1] })
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
struct TestCase {
original: &'static [u8],
param: Param,
compressed: &'static [u8],
}
impl TestCase {
const fn from_level(lvl: Level, original: &'static [u8], compressed: &'static [u8]) -> Self {
Self {
original,
param: Param::from_level_size(lvl, original.len() as u64),
compressed,
}
}
fn test_compress_reader(self) {
let mut reader =
PartialIo(lzlib::read::LzEncoder::new(self.param, PartialIo(self.original)).unwrap());
let mut ret = Vec::new();
reader.read_to_end(&mut ret).unwrap();
assert_eq!(ret, self.compressed)
}
fn test_decompress_reader(self) {
let mut reader =
PartialIo(lzlib::read::LzDecoder::new(PartialIo(self.compressed)).unwrap());
let mut ret = Vec::new();
reader.read_to_end(&mut ret).unwrap();
assert_eq!(ret, self.original);
}
fn test_compress_writer(self) {
let mut ret = Vec::new();
let mut writer =
PartialIo(lzlib::write::LzEncoder::new(self.param, PartialIo(&mut ret)).unwrap());
writer.write_all(self.original).unwrap();
writer.0.into_inner().unwrap();
assert_eq!(ret, self.compressed);
}
fn test_decompress_writer(self) {
let mut ret = Vec::new();
let mut writer = PartialIo(lzlib::write::LzDecoder::new(PartialIo(&mut ret)).unwrap());
writer.write_all(self.compressed).unwrap();
writer.0.into_inner().unwrap();
assert_eq!(ret, self.original);
}
}
macro_rules! mk_test {
($v:ident, $e:expr) => {
mod $v {
const TEST: crate::TestCase = $e;
mod read {
#[test]
fn encoder() {
super::TEST.test_compress_reader();
}
#[test]
fn decoder() {
super::TEST.test_decompress_reader();
}
}
mod write {
#[test]
fn encoder() {
super::TEST.test_compress_writer()
}
#[test]
fn decoder() {
super::TEST.test_decompress_writer()
}
}
}
};
}
macro_rules! mk_level_test {
($lvl:literal, $original:expr, $compress_base:literal) => {
paste::paste!(
mk_test!(
[< level $lvl >],
crate::TestCase::from_level(
lzlib::Level::[< Level $lvl >],
$original,
include_bytes!(concat!($compress_base, "/level_", $lvl, ".lz"))
)
);
);
};
}
macro_rules! mk_level_tests {
($name:ident, $original:expr, $compress_base: literal) => {
mod $name {
const ORIGINAL: &[u8] = $original;
mk_level_test!(1, super::ORIGINAL, $compress_base);
mk_level_test!(2, super::ORIGINAL, $compress_base);
mk_level_test!(3, super::ORIGINAL, $compress_base);
mk_level_test!(4, super::ORIGINAL, $compress_base);
mk_level_test!(5, super::ORIGINAL, $compress_base);
mk_level_test!(6, super::ORIGINAL, $compress_base);
mk_level_test!(7, super::ORIGINAL, $compress_base);
mk_level_test!(8, super::ORIGINAL, $compress_base);
mk_level_test!(9, super::ORIGINAL, $compress_base);
}
};
}
mk_level_tests!(empty, b"", "./data/empty.lz");
mk_level_tests!(
test,
include_bytes!("./data/test.txt"),
"./data/test.txt.lz"
);
mk_level_tests!(
fox_lf,
include_bytes!("./data/fox_lf.txt"),
"./data/fox_lf.txt.lz"
);