import numpy as np import pytest from app.services.gaze_sequence import extract_gaze_sequence from app.services.aoi_analysis import compute_aoi_attention from app.services.heatmap import generate_heatmap_overlay, generate_standalone_heatmap from app.services.image_processing import prepare_for_inference, upscale_saliency from PIL import Image class TestGazeSequence: def test_extracts_correct_number_of_fixations(self): saliency = np.random.rand(100, 100) result = extract_gaze_sequence(saliency, num_fixations=5) assert len(result) == 5 def test_fixations_are_ranked(self): saliency = np.random.rand(100, 100) result = extract_gaze_sequence(saliency, num_fixations=3) ranks = [p["rank"] for p in result] assert ranks == [1, 2, 3] def test_first_fixation_is_at_peak(self): saliency = np.zeros((100, 100)) saliency[50, 75] = 1.0 # Set a clear peak result = extract_gaze_sequence(saliency, num_fixations=1) assert result[0]["x"] == 75 assert result[0]["y"] == 50 def test_coordinates_have_percentages(self): saliency = np.random.rand(200, 300) result = extract_gaze_sequence(saliency, num_fixations=1) assert 0 <= result[0]["x_pct"] <= 100 assert 0 <= result[0]["y_pct"] <= 100 class TestAOIAnalysis: def test_full_image_aoi_gets_100_percent(self): saliency = np.ones((100, 100)) regions = [{"x": 0, "y": 0, "width": 100, "height": 100}] result = compute_aoi_attention(saliency, regions) assert abs(result[0]["attention_pct"] - 100.0) < 0.1 def test_half_image_aoi(self): saliency = np.ones((100, 100)) regions = [{"x": 0, "y": 0, "width": 50, "height": 100}] result = compute_aoi_attention(saliency, regions) assert abs(result[0]["attention_pct"] - 50.0) < 1.0 def test_density_calculation(self): saliency = np.zeros((100, 100)) saliency[0:10, 0:10] = 1.0 # High saliency in small region regions = [{"x": 0, "y": 0, "width": 10, "height": 10}] result = compute_aoi_attention(saliency, regions) assert result[0]["attention_density"] > 1.0 def test_zero_saliency(self): saliency = np.zeros((100, 100)) regions = [{"x": 0, "y": 0, "width": 50, "height": 50}] result = compute_aoi_attention(saliency, regions) assert result[0]["attention_pct"] == 0.0 class TestHeatmap: def test_generates_overlay(self): img = Image.new("RGB", (100, 100), color="white") saliency = np.random.rand(100, 100) result = generate_heatmap_overlay(img, saliency) assert result.size == (100, 100) assert result.mode == "RGB" def test_generates_standalone(self): saliency = np.random.rand(100, 100) result = generate_standalone_heatmap(saliency) assert result.size == (100, 100) class TestImageProcessing: def test_resize_large_image(self): img = Image.new("RGB", (2000, 1000)) resized, scale = prepare_for_inference(img) assert max(resized.size) <= 1024 assert scale < 1.0 def test_no_resize_small_image(self): img = Image.new("RGB", (500, 300)) resized, scale = prepare_for_inference(img) assert resized.size == (500, 300) assert scale == 1.0 def test_upscale_saliency(self): saliency = np.random.rand(50, 50) result = upscale_saliency(saliency, 200, 300) assert result.shape == (200, 300)