mirror of
https://gitea.tendokyu.moe/beerpsi/fsdecrypt.git
synced 2026-09-22 22:17:55 +03:00
test: add e2e fixture decryption test
Decrypts real .app/.opt containers dropped into a git-ignored fixtures/ dir (copied to a temp dir first so extraction never touches the fixtures), asserting each produces a non-empty extraction. No-op when fixtures/ is empty, so the suite stays green without the proprietary sample data. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
0a7b633310
commit
a73f71e3de
@@ -9,3 +9,6 @@
|
||||
flamegraph.svg
|
||||
CLAUDE.md
|
||||
memory/
|
||||
|
||||
# Local e2e test fixtures (real, proprietary containers — never committed)
|
||||
/fixtures/
|
||||
|
||||
@@ -72,6 +72,15 @@ scripts/test.sh --no-docker # skip the Docker/Linux step
|
||||
image to build and test the static Linux binary — the same way release artifacts
|
||||
are produced — so both targets can be validated from any host.
|
||||
|
||||
### End-to-end fixtures
|
||||
|
||||
The `tests/e2e.rs` test decrypts real containers placed in a `fixtures/`
|
||||
directory at the repo root and checks that each extracts successfully. That
|
||||
folder is git-ignored — the proprietary sample containers are never committed —
|
||||
and the test is a no-op when it is empty, so just drop a few `.app`/`.opt` files
|
||||
in `fixtures/` and run `cargo test` (or `scripts/test.sh`) to exercise the full
|
||||
decrypt-and-extract path.
|
||||
|
||||
## License
|
||||
|
||||
[BSD Zero Clause License](LICENSE) (0BSD)
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//! End-to-end decryption test driven by local fixtures.
|
||||
//!
|
||||
//! Drop real `.app` / `.opt` containers into the git-ignored `fixtures/`
|
||||
//! directory at the crate root. Each one is copied to a temp dir, run through
|
||||
//! the built binary, and checked for a non-empty extraction output. When
|
||||
//! `fixtures/` is absent or empty the test is a no-op, so the suite stays green
|
||||
//! without the (proprietary) sample data.
|
||||
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
fn fixture_files() -> Vec<PathBuf> {
|
||||
let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("fixtures");
|
||||
let Ok(entries) = fs::read_dir(dir) else {
|
||||
return Vec::new();
|
||||
};
|
||||
let mut files: Vec<PathBuf> = entries
|
||||
.filter_map(|e| e.ok().map(|e| e.path()))
|
||||
.filter(|p| {
|
||||
p.is_file()
|
||||
&& matches!(
|
||||
p.extension().and_then(|e| e.to_str()),
|
||||
Some("app") | Some("opt")
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
files.sort();
|
||||
files
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrypts_fixture_containers() {
|
||||
let files = fixture_files();
|
||||
if files.is_empty() {
|
||||
eprintln!(
|
||||
"skipping e2e: no .app/.opt fixtures in {}/fixtures — add containers to run this test",
|
||||
env!("CARGO_MANIFEST_DIR")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Work in a temp dir so extraction never touches the fixtures folder. The
|
||||
// tool extracts next to its input, so we copy each fixture in first.
|
||||
let workdir = std::env::temp_dir().join(format!("fsdecrypt-e2e-{}", std::process::id()));
|
||||
let _ = fs::remove_dir_all(&workdir);
|
||||
fs::create_dir_all(&workdir).expect("create work dir");
|
||||
|
||||
for src in &files {
|
||||
let name = src.file_name().unwrap().to_os_string();
|
||||
let input = workdir.join(&name);
|
||||
fs::copy(src, &input).expect("copy fixture into work dir");
|
||||
|
||||
let output = Command::new(env!("CARGO_BIN_EXE_fsdecrypt"))
|
||||
.arg(&input)
|
||||
.output()
|
||||
.expect("failed to run fsdecrypt");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"decrypting {name:?} failed (exit {:?})\n--- stdout ---\n{stdout}\n--- stderr ---\n{stderr}",
|
||||
output.status.code()
|
||||
);
|
||||
|
||||
// A default run extracts into a folder named after the input (no extension).
|
||||
let out_dir = input.with_extension("");
|
||||
let produced = fs::read_dir(&out_dir).map(|rd| rd.count()).unwrap_or(0);
|
||||
assert!(
|
||||
produced > 0,
|
||||
"{name:?}: expected extracted entries in {}",
|
||||
out_dir.display()
|
||||
);
|
||||
println!("ok: {name:?} -> {produced} top-level entr(y/ies) extracted");
|
||||
}
|
||||
|
||||
let _ = fs::remove_dir_all(&workdir);
|
||||
}
|
||||
Reference in New Issue
Block a user