XmLLM / tests /unit /test_geo_polygon.py
Claude
Code quality: fix all ruff warnings, add CI/CD, improve test coverage
bbbfba8 unverified
Raw
History Blame Contribute Delete
3.97 kB
"""Tests for geometry/polygon.py β€” polygon operations."""
from __future__ import annotations
import pytest
from src.app.geometry import polygon
class TestPolygonToBbox:
def test_rectangle(self) -> None:
poly = [(100, 200), (400, 200), (400, 250), (100, 250)]
result = polygon.polygon_to_bbox(poly)
assert result == (100, 200, 300, 50)
def test_triangle(self) -> None:
poly = [(0, 0), (100, 0), (50, 80)]
result = polygon.polygon_to_bbox(poly)
assert result == (0, 0, 100, 80)
def test_too_few_points(self) -> None:
with pytest.raises(ValueError, match="at least 3"):
polygon.polygon_to_bbox([(0, 0), (1, 1)])
class TestBboxToPolygon:
def test_rectangle(self) -> None:
result = polygon.bbox_to_polygon((10, 20, 100, 50))
assert result == [(10, 20), (110, 20), (110, 70), (10, 70)]
def test_roundtrip(self) -> None:
original = (10, 20, 100, 50)
poly = polygon.bbox_to_polygon(original)
back = polygon.polygon_to_bbox(poly)
assert back == original
class TestPolygonArea:
def test_unit_square(self) -> None:
poly = [(0, 0), (1, 0), (1, 1), (0, 1)]
assert polygon.polygon_area(poly) == pytest.approx(1.0)
def test_rectangle(self) -> None:
poly = [(0, 0), (10, 0), (10, 5), (0, 5)]
assert polygon.polygon_area(poly) == pytest.approx(50.0)
def test_triangle(self) -> None:
poly = [(0, 0), (10, 0), (5, 8)]
assert polygon.polygon_area(poly) == pytest.approx(40.0)
def test_too_few_points(self) -> None:
assert polygon.polygon_area([(0, 0)]) == 0.0
class TestPolygonCentroid:
def test_square(self) -> None:
poly = [(0, 0), (10, 0), (10, 10), (0, 10)]
cx, cy = polygon.polygon_centroid(poly)
assert cx == pytest.approx(5.0)
assert cy == pytest.approx(5.0)
def test_too_few(self) -> None:
with pytest.raises(ValueError, match="at least 3"):
polygon.polygon_centroid([(0, 0)])
class TestValidatePolygon:
def test_valid_polygon(self) -> None:
poly = [(0, 0), (10, 0), (10, 10), (0, 10)]
assert polygon.validate_polygon(poly) == []
def test_too_few_points(self) -> None:
warnings = polygon.validate_polygon([(0, 0)])
assert any("fewer than 3" in w for w in warnings)
def test_duplicate_consecutive(self) -> None:
poly = [(0, 0), (10, 0), (10, 0), (0, 10)]
warnings = polygon.validate_polygon(poly)
assert any("Duplicate" in w for w in warnings)
def test_negative_coords(self) -> None:
poly = [(-5, 0), (10, 0), (10, 10)]
warnings = polygon.validate_polygon(poly)
assert any("Negative" in w for w in warnings)
def test_degenerate_line(self) -> None:
poly = [(0, 0), (10, 0), (20, 0)]
warnings = polygon.validate_polygon(poly)
assert any("zero area" in w for w in warnings)
class TestClockwise:
"""In screen coordinates (y-axis down), the signed-area formula gives
positive for CW when vertices go right-then-down (like (0,0)β†’(0,10)β†’(10,10)β†’(10,0)).
"""
def test_clockwise(self) -> None:
# In screen coords: left-down-right-up = clockwise
cw = [(0, 0), (0, 10), (10, 10), (10, 0)]
assert polygon.is_clockwise(cw) is True
def test_counter_clockwise(self) -> None:
# In screen coords: right-down-left-up = counter-clockwise
ccw = [(0, 0), (10, 0), (10, 10), (0, 10)]
assert polygon.is_clockwise(ccw) is False
def test_ensure_clockwise_already(self) -> None:
cw = [(0, 0), (0, 10), (10, 10), (10, 0)]
result = polygon.ensure_clockwise(cw)
assert result == cw
def test_ensure_clockwise_reverses(self) -> None:
ccw = [(0, 0), (10, 0), (10, 10), (0, 10)]
result = polygon.ensure_clockwise(ccw)
assert polygon.is_clockwise(result) is True