testspace / tests /test_core.py
Mayug Maniparambil
Isolate native loopy verifier in subprocess; harden submit handler
f227b96
Raw
History Blame Contribute Delete
6.77 kB
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], " +--+--+--+--+--+")