diff --git a/src/leakgauge/cli.py b/src/leakgauge/cli.py index cd5ae02..8e3860d 100644 --- a/src/leakgauge/cli.py +++ b/src/leakgauge/cli.py @@ -126,6 +126,14 @@ def _run(argv: list[str]) -> int: print(f"[leakgauge] --max-steps must be >= 1 (got {args.max_steps})", file=sys.stderr) return 2 + if args.k < 1: + print(f"[leakgauge] --k must be >= 1 (got {args.k})", file=sys.stderr) + return 2 + + if args.seed < 0: + print(f"[leakgauge] --seed must be >= 0 (got {args.seed})", file=sys.stderr) + return 2 + selected: list[Case] | None = None suite_label = args.suite if args.case is not None: diff --git a/tests/test_cli_validation.py b/tests/test_cli_validation.py new file mode 100644 index 0000000..2e230ad --- /dev/null +++ b/tests/test_cli_validation.py @@ -0,0 +1,33 @@ +"""--k and --seed are validated before a run starts, so a degenerate value +(zero repeats, negative seed) fails with a clear message instead of a confusing +empty run downstream.""" + +from __future__ import annotations + +from pathlib import Path + +from leakgauge.cli import main + + +def test_k_zero_errors_cleanly(tmp_path: Path) -> None: + rc = main(["--k", "0", "--results-dir", str(tmp_path)]) + assert rc == 2 + assert not (tmp_path / "stub_demo.json").exists() # nothing written on error + + +def test_k_negative_errors_cleanly(tmp_path: Path) -> None: + rc = main(["--k", "-1", "--results-dir", str(tmp_path)]) + assert rc == 2 + assert not (tmp_path / "stub_demo.json").exists() + + +def test_seed_negative_errors_cleanly(tmp_path: Path) -> None: + rc = main(["--seed", "-1", "--results-dir", str(tmp_path)]) + assert rc == 2 + assert not (tmp_path / "stub_demo.json").exists() + + +def test_valid_k_and_seed_still_run(tmp_path: Path) -> None: + rc = main(["--k", "2", "--seed", "0", "--results-dir", str(tmp_path)]) + assert rc == 0 + assert (tmp_path / "stub_demo.json").exists()