build123d/tests/test_examples.py
Ami Fischman 80097a9227 Add a new TestCase that asserts that examples exit successfully.
Examples changes that were necessary:
- loft.py: failed on macos (only) because of (seemingly) over-precise
  floating-point accuracy assertion. Loosened the tolerance, and
  expressed it as a multiple of the expected value.
  > AssertionError: delta=0.002982314711971412 is greater than tolerance=0.001; got=1306.3375467197516, want=1306.3405290344635
- packed_boxes.py: only emit output files when GEN_DOCS is
  True (mimicking lego.py).
2025-02-22 10:11:06 -08:00

86 lines
2.5 KiB
Python

"""
build123d Example tests
name: test_examples.py
by: fischman
date: February 21 2025
desc: Unit tests for the build123d examples, ensuring they don't raise.
"""
from pathlib import Path
import os
import subprocess
import sys
import tempfile
import unittest
_examples_dir = Path(os.path.abspath(os.path.dirname(__file__))).parent / "examples"
_MOCK_OCP_VSCODE_CONTENTS = """
from pathlib import Path
import re
import sys
from unittest.mock import Mock
mock_module = Mock()
mock_module.show = Mock()
mock_module.show_object = Mock()
mock_module.show_all = Mock()
sys.modules["ocp_vscode"] = mock_module
"""
def generate_example_test(path: Path):
"""Generate and return a function to test the example at `path`."""
name = path.name
def assert_example_does_not_raise(self):
with tempfile.TemporaryDirectory(
prefix=f"build123d_test_examples_{name}"
) as tmpdir:
# More examples emit output files than read input files,
# so default to running with a temporary directory to
# avoid cluttering the git working directory. For
# examples that want to read assets from the examples
# directory, use that. If an example is added in the
# future that wants to both read assets from the examples
# directory and write output files, deal with it then.
cwd = tmpdir if 'benchy' not in path.name else _examples_dir
mock_ocp_vscode = Path(tmpdir) / "_mock_ocp_vscode.py"
with open(mock_ocp_vscode, "w", encoding="utf-8") as f:
f.write(_MOCK_OCP_VSCODE_CONTENTS)
got = subprocess.run(
[
sys.executable,
"-c",
f"exec(open(r'{mock_ocp_vscode}').read()); exec(open(r'{path}').read())",
],
capture_output=True,
cwd=cwd,
check=False,
)
self.assertEqual(
0, got.returncode, f"stdout/stderr: {got.stdout} / {got.stderr}"
)
return assert_example_does_not_raise
class TestExamples(unittest.TestCase):
"""Tests build123d examples."""
for example in sorted(_examples_dir.iterdir()):
if example.name.startswith("_") or not example.name.endswith(".py"):
continue
setattr(
TestExamples,
f"test_{example.name.replace('.', '_')}",
generate_example_test(example),
)
if __name__ == "__main__":
unittest.main()