//! Saving never silently replaces what another app wrote to the open file since it was opened or //! saved here (#1330): Save and auto-save refuse, `overwrite` and Revert to saved settle it. use serde_json::json; use crate::Session; use crate::cmd::file::FileSnapshot; fn temp_file(name: &str) -> String { let dir = std::env::temp_dir().join(format!("figcraft-disk-changes-{}-{name}", std::process::id())); std::fs::create_dir_all(&dir).unwrap(); dir.join("TESTE.figcraft").to_string_lossy().into_owned() } /// What the file on disk names its first page. fn page_on_disk(path: &str) -> String { let mut s = Session::new(); s.execute("file.open", &json!({"path": path})).unwrap(); let ds = s.ds().unwrap(); ds.doc.node(ds.page).unwrap().name.clone() } /// The app has `path` open with an unsaved edit, after figcraft-cli renamed its page on disk. fn app_and_cli(path: &str) -> Session { let mut setup = Session::new(); setup.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 10, "height": 10})).unwrap(); setup.execute("file.save", &json!({"path": path})).unwrap(); let mut app = Session::new(); app.execute("file.open", &json!({"path": path})).unwrap(); let mut cli = Session::new(); cli.execute("file.open", &json!({"path": path})).unwrap(); cli.execute("page.rename", &json!({"name": "CLI VENCEU"})).unwrap(); cli.execute("file.save", &json!({})).unwrap(); app.execute("shape.rectangle", &json!({"x": 20, "y": 0, "width": 10, "height": 10})).unwrap(); app } #[test] fn saving_over_changes_made_on_disk_is_refused_until_asked() { let path = temp_file("save"); let mut app = app_and_cli(&path); let err = app.execute("file.save", &json!({})).unwrap_err().to_string(); assert!(err.contains("changed on disk"), "{err}"); assert_eq!(page_on_disk(&path), "CLI VENCEU", "the CLI's change is still in the file"); assert!(app.ds().unwrap().is_dirty(), "the app's edit stays unsaved"); // Asked to, the save replaces it; from then on the file is the app's again. app.execute("file.save", &json!({"overwrite": true})).unwrap(); assert_ne!(page_on_disk(&path), "CLI VENCEU"); app.execute("shape.rectangle", &json!({"x": 40, "y": 0, "width": 10, "height": 10})).unwrap(); app.execute("file.save", &json!({})).unwrap(); let _ = std::fs::remove_file(&path); } #[test] fn reverting_loads_the_changes_made_on_disk_and_saves_again() { let path = temp_file("revert"); let mut app = app_and_cli(&path); app.execute("file.revert", &json!({})).unwrap(); let ds = app.ds().unwrap(); assert_eq!(ds.doc.node(ds.page).unwrap().name, "CLI VENCEU"); app.execute("shape.rectangle", &json!({"x": 20, "y": 0, "width": 10, "height": 10})).unwrap(); app.execute("file.save", &json!({})).unwrap(); assert_eq!(page_on_disk(&path), "CLI VENCEU", "saved on top of the CLI's change"); let _ = std::fs::remove_file(&path); } #[test] fn auto_save_leaves_changes_made_on_disk_alone() { let path = temp_file("auto"); let mut app = app_and_cli(&path); let snapshot = FileSnapshot::of(app.ds().unwrap()); let bytes = snapshot.encode().unwrap(); assert!(snapshot.save(&mut app, &bytes).is_err()); assert_eq!(page_on_disk(&path), "CLI VENCEU"); let _ = std::fs::remove_file(&path); }