Uses assert_cmd + tempfile to spin up a fresh vault per test. Covers init layout, add/list/get mask semantics, rm/restore/purge cycle, and generate smoke. Adds RELICARIO_TEST_PASSPHRASE env-var hatch in unlock_interactive and cmd_init so tests don't need a TTY. Also fixes read_params in session.rs to correctly parse the nested params.json format (kdf sub-object) rather than trying to deserialize the whole file as KdfParams. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
118 lines
3.9 KiB
Rust
118 lines
3.9 KiB
Rust
//! Shared helpers for CLI integration tests.
|
|
//!
|
|
//! `TestVault::init()` spins up a fresh vault in a `TempDir` using
|
|
//! `RELICARIO_TEST_PASSPHRASE` as the escape hatch (bypasses TTY prompts).
|
|
//! Every `run()` / `run_with_input()` call sets both `RELICARIO_IMAGE` and
|
|
//! `RELICARIO_TEST_PASSPHRASE`, so vault-mutating commands unlock without
|
|
//! interactive input.
|
|
//!
|
|
//! Note for Task 23 implementers: commands that prompt for a *new item
|
|
//! password* (i.e. `edit` when changing a Login password) also use
|
|
//! `rpassword`. Plumb `RELICARIO_TEST_ITEM_PASSWORD` through `cmd_edit` in
|
|
//! main.rs, or use an item type / edit path that avoids the rpassword call.
|
|
|
|
use std::io::Write;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::{Command, Stdio};
|
|
|
|
use assert_cmd::cargo::CommandCargoExt;
|
|
use tempfile::TempDir;
|
|
|
|
pub struct TestVault {
|
|
pub dir: TempDir,
|
|
pub reference_image: PathBuf,
|
|
pub passphrase: String,
|
|
}
|
|
|
|
impl TestVault {
|
|
pub fn init() -> Self {
|
|
let dir = TempDir::new().expect("tempdir");
|
|
let carrier = make_test_jpeg(400, 300);
|
|
let carrier_path = dir.path().join("carrier.jpg");
|
|
std::fs::write(&carrier_path, &carrier).unwrap();
|
|
|
|
let passphrase = "correct horse battery staple 2026".to_string();
|
|
let ref_path = dir.path().join("reference.jpg");
|
|
|
|
let mut cmd = Command::cargo_bin("relicario").unwrap();
|
|
cmd.current_dir(dir.path())
|
|
.env("RELICARIO_TEST_PASSPHRASE", &passphrase)
|
|
.args([
|
|
"init",
|
|
"--image",
|
|
carrier_path.to_str().unwrap(),
|
|
"--output",
|
|
ref_path.to_str().unwrap(),
|
|
])
|
|
.stdin(Stdio::null())
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped());
|
|
let out = cmd.output().unwrap();
|
|
assert!(
|
|
out.status.success(),
|
|
"init failed:\nstdout: {}\nstderr: {}",
|
|
String::from_utf8_lossy(&out.stdout),
|
|
String::from_utf8_lossy(&out.stderr)
|
|
);
|
|
|
|
Self {
|
|
dir,
|
|
reference_image: ref_path,
|
|
passphrase,
|
|
}
|
|
}
|
|
|
|
pub fn path(&self) -> &Path {
|
|
self.dir.path()
|
|
}
|
|
|
|
pub fn run(&self, args: &[&str]) -> std::process::Output {
|
|
let mut cmd = Command::cargo_bin("relicario").unwrap();
|
|
cmd.current_dir(self.dir.path())
|
|
.env("RELICARIO_IMAGE", &self.reference_image)
|
|
.env("RELICARIO_TEST_PASSPHRASE", &self.passphrase)
|
|
.args(args)
|
|
.stdin(Stdio::null())
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped());
|
|
cmd.output().unwrap()
|
|
}
|
|
|
|
pub fn run_with_input(&self, args: &[&str], extra: &[&str]) -> std::process::Output {
|
|
let mut cmd = Command::cargo_bin("relicario").unwrap();
|
|
cmd.current_dir(self.dir.path())
|
|
.env("RELICARIO_IMAGE", &self.reference_image)
|
|
.env("RELICARIO_TEST_PASSPHRASE", &self.passphrase)
|
|
.args(args)
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.stderr(Stdio::piped());
|
|
let mut child = cmd.spawn().unwrap();
|
|
{
|
|
let stdin = child.stdin.as_mut().unwrap();
|
|
for line in extra {
|
|
writeln!(stdin, "{line}").unwrap();
|
|
}
|
|
}
|
|
child.wait_with_output().unwrap()
|
|
}
|
|
}
|
|
|
|
pub fn make_test_jpeg(w: u32, h: u32) -> Vec<u8> {
|
|
use image::codecs::jpeg::JpegEncoder;
|
|
use image::{ExtendedColorType, ImageBuffer, ImageEncoder, Rgb};
|
|
|
|
let img = ImageBuffer::from_fn(w, h, |x, y| {
|
|
Rgb([
|
|
((x * 7 + y * 13) % 256) as u8,
|
|
((x * 11 + y * 3) % 256) as u8,
|
|
((x * 5 + y * 17) % 256) as u8,
|
|
])
|
|
});
|
|
let mut out = Vec::new();
|
|
JpegEncoder::new_with_quality(&mut out, 92)
|
|
.write_image(img.as_raw(), w, h, ExtendedColorType::Rgb8)
|
|
.unwrap();
|
|
out
|
|
}
|