first draft
This commit is contained in:
87
tests/test_crossword.py
Normal file
87
tests/test_crossword.py
Normal file
@ -0,0 +1,87 @@
|
||||
import pytest
|
||||
from multiplayer_crosswords.crossword import Crossword, Orientation, PlacedWord
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
class DummyWord:
|
||||
def __init__(self, word):
|
||||
self.word = word
|
||||
|
||||
class DummyDictionary:
|
||||
def __init__(self, words):
|
||||
self.words = words
|
||||
|
||||
def make_crossword(rows=5, cols=5):
|
||||
dictionary = DummyDictionary([DummyWord("HELLO"), DummyWord("WORLD")])
|
||||
return Crossword(rows, cols, dictionary)
|
||||
|
||||
def test_can_place_word_empty_grid_horizontal():
|
||||
cw = make_crossword()
|
||||
word = DummyWord("HELLO")
|
||||
assert cw.can_place_word(word, 0, 0, Orientation.HORIZONTAL)
|
||||
assert not cw.can_place_word(word, 0, 1, Orientation.HORIZONTAL) # would go out of bounds
|
||||
|
||||
def test_can_place_word_empty_grid_vertical():
|
||||
cw = make_crossword()
|
||||
word = DummyWord("HELLO")
|
||||
assert cw.can_place_word(word, 0, 0, Orientation.VERTICAL)
|
||||
assert not cw.can_place_word(word, 1, 0, Orientation.VERTICAL) # would go out of bounds
|
||||
|
||||
def test_add_word_and_grid_update():
|
||||
cw = make_crossword()
|
||||
word = DummyWord("HELLO")
|
||||
assert cw.add_word(word, 0, 0, Orientation.HORIZONTAL)
|
||||
# Check grid contents
|
||||
assert cw.grid[0][0] == "H"
|
||||
assert cw.grid[0][1] == "E"
|
||||
assert cw.grid[0][2] == "L"
|
||||
assert cw.grid[0][3] == "L"
|
||||
assert cw.grid[0][4] == "O"
|
||||
# Start and end blocks
|
||||
assert cw.grid[0][0-0][0-1] == "#" if cw._in_bounds(0, -1) else True
|
||||
assert cw.grid[0][5] == "#" if cw._in_bounds(0, 5) else True
|
||||
|
||||
def test_cannot_place_overlapping_different_letter():
|
||||
cw = make_crossword()
|
||||
word1 = DummyWord("HELLO")
|
||||
word2 = DummyWord("WORLD")
|
||||
assert cw.add_word(word1, 0, 0, Orientation.HORIZONTAL)
|
||||
# Try to place "WORLD" vertically overlapping 'E' with 'O'
|
||||
assert not cw.can_place_word(word2, 0, 1, Orientation.VERTICAL)
|
||||
|
||||
def test_can_place_overlapping_same_letter():
|
||||
cw = make_crossword()
|
||||
word1 = DummyWord("HELLO")
|
||||
word2 = DummyWord("EVE")
|
||||
assert cw.add_word(word1, 0, 0, Orientation.HORIZONTAL)
|
||||
# "EVE" vertical, E overlaps at (0,1)
|
||||
word2 = DummyWord("EVE")
|
||||
assert cw.can_place_word(word2, 0, 1, Orientation.VERTICAL)
|
||||
assert cw.add_word(word2, 0, 1, Orientation.VERTICAL)
|
||||
|
||||
def test_blocks_are_placed_correctly():
|
||||
cw = make_crossword()
|
||||
word = DummyWord("HI")
|
||||
assert cw.add_word(word, 2, 2, Orientation.HORIZONTAL)
|
||||
# Start block
|
||||
assert cw.grid[2][1] == "#"
|
||||
# End block
|
||||
assert cw.grid[2][4] == "#"
|
||||
|
||||
def test_str_representation():
|
||||
cw = make_crossword()
|
||||
word = DummyWord("HI")
|
||||
cw.add_word(word, 0, 0, Orientation.HORIZONTAL)
|
||||
s = str(cw)
|
||||
assert "HI" in s
|
||||
assert "." in s
|
||||
|
||||
def test_placed_words_tracking():
|
||||
cw = make_crossword()
|
||||
word = DummyWord("HI")
|
||||
cw.add_word(word, 1, 1, Orientation.VERTICAL)
|
||||
assert len(cw.placed_words) == 1
|
||||
placed = cw.placed_words[0]
|
||||
assert placed.word == word
|
||||
assert placed.row == 1
|
||||
assert placed.col == 1
|
||||
assert placed.orientation == Orientation.VERTICAL
|
||||
105
tests/test_dictionary.py
Normal file
105
tests/test_dictionary.py
Normal file
@ -0,0 +1,105 @@
|
||||
import pytest
|
||||
from multiplayer_crosswords.dictionary import Word, Dictionary
|
||||
|
||||
def test_add_word_and_to_dict():
|
||||
d = Dictionary()
|
||||
w = Word("apple", ["a red or green fruit"], 0.2)
|
||||
d.add_word(w)
|
||||
result = d.to_dict()
|
||||
assert "words" in result
|
||||
assert len(result["words"]) == 1
|
||||
assert result["words"][0]["word"] == "apple"
|
||||
assert result["words"][0]["hints"] == ["a red or green fruit"]
|
||||
assert result["words"][0]["difficulty"] == 0.2
|
||||
|
||||
def test_from_dict_and_to_dict_roundtrip():
|
||||
data = {
|
||||
"words": [
|
||||
{"word": "banana", "hints": ["a yellow fruit", "something monkeys like to eat"], "difficulty": 0.1},
|
||||
{"word": "car", "hints": ["vehicle", "four wheels"], "difficulty": 0.3}
|
||||
]
|
||||
}
|
||||
d = Dictionary.from_dict(data)
|
||||
assert len(d.words) == 2
|
||||
assert d.words[0].word == "banana"
|
||||
assert d.words[1].hints == ["vehicle", "four wheels"]
|
||||
assert d.words[1].difficulty == 0.3
|
||||
assert d.to_dict() == data
|
||||
|
||||
def test_to_json_and_from_json():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("dog", ["animal", "barks"], 0.15))
|
||||
json_str = d.to_json()
|
||||
d2 = Dictionary.from_json(json_str)
|
||||
assert len(d2.words) == 1
|
||||
assert d2.words[0].word == "dog"
|
||||
assert d2.words[0].hints == ["animal", "barks"]
|
||||
assert d2.words[0].difficulty == 0.15
|
||||
|
||||
def test_empty_dictionary_to_dict_and_json():
|
||||
d = Dictionary()
|
||||
assert d.to_dict() == {"words": []}
|
||||
json_str = d.to_json()
|
||||
assert json_str.strip().startswith("{")
|
||||
d2 = Dictionary.from_json(json_str)
|
||||
assert isinstance(d2, Dictionary)
|
||||
assert d2.words == []
|
||||
|
||||
def test_word_to_dict_and_from_dict():
|
||||
w = Word("cat", ["animal", "meows"], 0.12)
|
||||
d = w.to_dict()
|
||||
assert d == {"word": "cat", "hints": ["animal", "meows"], "difficulty": 0.12}
|
||||
w2 = Word.from_dict(d)
|
||||
assert w2.word == "cat"
|
||||
assert w2.hints == ["animal", "meows"]
|
||||
assert w2.difficulty == 0.12
|
||||
|
||||
def test_find_by_pattern_exact_match():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("apple", ["fruit"], 0.2))
|
||||
d.add_word(Word("apply", ["verb"], 0.3))
|
||||
d.add_word(Word("angle", ["geometry"], 0.4))
|
||||
result = d.find_by_pattern("apple")
|
||||
assert [r.word for r in result] == ["apple"]
|
||||
|
||||
def test_find_by_pattern_with_wildcards():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("apple", ["fruit"], 0.2))
|
||||
d.add_word(Word("apply", ["verb"], 0.3))
|
||||
d.add_word(Word("angle", ["geometry"], 0.4))
|
||||
d.add_word(Word("ample", ["enough"], 0.5))
|
||||
# Pattern: a**le should match apple and angle and ample
|
||||
result = sorted([w.word for w in d.find_by_pattern("a**le")])
|
||||
assert set(result) == {"apple", "angle", "ample"}
|
||||
|
||||
def test_find_by_pattern_all_wildcards():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("apple", ["fruit"], 0.2))
|
||||
d.add_word(Word("apply", ["verb"], 0.3))
|
||||
d.add_word(Word("angle", ["geometry"], 0.4))
|
||||
# Pattern: ***** should match all 5-letter words
|
||||
result = sorted([w.word for w in d.find_by_pattern("*****")])
|
||||
assert set(result) == {"apple", "apply", "angle"}
|
||||
|
||||
def test_find_by_pattern_no_match():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("apple", ["fruit"], 0.2))
|
||||
d.add_word(Word("apply", ["verb"], 0.3))
|
||||
# Pattern: z**** should match nothing
|
||||
result = d.find_by_pattern("z****")
|
||||
assert list(result) == []
|
||||
|
||||
def test_find_by_pattern_duplicate_letters():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("level", ["word"], 0.1))
|
||||
d.add_word(Word("lever", ["tool"], 0.2))
|
||||
# Pattern: l*vel should match "level" only
|
||||
result = d.find_by_pattern("l*vel")
|
||||
assert [r.word for r in result] == ["level"]
|
||||
|
||||
def test_find_by_pattern_length_not_in_index():
|
||||
d = Dictionary()
|
||||
d.add_word(Word("cat", ["animal"], 0.1))
|
||||
# Pattern: four letters, but only 3-letter word in dict
|
||||
result = d.find_by_pattern("****")
|
||||
assert [r.word for r in result] == []
|
||||
Reference in New Issue
Block a user