use super::*;
use tempfile::TempDir;
const CORRUPT: &str = "+++\ntitle = \"x\"\ntitle = \"x\"\n+++\n";
fn seal_with_changed(dir: &Path, changed: &[&str], pre: &[&str]) -> (Result<String, OpError>, Vec<String>) {
let jrn = journal();
let mut anvil = FakeAnvil::new(jrn.clone(), None);
anvil.changed_files = changed.iter().map(ToString::to_string).collect();
let plugins = FakePlugins::new(jrn.clone(), None);
let base = FakeBase { j: jrn.clone(), fail_stage: false, fail_finalize: false };
let pre: Vec<_> = pre.iter().map(|n| plugin(n)).collect();
let result = Engine::new(&anvil, &plugins, &test_log()).seal(&base, Verb::Update, dir, &pre, &[]);
let log = jrn.borrow().clone();
(result, log)
}
#[test]
fn a_pre_corrupted_sibling_ball_aborts_before_the_seal() {
let tmp = TempDir::new().unwrap();
std::fs::create_dir(tmp.path().join("tasks")).unwrap();
std::fs::write(tmp.path().join("tasks/bl-sib.md"), CORRUPT).unwrap();
let (r, log) = seal_with_changed(tmp.path(), &["tasks/bl-new.md", "tasks/bl-sib.md"], &["p", "q"]);
let err = r.unwrap_err();
assert!(matches!(err, OpError::Invalid(_)));
let msg = err.to_string();
assert!(msg.contains("tasks/bl-sib.md"), "names the file: {msg}");
assert!(msg.contains("pre plugin q"), "names the LAST pre plugin: {msg}");
assert!(msg.contains("duplicate"), "carries the parse error: {msg}");
assert_eq!(
log,
["open", "stage", "run:p:pre", "run:q:pre", "rollback:q:pre", "rollback:p:pre", "close"]
);
}
#[test]
fn a_plugin_free_corruption_is_still_refused_without_a_name() {
let tmp = TempDir::new().unwrap();
std::fs::create_dir(tmp.path().join("tasks")).unwrap();
std::fs::write(tmp.path().join("tasks/bl-x.md"), "no frontmatter at all").unwrap();
let (r, _log) = seal_with_changed(tmp.path(), &["tasks/bl-x.md"], &[]);
let msg = r.unwrap_err().to_string();
assert!(msg.contains("tasks/bl-x.md does not parse"), "no plugin to name: {msg}");
assert!(msg.contains("frontmatter"), "carries the parse error: {msg}");
}
#[test]
fn parseable_deleted_and_non_ball_changes_seal_cleanly() {
let tmp = TempDir::new().unwrap();
std::fs::create_dir(tmp.path().join("tasks")).unwrap();
let ok = crate::task::Task { title: "fine".into(), ..Default::default() };
crate::taskfile::write_task(tmp.path(), "bl-ok", &ok).unwrap();
let (r, log) = seal_with_changed(tmp.path(), &["notes.txt", "tasks/bl-gone.md", "tasks/bl-ok.md"], &["p"]);
assert_eq!(r.unwrap(), "C1");
assert_eq!(log, ["open", "stage", "run:p:pre", "head", "finalize", "seal", "close"]);
}
#[test]
fn a_failing_changed_read_aborts_as_an_anvil_error() {
let (r, log) = run_seal(Some("changed"), false, false, None, &[], &[]);
assert!(matches!(r, Err(OpError::Anvil(_))));
assert_eq!(log, ["open", "stage", "close"]);
}