from __future__ import annotations import tempfile import unittest from pathlib import Path from space_app.dataset import DatasetStore from space_app.db import SessionStore from space_app.models import DatasetRow, normalize_player_name from space_app.board_utils import normalize_board_for_display, normalize_board_for_submission class CoreTests(unittest.TestCase): def test_normalize_player_name(self) -> None: self.assertEqual(normalize_player_name(" Ada Lovelace "), "ada lovelace") def test_dataset_store_lists_first_fifty_in_dataset_order(self) -> None: rows = [ DatasetRow( filename=f"puzzle_{index:02d}.txt", puzzlename="bridges", args="5x5de", problem=str(index), solution=str(index), difficulty="easy", ) for index in range(60) ] store = DatasetStore(rows, seed=0) listed = store.list_rows( puzzle_type="bridges", difficulty="easy", ) self.assertEqual(len(listed), 50) self.assertEqual(listed[0].filename, "puzzle_00.txt") self.assertEqual(listed[-1].filename, "puzzle_49.txt") def test_session_store_records_submission(self) -> None: with tempfile.TemporaryDirectory() as tempdir: store = SessionStore(Path(tempdir) / "sessions.sqlite") session = store.create_session( player_name_raw="Ada", player_name_norm="ada", puzzle_type="bridges", difficulty="easy", dataset_variant="plain", puzzle_filename="a.txt", args="5x5de", engine="bridges_ascii", ) store.mark_ready(session["id"]) updated = store.record_submission( session_id=session["id"], solved=False, submitted_artifact="artifact", verification_payload={"correct": False}, ) self.assertEqual(updated["status"], "attempted") self.assertEqual(updated["submission_count"], 1) def test_loopy_normalization_marks_unclicked_edges_blocked(self) -> None: problem = "\n".join( [ "+++++++++++++", "+ +", "+ 0 +", "+ +", "+ 2 1 3 2 +", "+ +", "+ 2 3 +", "+ +", "+ 2 2 +", "+ +", "+ 3 2 3 +", "+ +", "+++++++++++++", ] ) partial = "\n".join( [ "+++++++++++++", "+ - +", "+ 0 +", "+ +", "+ 2 1 3 2 +", "+ +", "+ 2 3 +", "+ +", "+ 2 2 +", "+ +", "+ 3 2 3 +", "+ +", "+++++++++++++", ] ) normalized_submission = normalize_board_for_submission( puzzle_type="loopy", problem_ascii=problem, board_ascii=partial, ) self.assertEqual(len(normalized_submission.splitlines()), 11) self.assertTrue(all(len(line) == 11 for line in normalized_submission.splitlines())) self.assertIn("x", normalized_submission) self.assertIn("-", normalized_submission) redisplayed = normalize_board_for_display( puzzle_type="loopy", problem_ascii=problem, board_ascii=normalized_submission, ) self.assertEqual(len(redisplayed.splitlines()), 13) self.assertIn("+", redisplayed) def test_loopy_normalization_handles_misshapen_board_without_crashing(self) -> None: # A submitted board with the wrong number of rows/columns (e.g. a # border-less compact grid) must not raise IndexError during # normalization; it should normalize to the expected shape instead. problem = "\n".join( [ "+++++++++++++", "+ +", "+ 3 3 +", "+ +", "+ 2 1 0 1 2 +", "+ +", "+ 2 1 0 +", "+ +", "+ 3 +", "+ +", "+ 2 2 +", "+ +", "+++++++++++++", ] ) misshapen = "\n".join(["x x x", "| | |", "x x x"]) # only 3x5, far too small normalized = normalize_board_for_submission( puzzle_type="loopy", problem_ascii=problem, board_ascii=misshapen, ) self.assertEqual(len(normalized.splitlines()), 11) self.assertTrue(all(len(line) == 11 for line in normalized.splitlines())) def test_pattern_normalization_makes_unclicked_cells_white(self) -> None: board = "\n".join( [ " 1 ", " +--+--+", " 1| |##|", " +--+--+", " 1|##| |", " +--+--+", ] ) normalized = normalize_board_for_display( puzzle_type="pattern", problem_ascii=board, board_ascii=board, ) self.assertIn("|..|##|", normalized) self.assertIn("|##|..|", normalized) def test_pattern_normalization_keeps_top_and_bottom_borders(self) -> None: board = "\n".join( [ " 1 ", " 1 2 3 3 3 ", " +--+--+--+--+--+", "2 1| | | | | |", " +--+--+--+--+--+", " 1| | | | | |", " +--+--+--+--+--+", " 3| | | | | |", " +--+--+--+--+--+", " 3| | | | | |", " +--+--+--+--+--+", " 3| | | | | |", " +--+--+--+--+--+", ] ) normalized = normalize_board_for_display( puzzle_type="pattern", problem_ascii=board, board_ascii=board, ) lines = normalized.splitlines() self.assertEqual(lines.count(" +--+--+--+--+--+"), 6) self.assertEqual(lines[2], " +--+--+--+--+--+") self.assertEqual(lines[-1], " +--+--+--+--+--+")