320 lines
10 KiB
Python
320 lines
10 KiB
Python
"""
|
|
Tests for String Splitter Node
|
|
|
|
Run with: python test_string_splitter.py
|
|
"""
|
|
|
|
import inspect
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add parent directory to path to import node modules
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
from string_splitter import StringSplitter
|
|
|
|
|
|
|
|
def test_basic_split():
|
|
"""Test basic string splitting"""
|
|
node = StringSplitter()
|
|
|
|
result, count = node.split_string("a,b,c", ",")
|
|
# With OUTPUT_IS_LIST, the function still returns a regular list
|
|
# ComfyUI handles the list wrapping/unwrapping
|
|
assert isinstance(result, list), f"Should return list, got {type(result)}"
|
|
assert result == ["a", "b", "c"], f"Expected ['a', 'b', 'c'], got {result}"
|
|
assert count == 3, f"Expected count 3, got {count}"
|
|
|
|
print("✓ test_basic_split passed")
|
|
|
|
|
|
def test_frame_numbers():
|
|
"""Test splitting frame numbers (your use case)"""
|
|
node = StringSplitter()
|
|
|
|
result, count = node.split_string("10,25,42,100", ",")
|
|
assert result == ["10", "25", "42", "100"], f"Expected frame list, got {result}"
|
|
assert count == 4, f"Expected 4 frames, got {count}"
|
|
|
|
print("✓ test_frame_numbers passed")
|
|
|
|
|
|
def test_whitespace_handling():
|
|
"""Test whitespace stripping"""
|
|
node = StringSplitter()
|
|
|
|
# With strip (default)
|
|
result, _ = node.split_string(" a , b , c ", ",", strip_whitespace=True)
|
|
assert result == ["a", "b", "c"], f"Expected stripped, got {result}"
|
|
|
|
# Without strip
|
|
result, _ = node.split_string(" a , b , c ", ",", strip_whitespace=False)
|
|
assert result == [" a ", " b ", " c "], f"Expected unstripped, got {result}"
|
|
|
|
print("✓ test_whitespace_handling passed")
|
|
|
|
|
|
def test_different_delimiters():
|
|
"""Test various delimiters"""
|
|
node = StringSplitter()
|
|
|
|
# Pipe
|
|
result, _ = node.split_string("a|b|c", "|")
|
|
assert result == ["a", "b", "c"], f"Pipe delimiter failed"
|
|
|
|
# Newline
|
|
result, _ = node.split_string("a\nb\nc", "\n")
|
|
assert result == ["a", "b", "c"], f"Newline delimiter failed"
|
|
|
|
# Multi-character
|
|
result, _ = node.split_string("a::b::c", "::")
|
|
assert result == ["a", "b", "c"], f"Multi-char delimiter failed"
|
|
|
|
print("✓ test_different_delimiters passed")
|
|
|
|
|
|
def test_remove_empty():
|
|
"""Test removing empty strings"""
|
|
node = StringSplitter()
|
|
|
|
# With empty strings, keep them
|
|
result, count = node.split_string("a,,c", ",", remove_empty=False)
|
|
assert result == ["a", "", "c"], f"Expected empty string, got {result}"
|
|
assert count == 3
|
|
|
|
# Remove empty strings
|
|
result, count = node.split_string("a,,c", ",", remove_empty=True)
|
|
assert result == ["a", "c"], f"Expected no empty strings, got {result}"
|
|
assert count == 2
|
|
|
|
# Multiple consecutive delimiters
|
|
result, count = node.split_string("a,,,b", ",", remove_empty=True)
|
|
assert result == ["a", "b"], f"Expected ['a', 'b'], got {result}"
|
|
assert count == 2
|
|
|
|
print("✓ test_remove_empty passed")
|
|
|
|
|
|
def test_edge_cases():
|
|
"""Test edge cases"""
|
|
node = StringSplitter()
|
|
|
|
# Empty string
|
|
result, count = node.split_string("", ",")
|
|
assert result == [], f"Empty string should split to list with one empty string, saw {result}"
|
|
assert count == 0, f"Empty string should have a count of zero, saw {result}"
|
|
|
|
# Empty string with remove_empty
|
|
result, count = node.split_string("", ",", remove_empty=True)
|
|
assert result == [], f"Empty string with remove_empty should be empty list, saw {result}"
|
|
assert count == 0, f"Empty string should have a count of zero, saw {result}"
|
|
|
|
# Single item
|
|
result, count = node.split_string("only", ",")
|
|
assert result == ["only"], f"Single item failed"
|
|
assert count == 1, f"Single item string should have a count of one, saw {result}"
|
|
|
|
# No delimiters
|
|
result, count = node.split_string("no-delimiters", ",")
|
|
assert result == ["no-delimiters"], f"No delimiters should return single item"
|
|
assert count == 1, f"List with no delimiters count of one, saw {result}"
|
|
|
|
print("✓ test_edge_cases passed")
|
|
|
|
|
|
def test_return_types():
|
|
"""Validate return types"""
|
|
node = StringSplitter()
|
|
|
|
result = node.split_string("a,b,c", ",")
|
|
|
|
assert isinstance(result, tuple), f"Should return tuple"
|
|
assert len(result) == 2, f"Should return 2 items"
|
|
assert isinstance(result[0], list), f"First item should be list"
|
|
assert isinstance(result[1], int), f"Second item should be int"
|
|
|
|
print("✓ test_return_types passed")
|
|
|
|
|
|
def test_input_types_structure():
|
|
"""Validate INPUT_TYPES matches function signature"""
|
|
input_types = StringSplitter.INPUT_TYPES()
|
|
|
|
all_inputs = set()
|
|
if "required" in input_types:
|
|
all_inputs.update(input_types["required"].keys())
|
|
if "optional" in input_types:
|
|
all_inputs.update(input_types["optional"].keys())
|
|
|
|
function = getattr(StringSplitter(), StringSplitter.FUNCTION)
|
|
sig = inspect.signature(function)
|
|
function_params = set(sig.parameters.keys()) - {'self'}
|
|
|
|
missing = function_params - all_inputs
|
|
extra = all_inputs - function_params
|
|
|
|
assert not missing, f"Function has params not in INPUT_TYPES: {missing}"
|
|
assert not extra, f"INPUT_TYPES has entries not in function: {extra}"
|
|
|
|
print("✓ test_input_types_structure passed")
|
|
|
|
"""
|
|
Additional tests for String Splitter type casting
|
|
|
|
Add these to your existing test_string_splitter.py
|
|
"""
|
|
|
|
def test_int_casting():
|
|
"""Test casting to integers"""
|
|
node = StringSplitter()
|
|
|
|
# Basic int casting
|
|
result, count = node.split_string("10,25,42,100", ",", output_type="INT")
|
|
assert result == [10, 25, 42, 100], f"Expected [10, 25, 42, 100], got {result}"
|
|
assert all(isinstance(x, int) for x in result), "All items should be integers"
|
|
|
|
# Negative numbers
|
|
result, _ = node.split_string("-5,0,5", ",", output_type="INT")
|
|
assert result == [-5, 0, 5], f"Expected [-5, 0, 5], got {result}"
|
|
|
|
print("✓ test_int_casting passed")
|
|
|
|
|
|
def test_float_casting():
|
|
"""Test casting to floats"""
|
|
node = StringSplitter()
|
|
|
|
# Basic float casting
|
|
result, count = node.split_string("1.5,2.0,3.14", ",", output_type="FLOAT")
|
|
assert result == [1.5, 2.0, 3.14], f"Expected [1.5, 2.0, 3.14], got {result}"
|
|
assert all(isinstance(x, float) for x in result), "All items should be floats"
|
|
|
|
# Integers can be cast to float
|
|
result, _ = node.split_string("10,20,30", ",", output_type="FLOAT")
|
|
assert result == [10.0, 20.0, 30.0], f"Expected [10.0, 20.0, 30.0], got {result}"
|
|
|
|
print("✓ test_float_casting passed")
|
|
|
|
|
|
def test_string_output_type():
|
|
"""Test explicit STRING output type"""
|
|
node = StringSplitter()
|
|
|
|
# Should remain strings even if they look like numbers
|
|
result, _ = node.split_string("10,20,30", ",", output_type="STRING")
|
|
assert result == ["10", "20", "30"], f"Expected ['10', '20', '30'], got {result}"
|
|
assert all(isinstance(x, str) for x in result), "All items should be strings"
|
|
|
|
print("✓ test_string_output_type passed")
|
|
|
|
|
|
def test_invalid_int_casting():
|
|
"""Test that invalid int casting raises proper error"""
|
|
node = StringSplitter()
|
|
|
|
try:
|
|
node.split_string("10,abc,30", ",", output_type="INT")
|
|
assert False, "Should have raised ValueError"
|
|
except ValueError as e:
|
|
assert "Failed to convert" in str(e), "Error message should be helpful"
|
|
|
|
print("✓ test_invalid_int_casting passed")
|
|
|
|
|
|
def test_invalid_float_casting():
|
|
"""Test that invalid float casting raises proper error"""
|
|
node = StringSplitter()
|
|
|
|
try:
|
|
node.split_string("1.5,not_a_number,3.14", ",", output_type="FLOAT")
|
|
assert False, "Should have raised ValueError"
|
|
except ValueError as e:
|
|
assert "Failed to convert" in str(e), "Error message should be helpful"
|
|
|
|
print("✓ test_invalid_float_casting passed")
|
|
|
|
|
|
def test_empty_string_with_casting():
|
|
"""Test empty string handling with type casting"""
|
|
node = StringSplitter()
|
|
|
|
# Empty strings should be removed before casting
|
|
result, count = node.split_string("10,,20", ",", output_type="INT", remove_empty=True)
|
|
assert result == [10, 20], f"Expected [10, 20], got {result}"
|
|
assert count == 2
|
|
|
|
# Without remove_empty, it should fail to cast empty string
|
|
try:
|
|
node.split_string("10,,20", ",", output_type="INT", remove_empty=False)
|
|
assert False, "Should fail to cast empty string to INT"
|
|
except ValueError:
|
|
pass # Expected
|
|
|
|
print("✓ test_empty_string_with_casting passed")
|
|
|
|
|
|
def test_whitespace_with_casting():
|
|
"""Test whitespace handling with numeric casting"""
|
|
node = StringSplitter()
|
|
|
|
# Whitespace should be stripped before casting
|
|
result, _ = node.split_string(" 10 , 20 , 30 ", ",", strip_whitespace=True, output_type="INT")
|
|
assert result == [10, 20, 30], f"Expected [10, 20, 30], got {result}"
|
|
|
|
print("✓ test_whitespace_with_casting passed")
|
|
|
|
def test_empty_string():
|
|
node = StringSplitter()
|
|
result, count = node.split_string("", ",")
|
|
assert result == [], "Empty string should return empty list"
|
|
assert count == 0
|
|
|
|
print("✓ test_empty_string passed")
|
|
|
|
def run_all_tests():
|
|
"""Run all test functions"""
|
|
print("Running tests for StringSplitter...\n")
|
|
|
|
try:
|
|
test_basic_split()
|
|
test_frame_numbers()
|
|
test_whitespace_handling()
|
|
test_different_delimiters()
|
|
test_remove_empty()
|
|
test_edge_cases()
|
|
test_return_types()
|
|
test_input_types_structure()
|
|
|
|
test_int_casting()
|
|
test_float_casting()
|
|
test_string_output_type()
|
|
test_invalid_int_casting()
|
|
test_invalid_float_casting()
|
|
test_empty_string_with_casting()
|
|
test_whitespace_with_casting()
|
|
|
|
test_empty_string()
|
|
|
|
print("\n" + "="*50)
|
|
print("✅ ALL TESTS PASSED!")
|
|
print("="*50)
|
|
return True
|
|
|
|
except AssertionError as e:
|
|
print("\n" + "="*50)
|
|
print(f"❌ TEST FAILED: {e}")
|
|
print("="*50)
|
|
return False
|
|
except Exception as e:
|
|
print("\n" + "="*50)
|
|
print(f"❌ UNEXPECTED ERROR: {e}")
|
|
print("="*50)
|
|
import traceback
|
|
traceback.print_exc()
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
success = run_all_tests()
|
|
exit(0 if success else 1)
|