205 lines
7.6 KiB
Python
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
|