import tempfile import unittest from pathlib import Path from unittest.mock import patch import svg2gcode class DrawingBoundsTests(unittest.TestCase): def setUp(self): self.directory = tempfile.TemporaryDirectory() self.addCleanup(self.directory.cleanup) self.source = Path(self.directory.name) / "drawing.svg" self.output = Path(self.directory.name) / "drawing.gcode" for name, value in ( ("bed_max_x", 200), ("bed_max_y", 280), ("units", "mm"), ("auto_scale", False), ): patcher = patch.object(svg2gcode, name, value) patcher.start() self.addCleanup(patcher.stop) def write_line(self, x1, y1, x2, y2, width=200, height=280, transform=""): self.source.write_text( f'' f'' ) def test_exact_boundaries_are_allowed(self): self.write_line(0, 0, 200, 280) shapes = svg2gcode.get_shapes(self.source, False) self.assertIn((0, 280), shapes[0]) self.assertIn((200, 0), shapes[0]) def test_each_boundary_is_enforced(self): for x, y in ((-0.0001, 100), (200.0001, 100), (100, -0.0001), (100, 280.0001)): with self.subTest(x=x, y=y): self.write_line(10, 10, x, y) with self.assertRaisesRegex(ValueError, "outside bed limits"): svg2gcode.get_shapes(self.source, False) def test_transformed_coordinates_are_checked(self): self.write_line(10, 10, 20, 20, transform="translate(200, 0)") with self.assertRaisesRegex(ValueError, "outside bed limits"): svg2gcode.get_shapes(self.source, False) def test_points_are_converted_before_checking(self): self.write_line(0, 0, 500, 500, width=500, height=500) with patch.object(svg2gcode, "units", "points"): shapes = svg2gcode.get_shapes(self.source, False) self.assertAlmostEqual(shapes[0][-1][0], 500 * 0.352778) def test_auto_scaling_is_applied_before_checking(self): self.write_line(0, 0, 400, 560, width=400, height=560) shapes = svg2gcode.get_shapes(self.source, True) self.assertTrue(all(0 <= x <= 200 and 0 <= y <= 280 for shape in shapes for x, y in shape)) self.assertEqual(shapes[0], [(0, 280), (200, 0)]) def test_fitting_preserves_in_bounds_coordinates(self): self.write_line(10, 10, 20, 20) self.assertEqual(svg2gcode.get_shapes(self.source, True), svg2gcode.get_shapes(self.source, False)) def test_negative_coordinates_are_shifted_and_scaled(self): self.write_line(-100, -100, 300, 300, height=200) shapes = svg2gcode.get_shapes(self.source, True) self.assertEqual(shapes[0], [(0, 200), (200, 0)]) def test_horizontal_vertical_and_single_point_drawings(self): for coords, expected in ( ((-100, 100, 300, 100), [(0, 0), (200, 0)]), ((100, -100, 100, 300), [(0, 280), (0, 0)]), ((300, 100, 300, 100), [(0, 0)]), ): with self.subTest(coords=coords): self.write_line(*coords) self.assertEqual(svg2gcode.get_shapes(self.source, True)[0], expected) def test_fitting_uses_drawing_not_canvas_dimensions(self): self.write_line(10, 300, 20, 350, width=500, height=500) self.assertEqual(svg2gcode.get_shapes(self.source, True)[0], [(10, 200), (20, 150)]) def test_fitting_transformed_coordinates(self): self.write_line(10, 10, 20, 20, transform="translate(200, 0)") shapes = svg2gcode.get_shapes(self.source, True) self.assertTrue(all(0 <= x <= 200 and 0 <= y <= 280 for shape in shapes for x, y in shape)) def test_invalid_bed_dimensions_are_rejected(self): self.write_line(10, 10, 20, 20) for dimension in (0, -1, float("inf")): with patch.object(svg2gcode, "bed_max_x", dimension): with self.assertRaisesRegex(ValueError, "Bed dimensions"): svg2gcode.get_shapes(self.source, True) def test_canvas_size_alone_does_not_reject_in_bounds_drawing(self): self.write_line(10, 300, 20, 350, width=500, height=500) self.assertTrue(svg2gcode.get_shapes(self.source, False)) def test_failure_does_not_create_or_overwrite_output(self): self.write_line(10, 10, 201, 20) with patch.object(svg2gcode, "optimise_path") as optimise_path: with self.assertRaisesRegex(ValueError, "X201.000000"): svg2gcode.main(self.source, self.output) self.assertFalse(self.output.exists()) self.output.write_text("existing output") with self.assertRaises(ValueError): svg2gcode.main(self.source, self.output) self.assertEqual(self.output.read_text(), "existing output") optimise_path.assert_not_called() if __name__ == "__main__": unittest.main()