From c28daa479bbece9289f443baa460a70ca5b4a93a Mon Sep 17 00:00:00 2001 From: arnav-hiwarkar Date: Sat, 17 Oct 2026 15:35:12 +0530 Subject: [PATCH] #1714: test several comps, negative and malformed saved times Co-Authored-By: Claude Opus 5.5 --- crates/engine/src/tests.rs | 17 +++++++++++++---- crates/project/src/tests.rs | 8 +++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 458583ee..b3f0602b 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -691,6 +691,7 @@ fn reopening_a_project_restores_its_active_comp() { /// current time it was saved at, not at 0, where a layer starting later shows nothing (#1714). #[test] fn reopening_a_project_restores_layer_times_and_current_time() { + use effectcraft_project::ItemId; use effectcraft_time::{FrameRate, Tick}; let dir = std::env::temp_dir().join(format!("ec-test-1714-{}", std::process::id())); std::fs::create_dir_all(&dir).unwrap(); @@ -706,21 +707,29 @@ fn reopening_a_project_restores_layer_times_and_current_time() { (l.start_time, l.in_point, l.out_point) = (Tick(144_086_342_400), Tick(1_334_917_584_000), Tick(12_853_349_308_800)); s.execute("time.set", json!({"time": 6.0})).unwrap(); let t = s.time(); + // A second comp keeps its own time. + let b = ItemId(s.execute("comp.new", json!({"name": "B"})).unwrap()["comp"].as_u64().unwrap()); + s.execute("time.set", json!({"time": 2.0})).unwrap(); + let tb = s.time(); + s.execute("comp.open", json!({"comp": "C"})).unwrap(); s.execute("file.saveAs", json!({"path": path})).unwrap(); let mut s2 = Session::default(); s2.execute("file.open", json!({"path": path})).unwrap(); let l = s2.project.comp(cid).unwrap().layers.first().unwrap(); assert_eq!((l.start_time, l.in_point, l.out_point), (Tick(144_086_342_400), Tick(1_334_917_584_000), Tick(12_853_349_308_800))); - assert_eq!(s2.time(), t); + assert_eq!((s2.time(), s2.state.times.get(&b).copied()), (t, Some(tb))); assert!(l.in_point <= s2.time() && s2.time() < l.out_point, "the layer shows at the reopened time"); assert!(!s2.is_dirty()); - // A saved time past the comp's end (a hand-edited file) lands on its last frame. - let text = std::fs::read_to_string(&path).unwrap().replace(&format!("\"{}\": {}", cid.0, t.0), &format!("\"{}\": {}", cid.0, i64::MAX)); - std::fs::write(&path, text).unwrap(); + // Hand-edited times past the end or before the start land on the last or first frame. + let mut file: serde_json::Value = serde_json::from_str(&std::fs::read_to_string(&path).unwrap()).unwrap(); + file["compTimes"] = json!({cid.0.to_string(): i64::MAX, b.0.to_string(): -5}); + std::fs::write(&path, file.to_string()).unwrap(); let mut s3 = Session::default(); s3.execute("file.open", json!({"path": path})).unwrap(); let c = s3.project.comp(cid).unwrap(); assert_eq!(s3.time(), c.frame_rate.snap_nearest(c.duration - c.frame_duration())); + assert_eq!(s3.time(), c.frame_rate.snap_nearest(c.duration - c.frame_duration())); + assert_eq!(s3.state.times.get(&b).copied(), Some(Tick::ZERO)); } diff --git a/crates/project/src/tests.rs b/crates/project/src/tests.rs index 4edd8661..8cd52092 100644 --- a/crates/project/src/tests.rs +++ b/crates/project/src/tests.rs @@ -180,7 +180,13 @@ fn project_files_remember_the_open_comps() { // Files from before #748 have no view; a garbled one is ignored, not an error. assert_eq!(crate::saved_view(&p.to_file_json().unwrap()), crate::SavedView::default()); let odd = text.replacen(&format!("\"activeComp\": {}", cid.0), "\"activeComp\": \"Main\"", 1); - assert_eq!(crate::saved_view(&odd), crate::SavedView { active_comp: None, ..view }); + assert_eq!(crate::saved_view(&odd), crate::SavedView { active_comp: None, ..view.clone() }); + // Entries that aren't an id and a whole tick count are skipped; the rest are kept. + let times = text.replacen("\"compTimes\": {", "\"compTimes\": {\"x\": 1, \"7\": \"a\", \"8\": 1.5, \"9\": -4,", 1); + let expect = [(cid, effectcraft_time::Tick(4_237_833_600)), (crate::ItemId(9), effectcraft_time::Tick(-4))].into(); + assert_eq!(crate::saved_view(×).comp_times, expect); + let not_a_map = text.replacen("\"compTimes\": {", "\"compTimes\": [], \"unused\": {", 1); + assert_eq!(crate::saved_view(¬_a_map), crate::SavedView { comp_times: Default::default(), ..view }); } /// The Project panel's "used N times": layers in every comp that use the item directly, a precomp