Reject missing or non-numeric values in mix.pan and mix.trim

Found while testing crates/engine/src/cmd/mix.rs:237 (pan); same pattern at mix.rs:76 (mix.trim)

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-17 09:54:08 +02:00
co-authored by Claude Haiku 5.5
parent f3a19480d8
commit 4a4e82daba
2 changed files with 46 additions and 2 deletions
+4 -2
View File
@@ -73,7 +73,8 @@ pub fn specs() -> Vec<CommandSpec> {
)),
cmd!("mix.trim", "Input Trim", [], None, "{tracks?, db}", has_selection, |e, p| {
let tracks = tracks_required(e, "mix.trim", p)?;
let db = f32_or(p, "db", 0.0).clamp(-144.0, 24.0);
let db = (p.get("db").and_then(Value::as_f64).filter(|v| v.is_finite()).ok_or_else(|| bad("mix.trim", "`db` (number) required"))? as f32)
.clamp(-144.0, 24.0);
let s = e.session_mut();
for t in tracks {
if let Some(tr) = s.track_mut(t) {
@@ -234,7 +235,8 @@ fn volume(e: &mut Engine, p: &Value) -> Result<Value> {
fn pan(e: &mut Engine, p: &Value) -> Result<Value> {
let tracks = tracks_required(e, "mix.pan", p)?;
let v = f32_or(p, "pan", 0.0).clamp(-1.0, 1.0);
let v = (p.get("pan").and_then(Value::as_f64).filter(|v| v.is_finite()).ok_or_else(|| bad("mix.pan", "`pan` (number) required"))? as f32)
.clamp(-1.0, 1.0);
let idx = i64_or(p, "index", 0).clamp(0, 1) as usize;
let s = e.session_mut();
for t in &tracks {
@@ -0,0 +1,42 @@
use serde_json::json;
use soundcraft_engine::{Engine, EngineError};
fn engine_with_kick() -> Engine {
let mut e = Engine::default();
e.execute("track.new", &json!({"name": "Kick", "format": "stereo"})).unwrap();
e
}
fn kick_pan(e: &Engine) -> Vec<f32> {
e.session().tracks.iter().find(|t| t.name == "Kick").unwrap().mixer.pan.to_vec()
}
fn kick_trim(e: &Engine) -> f32 {
e.session().tracks.iter().find(|t| t.name == "Kick").unwrap().mixer.trim_db
}
#[test]
fn mix_pan_rejects_a_missing_or_non_numeric_pan_and_keeps_the_pan() {
let mut e = engine_with_kick();
e.execute("mix.pan", &json!({"tracks": ["Kick"], "pan": -1.0})).unwrap();
assert_eq!(kick_pan(&e)[0], -1.0);
for params in [json!({"tracks": ["Kick"]}), json!({"tracks": ["Kick"], "pan": "left"}), json!({"tracks": ["Kick"], "pan": null})] {
let r = e.execute("mix.pan", &params);
assert!(matches!(r, Err(EngineError::BadParams(..))), "{params}: expected BadParams, got {r:?}");
assert_eq!(kick_pan(&e)[0], -1.0, "{params}: the pan must be untouched");
}
}
#[test]
fn mix_trim_rejects_a_missing_or_non_numeric_db_and_keeps_the_trim() {
let mut e = engine_with_kick();
e.execute("mix.trim", &json!({"tracks": ["Kick"], "db": -6.0})).unwrap();
assert_eq!(kick_trim(&e), -6.0);
for params in [json!({"tracks": ["Kick"]}), json!({"tracks": ["Kick"], "db": "loud"}), json!({"tracks": ["Kick"], "db": null})] {
let r = e.execute("mix.trim", &params);
assert!(matches!(r, Err(EngineError::BadParams(..))), "{params}: expected BadParams, got {r:?}");
assert_eq!(kick_trim(&e), -6.0, "{params}: the trim must be untouched");
}
}