use bashkit::{Bash, CheckoutPolicy};
use std::path::PathBuf;
fn fixture(name: &str) -> Vec<u8> {
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/snapshots")
.join(name);
std::fs::read(&path).unwrap_or_else(|e| panic!("missing fixture {}: {e}", path.display()))
}
async fn assert_golden_state(bash: &mut Bash) {
assert_eq!(
bash.exec("echo $GOLDEN").await.unwrap().stdout.trim(),
"fixture"
);
assert_eq!(
bash.exec("echo $EXPORTED").await.unwrap().stdout.trim(),
"yes"
);
assert_eq!(
bash.exec("echo ${arr[1]}").await.unwrap().stdout.trim(),
"beta"
);
assert_eq!(bash.exec("pwd").await.unwrap().stdout.trim(), "/golden");
assert_eq!(
bash.exec("greet world").await.unwrap().stdout.trim(),
"hi world"
);
assert_eq!(
bash.exec("cat /golden/text.txt").await.unwrap().stdout,
"plain text\n"
);
assert_eq!(
bash.exec("readlink /golden/link")
.await
.unwrap()
.stdout
.trim(),
"/golden/text.txt"
);
assert_eq!(
bash.exec("test -d /golden/nested && echo present")
.await
.unwrap()
.stdout
.trim(),
"present"
);
assert_eq!(
bash.exec("od -An -tx1 /golden/blob.bin")
.await
.unwrap()
.stdout
.split_whitespace()
.collect::<Vec<_>>()
.join(" "),
"00 01 ff fe 7f 80 00 41 42 0a 0d"
);
}
async fn restore_fixture(name: &str) -> Bash {
let mut bash = Bash::new();
bash.restore_snapshot_with_policy(&fixture(name), CheckoutPolicy::Force)
.unwrap_or_else(|e| panic!("fixture {name} failed to restore: {e}"));
bash
}
#[tokio::test]
async fn v1_json_fixture_still_restores() {
let bytes = fixture("v1.snapshot");
assert_eq!(bytes[32], b'{', "v1 fixture should be a JSON payload");
let mut bash = restore_fixture("v1.snapshot").await;
assert_golden_state(&mut bash).await;
}
#[tokio::test]
async fn v2_container_fixture_still_restores() {
let bytes = fixture("v2.snapshot");
assert_eq!(
&bytes[32..38],
b"BKSNAP",
"v2 fixture should be a container"
);
let mut bash = restore_fixture("v2.snapshot").await;
assert_golden_state(&mut bash).await;
}
#[tokio::test]
async fn fixtures_are_rejected_when_corrupted() {
for name in ["v1.snapshot", "v2.snapshot"] {
let mut damaged = fixture(name);
let at = damaged.len() / 2;
damaged[at] ^= 0xff;
let mut bash = Bash::new();
assert!(
bash.restore_snapshot_with_policy(&damaged, CheckoutPolicy::Force)
.is_err(),
"corrupted {name} restored anyway"
);
}
}
#[tokio::test]
async fn every_fixture_in_the_corpus_is_exercised() {
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/snapshots");
let mut found: Vec<String> = std::fs::read_dir(&dir)
.unwrap()
.filter_map(|e| e.ok())
.map(|e| e.file_name().to_string_lossy().into_owned())
.filter(|n| n.ends_with(".snapshot"))
.collect();
found.sort();
assert_eq!(
found,
vec!["v1.snapshot".to_string(), "v2.snapshot".to_string()],
"corpus changed: add a restore test for each new fixture"
);
}