Files
create/tests/run_kindred_tests.py
forbes-0023 bdbe1b163a docs: add FileOrigin API reference and Kindred addon test suite
- Add docs/src/reference/cpp-file-origin.md: full API reference for the
  FileOrigin abstract interface, OriginType/ConnectionState enums,
  LocalFileOrigin behavior, and ownership detection algorithm
- Add SUMMARY.md entry under new 'C++ API Reference' section
- Add tests/test_kindred_pure.py: 78 pure-logic unit tests covering
  update_checker, datum_commands, spreadsheet_commands, silo_commands,
  silo_start, and silo_origin (no FreeCAD binary required)
- Add tests/run_kindred_tests.py: two-tier test runner with CI exit codes
- Add pixi task 'test-kindred' for running addon tests
- Add CI/CD step in build.yml to run addon tests before build

Closes #130
2026-02-10 07:54:26 -06:00

104 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""Runner for Kindred Create addon tests.
Tier 1 (pure logic) tests run with the system Python — no FreeCAD binary
required. Tier 2 (FreeCAD headless) tests are skipped unless FreeCADCmd
is found on PATH.
Usage:
python3 tests/run_kindred_tests.py # Tier 1 only
python3 tests/run_kindred_tests.py --all # Tier 1 + Tier 2 (needs FreeCADCmd)
Exit codes:
0 All tests passed
1 One or more tests failed
"""
import os
import shutil
import subprocess
import sys
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
def run_pure_tests() -> bool:
"""Discover and run Tier 1 pure-logic tests. Returns True on success."""
loader = unittest.TestLoader()
suite = loader.discover(
start_dir=str(REPO_ROOT / "tests"),
pattern="test_kindred_pure.py",
top_level_dir=str(REPO_ROOT / "tests"),
)
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
return result.wasSuccessful()
def run_freecad_tests() -> bool:
"""Run Tier 2 tests inside FreeCADCmd. Returns True on success."""
freecad_cmd = shutil.which("FreeCADCmd")
if not freecad_cmd:
# Check build directories
for candidate in (
REPO_ROOT / "build" / "debug" / "bin" / "FreeCADCmd",
REPO_ROOT / "build" / "release" / "bin" / "FreeCADCmd",
):
if candidate.exists():
freecad_cmd = str(candidate)
break
if not freecad_cmd:
print("\n[SKIP] FreeCADCmd not found — skipping Tier 2 tests")
return True # Not a failure, just skipped
print(f"\n{'=' * 70}")
print(f"Tier 2: FreeCAD headless tests via {freecad_cmd}")
print(f"{'=' * 70}\n")
# Tier 2 test modules registered via FreeCAD.__unit_test__
test_modules = ["TestKindredCreate"]
all_ok = True
for mod in test_modules:
print(f"--- Running {mod} ---")
proc = subprocess.run(
[freecad_cmd, "-t", mod],
cwd=str(REPO_ROOT),
timeout=120,
)
if proc.returncode != 0:
all_ok = False
return all_ok
def main():
os.chdir(REPO_ROOT)
run_all = "--all" in sys.argv
print(f"{'=' * 70}")
print("Tier 1: Pure-logic tests (no FreeCAD binary required)")
print(f"{'=' * 70}\n")
tier1_ok = run_pure_tests()
tier2_ok = True
if run_all:
tier2_ok = run_freecad_tests()
print(f"\n{'=' * 70}")
print(f" Tier 1 (pure): {'PASS' if tier1_ok else 'FAIL'}")
if run_all:
print(f" Tier 2 (FreeCAD): {'PASS' if tier2_ok else 'FAIL'}")
print(f"{'=' * 70}")
sys.exit(0 if (tier1_ok and tier2_ok) else 1)
if __name__ == "__main__":
main()