173 lines
7 KiB
Python
173 lines
7 KiB
Python
from __future__ import annotations
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.append(str(PROJECT_ROOT.parent))
|
|
|
|
# Ensure mock bpy is set up
|
|
from tests.test_lists import mock_bpy
|
|
|
|
from NodeSlicer.core.nodeslicer.sockets import SLICESOCK_DirPath, SLICESOCK_FilePath, InputNodeSocket
|
|
from NodeSlicer.infra.blender.blender_slice_nodes_generic import SliceNode, resolve_input
|
|
from NodeSlicer.core.nodeslicer.nodes.output.gcode_to_file import SLICENODE_GcodeToFile
|
|
from NodeSlicer.core.nodeslicer.nodes.output.mesh_to_pdf import SLICENODE_MeshToPdf
|
|
from NodeSlicer.infra.blender.list_utils import LIST_CAPABLE_SOCKET_TYPES
|
|
|
|
|
|
class TestPathSockets(unittest.TestCase):
|
|
def test_socket_definitions(self):
|
|
"""Test that SLICESOCK_DirPath and SLICESOCK_FilePath are properly defined subclasses."""
|
|
self.assertTrue(issubclass(SLICESOCK_DirPath, InputNodeSocket))
|
|
self.assertTrue(issubclass(SLICESOCK_FilePath, InputNodeSocket))
|
|
|
|
dir_sock = SLICESOCK_DirPath()
|
|
file_sock = SLICESOCK_FilePath()
|
|
|
|
self.assertEqual(dir_sock.default, "")
|
|
self.assertEqual(file_sock.default, "")
|
|
self.assertEqual(dir_sock.value, "")
|
|
self.assertEqual(file_sock.value, "")
|
|
|
|
dir_sock.value = "/custom/directory/path"
|
|
file_sock.value = "/custom/file/path.gcode"
|
|
self.assertEqual(dir_sock.value, "/custom/directory/path")
|
|
self.assertEqual(file_sock.value, "/custom/file/path.gcode")
|
|
|
|
def test_list_capable_socket_types(self):
|
|
"""Ensure path sockets are recognized as valid socket types in list utilities."""
|
|
self.assertIn("SLICESOCK_DirPath", LIST_CAPABLE_SOCKET_TYPES)
|
|
self.assertIn("SLICESOCK_FilePath", LIST_CAPABLE_SOCKET_TYPES)
|
|
|
|
def test_add_input_subtype_mapping(self):
|
|
"""Test that add_input maps subtype='DIR_PATH' and subtype='FILE_PATH' to the appropriate socket."""
|
|
class DummyNode(SliceNode):
|
|
def __init__(self):
|
|
self.inputs = MagicMock()
|
|
self.outputs = MagicMock()
|
|
|
|
node = DummyNode()
|
|
node.add_input("NodeSocketString", "Folder", subtype="DIR_PATH")
|
|
node.inputs.new.assert_called_with("SLICESOCK_DirPath", "Folder", identifier="Folder")
|
|
|
|
node.add_input("NodeSocketString", "File", subtype="FILE_PATH")
|
|
node.inputs.new.assert_called_with("SLICESOCK_FilePath", "File", identifier="File")
|
|
|
|
# Case-insensitive and alias tests
|
|
node.add_input("NodeSocketString", "Dir", subtype="folder")
|
|
node.inputs.new.assert_called_with("SLICESOCK_DirPath", "Dir", identifier="Dir")
|
|
|
|
node.add_input("NodeSocketString", "Doc", subtype="file")
|
|
node.inputs.new.assert_called_with("SLICESOCK_FilePath", "Doc", identifier="Doc")
|
|
|
|
# Standard string without subtype remains NodeSocketString
|
|
node.add_input("NodeSocketString", "Name")
|
|
node.inputs.new.assert_called_with("NodeSocketString", "Name", identifier="Name")
|
|
|
|
# Direct socket type specification
|
|
node.add_input("SLICESOCK_DirPath", "TargetDir")
|
|
node.inputs.new.assert_called_with("SLICESOCK_DirPath", "TargetDir", identifier="TargetDir")
|
|
|
|
def test_add_output_subtype_mapping(self):
|
|
"""Test that add_output also supports subtype mapping."""
|
|
class DummyNode(SliceNode):
|
|
def __init__(self):
|
|
self.inputs = MagicMock()
|
|
self.outputs = MagicMock()
|
|
|
|
node = DummyNode()
|
|
node.add_output("NodeSocketString", "OutFolder", subtype="DIR_PATH")
|
|
node.outputs.new.assert_called_with("SLICESOCK_DirPath", "OutFolder", identifier="OutFolder")
|
|
|
|
node.add_output("NodeSocketString", "OutFile", subtype="FILE_PATH")
|
|
node.outputs.new.assert_called_with("SLICESOCK_FilePath", "OutFile", identifier="OutFile")
|
|
|
|
def test_nodes_use_dir_path_socket(self):
|
|
"""Verify that GcodeToFile and MeshToPdf configure the Folder socket with DIR_PATH subtype."""
|
|
class MockSocketCollection:
|
|
def __init__(self):
|
|
self.created = []
|
|
|
|
def new(self, bl_idname, name, identifier=""):
|
|
mock_sock = MagicMock()
|
|
mock_sock.bl_idname = bl_idname
|
|
mock_sock.name = name
|
|
mock_sock.identifier = identifier or name
|
|
self.created.append((bl_idname, name, identifier, mock_sock))
|
|
return mock_sock
|
|
|
|
def __iter__(self):
|
|
return iter([item[3] for item in self.created])
|
|
|
|
def get(self, name):
|
|
for bl_id, n, ident, s in self.created:
|
|
if n == name:
|
|
return s
|
|
return None
|
|
|
|
class InspectGcodeToFile(SLICENODE_GcodeToFile):
|
|
def __init__(self):
|
|
self.inputs = MockSocketCollection()
|
|
self.outputs = MockSocketCollection()
|
|
self._data = {}
|
|
|
|
class InspectMeshToPdf(SLICENODE_MeshToPdf):
|
|
def __init__(self):
|
|
self.inputs = MockSocketCollection()
|
|
self.outputs = MockSocketCollection()
|
|
self._data = {}
|
|
|
|
gcode_node = InspectGcodeToFile()
|
|
gcode_node.init(None)
|
|
folder_in_gcode = next((bl_id for bl_id, name, _, _ in gcode_node.inputs.created if name == "Folder"), None)
|
|
self.assertEqual(folder_in_gcode, "SLICESOCK_DirPath")
|
|
|
|
pdf_node = InspectMeshToPdf()
|
|
pdf_node.init(None)
|
|
folder_in_pdf = next((bl_id for bl_id, name, _, _ in pdf_node.inputs.created if name == "Folder"), None)
|
|
self.assertEqual(folder_in_pdf, "SLICESOCK_DirPath")
|
|
|
|
def test_resolve_input_with_path_socket(self):
|
|
"""Verify resolve_input behavior for unlinked and linked path sockets."""
|
|
class DummySocket:
|
|
def __init__(self, name, bl_idname, value=""):
|
|
self.name = name
|
|
self.bl_idname = bl_idname
|
|
self.identifier = name
|
|
self.value = value
|
|
self.default = ""
|
|
self.is_linked = False
|
|
self.links = []
|
|
self.node = MagicMock()
|
|
|
|
sock = DummySocket("Folder", "SLICESOCK_DirPath", value="")
|
|
# Empty value returns default empty string
|
|
self.assertEqual(resolve_input(sock), "")
|
|
|
|
# Set value
|
|
sock.value = "/path/to/folder"
|
|
self.assertEqual(resolve_input(sock), "/path/to/folder")
|
|
|
|
# Linked socket follows upstream
|
|
class UpstreamNode(SliceNode):
|
|
def evaluate_output(self, socket_name, **kwargs):
|
|
return "/upstream/linked/path"
|
|
|
|
upstream = UpstreamNode()
|
|
from_socket = MagicMock()
|
|
from_socket.node = upstream
|
|
from_socket.name = "String Out"
|
|
from_socket.identifier = "String Out"
|
|
mock_link = MagicMock()
|
|
mock_link.from_socket = from_socket
|
|
|
|
sock.is_linked = True
|
|
sock.links = [mock_link]
|
|
|
|
self.assertEqual(resolve_input(sock), "/upstream/linked/path")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|