244 lines
7.7 KiB
Python
244 lines
7.7 KiB
Python
"""
|
|
Tests for String Index Selector Node
|
|
|
|
Run with: python test_string_index_selector.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_index_selector import StringIndexSelector
|
|
|
|
|
|
def test_basic_selection():
|
|
"""Test basic item selection"""
|
|
node = StringIndexSelector()
|
|
|
|
# Test selecting from comma-separated list
|
|
result, count = node.select_by_index("a,b,c,d", ",", 0)
|
|
assert result == "a", f"Expected 'a', got '{result}'"
|
|
assert count == 4, f"Expected count 4, got {count}"
|
|
|
|
result, count = node.select_by_index("a,b,c,d", ",", 2)
|
|
assert result == "c", f"Expected 'c', got '{result}'"
|
|
|
|
print("✓ test_basic_selection passed")
|
|
|
|
|
|
def test_frame_numbers():
|
|
"""Test your actual use case - frame numbers"""
|
|
node = StringIndexSelector()
|
|
|
|
frames = "10,25,42,100"
|
|
|
|
# Loop iteration 0 → frame 10
|
|
result, count = node.select_by_index(frames, ",", 0)
|
|
assert result == "10", f"Expected '10', got '{result}'"
|
|
assert count == 4, f"Expected 4 frames, got {count}"
|
|
|
|
# Loop iteration 2 → frame 42
|
|
result, count = node.select_by_index(frames, ",", 2)
|
|
assert result == "42", f"Expected '42', got '{result}'"
|
|
|
|
# Loop iteration 3 → frame 100
|
|
result, count = node.select_by_index(frames, ",", 3)
|
|
assert result == "100", f"Expected '100', got '{result}'"
|
|
|
|
print("✓ test_frame_numbers passed")
|
|
|
|
|
|
def test_whitespace_handling():
|
|
"""Test whitespace stripping"""
|
|
node = StringIndexSelector()
|
|
|
|
# With whitespace, strip enabled (default)
|
|
result, _ = node.select_by_index(" a , b , c ", ",", 1, strip_whitespace=True)
|
|
assert result == "b", f"Expected 'b', got '{result}'"
|
|
|
|
# With whitespace, strip disabled
|
|
result, _ = node.select_by_index(" a , b , c ", ",", 1, strip_whitespace=False)
|
|
assert result == " b ", f"Expected ' b ', got '{result}'"
|
|
|
|
print("✓ test_whitespace_handling passed")
|
|
|
|
|
|
def test_different_delimiters():
|
|
"""Test various delimiter types"""
|
|
node = StringIndexSelector()
|
|
|
|
# Pipe delimiter
|
|
result, _ = node.select_by_index("a|b|c", "|", 1)
|
|
assert result == "b", f"Expected 'b', got '{result}'"
|
|
|
|
# Tab delimiter
|
|
result, _ = node.select_by_index("a\tb\tc", "\t", 2)
|
|
assert result == "c", f"Expected 'c', got '{result}'"
|
|
|
|
# Multi-character delimiter
|
|
result, _ = node.select_by_index("a::b::c", "::", 0)
|
|
assert result == "a", f"Expected 'a', got '{result}'"
|
|
|
|
print("✓ test_different_delimiters passed")
|
|
|
|
|
|
def test_indexing_modes():
|
|
"""Test zero-indexed vs one-indexed"""
|
|
node = StringIndexSelector()
|
|
|
|
# Zero-indexed (0 = first item)
|
|
result, _ = node.select_by_index("a,b,c", ",", 0, zero_indexed=True)
|
|
assert result == "a", f"Expected 'a' with 0-indexing, got '{result}'"
|
|
|
|
# One-indexed (1 = first item)
|
|
result, _ = node.select_by_index("a,b,c", ",", 1, zero_indexed=False)
|
|
assert result == "a", f"Expected 'a' with 1-indexing, got '{result}'"
|
|
|
|
result, _ = node.select_by_index("a,b,c", ",", 2, zero_indexed=False)
|
|
assert result == "b", f"Expected 'b' with 1-indexing, got '{result}'"
|
|
|
|
print("✓ test_indexing_modes passed")
|
|
|
|
|
|
def test_out_of_range():
|
|
"""Test handling of invalid indices"""
|
|
node = StringIndexSelector()
|
|
|
|
# Index too high
|
|
result, count = node.select_by_index("a,b,c", ",", 10)
|
|
assert result == "", f"Expected empty string for out of range, got '{result}'"
|
|
assert count == 3, f"Should still return correct count"
|
|
|
|
# Negative index (if zero_indexed=True, shouldn't happen, but test anyway)
|
|
result, count = node.select_by_index("a,b,c", ",", -1)
|
|
assert result == "", f"Expected empty string for negative index, got '{result}'"
|
|
|
|
print("✓ test_out_of_range passed")
|
|
|
|
|
|
def test_edge_cases():
|
|
"""Test edge cases"""
|
|
node = StringIndexSelector()
|
|
|
|
# Empty string
|
|
result, count = node.select_by_index("", ",", 0)
|
|
assert result == None, f"Expected empty for empty string"
|
|
assert count == 0, f"Empty string splits to zero empty items"
|
|
|
|
# Single item
|
|
result, count = node.select_by_index("only", ",", 0)
|
|
assert result == "only", f"Expected 'only', got '{result}'"
|
|
assert count == 1
|
|
|
|
# No delimiters found
|
|
result, count = node.select_by_index("no-commas-here", ",", 0)
|
|
assert result == "no-commas-here", f"Expected full string, got '{result}'"
|
|
assert count == 1
|
|
|
|
print("✓ test_edge_cases passed")
|
|
|
|
|
|
def test_return_types():
|
|
"""Validate return types match RETURN_TYPES"""
|
|
node = StringIndexSelector()
|
|
|
|
result = node.select_by_index("a,b,c", ",", 0)
|
|
|
|
# Should return tuple
|
|
assert isinstance(result, tuple), f"Should return tuple, got {type(result)}"
|
|
assert len(result) == 2, f"Should return 2 items, got {len(result)}"
|
|
|
|
# First item should be string
|
|
assert isinstance(result[0], str), f"First return should be string, got {type(result[0])}"
|
|
|
|
# Second item should be int
|
|
assert isinstance(result[1], int), f"Second return should be int, got {type(result[1])}"
|
|
|
|
print("✓ test_return_types passed")
|
|
|
|
|
|
def test_input_types_structure():
|
|
"""Validate INPUT_TYPES matches function signature"""
|
|
input_types = StringIndexSelector.INPUT_TYPES()
|
|
|
|
# Collect all inputs
|
|
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())
|
|
|
|
# Get function parameters
|
|
function = getattr(StringIndexSelector(), StringIndexSelector.FUNCTION)
|
|
sig = inspect.signature(function)
|
|
function_params = set(sig.parameters.keys()) - {'self'}
|
|
|
|
# Check they match
|
|
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")
|
|
|
|
def test_output_type_handling():
|
|
"""Validate casting works vor various configured output_types"""
|
|
node = StringIndexSelector()
|
|
|
|
# default as string
|
|
result, count = node.select_by_index("1,2,3", ",", 1)
|
|
assert isinstance(result, str), f"Expected string, got '{type(result)}'"
|
|
|
|
# casting to integer
|
|
result, count = node.select_by_index("1,2,3", ",", 1, output_type='INT')
|
|
assert isinstance(result, int), f"Expected integer, got '{type(result)}'"
|
|
|
|
# casting to integer
|
|
result, count = node.select_by_index("1,2,3", ",", 1, output_type='FLOAT')
|
|
assert isinstance(result, float), f"Expected float 2, got '{type(result)}'"
|
|
|
|
print("✓ test_output_type_handling passed")
|
|
|
|
|
|
def run_all_tests():
|
|
"""Run all test functions"""
|
|
print("Running tests for StringIndexSelector...\n")
|
|
|
|
try:
|
|
test_basic_selection()
|
|
test_frame_numbers()
|
|
test_whitespace_handling()
|
|
test_different_delimiters()
|
|
test_indexing_modes()
|
|
test_out_of_range()
|
|
test_edge_cases()
|
|
test_return_types()
|
|
test_input_types_structure()
|
|
|
|
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)
|