Files
2026-02-01 16:42:23 -05:00

205 lines
7.6 KiB
Python

import pytest
import os
import tempfile
import torch
import numpy as np
from PIL import Image
from unittest.mock import patch, Mock
# Import the functions we're testing
import sys
try:
from nodes import sort_by, resize_with_aspect_ratio, get_edge_color
except ImportError:
# Fallback for when running tests directly
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
from nodes import sort_by, resize_with_aspect_ratio, get_edge_color
class TestSortBy:
"""Test cases for the sort_by function."""
def test_none_method_returns_original_order(self):
items = ['zebra', 'apple', 'banana']
result = sort_by(items, method='None')
assert result == ['zebra', 'apple', 'banana']
def test_alphabetical_asc(self):
items = ['zebra', 'apple', 'banana']
result = sort_by(items, method='Alphabetical (ASC)')
assert result == ['apple', 'banana', 'zebra']
def test_alphabetical_desc(self):
items = ['zebra', 'apple', 'banana']
result = sort_by(items, method='Alphabetical (DESC)')
assert result == ['zebra', 'banana', 'apple']
def test_sort_by_numerical_asc_mock_behavior(self):
# Test numerical sorting by mocking the extract_first_number behavior
with patch('nodes.extract_first_number') as mock_extract:
mock_extract.side_effect = [1, 2, 10]
items = ['file1.txt', 'file2.txt', 'file10.txt']
result = sort_by(items, method='Numerical (ASC)')
assert result == ['file1.txt', 'file2.txt', 'file10.txt']
assert mock_extract.call_count == len(items)
def test_sort_by_numerical_desc_mock_behavior(self):
# Test numerical sorting by mocking the extract_first_number behavior
with patch('nodes.extract_first_number') as mock_extract:
mock_extract.side_effect = [1, 2, 10]
items = ['file1.txt', 'file2.txt', 'file10.txt']
result = sort_by(items, method='Numerical (DESC)')
assert result == ['file10.txt', 'file2.txt', 'file1.txt']
assert mock_extract.call_count == len(items)
def test_datetime_sorting(self, temp_dir):
# Create test files with different timestamps
files = ['old.txt', 'new.txt']
for i, filename in enumerate(files):
filepath = os.path.join(temp_dir, filename)
with open(filepath, 'w') as f:
f.write('content')
# Set different modification times
timestamp = 1000000000 + i * 86400 # Different days
os.utime(filepath, (timestamp, timestamp))
result = sort_by(files, base_path=temp_dir, method='Datetime (ASC)')
assert result == ['old.txt', 'new.txt']
result = sort_by(files, base_path=temp_dir, method='Datetime (DESC)')
assert result == ['new.txt', 'old.txt']
def test_datetime_with_missing_file(self, temp_dir):
files = ['missing.txt', 'existing.txt']
# Create only one file
existing_path = os.path.join(temp_dir, 'existing.txt')
with open(existing_path, 'w') as f:
f.write('content')
# Should handle missing file gracefully
result = sort_by(files, base_path=temp_dir, method='Datetime (ASC)')
assert 'missing.txt' in result
assert 'existing.txt' in result
def test_unknown_method_returns_original(self):
items = ['zebra', 'apple', 'banana']
result = sort_by(items, method='Unknown Method')
assert result == ['zebra', 'apple', 'banana']
def test_empty_list(self):
result = sort_by([], method='Alphabetical (ASC)')
assert result == []
class TestResizeWithAspectRatio:
"""Test cases for resize_with_aspect_ratio function."""
@pytest.fixture
def sample_square_image(self):
return Image.new('RGB', (100, 100), color='red')
@pytest.fixture
def sample_wide_image(self):
return Image.new('RGB', (200, 100), color='blue')
@pytest.fixture
def sample_tall_image(self):
return Image.new('RGB', (100, 200), color='green')
def test_stretch_mode(self, sample_square_image):
result = resize_with_aspect_ratio(sample_square_image, 150, 75, 'stretch')
assert result.size == (150, 75)
def test_crop_mode_wide_image(self, sample_wide_image):
# Wide image cropped to square should crop width
result = resize_with_aspect_ratio(sample_wide_image, 100, 100, 'crop')
assert result.size == (100, 100)
def test_crop_mode_tall_image(self, sample_tall_image):
# Tall image cropped to square should crop height
result = resize_with_aspect_ratio(sample_tall_image, 100, 100, 'crop')
assert result.size == (100, 100)
def test_pad_mode_requires_edge_color(self, sample_wide_image):
with patch('nodes.get_edge_color', return_value=(255, 0, 0, 255)):
result = resize_with_aspect_ratio(sample_wide_image, 100, 200, 'pad')
assert result.size == (100, 200)
assert result.mode == 'RGBA'
def test_pad_mode_wide_image_to_tall(self, sample_wide_image):
with patch('nodes.get_edge_color', return_value=(255, 0, 0, 255)):
# Wide image (2:1) padded to tall (1:2) should pad width
result = resize_with_aspect_ratio(sample_wide_image, 50, 200, 'pad')
assert result.size == (50, 200)
def test_pad_mode_tall_image_to_wide(self, sample_tall_image):
with patch('nodes.get_edge_color', return_value=(0, 255, 0, 255)):
# Tall image (1:2) padded to wide (2:1) should pad height
result = resize_with_aspect_ratio(sample_tall_image, 200, 50, 'pad')
assert result.size == (200, 50)
class TestGetEdgeColor:
"""Test cases for get_edge_color function."""
def test_get_edge_color_rgb(self):
# Create image with solid red color
img = Image.new('RGB', (10, 10), color=(255, 0, 0))
result = get_edge_color(img)
# Should return RGBA tuple (converted from RGB)
assert len(result) == 4
assert result[0] == 255 # Red channel
assert result[1] == 0 # Green channel
assert result[2] == 0 # Blue channel
def test_get_edge_color_rgba(self):
# Create RGBA image with semi-transparent red
img = Image.new('RGBA', (10, 10), color=(255, 0, 0, 128))
result = get_edge_color(img)
assert len(result) == 4
assert result[0] == 255 # Red channel
assert result[1] == 0 # Green channel
assert result[2] == 0 # Blue channel
assert result[3] == 128 # Alpha channel
def test_get_edge_color_small_image(self):
# Test with minimum size image
img = Image.new('RGB', (1, 1), color=(100, 150, 200))
result = get_edge_color(img)
assert len(result) == 4
assert result[0] == 100
assert result[1] == 150
assert result[2] == 200
def test_get_edge_color_converts_to_rgba(self):
# Test that function properly converts any mode to RGBA
img = Image.new('L', (5, 5), color=128) # Grayscale
result = get_edge_color(img)
# Should be converted to RGBA
assert len(result) == 4
# Grayscale should have equal RGB values
assert result[0] == result[1] == result[2]
# Mock the extract_first_number function if it doesn't exist yet
def mock_extract_first_number(text):
"""Mock implementation of extract_first_number."""
import re
match = re.search(r'\d+', text)
return int(match.group()) if match else 0
# Patch extract_first_number if it doesn't exist
if not hasattr(sys.modules['nodes'], 'extract_first_number'):
sys.modules['nodes'].extract_first_number = mock_extract_first_number