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 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-24 00:55:09 +00:00
co-authored by Claude Haiku 5.5
parent 98702b5c44
commit 22762e3e76
2 changed files with 18 additions and 4 deletions
+4 -4
View File
@@ -765,10 +765,10 @@ pub fn specs() -> Vec<CommandSpec> {
),
// ---- 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)
+14
View File
@@ -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();