use crate::utils::setup;
use assert_cmd::cargo::cargo_bin_cmd;
use predicates::prelude::*;
use std::fs;
#[test]
fn diff_with_format_jsonl_and_content_difference() {
setup();
let dir = "diff_format_jsonl_content_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let file_path = format!("{dir}/file.txt");
fs::write(&file_path, "old-a").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &file_path])
.assert()
.success();
fs::write(&file_path, "new-a").unwrap();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.code(1)
.stderr("")
.stdout(format!(r#"{{"path":"{file_path}","kind":"content"}}"#) + "\n");
}
#[test]
fn diff_with_format_jsonl_and_missing_file() {
setup();
let dir = "diff_format_jsonl_missing_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let file_path = format!("{dir}/file.txt");
fs::write(&file_path, "content").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &file_path])
.assert()
.success();
fs::remove_file(&file_path).unwrap();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.code(1)
.stderr("")
.stdout(format!(r#"{{"path":"{file_path}","kind":"missing"}}"#) + "\n");
}
#[cfg(unix)]
#[test]
fn diff_with_format_jsonl_and_broken_hardlink() {
setup();
let dir = "diff_format_jsonl_hardlink_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let orig = format!("{dir}/orig.txt");
let link = format!("{dir}/link.txt");
fs::write(&orig, "content").unwrap();
fs::hard_link(&orig, &link).unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &orig, &link])
.assert()
.success();
fs::remove_file(&link).unwrap();
fs::write(&link, "content").unwrap();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.code(1)
.stderr("")
.stdout(format!(r#"{{"path":"{link}","kind":"hardlink","target":"{orig}"}}"#) + "\n");
}
#[test]
fn diff_with_format_jsonl_without_differences() {
setup();
let dir = "diff_format_jsonl_no_diff_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let file_path = format!("{dir}/file.txt");
fs::write(&file_path, "content").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &file_path])
.assert()
.success();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.success()
.stderr("")
.stdout("");
}
#[test]
fn diff_with_format_jsonl_and_size_and_type_differences() {
setup();
let dir = "diff_format_jsonl_kinds_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let size = format!("{dir}/size.txt");
let kind = format!("{dir}/kind.txt");
fs::write(&size, "short").unwrap();
fs::write(&kind, "y").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &size, &kind])
.assert()
.success();
fs::write(&size, "much longer content").unwrap();
fs::remove_file(&kind).unwrap();
fs::create_dir(&kind).unwrap();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.code(1)
.stderr("")
.stdout(
format!(r#"{{"path":"{size}","kind":"size"}}"#)
+ "\n"
+ &format!(r#"{{"path":"{kind}","kind":"type"}}"#)
+ "\n",
);
}
#[cfg(unix)]
#[test]
fn diff_with_format_jsonl_and_symlink_difference() {
use std::os::unix::fs::symlink;
setup();
let dir = "diff_format_jsonl_symlink_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let link = format!("{dir}/link");
symlink("orig", &link).unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &link])
.assert()
.success();
fs::remove_file(&link).unwrap();
symlink("other", &link).unwrap();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.code(1)
.stderr("")
.stdout(format!(r#"{{"path":"{link}","kind":"symlink"}}"#) + "\n");
}
#[cfg(unix)]
#[test]
fn diff_with_format_jsonl_and_metadata_differences() {
setup();
let dir = "diff_format_jsonl_metadata_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let file_path = format!("{dir}/file.txt");
fs::write(&file_path, "content").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args([
"create",
"-f",
&archive_path,
"--overwrite",
"--keep-permission",
"--keep-timestamp",
"--uid",
"12345",
"--uname",
"pna-absent-user",
"--gid",
"54321",
"--gname",
"pna-absent-group",
&file_path,
])
.assert()
.success();
std::fs::set_permissions(
&file_path,
std::os::unix::fs::PermissionsExt::from_mode(0o700),
)
.unwrap();
filetime::set_file_mtime(
&file_path,
filetime::FileTime::from_unix_time(946_684_800, 0),
)
.unwrap();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
"--unstable",
])
.assert()
.code(1)
.stderr("")
.stdout(
format!(r#"{{"path":"{file_path}","kind":"mode"}}"#)
+ "\n"
+ &format!(r#"{{"path":"{file_path}","kind":"mtime"}}"#)
+ "\n"
+ &format!(r#"{{"path":"{file_path}","kind":"uid"}}"#)
+ "\n"
+ &format!(r#"{{"path":"{file_path}","kind":"gid"}}"#)
+ "\n",
);
}
#[test]
fn diff_with_format_jsonl_without_unstable() {
setup();
let dir = "diff_format_jsonl_gate_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let file_path = format!("{dir}/file.txt");
fs::write(&file_path, "content").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &file_path])
.assert()
.success();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"jsonl",
])
.assert()
.code(2)
.stdout("")
.stderr(predicate::str::contains("requires --unstable flag"));
}
#[test]
fn diff_without_format_matches_plain() {
setup();
let dir = "diff_format_plain_test";
let _ = fs::remove_dir_all(dir);
fs::create_dir_all(dir).unwrap();
let file_path = format!("{dir}/file.txt");
fs::write(&file_path, "old-a").unwrap();
let archive_path = format!("{dir}/test.pna");
cargo_bin_cmd!("pna")
.args(["create", "-f", &archive_path, "--overwrite", &file_path])
.assert()
.success();
fs::write(&file_path, "new-a").unwrap();
let without_format = cargo_bin_cmd!("pna")
.args(["experimental", "diff", "-f", &archive_path])
.assert()
.code(1)
.stderr("")
.get_output()
.stdout
.clone();
cargo_bin_cmd!("pna")
.args([
"experimental",
"diff",
"-f",
&archive_path,
"--format",
"plain",
])
.assert()
.code(1)
.stderr("")
.stdout(without_format);
}