Skip to content

Commit b158315

Browse files
committed
✅ Add regression guard tests for bsdtar update @ and create -C-only
- archive_inclusion: verify update mode treats @-prefixed operands as filesystem paths (not archive inclusion) - missing_file: verify create mode rejects -C without real input files Both tests pass on main, proving these are pre-existing correct behaviors. They guard against regressions when the -C pipeline is changed.
1 parent dfce2be commit b158315

2 files changed

Lines changed: 90 additions & 0 deletions

File tree

cli/tests/cli/stdio/archive_inclusion.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,3 +718,62 @@ fn stdio_archive_inclusion_solid_with_filter() {
718718
"exclude.log should not be extracted"
719719
);
720720
}
721+
722+
/// Precondition: An archive exists and a file whose name starts with @ exists on disk.
723+
/// Action: Run bsdtar update mode with `@file` as an operand — note the leading `@`.
724+
/// Expectation: The `@` is NOT interpreted as archive inclusion. The file is added to
725+
/// the archive as a regular filesystem entry named `@file`.
726+
#[test]
727+
fn stdio_update_treats_at_prefix_as_filesystem_path() {
728+
setup();
729+
730+
let base = PathBuf::from("stdio_update_at_prefix_as_path");
731+
if base.exists() {
732+
fs::remove_dir_all(&base).unwrap();
733+
}
734+
fs::create_dir_all(&base).unwrap();
735+
736+
let archive_path = base.join("archive.pna");
737+
create_test_archive(&archive_path, &[("original.txt", "original")]);
738+
739+
// Create a file whose name literally starts with @
740+
fs::write(base.join("@data.txt"), "at-content").unwrap();
741+
742+
// Decoy: if @data.txt were misinterpreted as archive inclusion of "data.txt",
743+
// this archive's entries would leak into the result.
744+
create_test_archive(&base.join("data.txt"), &[("canary.txt", "canary")]);
745+
746+
// Pass "@data.txt" — a positional arg starting with @.
747+
// -C is infrastructure to make the relative path resolvable.
748+
// The actual thing under test is that "@data.txt" is treated as a literal
749+
// filesystem path, not parsed as an @archive inclusion reference.
750+
cargo_bin_cmd!("pna")
751+
.args([
752+
"--quiet",
753+
"compat",
754+
"bsdtar",
755+
"--unstable",
756+
"-uf",
757+
archive_path.to_str().unwrap(),
758+
"-C",
759+
base.to_str().unwrap(),
760+
"@data.txt",
761+
])
762+
.assert()
763+
.success();
764+
765+
let entry_names: HashSet<String> = get_archive_entry_names(&archive_path).into_iter().collect();
766+
assert!(
767+
entry_names.contains("original.txt"),
768+
"original entry should be preserved"
769+
);
770+
assert!(
771+
entry_names.contains("@data.txt"),
772+
"@ prefix should be part of the entry name, not stripped as archive inclusion"
773+
);
774+
assert!(
775+
!entry_names.contains("canary.txt"),
776+
"@data.txt must not be interpreted as archive inclusion of data.txt"
777+
);
778+
assert_eq!(entry_names.len(), 2, "exactly 2 entries expected");
779+
}

cli/tests/cli/stdio/missing_file.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::utils::setup;
22
use assert_cmd::cargo::cargo_bin_cmd;
3+
use std::fs;
4+
use std::path::PathBuf;
35

46
/// Precondition: No input paths are provided.
57
/// Action: Run `pna experimental stdio -c -f ...` without positional paths.
@@ -20,3 +22,32 @@ fn stdio_create_without_inputs_fails() {
2022
]);
2123
cmd.assert().failure();
2224
}
25+
26+
/// Precondition: A directory exists but no real input files are specified.
27+
/// Action: Run bsdtar create mode with only -C directory-change options
28+
/// and zero file operands.
29+
/// Expectation: Command fails — directory changes alone do not constitute input.
30+
#[test]
31+
fn stdio_create_with_only_directory_changes_fails() {
32+
setup();
33+
34+
let base = PathBuf::from("stdio_create_only_dir_changes");
35+
if base.exists() {
36+
fs::remove_dir_all(&base).unwrap();
37+
}
38+
fs::create_dir_all(&base).unwrap();
39+
40+
cargo_bin_cmd!("pna")
41+
.args([
42+
"--quiet",
43+
"compat",
44+
"bsdtar",
45+
"--unstable",
46+
"-cf",
47+
base.join("out.pna").to_str().unwrap(),
48+
"-C",
49+
base.to_str().unwrap(),
50+
])
51+
.assert()
52+
.failure();
53+
}

0 commit comments

Comments
 (0)