//! The calendar through the CLI: `run ` gives the engine's answer. mod common; use common::{empty_vault, exists, note, read_file, run}; use notescraft_engine::{Registry, Session, register_core}; use serde_json::{Value, json}; fn vault(name: &str) -> std::path::PathBuf { let root = empty_vault(name); note(&root, "Calendar/lunch.md", "---\ntitle: Lunch\nstart: 2026-10-20T12:00\nend: 2026-10-20T13:00\n---\n"); note(&root, "Calendar/clash.md", "---\ntitle: Dentist\nstart: 2026-10-20T12:30\nend: 2026-10-20T13:30\n---\n"); note(&root, "Calendar/standup.md", "---\ntitle: Standup\nstart: 2026-10-19T09:30\nrepeat: weekly\n---\n"); root } fn engine(root: &std::path::Path, id: &str, params: &Value) -> Value { let mut registry = Registry::new(); register_core(&mut registry).expect("register"); let mut session = Session::open_read_only(root).expect("open"); registry.run(id, &mut session, params).expect("engine run") } #[test] fn reads_match_the_engine_with_json() { let root = vault("cal-cli-read"); for (id, params) in [ ("calendar.agenda", json!({ "from": "2026-10-19", "to": "2026-11-02", "group": "day" })), ("calendar.free", json!({ "day": "2026-10-20", "min_minutes": 15 })), ("calendar.conflicts", json!({ "from": "2026-10-19", "to": "2026-10-25" })), ("calendar.year", json!({ "year": 2026 })), ] { let out = run(&root, &["--json", "run", id, ¶ms.to_string()]); assert_eq!(out.code, 0, "{id}: {}", out.stderr); assert_eq!(out.result(), engine(&root, id, ¶ms), "{id}"); } } #[test] fn writes_work_and_a_repeating_event_needs_a_scope() { let root = vault("cal-cli-write"); let added = run(&root, &["--json", "run", "calendar.add", &json!({ "text": "Gym 2026-11-03 at 7:00 for 1h" }).to_string()]); assert_eq!(added.code, 0, "{}", added.stderr); assert!(exists(&root, "Calendar/2026-11-03-gym.md")); let missing = run(&root, &["--json", "run", "calendar.edit", &json!({ "id": "Calendar/standup.md", "fields": { "title": "x" } }).to_string()]); assert_eq!(missing.code, 1); assert_eq!(missing.error_code(), "command_failed"); assert!(missing.stdout.contains("this, following or all"), "{}", missing.stdout); assert!(read_file(&root, "Calendar/standup.md").contains("title: Standup"), "nothing changed"); let scoped = run(&root, &["--json", "run", "calendar.edit", &json!({ "id": "Calendar/standup.md", "scope": "all", "fields": { "title": "Sync" } }).to_string()]); assert_eq!(scoped.code, 0, "{}", scoped.stderr); assert!(read_file(&root, "Calendar/standup.md").contains("title: Sync")); }