Spaces:
Running
Running
| 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], " +--+--+--+--+--+") | |