from __future__ import annotations import importlib.util from pathlib import Path import pytest from src.cad.parametric_parts import ( PART_CAPABILITIES, export_parametric_part, get_parametric_part_capability, list_parametric_part_capability_manifests, make_parametric_part, validate_part_parameters, ) EXPECTED_SIMPLECADAPI_PARTS = { "spur_gear", "straight_bevel_gear", "helical_gear", "herringbone_gear", "spur_ring_gear", "helical_ring_gear", "herringbone_ring_gear", "cycloidal_disc", "spur_rack", "helical_rack", "herringbone_rack", "ball_bearing", "roller_chain_sprocket", "bolt", "nut", "n_hole_flange", "naca_propeller_blade", "threaded_rod", } def test_catalog_covers_all_simplecadapi_formula_factories() -> None: assert EXPECTED_SIMPLECADAPI_PARTS <= set(PART_CAPABILITIES) manifests = list_parametric_part_capability_manifests() assert len(manifests) >= len(EXPECTED_SIMPLECADAPI_PARTS) by_id = {item["part_id"]: item for item in manifests} assert by_id["spur_gear"]["api_path"] == "simplecadapi.std.gear.make_spur_gear_rsolid" assert by_id["ball_bearing"]["result_kind"] == "assembly" assert by_id["roller_chain_sprocket"]["available"] is True def test_simplecadapi_is_vendored_under_project_src() -> None: import simplecadapi assert "/src/simplecadapi/" in str(Path(simplecadapi.__file__).as_posix()) + "/" assert hasattr(simplecadapi.std.fastener, "make_bolt_rsolid") assert hasattr(simplecadapi.std.bearing, "make_ball_bearing_rassembly") assert hasattr(simplecadapi.std.chain, "make_roller_chain_sprocket_rsolid") def test_validate_part_parameters_uses_underlying_signature() -> None: params = validate_part_parameters( "roller_chain_sprocket", { "n_teeth": 12, "chain_pitch": 6.35, "roller_diameter": 3.3, "sprocket_thickness": 3.0, }, ) assert params["bore_radius"] == 0.0 assert params["roller_clearance"] == 0.15 with pytest.raises(Exception, match="invalid_parametric_part_parameters"): validate_part_parameters("roller_chain_sprocket", {"n_teeth": 12}) def test_dependency_report_marks_sketch_solver_backed_gears() -> None: capability = get_parametric_part_capability("spur_gear") assert "py_slvs" in capability.required_packages if importlib.util.find_spec("py_slvs") is None: assert capability.missing_packages() == ("py_slvs",) def test_make_and_export_available_parametric_sprocket(tmp_path: Path) -> None: shape = make_parametric_part( "roller_chain_sprocket", { "n_teeth": 12, "chain_pitch": 6.35, "roller_diameter": 3.3, "sprocket_thickness": 3.0, "bore_radius": 1.2, }, ) assert shape.get_volume() > 0 manifest = export_parametric_part( "roller_chain_sprocket", { "n_teeth": 12, "chain_pitch": 6.35, "roller_diameter": 3.3, "sprocket_thickness": 3.0, "bore_radius": 1.2, }, tmp_path, ) assert Path(manifest["exported_files"]["step"]).exists() assert Path(manifest["exported_files"]["model"]).exists() assert manifest["geometry_summary"]["volume_mm3"] > 0