180 lines
6.1 KiB
Python
180 lines
6.1 KiB
Python
import unittest
|
|
from unittest.mock import MagicMock
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.append(str(PROJECT_ROOT.parent))
|
|
|
|
class DummyBase:
|
|
def _get_data_dict(self):
|
|
if not hasattr(self, "_data") or self._data is None:
|
|
self._data = {}
|
|
return self._data
|
|
|
|
def __getitem__(self, key):
|
|
return self._get_data_dict()[key]
|
|
|
|
def __setitem__(self, key, value):
|
|
self._get_data_dict()[key] = value
|
|
|
|
def __contains__(self, key):
|
|
return key in self._get_data_dict()
|
|
|
|
def get(self, key, default=None):
|
|
return self._get_data_dict().get(key, default)
|
|
|
|
class DummyObject:
|
|
def __init__(self, name="TestObj", obj_type='MESH'):
|
|
self.name = name
|
|
self.type = obj_type
|
|
|
|
mock_types = MagicMock()
|
|
mock_types.NodeSocket = type("NodeSocket", (DummyBase,), {})
|
|
mock_types.Node = DummyBase
|
|
mock_types.NodeCustomGroup = type("NodeCustomGroup", (DummyBase,), {})
|
|
mock_types.NodeTree = type("NodeTree", (DummyBase,), {})
|
|
mock_types.PropertyGroup = type("PropertyGroup", (DummyBase,), {})
|
|
mock_types.Operator = type("Operator", (DummyBase,), {})
|
|
mock_types.Panel = type("Panel", (DummyBase,), {})
|
|
mock_types.Menu = type("Menu", (DummyBase,), {})
|
|
mock_types.Object = DummyObject
|
|
mock_types.Collection = type("Collection", (DummyBase,), {})
|
|
|
|
if 'bpy' not in sys.modules:
|
|
mock_bpy = MagicMock()
|
|
mock_bpy.types = mock_types
|
|
sys.modules['bpy'] = mock_bpy
|
|
sys.modules['bpy.types'] = mock_types
|
|
sys.modules['bpy.props'] = MagicMock()
|
|
sys.modules['bpy.utils'] = MagicMock()
|
|
sys.modules['bpy.utils.previews'] = MagicMock()
|
|
sys.modules['bpy.app'] = MagicMock()
|
|
sys.modules['bpy.app.handlers'] = MagicMock()
|
|
|
|
import bpy
|
|
|
|
class TestNodeSocket:
|
|
def __init__(self, name="", identifier="", node=None):
|
|
self.name = name
|
|
self.identifier = identifier or name
|
|
self.is_linked = False
|
|
self.links = []
|
|
self.node = node
|
|
|
|
def __repr__(self):
|
|
return f"<TestNodeSocket name={self.name!r} identifier={self.identifier!r}>"
|
|
|
|
class TestSocketCollection(list):
|
|
def __init__(self, node=None):
|
|
super().__init__()
|
|
self.node = node
|
|
|
|
def new(self, type_name, name, identifier=""):
|
|
sock = TestNodeSocket(name, identifier or name, node=self.node)
|
|
self.append(sock)
|
|
return sock
|
|
|
|
def remove(self, sock):
|
|
if sock in self:
|
|
super().remove(sock)
|
|
|
|
def get(self, name, default=None):
|
|
for item in self:
|
|
if item.name == name or item.identifier == name:
|
|
return item
|
|
return default
|
|
|
|
def find(self, name):
|
|
for i, item in enumerate(self):
|
|
if item.name == name or item.identifier == name:
|
|
return i
|
|
return -1
|
|
|
|
def __contains__(self, item):
|
|
if isinstance(item, str):
|
|
return any(sock.name == item or sock.identifier == item for sock in self)
|
|
return super().__contains__(item)
|
|
|
|
def move(self, from_idx, to_idx):
|
|
item = self.pop(from_idx)
|
|
self.insert(to_idx, item)
|
|
|
|
class DummyCollection:
|
|
def __init__(self, name="TestCollection", objects=None):
|
|
self.name = name
|
|
self.objects = objects or []
|
|
|
|
from NodeSlicer.core.nodeslicer.nodes.inputs import SLICENODE_CollectionObjects
|
|
|
|
class TestCollectionObjectsSorting(unittest.TestCase):
|
|
def setUp(self):
|
|
self.node = SLICENODE_CollectionObjects()
|
|
self.node.inputs = TestSocketCollection(self.node)
|
|
self.node.outputs = TestSocketCollection(self.node)
|
|
|
|
def test_outputs_sorted_alphabetically(self):
|
|
# Create collection with objects in non-alphabetical order
|
|
obj_z = DummyObject("Zebra", 'MESH')
|
|
obj_a = DummyObject("Apple", 'MESH')
|
|
obj_m = DummyObject("Mango", 'MESH')
|
|
obj_camera = DummyObject("Camera", 'CAMERA') # Should be ignored
|
|
|
|
collection = DummyCollection("Fruits", [obj_z, obj_a, obj_camera, obj_m])
|
|
self.node.collection = collection
|
|
|
|
self.node._update_outputs()
|
|
|
|
output_names = [o.name for o in self.node.outputs]
|
|
self.assertEqual(output_names, ["Apple", "Mango", "Zebra"])
|
|
|
|
def test_dynamic_add_and_reorder(self):
|
|
# Initial collection with B and D
|
|
obj_b = DummyObject("Banana", 'MESH')
|
|
obj_d = DummyObject("Date", 'MESH')
|
|
collection = DummyCollection("Fruits", [obj_b, obj_d])
|
|
self.node.collection = collection
|
|
|
|
self.node._update_outputs()
|
|
self.assertEqual([o.name for o in self.node.outputs], ["Banana", "Date"])
|
|
|
|
# Add Apple (which should be placed at the beginning) and Cherry (between Banana and Date)
|
|
obj_a = DummyObject("Apple", 'MESH')
|
|
obj_c = DummyObject("Cherry", 'MESH')
|
|
collection.objects.extend([obj_a, obj_c])
|
|
|
|
self.node._update_outputs()
|
|
self.assertEqual([o.name for o in self.node.outputs], ["Apple", "Banana", "Cherry", "Date"])
|
|
|
|
def test_remove_object(self):
|
|
obj_a = DummyObject("Apple", 'MESH')
|
|
obj_b = DummyObject("Banana", 'MESH')
|
|
obj_c = DummyObject("Cherry", 'MESH')
|
|
collection = DummyCollection("Fruits", [obj_a, obj_b, obj_c])
|
|
self.node.collection = collection
|
|
|
|
self.node._update_outputs()
|
|
self.assertEqual([o.name for o in self.node.outputs], ["Apple", "Banana", "Cherry"])
|
|
|
|
# Remove Banana
|
|
collection.objects = [obj_a, obj_c]
|
|
self.node._update_outputs()
|
|
self.assertEqual([o.name for o in self.node.outputs], ["Apple", "Cherry"])
|
|
|
|
def test_evaluate_output(self):
|
|
obj_a = DummyObject("Apple", 'MESH')
|
|
bpy.data.objects = {"Apple": obj_a}
|
|
from NodeSlicer.core.nodeslicer.nodes import inputs as inp_module
|
|
inp_module.bpy.data.objects = {"Apple": obj_a}
|
|
collection = DummyCollection("Fruits", [obj_a])
|
|
self.node.collection = collection
|
|
self.node._update_outputs()
|
|
|
|
result = self.node.evaluate_output("Apple")
|
|
self.assertEqual(result, obj_a)
|
|
|
|
result_nonexistent = self.node.evaluate_output("NonExistent")
|
|
self.assertIsNone(result_nonexistent)
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|