148 lines
6.3 KiB
Python
148 lines
6.3 KiB
Python
import contextlib
|
|
import io
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from unittest import mock
|
|
|
|
from tests.python.support.paths import add_repo_path, repo_path
|
|
|
|
add_repo_path("skills/cad/scripts")
|
|
|
|
from step import cli
|
|
|
|
|
|
class StepCliTests(unittest.TestCase):
|
|
def test_requires_explicit_target(self) -> None:
|
|
with self.assertRaises(SystemExit) as cm:
|
|
cli.main([])
|
|
self.assertEqual(2, cm.exception.code)
|
|
|
|
def test_passes_targets_in_order_without_kind_for_generated_sources(self) -> None:
|
|
with mock.patch.object(cli, "generate_step_targets", return_value=0) as generate:
|
|
self.assertEqual(0, cli.main(["parts/second.py", "parts/first.py"]))
|
|
|
|
generate.assert_called_once()
|
|
self.assertEqual(["parts/second.py", "parts/first.py"], generate.call_args.args[0])
|
|
self.assertIsNone(generate.call_args.kwargs["direct_step_kind"])
|
|
self.assertFalse(generate.call_args.kwargs["step_options"].has_metadata)
|
|
self.assertIsNone(generate.call_args.kwargs["output"])
|
|
self.assertFalse(generate.call_args.kwargs["skip_step_write"])
|
|
self.assertFalse(generate.call_args.kwargs["verbose"])
|
|
|
|
def test_passes_direct_step_kind(self) -> None:
|
|
with mock.patch.object(cli, "generate_step_targets", return_value=0) as generate:
|
|
self.assertEqual(0, cli.main(["--kind", "assembly", "assemblies/second.step", "assemblies/first.step"]))
|
|
|
|
generate.assert_called_once()
|
|
self.assertEqual(["assemblies/second.step", "assemblies/first.step"], generate.call_args.args[0])
|
|
self.assertEqual("assembly", generate.call_args.kwargs["direct_step_kind"])
|
|
self.assertFalse(generate.call_args.kwargs["step_options"].has_metadata)
|
|
self.assertIsNone(generate.call_args.kwargs["output"])
|
|
self.assertFalse(generate.call_args.kwargs["verbose"])
|
|
|
|
def test_passes_verbose_flag(self) -> None:
|
|
with mock.patch.object(cli, "generate_step_targets", return_value=0) as generate:
|
|
self.assertEqual(0, cli.main(["parts/sample.py", "--verbose"]))
|
|
|
|
self.assertTrue(generate.call_args.kwargs["verbose"])
|
|
|
|
def test_passes_skip_step_write_flag(self) -> None:
|
|
with mock.patch.object(cli, "generate_step_targets", return_value=0) as generate:
|
|
self.assertEqual(0, cli.main(["parts/sample.py", "--skip-step-write"]))
|
|
|
|
self.assertTrue(generate.call_args.kwargs["skip_step_write"])
|
|
|
|
def test_passes_output_flag(self) -> None:
|
|
with mock.patch.object(cli, "generate_step_targets", return_value=0) as generate:
|
|
self.assertEqual(0, cli.main(["parts/sample.py", "-o", "STEP/sample.step"]))
|
|
|
|
self.assertEqual("STEP/sample.step", generate.call_args.kwargs["output"])
|
|
|
|
def test_output_flag_rejects_multiple_targets(self) -> None:
|
|
with self.assertRaises(SystemExit) as cm:
|
|
cli.main(["parts/first.py", "parts/second.py", "-o", "STEP/first.step"])
|
|
self.assertEqual(2, cm.exception.code)
|
|
|
|
def test_passes_import_metadata_flags(self) -> None:
|
|
with mock.patch.object(cli, "generate_step_targets", return_value=0) as generate:
|
|
self.assertEqual(
|
|
0,
|
|
cli.main(
|
|
[
|
|
"--kind",
|
|
"part",
|
|
"imports/sample_part.step",
|
|
"--stl",
|
|
"../meshes/sample_part.stl",
|
|
"--3mf",
|
|
"../meshes/sample_part.3mf",
|
|
"--glb",
|
|
"../meshes/sample_part.glb",
|
|
"--mesh-tolerance",
|
|
"0.2",
|
|
"--mesh-angular-tolerance",
|
|
"0.25",
|
|
]
|
|
),
|
|
)
|
|
|
|
generate.assert_called_once()
|
|
self.assertEqual(["imports/sample_part.step"], generate.call_args.args[0])
|
|
self.assertEqual("part", generate.call_args.kwargs["direct_step_kind"])
|
|
options = generate.call_args.kwargs["step_options"]
|
|
self.assertEqual("../meshes/sample_part.stl", options.stl)
|
|
self.assertEqual("../meshes/sample_part.3mf", options.three_mf)
|
|
self.assertEqual("../meshes/sample_part.glb", options.glb)
|
|
self.assertEqual(0.2, options.mesh_tolerance)
|
|
self.assertEqual(0.25, options.mesh_angular_tolerance)
|
|
|
|
def test_rejects_invalid_numeric_flag(self) -> None:
|
|
with self.assertRaises(SystemExit) as cm:
|
|
cli.main(["imports/sample_part.step", "--mesh-tolerance", "nan"])
|
|
self.assertEqual(2, cm.exception.code)
|
|
|
|
def test_rejects_removed_inspect_flag(self) -> None:
|
|
with self.assertRaises(SystemExit) as cm:
|
|
cli.main(["parts/sample.step", "--inspect", "refs {cad_token} --facts"])
|
|
self.assertEqual(2, cm.exception.code)
|
|
|
|
def test_help_has_current_step_flags_only(self) -> None:
|
|
stream = io.StringIO()
|
|
with self.assertRaises(SystemExit) as cm, contextlib.redirect_stdout(stream):
|
|
cli.main(["--help"])
|
|
self.assertEqual(0, cm.exception.code)
|
|
help_text = stream.getvalue()
|
|
self.assertIn("--kind", help_text)
|
|
self.assertIn("--stl", help_text)
|
|
self.assertIn("--3mf", help_text)
|
|
self.assertIn("--glb", help_text)
|
|
self.assertIn("--skip-step-write", help_text)
|
|
self.assertIn("--output", help_text)
|
|
self.assertIn("--mesh-tolerance", help_text)
|
|
self.assertIn("--verbose", help_text)
|
|
|
|
def test_cli_does_not_reserve_common_module_name(self) -> None:
|
|
skill_root = repo_path("skills/cad")
|
|
code = (
|
|
"import sys; sys.path.insert(0, 'scripts'); import step.cli; "
|
|
"print('common' in sys.modules); "
|
|
"print('OCP.OCP' in sys.modules); "
|
|
"print('cadpy.step_scene' in sys.modules)"
|
|
)
|
|
result = subprocess.run(
|
|
[sys.executable, "-c", code],
|
|
cwd=skill_root,
|
|
check=False,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
)
|
|
self.assertEqual("", result.stderr)
|
|
self.assertEqual(0, result.returncode)
|
|
self.assertEqual(["False", "False", "False"], result.stdout.strip().splitlines())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|