- 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
104 lines
2.7 KiB
Python
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()
|