From 88d7a31d9d4edba3d3451cfe871df0e64e340707 Mon Sep 17 00:00:00 2001 From: Aditya Raut Date: Mon, 29 Jun 2026 23:49:48 +0000 Subject: [PATCH] feat(validate): add --all flag to validate all example case files --- toolchain/mfc/cli/commands.py | 10 ++++++ toolchain/mfc/validate.py | 61 ++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/toolchain/mfc/cli/commands.py b/toolchain/mfc/cli/commands.py index 2fce946693..5fe4b4c183 100644 --- a/toolchain/mfc/cli/commands.py +++ b/toolchain/mfc/cli/commands.py @@ -547,6 +547,8 @@ Positional( name="input", help="Path to case file to validate.", + nargs="?", + default=None, completion=Completion(type=CompletionType.FILES_PY), ), ], @@ -557,14 +559,22 @@ action=ArgAction.STORE_TRUE, default=False, ), + Argument( + name="all", + short="a", + help="Validate all example case files instead of a single file.", + action=ArgAction.STORE_TRUE, + ), ], examples=[ Example("./mfc.sh validate case.py", "Check syntax and constraints"), Example("./mfc.sh validate case.py -d", "Validate with toolchain debug output"), Example("./mfc.sh validate case.py --migrate", "Rewrite integer codes to named values"), + Example("./mfc.sh validate --all", "Validate every example case file"), ], key_options=[ ("-d, --debug-log", "Enable toolchain debug logging"), + ("-a, --all", "Validate all example case files"), ], ) diff --git a/toolchain/mfc/validate.py b/toolchain/mfc/validate.py index 8e16688aaf..9ec7c40f0e 100644 --- a/toolchain/mfc/validate.py +++ b/toolchain/mfc/validate.py @@ -4,6 +4,7 @@ import os import sys +import glob from .case_validator import CaseConstraintError, CaseValidator from .common import MFCException @@ -12,10 +13,64 @@ from .state import ARG +def _validate_one(input_file): + """Validate a single case file. Returns True if passed, False if failed.""" + try: + case = run_input.load(input_file, do_print=False) + stages = ["pre_process", "simulation", "post_process"] + all_passed = True + for stage in stages: + try: + validator = CaseValidator(case.params) + validator.validate(stage) + except CaseConstraintError: + all_passed = False + return all_passed + except MFCException: + return False + + def validate(): """Validate a case file without building or running.""" + + if ARG("all"): + example_files = sorted(glob.glob("examples/**/case.py", recursive=True)) + + if not example_files: + cons.print("[bold red]No example case files found in examples/[/bold red]") + sys.exit(1) + + cons.print(f"Validating [bold]{len(example_files)}[/bold] example case files...\n") + + passed = [] + failed = [] + + for f in example_files: + if _validate_one(f): + passed.append(f) + cons.print(f"[bold green]✓[/bold green] {f}") + else: + failed.append(f) + cons.print(f"[bold red]✗[/bold red] {f}") + + cons.print() + cons.print(f"[bold green]{len(passed)} passed[/bold green], [bold red]{len(failed)} failed[/bold red] out of {len(example_files)} total.") + + if failed: + cons.print("\n[bold red]Failed cases:[/bold red]") + for f in failed: + cons.print(f" {f}") + sys.exit(1) + else: + cons.print("[bold green]All example cases passed validation![/bold green]") + return + input_file = ARG("input") + if not input_file: + cons.print("[bold red]Error:[/bold red] Provide a case file or use --all to validate all examples.") + sys.exit(1) + if not os.path.isfile(input_file): cons.print(f"[bold red]Error:[/bold red] File not found: {input_file}") sys.exit(1) @@ -23,12 +78,10 @@ def validate(): cons.print(f"Validating [bold magenta]{input_file}[/bold magenta]...\n") try: - # Step 1: Load and parse case file (checks syntax) case = run_input.load(input_file, do_print=False) cons.print("[bold green]✓[/bold green] Syntax valid - case file parsed successfully") cons.print(f" [dim]Loaded {len(case.params)} parameters[/dim]") - # Step 2: Run constraint validation for each stage stages = ["pre_process", "simulation", "post_process"] all_passed = True @@ -45,12 +98,10 @@ def validate(): except CaseConstraintError as e: all_passed = False cons.print(f"[bold yellow]![/bold yellow] {stage} constraints: issues found") - # Show the constraint violations indented for line in str(e).split("\n"): if line.strip(): cons.print(f" [dim]{line}[/dim]") - # Step 3: Show summary cons.print() if all_passed: cons.print("[bold green]Case validation complete - all checks passed![/bold green]") @@ -89,4 +140,4 @@ def validate(): except MFCException as e: cons.print("\n[bold red]✗ Validation failed:[/bold red]") cons.print(f"{e}") - sys.exit(1) + sys.exit(1) \ No newline at end of file