Initial Commit

This commit is contained in:
2026-07-23 10:32:19 +01:00
commit 7027db5a16
4 changed files with 1131 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
"""Small regression tests for the dependency-free PDF generator."""
import math
import random
import tempfile
import unittest
from pathlib import Path
from golf_course_generator import (
A4_HEIGHT,
A4_WIDTH,
CARD_HEIGHT,
CARD_WIDTH,
GRID_COLUMNS,
GRID_ROWS,
GRID_SPACING,
GRID_X_OFFSET,
GRID_Y_OFFSET,
MIN_TEE_TO_CUP_DISTANCE,
Rect,
_natural_area_boundary_loops,
_natural_shape,
_rectangles_intersect,
_start_and_finish_fairways,
_tree_group_points,
build_a4_pdf,
build_a4_sheet,
write_sheet,
)
class GolfCourseGeneratorTests(unittest.TestCase):
def test_sheet_is_a_nonempty_single_page_pdf(self) -> None:
document = build_a4_sheet(seed=123456)
self.assertTrue(document.startswith(b"%PDF-1.4"))
self.assertIn(f"/MediaBox [0 0 {A4_WIDTH:.3f} {A4_HEIGHT:.3f}]".encode(), document)
self.assertIn(b"/Count 1", document)
self.assertIn(b"/BaseFont /Courier", document)
self.assertGreater(len(document), 25_000)
def test_seed_makes_output_repeatable(self) -> None:
self.assertEqual(build_a4_sheet(4321), build_a4_sheet(4321))
self.assertNotEqual(build_a4_sheet(4321), build_a4_sheet(4322))
def test_36_courses_are_packed_into_nine_pages(self) -> None:
document = build_a4_pdf(course_count=36, seed=36)
self.assertIn(b"/Count 9", document)
self.assertEqual(document.count(b"/Type /Page /Parent"), 9)
self.assertIn(b"(Hole 36)", document)
def test_rejects_a_non_positive_course_count(self) -> None:
with self.assertRaises(ValueError):
build_a4_pdf(course_count=0)
def test_tee_and_cup_are_separated_fairway_grid_dots(self) -> None:
board = Rect(0, 0, GRID_COLUMNS * GRID_SPACING, GRID_ROWS * GRID_SPACING)
tee_fairway, tee, cup_fairway, cup = _start_and_finish_fairways(random.Random(52), board)
self.assertGreaterEqual(math.dist(tee, cup), MIN_TEE_TO_CUP_DISTANCE)
for point, fairway in ((tee, tee_fairway), (cup, cup_fairway)):
x_index = (point[0] - (board.x + GRID_X_OFFSET)) / GRID_SPACING
y_index = (point[1] - (board.y + GRID_Y_OFFSET)) / GRID_SPACING
self.assertAlmostEqual(x_index, round(x_index), places=8)
self.assertAlmostEqual(y_index, round(y_index), places=8)
self.assertTrue(any(part.x < point[0] < part.right and part.y < point[1] < part.top for part in fairway))
def test_course_cards_and_playfields_have_the_requested_dimensions(self) -> None:
self.assertEqual(CARD_WIDTH, 3 * 72)
self.assertEqual(CARD_HEIGHT, 5 * 72)
self.assertEqual((GRID_COLUMNS, GRID_ROWS), (16, 26))
def test_tree_groups_and_terrain_do_not_overlap(self) -> None:
board = Rect(0, 0, GRID_COLUMNS * GRID_SPACING, GRID_ROWS * GRID_SPACING)
rng = random.Random(19)
first = _natural_shape(rng, board, cell_count=14, avoid=[], blocked=[])
second = _natural_shape(rng, board, cell_count=8, avoid=[], blocked=first)
terrain = [*first, *second]
for cell in first[1:]:
self.assertTrue(
any(abs(cell.x - earlier.x) + abs(cell.y - earlier.y) == GRID_SPACING for earlier in first)
)
self.assertTrue(all(not _rectangles_intersect(part, blocked) for part in second for blocked in first))
for x, y, _ in _tree_group_points(rng, board, terrain=terrain, avoid=[]):
self.assertAlmostEqual((x - (board.x + GRID_X_OFFSET)) / GRID_SPACING, round((x - (board.x + GRID_X_OFFSET)) / GRID_SPACING), places=8)
self.assertAlmostEqual((y - (board.y + GRID_Y_OFFSET)) / GRID_SPACING, round((y - (board.y + GRID_Y_OFFSET)) / GRID_SPACING), places=8)
self.assertTrue(all(math.dist((x, y + 10), (max(feature.x, min(x, feature.right)), max(feature.y, min(y + 10, feature.top)))) >= 13 for feature in terrain))
def test_connected_terrain_has_one_continuous_boundary_loop(self) -> None:
cells = [Rect(0, 0, GRID_SPACING, GRID_SPACING), Rect(GRID_SPACING, 0, GRID_SPACING, GRID_SPACING)]
loops = _natural_area_boundary_loops(cells)
self.assertEqual(len(loops), 1)
self.assertEqual(len(loops[0]), 6)
self.assertEqual(loops[0][0][0], loops[0][-1][1])
def test_sheet_includes_each_hole_label_and_can_be_written(self) -> None:
with tempfile.TemporaryDirectory() as directory:
destination = write_sheet(Path(directory) / "courses.pdf", seed=9)
document = destination.read_bytes()
for number in range(1, 5):
self.assertIn(f"Hole {number}".encode(), document)
self.assertIn(b"Strokes:", document)
if __name__ == "__main__":
unittest.main()