Files
by-ae-ae-in-workflow/tests/test_image_selector.py
T
by-aeandCursor Agent fac2070079 test: add comprehensive tests for image_selector utility functions
- Add tests for create_thumbnail with normal and extreme aspect ratios
- Add tests for pil_to_tensor with RGB/RGBA images and invalid inputs
- Add tests for load_images_from_folder edge cases
- Add tests for sort_image_paths
- Add tests for build_folder_tree
- Add tests for process_selected_images with empty input
- Add tests for LazyImageLoader class

Improves test coverage for previously untested utility functions.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-10-25 20:59:09 +00:00

235 lines
7.1 KiB
Python

"""
Tests for image_selector module
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import pytest
import torch
import numpy as np
from PIL import Image
def test_module_imports():
"""Test that image_selector can be imported"""
import image_selector
assert hasattr(image_selector, 'hex_to_rgb')
def test_hex_to_rgb():
"""Test hex color conversion"""
from image_selector import hex_to_rgb
# 6-character format
assert hex_to_rgb("#000000") == (0, 0, 0)
assert hex_to_rgb("#FFFFFF") == (255, 255, 255)
assert hex_to_rgb("#ff0000") == (255, 0, 0)
assert hex_to_rgb("#00FF00") == (0, 255, 0)
assert hex_to_rgb("#0000Ff") == (0, 0, 255)
# 3-character format (should expand: #RGB -> #RRGGBB)
assert hex_to_rgb("#000") == (0, 0, 0)
assert hex_to_rgb("#FFF") == (255, 255, 255)
assert hex_to_rgb("#F00") == (255, 0, 0)
assert hex_to_rgb("#0F0") == (0, 255, 0)
assert hex_to_rgb("#00F") == (0, 0, 255)
assert hex_to_rgb("#abc") == (170, 187, 204) # #aabbcc
def test_hex_to_rgb_invalid():
"""Test hex_to_rgb with invalid inputs"""
from image_selector import hex_to_rgb
with pytest.raises(ValueError):
hex_to_rgb("invalid")
with pytest.raises(ValueError):
hex_to_rgb("#FFFF") # 4 chars (invalid)
with pytest.raises(ValueError):
hex_to_rgb("FF0000") # Missing #
with pytest.raises(ValueError):
hex_to_rgb("#FF") # Too short (2 chars)
def test_create_thumbnail():
"""Test thumbnail creation with various aspect ratios"""
from image_selector import create_thumbnail
# Normal case - square image
img = Image.new('RGB', (100, 100), color='red')
result = create_thumbnail(img, (50, 50))
assert result.size == (50, 50)
# Wide image
img = Image.new('RGB', (200, 100), color='blue')
result = create_thumbnail(img, (50, 50))
assert result.size[0] == 50
assert result.size[1] <= 50
# Tall image
img = Image.new('RGB', (100, 200), color='green')
result = create_thumbnail(img, (50, 50))
assert result.size[0] <= 50
assert result.size[1] == 50
def test_create_thumbnail_extreme_aspect_ratios():
"""Test thumbnail creation with extreme aspect ratios that could produce 0-pixel dimensions"""
from image_selector import create_thumbnail
# Very wide image (1000x1)
img = Image.new('RGB', (1000, 1), color='blue')
result = create_thumbnail(img, (150, 150))
assert result.size[0] == 150
assert result.size[1] >= 1 # Should be at least 1 pixel
# Very tall image (1x1000)
img = Image.new('RGB', (1, 1000), color='green')
result = create_thumbnail(img, (150, 150))
assert result.size[0] >= 1 # Should be at least 1 pixel
assert result.size[1] == 150
# 1x1 pixel image
img = Image.new('RGB', (1, 1), color='red')
result = create_thumbnail(img, (150, 150))
assert result.size[0] >= 1
assert result.size[1] >= 1
def test_pil_to_tensor():
"""Test PIL to tensor conversion"""
from image_selector import pil_to_tensor
# RGB image
img = Image.new('RGB', (10, 10), color='red')
tensor, mask = pil_to_tensor(img)
assert tensor.shape == (1, 10, 10, 3)
assert mask.shape == (1, 10, 10)
assert torch.all(mask == 1.0) # All-white mask for RGB
# RGBA image with transparency
img = Image.new('RGBA', (10, 10), color=(255, 0, 0, 128))
tensor, mask = pil_to_tensor(img)
assert tensor.shape == (1, 10, 10, 3)
assert mask.shape == (1, 10, 10)
assert torch.all(mask <= 1.0)
assert torch.all(mask >= 0.0)
def test_pil_to_tensor_invalid():
"""Test pil_to_tensor with invalid inputs"""
from image_selector import pil_to_tensor
# None input
with pytest.raises(ValueError, match="Image cannot be None"):
pil_to_tensor(None)
# Non-PIL object
with pytest.raises(ValueError, match="Expected PIL Image"):
pil_to_tensor("not an image")
with pytest.raises(ValueError, match="Expected PIL Image"):
pil_to_tensor(123)
def test_load_images_from_folder():
"""Test loading images from folder"""
from image_selector import load_images_from_folder
import tempfile
# Empty folder
with tempfile.TemporaryDirectory() as tmpdir:
images, paths = load_images_from_folder(tmpdir)
assert len(images) == 0
assert len(paths) == 0
# Non-existent folder
images, paths = load_images_from_folder('/nonexistent/path')
assert len(images) == 0
assert len(paths) == 0
# Empty string
images, paths = load_images_from_folder('')
assert len(images) == 0
assert len(paths) == 0
def test_sort_image_paths():
"""Test sorting image paths"""
from image_selector import sort_image_paths
# Empty list
result = sort_image_paths([], 'name', True)
assert result == []
# Single item
result = sort_image_paths(['/path/to/image.jpg'], 'name', True)
assert result == ['/path/to/image.jpg']
# Name sorting
paths = ['/path/c.jpg', '/path/a.jpg', '/path/b.jpg']
result = sort_image_paths(paths, 'name', True)
assert result == ['/path/a.jpg', '/path/b.jpg', '/path/c.jpg']
# Descending
result = sort_image_paths(paths, 'name', False)
assert result == ['/path/c.jpg', '/path/b.jpg', '/path/a.jpg']
def test_build_folder_tree():
"""Test folder tree building"""
from image_selector import build_folder_tree
import tempfile
with tempfile.TemporaryDirectory() as tmpdir:
# Create a simple folder structure
os.makedirs(os.path.join(tmpdir, 'subfolder1'), exist_ok=True)
os.makedirs(os.path.join(tmpdir, 'subfolder2'), exist_ok=True)
tree = build_folder_tree(tmpdir, tmpdir)
# Should have at least the parent and current folder
assert len(tree) >= 2
# First item should be parent navigation
assert tree[0][0].startswith('⬆️')
# Second item should be current folder
assert tree[1][0].startswith('📁')
# Non-existent path
tree = build_folder_tree('/nonexistent/path', '/nonexistent/path')
assert len(tree) >= 2 # Should still have navigation items
def test_process_selected_images_empty():
"""Test process_selected_images with empty input"""
from image_selector import process_selected_images
images, masks, image_batch, mask_batch = process_selected_images([], [], None, None, '#000000')
assert len(images) == 0
assert len(masks) == 0
assert image_batch.shape == (0, 0, 0, 3)
assert mask_batch.shape == (0, 0, 0)
def test_lazy_image_loader():
"""Test LazyImageLoader class"""
from image_selector import LazyImageLoader
# Empty loader
loader = LazyImageLoader([])
assert loader.paths == []
# Non-existent image
loader = LazyImageLoader(['/nonexistent.jpg'])
thumb = loader.get_thumbnail('/nonexistent.jpg')
assert thumb is not None # Should return error placeholder
# Preload empty
loader.preload_visible([]) # Should not crash