use super::*;
use crate::test_support::FakeFs;
fn root() -> PathBuf {
PathBuf::from("/cfg/lernie")
}
fn lg() -> LernieGlobal {
LernieGlobal { root: root() }
}
fn wf(name: &str) -> PathBuf {
root().join("workflows").join(name)
}
#[test]
fn resolve_folds_root_from_env_and_lernie_home_collapse() {
let xdg = Env::from_pairs([("HOME", "/home/u"), ("XDG_CONFIG_HOME", "/home/u/.config")]);
assert_eq!(
LernieGlobal::resolve(&xdg).models(),
PathBuf::from("/home/u/.config/lernie/models.yaml")
);
let home = Env::from_pairs([("HOME", "/home/u"), ("LERNIE_HOME", "/srv/lernie")]);
assert_eq!(
LernieGlobal::resolve(&home).workflows_dir(),
PathBuf::from("/srv/lernie/workflows")
);
}
#[test]
fn workflows_lists_only_yaml_sorted_and_absent_is_empty() {
assert!(lg().workflows(&FakeFs::default()).unwrap().is_empty());
let fs = FakeFs::default();
for (name, body) in [
("b.yaml", "2"),
("a.yaml", "1"),
("notes.txt", "x"),
("README", "y"),
] {
fs.map().insert(wf(name), body.into());
}
fs.map().insert(lg().models(), b"m".to_vec());
assert_eq!(
lg().workflows(&fs).unwrap(),
vec![wf("a.yaml"), wf("b.yaml")]
);
}
#[test]
fn new_workflow_validates_the_name() {
assert_eq!(lg().new_workflow("deploy").unwrap(), wf("deploy.yaml"));
assert_eq!(lg().new_workflow(""), Err(WorkflowNameError::Empty));
assert_eq!(
lg().new_workflow(".hidden"),
Err(WorkflowNameError::DotLeading)
);
assert_eq!(lg().new_workflow("a/b"), Err(WorkflowNameError::Separator));
assert_eq!(lg().new_workflow("a\\b"), Err(WorkflowNameError::Separator));
}
#[test]
fn load_distinguishes_existing_from_new() {
let existing = FakeFs::seed(&lg().models(), b"provider: x\n");
let ed = Editor::load(lg().models(), &existing).unwrap();
assert_eq!(ed.draft(), "provider: x\n");
assert!(!ed.is_new());
assert_eq!(ed.path(), lg().models());
let ed = Editor::load(lg().models(), &FakeFs::default()).unwrap();
assert_eq!(ed.draft(), "");
assert!(ed.is_new());
}
#[test]
fn draft_mut_and_set_draft_edit_the_buffer() {
let mut ed = Editor::load(lg().models(), &FakeFs::default()).unwrap();
ed.draft_mut().push_str("k: v");
assert_eq!(ed.draft(), "k: v");
ed.set_draft("k: w".into());
assert_eq!(ed.draft(), "k: w");
}
#[test]
fn apply_edits_an_existing_file_and_tracks_the_snapshot() {
let fs = FakeFs::seed(&lg().models(), b"a");
let mut ed = Editor::load(lg().models(), &fs).unwrap();
ed.set_draft("b".into());
assert_eq!(ed.apply(&fs), Saved::Ok);
assert_eq!(fs.get(&lg().models()), Some(b"b".to_vec()));
ed.set_draft("c".into());
assert_eq!(ed.apply(&fs), Saved::Ok);
assert_eq!(fs.get(&lg().models()), Some(b"c".to_vec()));
}
#[test]
fn seeded_creates_a_new_workflow_guarded_must_not_exist() {
let fs = FakeFs::default();
let path = lg().new_workflow("deploy").unwrap();
let mut ed = Editor::seeded(path.clone(), b"steps: []\n");
assert!(ed.is_new());
assert_eq!(ed.draft(), "steps: []\n");
assert_eq!(ed.apply(&fs), Saved::Ok);
assert_eq!(fs.get(&path), Some(b"steps: []\n".to_vec()));
assert!(!ed.is_new());
let mut clash = Editor::seeded(path.clone(), b"other\n");
assert_eq!(clash.apply(&fs), Saved::Conflict);
assert_eq!(fs.get(&path), Some(b"steps: []\n".to_vec()));
}
#[test]
fn seeded_copies_from_existing_workflow_bytes() {
let src = FakeFs::seed(&wf("base.yaml"), b"shared: true\n");
let bytes = src.get(&wf("base.yaml")).unwrap();
let ed = Editor::seeded(wf("copy.yaml"), &bytes);
assert_eq!(ed.draft(), "shared: true\n");
assert!(ed.is_new());
}
#[test]
fn apply_refuses_a_concurrent_edit_and_reload_recovers() {
let fs = FakeFs::seed(&lg().models(), b"a");
let mut ed = Editor::load(lg().models(), &fs).unwrap();
ed.set_draft("mine".into());
fs.map().insert(lg().models(), b"theirs".to_vec());
assert_eq!(ed.apply(&fs), Saved::Conflict);
assert_eq!(fs.get(&lg().models()), Some(b"theirs".to_vec()));
ed.reload(&fs).unwrap();
assert_eq!(ed.draft(), "theirs");
ed.set_draft("merged".into());
assert_eq!(ed.apply(&fs), Saved::Ok);
}
#[test]
fn apply_maps_a_filesystem_error_to_io() {
let fs = FakeFs {
fail_write: true,
..FakeFs::default()
};
let mut ed = Editor::load(lg().models(), &fs).unwrap();
ed.set_draft("x".into());
assert!(matches!(ed.apply(&fs), Saved::Io { .. }));
}