Skip to content
This repository was archived by the owner on Jan 28, 2026. It is now read-only.

Commit 0c64a91

Browse files
Add Test Suite (#52)
* Start on test suite * Fix test suite
1 parent 5b16917 commit 0c64a91

10 files changed

Lines changed: 392 additions & 0 deletions

pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
dev = [
33
"pre-commit >= 4.5.0"
44
]
5+
tests = [
6+
"pytest >= 9.0.0",
7+
"pytest-cov >= 7.0.0",
8+
"tox >= 4.32.0",
9+
"tox-uv >= 1.29.0"
10+
]
511

612
[project]
713
dependencies = [
@@ -59,6 +65,7 @@ split-on-trailing-comma = false
5965
classmethod-decorators = ["classmethod"]
6066

6167
[tool.ruff.lint.per-file-ignores]
68+
"tests/*" = ["PLR2004", "S101"]
6269

6370
[tool.ruff.lint.pydocstyle]
6471
convention = "google"

tests/__init__.py

Whitespace-only changes.

tests/test_extractors.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from pathlib import Path
2+
3+
import numpy as np
4+
5+
import extract_dates as mod
6+
7+
8+
class FakeTextPage:
9+
def extractWORDS(self, delimiters: str | None = None) -> list[tuple]: # noqa: N802, ARG002
10+
return [
11+
(0, 0, 10, 10, "January"),
12+
(11, 0, 20, 10, "2024"),
13+
(30, 0, 40, 10, "February"),
14+
(41, 0, 50, 10, "2024"),
15+
(60, 0, 70, 10, "March"),
16+
(71, 0, 80, 10, "2024"),
17+
]
18+
19+
20+
class FakePage:
21+
def get_pixmap(self) -> "PM": # noqa: F821
22+
class PM:
23+
def tobytes(self, fmt: str) -> bytes: # noqa: ARG002
24+
return b"\x89PNG\r\n\x1a\n"
25+
26+
return PM()
27+
28+
def get_textpage_ocr(self, tessdata=None) -> FakeTextPage: # noqa: ARG002, ANN001
29+
return FakeTextPage()
30+
31+
32+
class FakeDoc:
33+
def __getitem__(self, idx: int) -> FakePage:
34+
return FakePage()
35+
36+
37+
def test_extract_png_calendars(monkeypatch) -> None: # noqa: ANN001
38+
monkeypatch.setattr(mod.pymupdf, "open", lambda _: FakeDoc())
39+
monkeypatch.setattr(mod.cv2, "imdecode", lambda *_: np.zeros((200, 300, 3)))
40+
41+
calendars = mod.extract_png_calendars(Path("fake.png"))
42+
43+
assert len(calendars) == 3
44+
assert [(c.month, c.year) for c in calendars] == [(1, 2024), (2, 2024), (3, 2024)]

tests/test_image_helpers.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import cv2
2+
import numpy as np
3+
4+
from extract_dates import keep_only_colours, remove_colours
5+
6+
7+
def test_remove_colours_masks_pixels(monkeypatch) -> None: # noqa: ANN001
8+
img = np.zeros((2, 2, 3), dtype=np.uint8)
9+
img[:] = [10, 10, 10]
10+
11+
def fake_in_range(*args, **kwargs) -> np.array: # noqa: ANN002, ANN003
12+
return np.array([[255, 0], [0, 0]], dtype=np.uint8)
13+
14+
monkeypatch.setattr(cv2, "inRange", fake_in_range)
15+
16+
result = remove_colours(img, [(10, 10, 10)])
17+
18+
assert (result[0, 0] == [255, 255, 255]).all()
19+
20+
21+
def test_keep_only_colours(monkeypatch) -> None: # noqa: ANN001
22+
img = np.ones((2, 2, 3), dtype=np.uint8) * 50
23+
24+
def fake_in_range(*args, **kwargs) -> np.array: # noqa: ANN002, ANN003
25+
return np.array([[255, 0], [0, 0]], dtype=np.uint8)
26+
27+
monkeypatch.setattr(cv2, "inRange", fake_in_range)
28+
29+
result = keep_only_colours(img, [(50, 50, 50)])
30+
31+
assert result.shape == img.shape

tests/test_main.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from pathlib import Path
2+
3+
import extract_dates as mod
4+
5+
6+
def test_main_writes_output(monkeypatch, tmp_path: Path) -> None: # noqa: ANN001
7+
monkeypatch.setattr(mod.Path, "glob", lambda self, pattern: []) # noqa: ARG005
8+
monkeypatch.setattr(mod, "extract_png_calendars", lambda *a, **k: [])
9+
monkeypatch.setattr(mod, "extract_pdf_calendars", lambda *a, **k: [])
10+
11+
monkeypatch.chdir(tmp_path)
12+
13+
mod.main()
14+
15+
output_dir = tmp_path / "output"
16+
assert output_dir.exists()

tests/test_mappings.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from extract_dates import adjust_mappings
2+
3+
4+
def test_adjust_mappings_single_row() -> None:
5+
mapped = [
6+
{"x0": 0, "y0": 0, "month": 1, "year": 2024},
7+
{"x0": 100, "y0": 0, "month": 2, "year": 2024},
8+
{"x0": 200, "y0": 0, "month": 3, "year": 2024},
9+
]
10+
11+
result = adjust_mappings(
12+
mapped=mapped, edges=(300, 300), x_offset=10, y_offset=10, rows=1, columns=3
13+
)
14+
15+
assert len(result) == 3
16+
assert result[0]["x0"] == 0
17+
assert result[0]["x1"] == 90
18+
assert result[-1]["x1"] == 300

tests/test_models.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from datetime import date
2+
3+
import numpy as np
4+
5+
from extract_dates import Calendar, Cell
6+
7+
8+
def test_calendar_equality_and_hash() -> None:
9+
img = np.zeros((10, 10, 3))
10+
a = Calendar(month=1, year=2024, calendar_image=img)
11+
b = Calendar(month=1, year=2024, calendar_image=img.copy())
12+
c = Calendar(month=2, year=2024, calendar_image=img)
13+
14+
assert a == b
15+
assert a != c
16+
assert len({a, b, c}) == 2
17+
18+
19+
def test_cell_equality_and_hash() -> None:
20+
d = date(2024, 1, 1)
21+
a = Cell(datestamp=d, colour="red")
22+
b = Cell(datestamp=d, colour="blue")
23+
c = Cell(datestamp=date(2024, 1, 2), colour="red")
24+
25+
assert a == b
26+
assert a != c
27+
assert len({a, b, c}) == 2

tests/test_parse.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from extract_dates import parse_month
2+
3+
4+
def test_parse_month_valid() -> None:
5+
dt = parse_month("January2024")
6+
assert dt.year == 2024
7+
assert dt.month == 1
8+
9+
10+
def test_parse_month_invalid() -> None:
11+
assert parse_month("FooBar") is None
12+
assert parse_month("") is None

tests/test_process_calendar.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import numpy as np
2+
3+
from extract_dates import PNG_COLOURS, process_calendar_squares
4+
5+
6+
def test_process_calendar_single_day(monkeypatch) -> None: # noqa: ANN001
7+
img = np.zeros((100, 700, 3), dtype=np.uint8)
8+
9+
def fake_analyze_square(*args, **kwargs) -> tuple[int, int, int]: # noqa: ANN002, ANN003
10+
return (0, 0, 255) # red (BGR)
11+
12+
monkeypatch.setattr("extract_dates.analyze_square", fake_analyze_square)
13+
14+
cells = process_calendar_squares(img=img, year=2024, month=1, colours=PNG_COLOURS)
15+
16+
assert len(cells) == 31
17+
assert any(cell.is_recycling for cell in cells)

0 commit comments

Comments
 (0)