//! The `block.*` commands: list, move, duplicate, delete and turn into, each one edit on disk. mod common; use common::{on_disk, seed, temp_vault}; use notescraft_engine::{Registry, Session, register_core}; use serde_json::{Value, json}; const NOTE: &str = "# Title\n\nFirst para\n\nSecond para\n"; fn setup(name: &str) -> (Registry, Session, common::TempVault) { let vault = temp_vault(name); seed(vault.path(), &[("n.md", NOTE)]); let mut registry = Registry::new(); register_core(&mut registry).expect("register"); let session = Session::open(vault.path()).expect("open"); (registry, session, vault) } fn run(registry: &Registry, session: &mut Session, id: &str, params: &Value) -> Value { registry.run(id, session, params).unwrap_or_else(|error| panic!("{id}: {error:?}")) } #[test] fn list_reports_every_top_level_block() { let (registry, mut session, _vault) = setup("block-list"); let result = run(®istry, &mut session, "block.list", &json!({ "path": "n.md" })); assert_eq!(result["blocks"].as_array().expect("blocks").len(), 3); } #[test] fn move_swaps_with_the_neighbour_and_is_undone_by_moving_back() { let (registry, mut session, vault) = setup("block-move"); run(®istry, &mut session, "block.move", &json!({ "path": "n.md", "index": 2, "direction": "up" })); assert_eq!(on_disk(vault.path(), "n.md"), "# Title\n\nSecond para\n\nFirst para\n"); run(®istry, &mut session, "block.move", &json!({ "path": "n.md", "index": 1, "direction": "down" })); assert_eq!(on_disk(vault.path(), "n.md"), NOTE); } #[test] fn duplicate_delete_and_turn_into_change_one_block() { let (registry, mut session, vault) = setup("block-edit"); run(®istry, &mut session, "block.turn_into", &json!({ "path": "n.md", "index": 1, "target": "heading2" })); assert!(on_disk(vault.path(), "n.md").contains("## First para")); run(®istry, &mut session, "block.duplicate", &json!({ "path": "n.md", "index": 2 })); assert_eq!(on_disk(vault.path(), "n.md").matches("Second para").count(), 2); run(®istry, &mut session, "block.delete", &json!({ "path": "n.md", "index": 3 })); assert_eq!(on_disk(vault.path(), "n.md").matches("Second para").count(), 1); } #[test] fn hostile_input_is_refused_not_applied() { let (registry, mut session, vault) = setup("block-hostile"); for params in [ json!({ "path": "n.md", "index": 99, "direction": "up" }), json!({ "path": "n.md", "index": 0, "direction": "left" }), json!({ "path": "../x.md", "index": 0, "direction": "up" }), ] { assert!(registry.run("block.move", &mut session, ¶ms).is_err(), "{params}"); } assert!(registry.run("block.turn_into", &mut session, &json!({ "path": "n.md", "index": 1, "target": "heading9" })).is_err()); assert_eq!(on_disk(vault.path(), "n.md"), NOTE); } const JSON_NOTE: &str = "# T\n\n```json\n{\"b\":1,\"a\":[1e5]}\n```\n"; #[test] fn json_format_and_minify_rewrite_only_the_block_body() { let vault = temp_vault("json-block"); seed(vault.path(), &[("j.md", JSON_NOTE)]); let mut registry = Registry::new(); register_core(&mut registry).expect("register"); let mut session = Session::open(vault.path()).expect("open"); let result = run(®istry, &mut session, "json.format_block", &json!({ "path": "j.md", "index": 1 })); assert_eq!(result["changed"], json!(true)); assert_eq!(on_disk(vault.path(), "j.md"), "# T\n\n```json\n{\n \"b\": 1,\n \"a\": [\n 1e5\n ]\n}\n```\n"); run(®istry, &mut session, "json.minify_block", &json!({ "path": "j.md", "index": 1 })); assert_eq!(on_disk(vault.path(), "j.md"), JSON_NOTE); } #[test] fn invalid_json_is_an_error_and_the_note_is_untouched() { let vault = temp_vault("json-invalid"); let broken = "```json\n{\"a\":\n```\n"; seed(vault.path(), &[("j.md", broken), ("p.md", "plain\n")]); let mut registry = Registry::new(); register_core(&mut registry).expect("register"); let mut session = Session::open(vault.path()).expect("open"); assert!(registry.run("json.format_block", &mut session, &json!({ "path": "j.md", "index": 0 })).is_err()); assert_eq!(on_disk(vault.path(), "j.md"), broken); assert!(registry.run("json.format_block", &mut session, &json!({ "path": "p.md", "index": 0 })).is_err()); assert_eq!(on_disk(vault.path(), "p.md"), "plain\n"); }