From 22762e3e7654743597082fefeec069a3588ab4ae Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:55:09 +0000 Subject: [PATCH] Reject fractional and out-of-range ratings in photo.rate Found while testing crates/engine/src/cmd/library.rs:736 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/cmd/library.rs | 8 ++++---- crates/engine/src/tests.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/cmd/library.rs b/crates/engine/src/cmd/library.rs index 334d9c92d..fb8f52a62 100644 --- a/crates/engine/src/cmd/library.rs +++ b/crates/engine/src/cmd/library.rs @@ -765,10 +765,10 @@ pub fn specs() -> Vec { ), // ---- rating / flags / labels cmd!("photo.rate", "Set Rating", ["Photo", "Set Rating"], None, "{rating: 0..5, ids?, advance?: bool}", has_selection, |s, p| { - let r = super::f64_req(p, "rating", "photo.rate")? as i64; - if !(0..=5).contains(&r) { - return Err(bad("photo.rate", "rating must be 0..5")); - } + let r = super::index_req(p, "rating", "photo.rate") + .ok() + .filter(|r| *r <= 5) + .ok_or_else(|| bad("photo.rate", "rating must be a whole number 0..5"))?; let v = for_targets(s, p, "Set Rating", |id| Some(Op::SetRating { id, rating: r as u8 }))?; advance_if(s, p); Ok(v) diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 218965812..93f4e6adc 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -108,6 +108,20 @@ fn demo_library_loads() { assert!(albums.as_array().unwrap().iter().any(|a| a["folder"] == true)); } +#[test] +fn rating_rejects_fractional_values() { + let mut s = demo(); + let id = s.active().unwrap(); + for bad in [5.9, -0.9, 0.5] { + let err = s.execute("photo.rate", &json!({"rating": bad})).unwrap_err(); + assert!(matches!(&err, crate::EngineError::BadParams { cmd, .. } if cmd == "photo.rate"), "{bad}: {err}"); + assert_eq!(s.catalog.photo(id).unwrap().rating, 0, "{bad} changed the rating"); + } + s.execute("photo.rate", &json!({"rating": 5.0})).unwrap(); + s.execute("photo.rate", &json!({"rating": 3})).unwrap(); + assert_eq!(s.catalog.photo(id).unwrap().rating, 3); +} + #[test] fn rating_flag_undo_redo() { let mut s = demo();