use super::*;
use crate::cli_outbound::Cli;
use std::fs;
use std::path::PathBuf;
use tempfile::tempdir;
#[test]
fn editor_env_value_appends_flag_and_quotes_the_binary() {
assert_eq!(
editor_env_value(Path::new("/opt/yog")),
"'/opt/yog' --editor-apply"
);
assert_eq!(
editor_env_value(Path::new("/home/x y/yog")),
"'/home/x y/yog' --editor-apply"
);
assert_eq!(
editor_env_value(Path::new("/o'd/yog")),
"'/o'\\''d/yog' --editor-apply"
);
}
fn plan(origin: &EditOrigin) -> EditPlan {
EditPlan::compose(
Path::new("/opt/yog"),
Path::new("/ws"),
"default",
origin,
Path::new("/state/stage/7-0"),
)
}
#[test]
fn compose_advance_is_config_ws_name() {
let p = plan(&EditOrigin::Advance);
assert_eq!(p.argv(), ["config", "/ws", "default"]);
assert_eq!(
p.env(),
[
("EDITOR", "'/opt/yog' --editor-apply"),
("YOG_EDIT_SRC", "/state/stage/7-0"),
]
);
}
#[test]
fn compose_fork_adds_from_source() {
let p = plan(&EditOrigin::Fork {
source: "base".to_string(),
});
assert_eq!(p.argv(), ["config", "/ws", "default", "--from", "base"]);
}
#[test]
fn compose_orphan_adds_orphan_flag() {
let p = plan(&EditOrigin::Orphan);
assert_eq!(p.argv(), ["config", "/ws", "default", "--orphan"]);
}
fn recorder(dir: &Path, log: &Path, code: i32) -> PathBuf {
let path = dir.join("litany");
let body = format!(
"#!/bin/sh\n{{ printf 'EDITOR=%s\\n' \"$EDITOR\"; \
printf 'SRC=%s\\n' \"$YOG_EDIT_SRC\"; \
for a in \"$@\"; do printf 'ARG=%s\\n' \"$a\"; done; }} >> {}\n\
printf 'out-text'\nprintf 'err-text' 1>&2\nexit {}\n",
log.display(),
code
);
crate::test_support::write_exec(&path, &body);
path
}
#[test]
fn drive_lands_env_and_argv_and_streams_the_outcome_to_ops_jsonl() {
let dir = tempdir().unwrap();
let log = dir.path().join("invocation.log");
let bin = recorder(dir.path(), &log, 0);
let state = dir.path().join("state");
let p = EditPlan::compose(
Path::new("/opt/yog"),
Path::new("/ws"),
"default",
&EditOrigin::Orphan,
Path::new("/state/stage/7-0"),
);
let entry = drive(
&Cli::new(&bin),
Path::new("/ws"),
&p,
"T0",
&state,
Origin::World,
);
assert_eq!(
fs::read_to_string(&log).unwrap(),
"EDITOR='/opt/yog' --editor-apply\nSRC=/state/stage/7-0\n\
ARG=config\nARG=/ws\nARG=default\nARG=--orphan\n"
);
assert_eq!(entry.exit, 0);
assert_eq!(entry.stdout, "out-text");
assert_eq!(entry.stderr, "err-text");
assert_eq!(entry.cwd, "/ws");
assert_eq!(entry.argv[0], bin.display().to_string());
assert_eq!(&entry.argv[1..], ["config", "/ws", "default", "--orphan"]);
let logged = opslog::tail(&state, 10);
assert_eq!(logged, vec![entry]);
}
#[test]
fn drive_records_spawn_failure_as_a_negative_exit() {
let dir = tempdir().unwrap();
let state = dir.path().join("state");
let p = plan(&EditOrigin::Advance);
let entry = drive(
&Cli::new("/definitely/not/a/real/litany-xyz"),
Path::new("/ws"),
&p,
"T0",
&state,
Origin::World,
);
assert_eq!(entry.exit, -1);
assert!(!entry.stderr.is_empty());
assert_eq!(opslog::tail(&state, 10).len(), 1);
}
#[test]
fn drive_records_a_signal_death_as_a_negative_exit() {
let dir = tempdir().unwrap();
let bin = dir.path().join("litany");
crate::test_support::write_exec(&bin, "#!/bin/sh\nkill -TERM $$\n");
let state = dir.path().join("state");
let p = plan(&EditOrigin::Advance);
let entry = drive(
&Cli::new(&bin),
Path::new("/ws"),
&p,
"T0",
&state,
Origin::World,
);
assert_eq!(entry.exit, -1);
}