Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions toolchain/mfc/cli/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,8 @@
Positional(
name="input",
help="Path to case file to validate.",
nargs="?",
default=None,
completion=Completion(type=CompletionType.FILES_PY),
),
],
Expand All @@ -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"),
],
)

Expand Down
61 changes: 56 additions & 5 deletions toolchain/mfc/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import os
import sys
import glob

from .case_validator import CaseConstraintError, CaseValidator
from .common import MFCException
Expand All @@ -12,23 +13,75 @@
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)

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

Expand All @@ -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]")
Expand Down Expand Up @@ -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)
Loading