diff --git a/crates/engine/src/cmd/page.rs b/crates/engine/src/cmd/page.rs index 8fccd607..0064ffe0 100644 --- a/crates/engine/src/cmd/page.rs +++ b/crates/engine/src/cmd/page.rs @@ -107,6 +107,9 @@ pub fn specs() -> Vec { let id = id(p, "id").unwrap_or(s.page()?); let k = req_num("page.move", p, "index")?.max(0.0) as usize; let doc = s.doc_mut()?; + if !doc.pages.contains(&id) { + return Err(bad("page.move", format!("{id} is not a page"))); + } doc.pages.retain(|x| *x != id); let k = k.min(doc.pages.len()); doc.pages.insert(k, id); diff --git a/crates/engine/src/panels_behaviour_tests.rs b/crates/engine/src/panels_behaviour_tests.rs index c1016c29..3866d592 100644 --- a/crates/engine/src/panels_behaviour_tests.rs +++ b/crates/engine/src/panels_behaviour_tests.rs @@ -337,6 +337,17 @@ fn pages_by_the_documented_rules() { assert_ne!(s.page().unwrap(), div, "deleting the open page opens a page, never a divider"); } +#[test] +fn page_move_refuses_what_is_not_a_page() { + let mut s = Session::new(); + let r = rect(&mut s, "r", 30.0, 40.0, None); + let before = pages(&mut s); + assert!(s.execute("page.move", &json!({"id": r, "index": 0})).is_err(), "a layer id is not a page"); + assert!(s.execute("page.move", &json!({"id": 999999, "index": 0})).is_err(), "a page that isn't there is not a page"); + assert_eq!(pages(&mut s), before, "the page list is untouched"); + assert!(s.doc().unwrap().validate().is_empty(), "the document still checks out"); +} + #[test] fn page_select_and_doc_switch_refuse_negative_or_fractional_indexes() { let mut s = Session::new();