use crate::utils::{EmbedExt, TestResources, archive, setup};
use clap::Parser;
use portable_network_archive::cli;
#[test]
fn archive_xattr_set() {
setup();
TestResources::extract_in("zstd.pna", "xattr_set/").unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_set/zstd.pna",
"--name",
"user.name",
"--value",
"pna developers!",
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
archive::for_each_entry("xattr_set/zstd.pna", |entry| {
if entry.name() == "raw/empty.txt" {
assert_eq!(
entry.metadata().xattrs(),
&[archive::xattr("user.name", b"pna developers!")]
);
} else {
assert!(
entry.metadata().xattrs().is_empty(),
"Entry {} should have no xattrs but has {:?}",
entry.name(),
entry.metadata().xattrs()
);
}
})
.unwrap();
}
#[test]
fn xattr_long_key_value() {
setup();
TestResources::extract_in("zstd.pna", "xattr_long/").unwrap();
let long_name = "user.".to_owned() + &"n".repeat(200);
let long_value = "v".repeat(1024);
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_long/zstd.pna",
"--name",
&long_name,
"--value",
&long_value,
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_long/zstd.pna",
"--name",
"user.special",
"--value",
"\0\n\r\x7f\u{1F600}",
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
archive::for_each_entry("xattr_long/zstd.pna", |entry| {
if entry.name() == "raw/empty.txt" {
assert_eq!(
entry.metadata().xattrs(),
&[
archive::xattr(long_name.as_str(), long_value.as_bytes()),
archive::xattr("user.special", "\0\n\r\x7f\u{1F600}".as_bytes()),
]
);
} else {
assert!(
entry.metadata().xattrs().is_empty(),
"Entry {} should have no xattrs but has {:?}",
entry.name(),
entry.metadata().xattrs()
);
}
})
.unwrap();
}
#[test]
fn xattr_empty_key() {
setup();
TestResources::extract_in("zstd.pna", "xattr_empty_key/").unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_empty_key/zstd.pna",
"--name",
"",
"--value",
"value",
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
archive::for_each_entry("xattr_empty_key/zstd.pna", |entry| {
if entry.name() == "raw/empty.txt" {
assert_eq!(entry.metadata().xattrs(), &[archive::xattr("", b"value")]);
} else {
assert!(
entry.metadata().xattrs().is_empty(),
"Entry {} should have no xattrs but has {:?}",
entry.name(),
entry.metadata().xattrs()
);
}
})
.unwrap();
}
#[test]
fn xattr_empty_value() {
setup();
TestResources::extract_in("zstd.pna", "xattr_empty_value/").unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_empty_value/zstd.pna",
"--name",
"user.empty",
"--value",
"",
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
archive::for_each_entry("xattr_empty_value/zstd.pna", |entry| {
if entry.name() == "raw/empty.txt" {
assert_eq!(
entry.metadata().xattrs(),
&[archive::xattr("user.empty", b"")]
);
} else {
assert!(
entry.metadata().xattrs().is_empty(),
"Entry {} should have no xattrs but has {:?}",
entry.name(),
entry.metadata().xattrs()
);
}
})
.unwrap();
}
#[test]
fn xattr_set_preserved_in_archive() {
setup();
TestResources::extract_in("zstd.pna", "xattr_set_preserved/").unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_set_preserved/zstd.pna",
"--name",
"user.roundtrip",
"--value",
"preserved_value",
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
let mut found = false;
archive::for_each_entry("xattr_set_preserved/zstd.pna", |entry| {
if entry.name() == "raw/empty.txt" {
found = true;
assert_eq!(
entry.metadata().xattrs(),
&[archive::xattr("user.roundtrip", b"preserved_value")]
);
}
})
.unwrap();
assert!(found, "raw/empty.txt entry not found in archive");
}
#[test]
#[cfg(unix)]
fn xattr_round_trip_preservation() {
setup();
if !xattr::SUPPORTED_PLATFORM {
eprintln!("Skipping xattr_round_trip_preservation: platform does not support xattr");
return;
}
TestResources::extract_in("zstd.pna", "xattr_roundtrip/").unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"xattr",
"set",
"-f",
"xattr_roundtrip/zstd.pna",
"--name",
"user.roundtrip",
"--value",
"preserved_value",
"raw/empty.txt",
])
.unwrap()
.execute()
.unwrap();
cli::Cli::try_parse_from([
"pna",
"--quiet",
"x",
"-f",
"xattr_roundtrip/zstd.pna",
"--overwrite",
"--out-dir",
"xattr_roundtrip/out/",
"--keep-xattr",
])
.unwrap()
.execute()
.unwrap();
match xattr::get("xattr_roundtrip/out/raw/empty.txt", "user.roundtrip") {
Ok(Some(_)) => {}
Err(e) if e.kind() == std::io::ErrorKind::Unsupported => {
eprintln!("Skipping xattr round-trip verification: filesystem does not support xattrs");
return;
}
other => panic!("Unexpected xattr::get result: {:?}", other),
}
cli::Cli::try_parse_from([
"pna",
"--quiet",
"c",
"-f",
"xattr_roundtrip/roundtrip.pna",
"--overwrite",
"xattr_roundtrip/out/",
"--keep-xattr",
])
.unwrap()
.execute()
.unwrap();
let mut found = false;
archive::for_each_entry("xattr_roundtrip/roundtrip.pna", |entry| {
if entry.name().as_str().ends_with("raw/empty.txt") {
found = true;
assert!(
entry
.metadata()
.xattrs()
.contains(&archive::xattr("user.roundtrip", b"preserved_value")),
"round-tripped entry is missing user.roundtrip xattr: {:?}",
entry.metadata().xattrs()
);
}
})
.unwrap();
assert!(found, "raw/empty.txt entry not found in round-trip archive");
}