diff --git a/apps/designcraft-cli/src/main.rs b/apps/designcraft-cli/src/main.rs index 20e8509e7..51bf67f05 100644 --- a/apps/designcraft-cli/src/main.rs +++ b/apps/designcraft-cli/src/main.rs @@ -330,7 +330,10 @@ fn run(args: &[String]) -> Result<(), String> { } } "--page" => page = val()?.parse().map_err(|_| "bad --page")?, - "--scale" => scale = val()?.parse().map_err(|_| "bad --scale")?, + "--scale" => { + // 0, a negative value and NaN made a 1×1 image; infinity, "no such page". + scale = val()?.parse().ok().filter(|s: &f64| s.is_finite() && *s > 0.0).ok_or("bad --scale: expected a positive number")?; + } "--pdf-options" => { // The export adds its path to them. pdf_opts = match serde_json::from_str(&val()?).map_err(|e| format!("--pdf-options: {e}"))? { diff --git a/apps/designcraft-cli/tests/cli.rs b/apps/designcraft-cli/tests/cli.rs index 0cb9be859..173a605f4 100644 --- a/apps/designcraft-cli/tests/cli.rs +++ b/apps/designcraft-cli/tests/cli.rs @@ -252,6 +252,22 @@ fn run_export_options_come_before_their_export() { let _ = std::fs::remove_dir_all(&dir); } +/// `--scale 0`, a negative value or `nan` wrote a 1×1 PNG and exited 0; `inf` said "no such page". +#[test] +fn run_scale_that_is_not_finite_and_positive_is_an_error() { + let dir = std::env::temp_dir().join(format!("dc-cli-scale-{}", std::process::id())); + std::fs::create_dir_all(&dir).unwrap(); + let png = dir.join("a.png"); + for scale in ["nan", "0", "-2", "inf", "-inf"] { + let out = cli().args(["run", "--sample", "--scale", scale, "--export", png.to_str().unwrap()]).output().unwrap(); + let err = String::from_utf8_lossy(&out.stderr); + assert!(!out.status.success(), "--scale {scale}: {err}"); + assert!(err.contains("bad --scale"), "--scale {scale}: {err}"); + } + assert!(!png.exists(), "nothing is exported when the scale is wrong"); + let _ = std::fs::remove_dir_all(&dir); +} + /// `--pdf-options` must be a JSON object; any other JSON value used to panic when the PDF path was set on it. #[test] fn pdf_options_that_are_not_an_object_are_an_error_not_a_panic() {