"""Tests for core/validator.py — CNC manufacturability validation. These tests require CadQuery to be installed. """ import pytest from core.executor import execute_cadquery from core.validator import validate_for_cnc, CNCValidationResult, CNCIssue pytestmark = pytest.mark.requires_cadquery def _make_solid(code: str): """Helper to create a CadQuery Workplane from code.""" result = execute_cadquery(code) assert result.success, f"Code failed: {result.error}" return result.result class TestValidateForCnc: def test_simple_box_is_machinable(self): solid = _make_solid("result = cq.Workplane('XY').box(50, 30, 10)") val = validate_for_cnc(solid, "test_box") assert val.machinable is True assert val.error_count == 0 def test_result_has_part_name(self): solid = _make_solid("result = cq.Workplane('XY').box(50, 30, 10)") val = validate_for_cnc(solid, "my_part") assert val.part_name == "my_part" def test_axis_recommendation_default_3axis(self): solid = _make_solid("result = cq.Workplane('XY').box(50, 30, 10)") val = validate_for_cnc(solid) assert "3-axis" in val.axis_recommendation or "3" in val.axis_recommendation def test_complex_part_gets_higher_axis(self): code = ''' result = cq.Workplane('XY').box(50, 50, 50) for i in range(5): result = result.faces('>Z').workplane().pushPoints([(i*8-16, 0)]).hole(3) for i in range(5): result = result.faces('>X').workplane().pushPoints([(i*8-16, 0)]).hole(3) ''' solid = _make_solid(code) val = validate_for_cnc(solid) assert val.part_name is not None def test_oversized_part_flagged(self): solid = _make_solid("result = cq.Workplane('XY').box(600, 600, 600)") val = validate_for_cnc(solid, config={"max_part_size_mm": 500.0}) assert any(i.category == "Size" for i in val.issues) def test_tiny_part_flagged(self): solid = _make_solid("result = cq.Workplane('XY').box(0.5, 0.5, 0.5)") val = validate_for_cnc(solid, config={"min_part_size_mm": 1.0}) assert any(i.category == "Size" for i in val.issues) def test_summary_format(self): solid = _make_solid("result = cq.Workplane('XY').box(50, 30, 10)") val = validate_for_cnc(solid, "test") summary = val.summary() assert isinstance(summary, str) assert "test" in summary def test_custom_config(self): solid = _make_solid("result = cq.Workplane('XY').box(50, 30, 10)") val = validate_for_cnc(solid, config={"min_wall_thickness_mm": 0.5}) assert isinstance(val, CNCValidationResult) def test_error_and_warning_counts(self): solid = _make_solid("result = cq.Workplane('XY').box(50, 30, 10)") val = validate_for_cnc(solid) assert val.error_count >= 0 assert val.warning_count >= 0 assert val.error_count + val.warning_count <= len(val.issues)