111 lines
4.7 KiB
Python
111 lines
4.7 KiB
Python
"""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()
|