use assert_cmd::cargo;
use predicates::prelude::*;
use std::fs::{create_dir_all, metadata, remove_dir_all, write};
use std::path::PathBuf;
use zst_compress::auxiliary::DirGuard;
#[test]
fn test_cli() {
run_test(
"tests/data_default",
&["."],
"/2) Compress:",
&vec![false, false, false, true, true, true],
&["-x", "."],
"/3) Extract:",
&vec![true, true, true, false, false, false],
)
.unwrap();
run_test(
"tests/data_preserve",
&["--preserve", "."],
"Compress:",
&vec![true, true, true, true, true, true],
&["--preserve", "--extract", "."],
"Extract:",
&vec![true, true, true, true, true, true],
)
.unwrap();
run_test(
"tests/data_single",
&[".", "--include", "large_test.bin"],
"(1/1) Compress:",
&vec![true, true, false, false, false, true],
&[".", "--preserve", "--extract"],
"/2) Extract:",
&vec![true, true, true, false, false, true],
)
.unwrap();
}
fn run_test(
test_data_dir: &str,
compress_args: &[&str],
compress_expect: &str,
compress_files_status: &Vec<bool>,
decompress_args: &[&str],
decompress_expect: &str,
decompress_files_status: &Vec<bool>,
) -> Result<(), Box<dyn std::error::Error>> {
let test_dir = PathBuf::from(test_data_dir);
{
let _dir_guard = run_setup(&test_dir)?;
let (filenames, filesizes) = run_test_files_create()?;
run_test_command(compress_args, compress_expect)?;
run_test_files_check(&filenames, &filesizes, compress_files_status)?;
run_test_command(decompress_args, decompress_expect)?;
run_test_files_check(&filenames, &filesizes, decompress_files_status)?;
}
run_cleanup(&test_dir)?;
Ok(())
}
fn run_setup(test_dir: &PathBuf) -> Result<DirGuard, Box<dyn std::error::Error>> {
create_dir_all(test_dir)?;
DirGuard::new(test_dir).map_err(|e| {
Box::new(std::io::Error::other(format!(
"Failed to change directory: {e}"
))) as Box<dyn std::error::Error>
})
}
fn run_cleanup(test_dir: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
let _ = remove_dir_all(test_dir);
Ok(())
}
fn run_test_files_create() -> Result<(Vec<PathBuf>, Vec<u64>), Box<dyn std::error::Error>> {
create_dir_all(PathBuf::from("dir"))?;
let dir_bin_input = PathBuf::from("dir/data1.bin");
let dir_text_input = PathBuf::from("dir/text.txt");
let file_input = PathBuf::from("large_test.bin");
let dir_output = PathBuf::from("dir.tar.zst");
let dir_filelist_output = PathBuf::from("dir_archived-filelist.txt");
let file_output = PathBuf::from("large_test.bin.tar.zst");
let pattern = b"BINARYDATAPATTERN1234567890";
let mut dir_bin_data = Vec::with_capacity(1_000_000);
while dir_bin_data.len() < 1_000_000 {
dir_bin_data.extend_from_slice(pattern);
}
dir_bin_data.truncate(1_000_000);
write(&dir_bin_input, &dir_bin_data)?;
write(
&dir_text_input,
"This is a test text file\nwith multiple lines\n",
)?;
let pattern = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let mut data = Vec::with_capacity(1_000_000);
while data.len() < 2_000_000 {
data.extend_from_slice(pattern);
}
data.truncate(2_000_000);
write(&file_input, &data)?;
Ok((
vec![
dir_bin_input.clone(),
dir_text_input.clone(),
file_input.clone(),
dir_output,
dir_filelist_output,
file_output,
],
vec![
metadata(&dir_bin_input)?.len(),
metadata(&dir_text_input)?.len(),
metadata(&file_input)?.len(),
],
))
}
fn run_test_files_check(
filenames: &Vec<PathBuf>,
filesizes: &Vec<u64>,
status: &Vec<bool>,
) -> Result<(), Box<dyn std::error::Error>> {
for file_index in 0..filenames.len() {
match status[file_index] {
true => {
let path = &filenames[file_index];
assert!(
path.exists(),
"File {} should exist but doesn't",
path.display()
);
if file_index == 3 || file_index == 5 {
let input_size = filesizes[file_index - 3];
let output_size = metadata(path)?.len();
assert!(
output_size < input_size,
"Compressed file {} ({} bytes) should be smaller than input ({} bytes)",
path.display(),
output_size,
input_size
);
}
else if file_index == 4 && path.exists() {
let contents = std::fs::read_to_string(path)?;
println!("{contents}");
assert!(
contents.contains("data1.bin"),
"Filelist should contain 'data1.bin'"
);
assert!(
contents.contains("text.txt"),
"Filelist should contain 'text.txt'"
);
}
}
false => {
assert!(!filenames[file_index].exists());
}
}
}
Ok(())
}
fn run_test_command(
args: &[&str],
expected_output: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = cargo::cargo_bin_cmd!(env!("CARGO_PKG_NAME"));
for arg in args {
cmd.arg(arg);
}
cmd.assert()
.success()
.stdout(predicate::str::contains(expected_output));
Ok(())
}