Loading...
No commits yet
Not committed History
Blame
test_crop_tif.py • 5.7 KB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Test file for: crop_tif.py

import os
import sys
from pathlib import Path

import pytest

# Add scripts/python to path for imports
ROOT_DIR = Path(__file__).resolve().parent.parent.parent
sys.path.insert(0, str(ROOT_DIR / "scripts" / "python"))

# Check for dependencies
try:
    import cv2
    import numpy as np
    from crop_tif import crop_tif, find_content_area, resize_image

    HAS_CV2 = True
except ImportError:
    HAS_CV2 = False


# Tests for find_content_area
@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_find_content_area_returns_tuple(tmp_path):
    """Test that find_content_area returns a 4-tuple for valid image."""
    # Create a simple test image with content
    img = np.ones((100, 100, 3), dtype=np.uint8) * 255  # White background
    img[20:80, 20:80] = 0  # Black square in center

    test_image = tmp_path / "test.tif"
    cv2.imwrite(str(test_image), img)

    result = find_content_area(str(test_image))
    assert isinstance(result, tuple)
    assert len(result) == 4
    x, y, w, h = result
    assert all(isinstance(v, (int, np.integer)) for v in result)


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_find_content_area_all_white(tmp_path):
    """Test that all-white image returns full dimensions."""
    # Create all-white image
    img = np.ones((100, 150, 3), dtype=np.uint8) * 255

    test_image = tmp_path / "white.tif"
    cv2.imwrite(str(test_image), img)

    x, y, w, h = find_content_area(str(test_image))
    # Should return full image dimensions
    assert w == 150
    assert h == 100


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_find_content_area_missing_file():
    """Test that FileNotFoundError is raised for missing file."""
    with pytest.raises(FileNotFoundError):
        find_content_area("/nonexistent/path/image.tif")


# Tests for resize_image
@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_resize_image_no_change():
    """Test that small image within limits stays same size."""
    img = np.ones((100, 200, 3), dtype=np.uint8) * 255

    result = resize_image(img, max_width=2000, max_height=2000)

    assert result.shape[0] == 100  # height
    assert result.shape[1] == 200  # width


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_resize_image_downscale_width():
    """Test that wide image gets scaled down to fit max_width."""
    img = np.ones((100, 3000, 3), dtype=np.uint8) * 255

    result = resize_image(img, max_width=2000, max_height=2000)

    assert result.shape[1] == 2000  # width limited
    assert result.shape[0] < 100  # height scaled proportionally


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_resize_image_downscale_height():
    """Test that tall image gets scaled down to fit max_height."""
    img = np.ones((3000, 100, 3), dtype=np.uint8) * 255

    result = resize_image(img, max_width=2000, max_height=2000)

    assert result.shape[0] == 2000  # height limited
    assert result.shape[1] < 100  # width scaled proportionally


# Tests for crop_tif
@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_crop_tif_output_created(tmp_path, capsys):
    """Test that crop_tif creates output file."""
    # Create test image
    img = np.ones((200, 200, 3), dtype=np.uint8) * 255
    img[50:150, 50:150] = 0  # Black square

    input_file = tmp_path / "input.tif"
    output_file = tmp_path / "output.tif"
    cv2.imwrite(str(input_file), img)

    crop_tif(str(input_file), str(output_file), resize=False)

    assert output_file.exists()
    # Verify it's a valid image
    result_img = cv2.imread(str(output_file))
    assert result_img is not None


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_crop_tif_missing_file_raises():
    """Test that FileNotFoundError is raised for missing input."""
    with pytest.raises(FileNotFoundError):
        crop_tif("/nonexistent/input.tif", "/tmp/output.tif")


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_crop_tif_no_output_no_overwrite_raises():
    """Test that ValueError is raised when no output and no overwrite."""
    with pytest.raises(ValueError, match="output_path must be specified"):
        crop_tif("input.tif", output_path=None, overwrite=False)


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_crop_tif_with_overwrite(tmp_path, capsys):
    """Test that crop_tif can overwrite input file."""
    # Create test image
    img = np.ones((200, 200, 3), dtype=np.uint8) * 255
    img[50:150, 50:150] = 0

    input_file = tmp_path / "test.tif"
    cv2.imwrite(str(input_file), img)

    crop_tif(str(input_file), output_path=None, overwrite=True, resize=False)

    # File should still exist
    assert input_file.exists()
    result_img = cv2.imread(str(input_file))
    assert result_img is not None


@pytest.mark.skipif(not HAS_CV2, reason="cv2 (opencv-python) not available")
def test_crop_tif_with_resize(tmp_path, capsys):
    """Test that crop_tif resizes when requested."""
    # Create large test image
    img = np.ones((3000, 3000, 3), dtype=np.uint8) * 255
    img[100:2900, 100:2900] = 0

    input_file = tmp_path / "large.tif"
    output_file = tmp_path / "resized.tif"
    cv2.imwrite(str(input_file), img)

    crop_tif(
        str(input_file), str(output_file), resize=True, max_width=1000, max_height=1000
    )

    result_img = cv2.imread(str(output_file))
    assert result_img.shape[0] <= 1000
    assert result_img.shape[1] <= 1000


if __name__ == "__main__":
    import pytest

    pytest.main([os.path.abspath(__file__), "-v"])