You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
LightWork3D/tests/python/freecad_exchange_template_a...

287 lines
9.2 KiB
Python

import importlib
import json
import sys
import types
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
MODULE_DIR = REPO_ROOT / "src" / "Mod" / "FreeCADExchange"
if str(MODULE_DIR) not in sys.path:
sys.path.insert(0, str(MODULE_DIR))
def _install_fake_freecad():
class Vector:
def __init__(self, x=0.0, y=0.0, z=0.0):
self.x = float(x)
self.y = float(y)
self.z = float(z)
class Rotation:
def __init__(self, axis=None, angle=None):
self.Axis = axis
self.Angle = angle
class Placement:
def __init__(self, base=None, rotation=None):
self.Base = base
self.Rotation = rotation
fake_freecad = types.ModuleType("FreeCAD")
fake_freecad.Vector = Vector
fake_freecad.Rotation = Rotation
fake_freecad.Placement = Placement
fake_freecad.ActiveDocument = None
fake_freecad.Console = types.SimpleNamespace(
PrintMessage=lambda *args, **kwargs: None,
PrintWarning=lambda *args, **kwargs: None,
PrintError=lambda *args, **kwargs: None,
)
sys.modules["FreeCAD"] = fake_freecad
fake_freecadgui = types.ModuleType("FreeCADGui")
fake_freecadgui.addCommand = lambda *args, **kwargs: None
fake_freecadgui.Selection = types.SimpleNamespace(getSelectionEx=lambda: [])
sys.modules["FreeCADGui"] = fake_freecadgui
def _install_fake_freecad_without_gui_commands():
_install_fake_freecad()
sys.modules["FreeCADGui"] = types.ModuleType("FreeCADGui")
class FakeViewObject:
def __init__(self):
self.Visibility = True
self.ShapeColor = None
class FakeObject:
def __init__(self, name, type_id):
self.Name = name
self.Label = name
self.TypeId = type_id
self.PropertiesList = []
self.Group = []
self.ViewObject = FakeViewObject()
self.Placement = None
def isDerivedFrom(self, type_name):
if self.TypeId == type_name:
return True
if type_name == "App::DocumentObjectGroup":
return self.TypeId == "App::DocumentObjectGroup"
if type_name == "App::LocalCoordinateSystem":
return self.TypeId in {
"Part::LocalCoordinateSystem",
"PartDesign::CoordinateSystem",
}
return False
def addProperty(self, prop_type, prop_name, group_name, description):
if prop_name not in self.PropertiesList:
self.PropertiesList.append(prop_name)
def addObject(self, child):
if child not in self.Group:
self.Group.append(child)
class FakeVertex:
def __init__(self, point):
self.Point = point
class FakeEdge:
ShapeType = "Edge"
def __init__(self, start, end):
self.Vertexes = [FakeVertex(start), FakeVertex(end)]
class FakeShape:
def __init__(self, edges=None):
self.Edges = edges or []
class FakeSelectionItem:
def __init__(self, obj=None, sub_objects=None, picked_points=None):
self.Object = obj
self.SubObjects = sub_objects or []
self.PickedPoints = picked_points or []
class FakeDocument:
def __init__(self):
self.Name = "TemplateDoc"
self.Objects = []
self.recomputed = False
self.saved_path = ""
def addObject(self, type_name, name):
obj = FakeObject(name, type_name)
self.Objects.append(obj)
return obj
def getObject(self, name):
for obj in self.Objects:
if obj.Name == name:
return obj
return None
def recompute(self):
self.recomputed = True
def saveAs(self, path):
self.saved_path = path
def _reload_modules():
for name in ["TerminalObjects", "TemplateAuthoring"]:
sys.modules.pop(name, None)
return importlib.import_module("TemplateAuthoring")
class TemplateAuthoringTest(unittest.TestCase):
def test_template_authoring_command_titles_are_chinese(self):
_install_fake_freecad()
template_authoring = _reload_modules()
self.assertEqual(
"添加模板端子",
template_authoring.CommandAddTemplateTerminal().GetResources()["MenuText"],
)
self.assertEqual(
"校验模板端子",
template_authoring.CommandValidateTemplateTerminals().GetResources()["MenuText"],
)
self.assertEqual(
"设置端子局部路径",
template_authoring.CommandSetTemplateTerminalLocalRoute().GetResources()["MenuText"],
)
self.assertEqual(
"保存模板为 FCStd",
template_authoring.CommandSaveTemplateAsFCStd().GetResources()["MenuText"],
)
def test_import_skips_command_registration_when_gui_has_no_add_command(self):
_install_fake_freecad_without_gui_commands()
template_authoring = _reload_modules()
self.assertTrue(hasattr(template_authoring, "save_template_as_fcstd"))
def test_create_template_terminal_writes_lcs_semantics(self):
_install_fake_freecad()
template_authoring = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
terminal = template_authoring.create_template_terminal(
doc,
"P1",
app.Vector(10, 20, 30),
terminal_type="primary",
)
self.assertEqual("Terminal_P1", terminal.Name)
self.assertEqual("P1", terminal.Label)
self.assertEqual("Terminal", terminal.Role)
self.assertTrue(terminal.CanWire)
self.assertEqual("P1", terminal.QetTemplateSlotName)
self.assertEqual("P1", terminal.QetTerminalLabel)
self.assertEqual("primary", terminal.QetTerminalType)
self.assertEqual(10.0, terminal.Placement.Base.x)
self.assertEqual(20.0, terminal.Placement.Base.y)
self.assertEqual(30.0, terminal.Placement.Base.z)
self.assertTrue(doc.recomputed)
def test_set_template_terminal_local_route_points_writes_json_property(self):
_install_fake_freecad()
template_authoring = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
terminal = template_authoring.create_template_terminal(doc, "P1", app.Vector(1, 2, 3))
template_authoring.set_template_terminal_local_route_points(
terminal,
[
app.Vector(0, 0, 0),
[8, 0, 0],
{"x": 8, "y": 20, "z": 0},
],
)
self.assertIn("QetTerminalLocalRoutePointsJson", terminal.PropertiesList)
self.assertEqual(
[[0.0, 0.0, 0.0], [8.0, 0.0, 0.0], [8.0, 20.0, 0.0]],
json.loads(terminal.QetTerminalLocalRoutePointsJson),
)
def test_set_selected_template_terminal_local_route_points_uses_terminal_local_coordinates(self):
_install_fake_freecad()
template_authoring = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
terminal = template_authoring.create_template_terminal(doc, "P1", app.Vector(10, 0, 0))
path = doc.addObject("Part::Feature", "LocalExitPath")
path.Shape = FakeShape(
edges=[
FakeEdge(app.Vector(10, 0, 0), app.Vector(20, 0, 0)),
FakeEdge(app.Vector(20, 0, 0), app.Vector(20, 15, 0)),
]
)
template_authoring.set_selected_template_terminal_local_route_points(
[
FakeSelectionItem(obj=terminal),
FakeSelectionItem(obj=path),
]
)
self.assertEqual(
[[0.0, 0.0, 0.0], [10.0, 0.0, 0.0], [10.0, 15.0, 0.0]],
json.loads(terminal.QetTerminalLocalRoutePointsJson),
)
def test_validate_template_terminals_reports_missing_slot_name(self):
_install_fake_freecad()
template_authoring = _reload_modules()
doc = FakeDocument()
terminal = doc.addObject("Part::LocalCoordinateSystem", "BrokenTerminal")
terminal.addProperty("App::PropertyString", "Role", "QET Template", "role")
terminal.Role = "Terminal"
terminal.addProperty(
"App::PropertyBool",
"CanWire",
"QET Template",
"can wire",
)
terminal.CanWire = True
report = template_authoring.validate_template_terminals(doc)
self.assertEqual(1, report["total_terminals"])
self.assertEqual(0, report["valid_terminals"])
self.assertEqual(1, len(report["warnings"]))
self.assertIn("QetTemplateSlotName", report["warnings"][0])
def test_save_template_as_fcstd_adds_extension_and_saves_valid_template(self):
_install_fake_freecad()
template_authoring = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
template_authoring.create_template_terminal(doc, "P1", app.Vector(1, 2, 3))
report = template_authoring.save_template_as_fcstd(doc, "D:/tmp/current-transformer")
self.assertEqual("D:/tmp/current-transformer.FCStd", doc.saved_path)
self.assertEqual("D:/tmp/current-transformer.FCStd", report["path"])
self.assertEqual(1, report["valid_terminals"])
if __name__ == "__main__":
unittest.main()