use assert_cmd::Command;
use predicates::prelude::*;
use std::fs;
use tempfile::TempDir;
type Result<T> = anyhow::Result<T>;
fn zzz_cmd() -> Command {
Command::cargo_bin("zzz").expect("failed to find zzz binary")
}
#[test]
fn test_cli_help() {
zzz_cmd()
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains(
"Create and extract archives in multiple formats",
))
.stdout(predicate::str::contains("Commands:"))
.stdout(predicate::str::contains("compress"))
.stdout(predicate::str::contains("extract"))
.stdout(predicate::str::contains("list"));
}
#[test]
fn test_cli_version() {
zzz_cmd()
.arg("--version")
.assert()
.success()
.stdout(predicate::str::contains("zzz"));
}
#[test]
fn test_compress_help() {
zzz_cmd()
.args(["compress", "--help"])
.assert()
.success()
.stdout(predicate::str::contains(
"compress files/directories (supports",
))
.stdout(predicate::str::contains("--level"))
.stdout(predicate::str::contains("--output"))
.stdout(predicate::str::contains("--progress"))
.stdout(predicate::str::contains("--exclude"));
}
#[test]
fn test_compress_single_file() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("test.txt");
let output_file = temp_dir.path().join("test.zst");
fs::write(&source_file, "Hello, CLI test!")?;
zzz_cmd()
.args(["compress", "--output"])
.arg(&output_file)
.arg(&source_file)
.assert()
.success()
.stdout(predicate::str::contains("compressed"))
.stdout(predicate::str::contains("test.txt"))
.stdout(predicate::str::contains("test.zst"));
assert!(output_file.exists());
Ok(())
}
#[test]
fn test_compress_with_short_alias() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("test.txt");
let output_file = temp_dir.path().join("test.zst");
fs::write(&source_file, "Test content")?;
zzz_cmd()
.args(["c", "-o"])
.arg(&output_file)
.arg(&source_file)
.assert()
.success();
assert!(output_file.exists());
Ok(())
}
#[test]
fn test_compress_directory() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_dir = temp_dir.path().join("testdir");
let output_file = temp_dir.path().join("testdir.zst");
fs::create_dir(&source_dir)?;
fs::write(source_dir.join("file1.txt"), "content1")?;
fs::write(source_dir.join("file2.txt"), "content2")?;
let subdir = source_dir.join("subdir");
fs::create_dir(&subdir)?;
fs::write(subdir.join("nested.txt"), "nested")?;
zzz_cmd()
.args(["compress", "-o"])
.arg(&output_file)
.arg(&source_dir)
.assert()
.success()
.stdout(predicate::str::contains("compressed"));
assert!(output_file.exists());
Ok(())
}
#[test]
fn test_compress_with_custom_level() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("test.txt");
let output_file = temp_dir.path().join("test.zst");
fs::write(&source_file, "Test compression level")?;
zzz_cmd()
.args(["compress", "--level", "1", "-o"])
.arg(&output_file)
.arg(&source_file)
.assert()
.success();
assert!(output_file.exists());
Ok(())
}
#[test]
fn test_compress_with_custom_excludes() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_dir = temp_dir.path().join("source");
let output_file = temp_dir.path().join("filtered.zst");
fs::create_dir(&source_dir)?;
fs::write(source_dir.join("keep.txt"), "keep this")?;
fs::write(source_dir.join("exclude.log"), "exclude this")?;
fs::write(source_dir.join("test_file.txt"), "exclude this too")?;
zzz_cmd()
.args([
"compress",
"--exclude",
"*.log",
"--exclude",
"test_*",
"-o",
])
.arg(&output_file)
.arg(&source_dir)
.assert()
.success();
assert!(output_file.exists());
Ok(())
}
#[test]
fn test_extract_archive() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("test.txt");
let archive_file = temp_dir.path().join("test.zst");
let extract_dir = temp_dir.path().join("extracted");
fs::write(&source_file, "Extract test content")?;
zzz_cmd()
.args(["compress", "-o"])
.arg(&archive_file)
.arg(&source_file)
.assert()
.success();
fs::create_dir(&extract_dir)?;
zzz_cmd()
.args(["extract", "-C"])
.arg(&extract_dir)
.arg(&archive_file)
.assert()
.success()
.stdout(predicate::str::contains("extracting").or(predicate::str::is_empty()));
let extracted_file = extract_dir.join("test.txt");
assert!(extracted_file.exists());
assert_eq!(fs::read_to_string(extracted_file)?, "Extract test content");
Ok(())
}
#[test]
fn test_extract_with_alias() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("test.txt");
let archive_file = temp_dir.path().join("test.zst");
let extract_dir = temp_dir.path().join("extracted");
fs::write(&source_file, "Test content")?;
zzz_cmd()
.args(["c", "-o"])
.arg(&archive_file)
.arg(&source_file)
.assert()
.success();
fs::create_dir(&extract_dir)?;
zzz_cmd()
.args(["x", "-C"])
.arg(&extract_dir)
.arg(&archive_file)
.assert()
.success();
assert!(extract_dir.join("test.txt").exists());
Ok(())
}
#[test]
fn test_list_archive() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_dir = temp_dir.path().join("source");
let archive_file = temp_dir.path().join("list_test.zst");
fs::create_dir(&source_dir)?;
fs::write(source_dir.join("file1.txt"), "content1")?;
fs::write(source_dir.join("file2.txt"), "content2")?;
let subdir = source_dir.join("subdir");
fs::create_dir(&subdir)?;
fs::write(subdir.join("nested.txt"), "nested")?;
zzz_cmd()
.args(["compress", "-o"])
.arg(&archive_file)
.arg(&source_dir)
.assert()
.success();
zzz_cmd()
.args(["list"])
.arg(&archive_file)
.assert()
.success()
.stdout(predicate::str::contains("file1.txt"))
.stdout(predicate::str::contains("file2.txt"))
.stdout(predicate::str::contains("nested.txt"));
Ok(())
}
#[test]
fn test_list_with_alias_and_verbose() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("test.txt");
let archive_file = temp_dir.path().join("test.zst");
fs::write(&source_file, "Test content for verbose listing")?;
zzz_cmd()
.args(["c", "-o"])
.arg(&archive_file)
.arg(&source_file)
.assert()
.success();
zzz_cmd()
.args(["l", "--verbose"])
.arg(&archive_file)
.assert()
.success()
.stdout(predicate::str::contains("test.txt"))
.stdout(predicate::str::contains("B"));
Ok(())
}
#[test]
fn test_compress_auto_output_name() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("auto_name.txt");
let expected_output = temp_dir.path().join("auto_name.txt.zst");
fs::write(&source_file, "Auto naming test")?;
zzz_cmd()
.args(["compress"])
.arg(&source_file)
.current_dir(&temp_dir)
.assert()
.success();
assert!(expected_output.exists());
Ok(())
}
#[test]
fn test_error_missing_input_file() {
zzz_cmd()
.args(["compress", "/nonexistent/file.txt"])
.assert()
.failure()
.stderr(predicate::str::contains("error"));
}
#[test]
fn test_error_invalid_compression_level() {
let temp_dir = TempDir::new().unwrap();
let source_file = temp_dir.path().join("test.txt");
fs::write(&source_file, "test").unwrap();
zzz_cmd()
.args(["compress", "--level", "25"]) .arg(&source_file)
.assert()
.failure();
}
#[test]
fn test_verbose_output() -> Result<()> {
let temp_dir = TempDir::new()?;
let source_file = temp_dir.path().join("verbose_test.txt");
let output_file = temp_dir.path().join("verbose_test.zst");
fs::write(&source_file, "Verbose test content")?;
zzz_cmd()
.args(["--verbose", "compress", "-o"])
.arg(&output_file)
.arg(&source_file)
.assert()
.success()
.stdout(predicate::str::contains("compressing"))
.stdout(predicate::str::contains("compressed"));
Ok(())
}