Files
Marcos Paulo 46d5c3ec96
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: local note snapshots and the Versions tab
Every save of a changed note keeps a snapshot (at most one per 5 minutes, newest 20, under
.notescraft/history), engine history.list/history.read, a Versions tab with Compare and Restore.
Task 31 marked built (git history existed), task 34 deferred by the owner.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 16:05:29 -03:00

70 lines
4.1 KiB
Rust

//! Saved workspaces: `workspace.save`, `workspace.list`, `workspace.load`, `workspace.delete`.
mod common;
use common::{temp_config, temp_vault};
use notescraft_engine::{Registry, Session, register_core};
use serde_json::json;
#[test]
fn a_layout_is_saved_listed_loaded_replaced_and_deleted() {
let vault = temp_vault("workspaces");
let config = temp_config("workspaces");
let mut registry = Registry::new();
register_core(&mut registry).expect("register");
let mut session = Session::open(vault.path()).expect("open");
session.use_settings_dir(config.path());
let layout = json!({"tabs": ["a.md", "b.md"], "active": 1});
registry.run("workspace.save", &mut session, &json!({"name": "Writing", "layout": layout})).expect("save");
registry.run("workspace.save", &mut session, &json!({"name": "Review", "layout": {"tabs": []}})).expect("save");
assert_eq!(registry.run("workspace.list", &mut session, &json!({})).expect("list")["workspaces"], json!(["Review", "Writing"]));
assert_eq!(registry.run("workspace.load", &mut session, &json!({"name": "Writing"})).expect("load")["layout"], layout);
registry.run("workspace.save", &mut session, &json!({"name": "Writing", "layout": {"tabs": ["c.md"]}})).expect("replace");
assert_eq!(registry.run("workspace.load", &mut session, &json!({"name": "Writing"})).expect("load")["layout"]["tabs"], json!(["c.md"]));
registry.run("workspace.delete", &mut session, &json!({"name": "Review"})).expect("delete");
assert_eq!(registry.run("workspace.list", &mut session, &json!({})).expect("list")["workspaces"], json!(["Writing"]));
assert!(registry.run("workspace.load", &mut session, &json!({"name": "Review"})).is_err());
assert!(registry.run("workspace.delete", &mut session, &json!({"name": "Review"})).is_err());
}
#[test]
fn hostile_names_and_oversized_layouts_are_refused() {
let vault = temp_vault("workspaces-bad");
let config = temp_config("workspaces-bad");
let mut registry = Registry::new();
register_core(&mut registry).expect("register");
let mut session = Session::open(vault.path()).expect("open");
session.use_settings_dir(config.path());
for name in ["", " pad", ".hidden", "../up", "a/b", "a\\b", "x:y", &"n".repeat(65), "tab\tname"] {
assert!(registry.run("workspace.save", &mut session, &json!({"name": name, "layout": {}})).is_err(), "{name:?}");
assert!(registry.run("workspace.load", &mut session, &json!({"name": name})).is_err(), "{name:?}");
}
let big = json!({"x": "y".repeat(300_000)});
assert!(registry.run("workspace.save", &mut session, &json!({"name": "big", "layout": big})).is_err());
assert_eq!(registry.run("workspace.list", &mut session, &json!({})).expect("list")["workspaces"], json!([]));
}
#[test]
fn saving_a_note_keeps_a_local_snapshot_a_command_lists_and_reads() {
let vault = temp_vault("snapshots");
let config = temp_config("snapshots");
std::fs::write(vault.path().join("n.md"), "first\n").expect("seed");
let mut registry = Registry::new();
register_core(&mut registry).expect("register");
let mut session = Session::open(vault.path()).expect("open");
session.use_settings_dir(config.path());
session.open_buffer("n.md").expect("buffer");
session.buffer_mut("n.md").expect("buffer").edit(0..5, "second").expect("edit");
session.save_buffer("n.md").expect("save");
session.buffer_mut("n.md").expect("buffer").edit(0..6, "third").expect("edit");
session.save_buffer("n.md").expect("save again at once");
let listed = registry.run("history.list", &mut session, &json!({"path": "n.md"})).expect("list");
let versions = listed["versions"].as_array().expect("array");
assert_eq!(versions.len(), 1, "the second save came inside the gap");
let id = versions[0]["id"].as_u64().expect("id");
let read = registry.run("history.read", &mut session, &json!({"path": "n.md", "id": id})).expect("read");
assert_eq!(read["text"], "second\n");
assert!(registry.run("history.read", &mut session, &json!({"path": "n.md", "id": 1})).is_err());
assert_eq!(registry.run("history.list", &mut session, &json!({"path": "other.md"})).expect("list")["versions"], json!([]));
}