| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| | import Path |
| | from CAMTests.PathTestUtils import PathTestBase |
| |
|
| |
|
| | class TestPathCommandAnnotations(PathTestBase): |
| | """Test Path.Command annotations functionality.""" |
| |
|
| | def test00(self): |
| | """Test basic annotations property access.""" |
| | |
| | c = Path.Command() |
| | self.assertIsInstance(c, Path.Command) |
| |
|
| | |
| | self.assertEqual(c.Annotations, {}) |
| |
|
| | |
| | c.Annotations = {"tool": "tap", "material": "steel"} |
| | self.assertEqual(c.Annotations, {"tool": "tap", "material": "steel"}) |
| |
|
| | |
| | self.assertEqual(c.Annotations.get("tool"), "tap") |
| | self.assertEqual(c.Annotations.get("material"), "steel") |
| | self.assertIsNone(c.Annotations.get("nonexistent")) |
| |
|
| | def test01(self): |
| | """Test annotations with command creation.""" |
| | |
| | c = Path.Command("G84", {"X": 10, "Y": 20, "Z": -5}) |
| |
|
| | |
| | c.Annotations = {"operation": "tapping", "thread": "M6"} |
| |
|
| | |
| | self.assertEqual(c.Name, "G84") |
| | self.assertEqual(c.Parameters["X"], 10.0) |
| | self.assertEqual(c.Parameters["Y"], 20.0) |
| | self.assertEqual(c.Parameters["Z"], -5.0) |
| |
|
| | |
| | self.assertEqual(c.Annotations["operation"], "tapping") |
| | self.assertEqual(c.Annotations["thread"], "M6") |
| |
|
| | def test02(self): |
| | """Test addAnnotations method with dictionary input.""" |
| | c = Path.Command("G1", {"X": 5, "Y": 5}) |
| |
|
| | |
| | result = c.addAnnotations({"note": "test note", "tool": "end mill"}) |
| |
|
| | |
| | self.assertIs(result, c) |
| |
|
| | |
| | self.assertEqual(c.Annotations["note"], "test note") |
| | self.assertEqual(c.Annotations["tool"], "end mill") |
| |
|
| | def test03(self): |
| | """Test addAnnotations method with string input.""" |
| | c = Path.Command("G2", {"X": 15, "Y": 15}) |
| |
|
| | |
| | result = c.addAnnotations("xyz:abc test:1234 operation:milling") |
| |
|
| | |
| | self.assertIs(result, c) |
| |
|
| | |
| | self.assertEqual(c.Annotations["xyz"], "abc") |
| | self.assertEqual(c.Annotations["test"], 1234) |
| | self.assertEqual(c.Annotations["operation"], "milling") |
| |
|
| | def test04(self): |
| | """Test annotations update behavior.""" |
| | c = Path.Command("G0", {"Z": 20}) |
| |
|
| | |
| | c.Annotations = {"initial": "value"} |
| | self.assertEqual(c.Annotations, {"initial": "value"}) |
| |
|
| | |
| | c.addAnnotations({"additional": "value2", "initial": "updated"}) |
| |
|
| | expected = {"initial": "updated", "additional": "value2"} |
| | self.assertEqual(c.Annotations, expected) |
| |
|
| | def test05(self): |
| | """Test method chaining in fluent interface.""" |
| | |
| | c = Path.Command("G84", {"X": 10, "Y": 10, "Z": 0.0}).addAnnotations("thread:M8 depth:15mm") |
| |
|
| | |
| | self.assertEqual(c.Name, "G84") |
| | self.assertEqual(c.Parameters["X"], 10.0) |
| | self.assertEqual(c.Parameters["Y"], 10.0) |
| | self.assertEqual(c.Parameters["Z"], 0.0) |
| |
|
| | |
| | self.assertEqual(c.Annotations["thread"], "M8") |
| | self.assertEqual(c.Annotations["depth"], "15mm") |
| |
|
| | def test06(self): |
| | """Test annotations with special characters and edge cases.""" |
| | c = Path.Command("G1") |
| |
|
| | |
| | c.Annotations = { |
| | "unicode": "café", |
| | "numbers": "123.45", |
| | "empty": "", |
| | "spaces": "value with spaces", |
| | } |
| |
|
| | self.assertEqual(c.Annotations["unicode"], "café") |
| | self.assertEqual(c.Annotations["numbers"], "123.45") |
| | self.assertEqual(c.Annotations["empty"], "") |
| | self.assertEqual(c.Annotations["spaces"], "value with spaces") |
| |
|
| | def test07(self): |
| | """Test annotations persistence through operations.""" |
| | c = Path.Command("G1", {"X": 10, "Y": 20}) |
| | c.Annotations = {"persistent": "value"} |
| |
|
| | |
| | c.Parameters = {"X": 30, "Y": 40} |
| | self.assertEqual(c.Annotations["persistent"], "value") |
| |
|
| | |
| | c.Name = "G2" |
| | self.assertEqual(c.Annotations["persistent"], "value") |
| |
|
| | def test08(self): |
| | """Test multiple annotation update methods.""" |
| | c = Path.Command() |
| |
|
| | |
| | c.Annotations = {"method1": "property"} |
| |
|
| | |
| | c.addAnnotations({"method2": "dict"}) |
| |
|
| | |
| | c.addAnnotations("method3:string") |
| |
|
| | |
| | expected = {"method1": "property", "method2": "dict", "method3": "string"} |
| | self.assertEqual(c.Annotations, expected) |
| |
|
| | def test09(self): |
| | """Test string parsing edge cases.""" |
| | c = Path.Command() |
| |
|
| | |
| | c.addAnnotations("simple:value") |
| | self.assertEqual(c.Annotations["simple"], "value") |
| |
|
| | |
| | c.Annotations = {} |
| | c.addAnnotations("key1:val1 key2:val2 key3:val3") |
| | expected = {"key1": "val1", "key2": "val2", "key3": "val3"} |
| | self.assertEqual(c.Annotations, expected) |
| |
|
| | |
| | c.Annotations = {} |
| | c.addAnnotations("valid:value invalid_no_colon") |
| | self.assertEqual(c.Annotations, {"valid": "value"}) |
| |
|
| | def test10(self): |
| | """Test annotations in gcode context.""" |
| | |
| | c = Path.Command( |
| | "G84", {"X": 25.0, "Y": 30.0, "Z": -10.0, "R": 2.0, "P": 0.5, "F": 100.0} |
| | ).addAnnotations("operation:tapping thread:M6x1.0 depth:10mm") |
| |
|
| | |
| | gcode = c.toGCode() |
| | self.assertIn("G84", gcode) |
| | self.assertIn("X25", gcode) |
| | self.assertIn("Y30", gcode) |
| | self.assertIn("Z-10", gcode) |
| |
|
| | |
| | self.assertEqual(c.Annotations["operation"], "tapping") |
| | self.assertEqual(c.Annotations["thread"], "M6x1.0") |
| | self.assertEqual(c.Annotations["depth"], "10mm") |
| |
|
| | |
| | gcode_parts = gcode.split(";", 1) |
| | main_gcode = gcode_parts[0] |
| | comment = gcode_parts[1] if len(gcode_parts) > 1 else "" |
| |
|
| | self.assertIn("operation:'tapping'", comment) |
| | self.assertIn("thread:'M6x1.0'", comment) |
| | self.assertIn("depth:'10mm'", comment) |
| | self.assertNotIn("operation", main_gcode) |
| | self.assertNotIn("thread", main_gcode) |
| | self.assertNotIn("depth", main_gcode) |
| |
|
| | def test11(self): |
| | """Test save/restore with mixed string and numeric annotations (in-memory).""" |
| | |
| | original = Path.Command("G1", {"X": 10.0, "Y": 20.0, "F": 1000.0}) |
| | original.Annotations = { |
| | "tool_name": "6mm_endmill", |
| | "spindle_speed": 12000.0, |
| | "feed_rate": 1500, |
| | "operation": "pocket", |
| | "depth_of_cut": -2.5, |
| | } |
| |
|
| | |
| | content = original.dumpContent() |
| |
|
| | |
| | restored = Path.Command() |
| | restored.restoreContent(content) |
| |
|
| | |
| | self.assertEqual(restored.Annotations["tool_name"], "6mm_endmill") |
| | self.assertEqual(restored.Annotations["spindle_speed"], 12000.0) |
| | self.assertEqual(restored.Annotations["feed_rate"], 1500.0) |
| | self.assertEqual(restored.Annotations["operation"], "pocket") |
| | self.assertEqual(restored.Annotations["depth_of_cut"], -2.5) |
| |
|
| | |
| | self.assertIsInstance(restored.Annotations["tool_name"], str) |
| | self.assertIsInstance(restored.Annotations["spindle_speed"], float) |
| | self.assertIsInstance(restored.Annotations["feed_rate"], float) |
| | self.assertIsInstance(restored.Annotations["operation"], str) |
| | self.assertIsInstance(restored.Annotations["depth_of_cut"], float) |
| |
|
| | |
| | self.assertEqual(restored.Name, "G1") |
| | |
| |
|
| | def test12(self): |
| | """Test save/restore with empty annotations (in-memory).""" |
| | |
| | simple = Path.Command("G0", {"Z": 5.0}) |
| | self.assertEqual(simple.Annotations, {}) |
| |
|
| | simple_content = simple.dumpContent() |
| | simple_restored = Path.Command() |
| | simple_restored.restoreContent(simple_content) |
| |
|
| | self.assertEqual(simple_restored.Annotations, {}) |
| | self.assertEqual(simple_restored.Name, "G0") |
| |
|
| | def test13(self): |
| | """Test save/restore with complex annotations and edge cases (in-memory).""" |
| | |
| | complex_cmd = Path.Command("G84", {"X": 25.4, "Y": 12.7, "Z": -8.0}) |
| | complex_cmd.Annotations = { |
| | |
| | "tool_type": "tap", |
| | "spindle_speed": 500.0, |
| | "zero_value": 0.0, |
| | "negative": -123.456, |
| | "large_number": 999999.999, |
| | "operation_id": "OP_030", |
| | "thread_spec": "M4x0.7", |
| | "scientific": 1.23e-6, |
| | } |
| |
|
| | |
| | complex_content = complex_cmd.dumpContent() |
| | complex_restored = Path.Command() |
| | complex_restored.restoreContent(complex_content) |
| |
|
| | |
| | self.assertEqual(len(complex_restored.Annotations), 8) |
| |
|
| | |
| | self.assertEqual(complex_restored.Annotations["tool_type"], "tap") |
| | self.assertIsInstance(complex_restored.Annotations["tool_type"], str) |
| |
|
| | self.assertEqual(complex_restored.Annotations["spindle_speed"], 500.0) |
| | self.assertIsInstance(complex_restored.Annotations["spindle_speed"], float) |
| |
|
| | self.assertEqual(complex_restored.Annotations["zero_value"], 0.0) |
| | self.assertEqual(complex_restored.Annotations["negative"], -123.456) |
| | self.assertEqual(complex_restored.Annotations["large_number"], 999999.999) |
| |
|
| | |
| | self.assertEqual(complex_restored.Annotations["operation_id"], "OP_030") |
| | self.assertEqual(complex_restored.Annotations["thread_spec"], "M4x0.7") |
| | self.assertIsInstance(complex_restored.Annotations["operation_id"], str) |
| | self.assertIsInstance(complex_restored.Annotations["thread_spec"], str) |
| |
|
| | |
| | self.assertAlmostEqual(complex_restored.Annotations["scientific"], 1.23e-6, places=6) |
| | self.assertIsInstance(complex_restored.Annotations["scientific"], float) |
| |
|
| | def test14(self): |
| | """Test Command constructor with positional annotations parameter.""" |
| | |
| | c1 = Path.Command("G1", {"X": 10.0, "Y": 5.0}, {"note": "Rapid move"}) |
| | self.assertEqual(c1.Name, "G1") |
| | self.assertEqual(c1.Parameters["X"], 10.0) |
| | self.assertEqual(c1.Parameters["Y"], 5.0) |
| | self.assertEqual(c1.Annotations["note"], "Rapid move") |
| |
|
| | def test15(self): |
| | """Test Command constructor with keyword annotations parameter.""" |
| | |
| | c1 = Path.Command("G1", {"X": 10.0, "Y": 5.0}, annotations={"note": "Rapid move"}) |
| | self.assertEqual(c1.Name, "G1") |
| | self.assertEqual(c1.Parameters["X"], 10.0) |
| | self.assertEqual(c1.Parameters["Y"], 5.0) |
| | self.assertEqual(c1.Annotations["note"], "Rapid move") |
| |
|
| | def test16(self): |
| | """Test Command constructor with numeric annotations.""" |
| | |
| | c1 = Path.Command("G2", {"X": 20.0, "Y": 15.0}, {"priority": 1}) |
| | self.assertEqual(c1.Name, "G2") |
| | self.assertEqual(c1.Parameters["X"], 20.0) |
| | self.assertEqual(c1.Parameters["Y"], 15.0) |
| | self.assertEqual(c1.Annotations["priority"], 1) |
| |
|
| | def test17(self): |
| | """Test Command constructor with mixed string and numeric annotations.""" |
| | |
| | c1 = Path.Command("G3", {"X": 30.0, "Y": 25.0}, {"note": "Arc move", "speed": 1500}) |
| | self.assertEqual(c1.Name, "G3") |
| | self.assertEqual(c1.Parameters["X"], 30.0) |
| | self.assertEqual(c1.Parameters["Y"], 25.0) |
| | self.assertEqual(c1.Annotations["note"], "Arc move") |
| | self.assertEqual(c1.Annotations["speed"], 1500) |
| |
|
| | def test18(self): |
| | """Test Command constructor with empty annotations.""" |
| | |
| | c1 = Path.Command("G0", {"X": 0.0, "Y": 0.0}, {}) |
| | self.assertEqual(c1.Name, "G0") |
| | self.assertEqual(c1.Parameters["X"], 0.0) |
| | self.assertEqual(c1.Parameters["Y"], 0.0) |
| | self.assertEqual(c1.Annotations, {}) |
| |
|
| | def test19(self): |
| | """Test Command constructor without annotations (backward compatibility).""" |
| | |
| | c1 = Path.Command("G1", {"X": 10.0, "Y": 5.0}) |
| | self.assertEqual(c1.Name, "G1") |
| | self.assertEqual(c1.Parameters["X"], 10.0) |
| | self.assertEqual(c1.Parameters["Y"], 5.0) |
| | self.assertEqual(c1.Annotations, {}) |
| |
|
| | def test20(self): |
| | """Test Command constructor with floating point annotations.""" |
| | |
| | c1 = Path.Command("G1", {"X": 10.0, "Y": 5.0}, {"retract": 15.5, "angle": 30.25}) |
| | self.assertEqual(c1.Name, "G1") |
| | self.assertEqual(c1.Parameters["X"], 10.0) |
| | self.assertEqual(c1.Parameters["Y"], 5.0) |
| | self.assertEqual(c1.Annotations["retract"], 15.5) |
| | self.assertEqual(c1.Annotations["angle"], 30.25) |
| |
|