/
Mihaham
/
Table-Time
Обзор
Документация
Войти
/
Mihaham
/
Table-Time
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
services/api/tests/test_plugins_coverage.py
188 строк
8 KB
MihahamYT
feat: full game catalog — 46 plugins, docs nav, web UI kit
14 июн 2026, 12:43
14 июн 2026, 12:43
2cd5f50
Код
Авторство
О чём код?
"""Extended unit tests for plugin coverage (yatzy, memo, koaliciya).""" import pytest from app.plugins.koaliciya.plugin import KoaliciyaPlugin from app.plugins.memo.plugin import MemoPlugin from app.plugins.shared.scoring import ( YATZY_CATEGORIES, score_yatzy_category, total_yatzy_score, ) from app.plugins.yatzy.plugin import YatzyPlugin @pytest.fixture def yatzy(): return YatzyPlugin() @pytest.fixture def memo(): return MemoPlugin() @pytest.fixture def koaliciya(): return KoaliciyaPlugin() def test_yatzy_keep_dice(yatzy): s = yatzy.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) s = yatzy.apply_action(s, "roll_dice", {}, "p1") dice = s["dice"] s = yatzy.apply_action(s, "keep_dice", {"indices": [0, 1]}, "p1") assert s["rolls_left"] == 1 assert len(s["dice"]) == 5 assert s["dice"][0] == dice[0] assert s["dice"][1] == dice[1] def test_yatzy_validation_errors(yatzy): s = yatzy.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) assert yatzy.validate_action(s, "bad", {}, "p1").error_code == "UNKNOWN_ACTION" assert yatzy.validate_action(s, "roll_dice", {}, "p2").error_code == "NOT_YOUR_TURN" s["winner_id"] = "p1" assert yatzy.validate_action(s, "roll_dice", {}, "p1").error_code == "GAME_FINISHED" s = yatzy.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) s["phase"] = "Rolled" s["dice"] = [1, 2, 3, 4, 5] s["rolls_left"] = 0 assert yatzy.validate_action(s, "keep_dice", {"indices": [0]}, "p1").error_code == "NO_REROLLS" assert yatzy.validate_action(s, "keep_dice", {"indices": ["x"]}, "p1").error_code == "INVALID_INDICES" assert yatzy.validate_action(s, "score_category", {"category": "bad"}, "p1").error_code == "INVALID_CATEGORY" s["phase"] = "AwaitRoll" assert yatzy.validate_action(s, "score_category", {"category": "ones"}, "p1").error_code == "WRONG_PHASE" def test_yatzy_allowed_actions_and_render(yatzy): s = yatzy.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) assert yatzy.allowed_actions(s, "p1") == ["roll_dice"] assert yatzy.allowed_actions(s, "p2") == [] s = yatzy.apply_action(s, "roll_dice", {}, "p1") actions = yatzy.allowed_actions(s, "p1") assert "score_category" in actions assert "keep_dice" in actions web = yatzy.render_web(s, {"p1": "A", "p2": "B"}, "p1") assert web.extra["dice"] tg = yatzy.render_telegram(s, {"p1": "A", "p2": "B"}) assert "Яцзы" in tg.caption assert yatzy.get_current_player(s) == "p1" assert not yatzy.is_finished(s) def test_yatzy_scoring_edge_cases(): assert score_yatzy_category([2, 2, 2, 3, 4], "three_of_kind") == 13 assert score_yatzy_category([1, 1, 2, 3, 4], "four_of_kind") == 0 assert score_yatzy_category([1, 2, 3, 5, 6], "small_straight") == 0 card = {c: 11 if c in ["ones", "twos", "threes", "fours", "fives", "sixes"] else 0 for c in YATZY_CATEGORIES} assert total_yatzy_score(card) == 66 + 35 def test_yatzy_all_face_scores(): assert score_yatzy_category([1, 0, 0, 0, 0], "ones") == 1 assert score_yatzy_category([2, 2, 0, 0, 0], "twos") == 4 assert score_yatzy_category([3, 3, 3, 0, 0], "threes") == 9 assert score_yatzy_category([4, 4, 4, 4, 0], "fours") == 16 assert score_yatzy_category([5, 0, 0, 0, 0], "fives") == 5 assert score_yatzy_category([6, 6, 0, 0, 0], "sixes") == 12 assert score_yatzy_category([2, 3, 4, 5, 6], "chance") == 20 assert score_yatzy_category([1, 2, 3, 4, 5], "yatzy") == 0 def test_shlyapa_judge_and_validations(): from app.plugins.shlyapa.plugin import ShlyapaPlugin p = ShlyapaPlugin() s = p.initial_state(["p1", "p2"], {"p1": "E", "p2": "G"}, {}) s["word"] = "test" assert p.validate_action(s, "guess", {"word": ""}, "p2").error_code == "WRONG_PHASE" s = p.apply_action(s, "start_guessing", {}, "p1") assert p.validate_action(s, "guess", {"word": ""}, "p2").error_code == "EMPTY_GUESS" assert p.validate_action(s, "guess", {"word": "x"}, "p1").error_code == "EXPLAINER_CANNOT_GUESS" assert p.validate_action(s, "skip_word", {}, "p2").error_code == "NOT_EXPLAINER" s = p.apply_action(s, "guess", {"word": "a"}, "p2") s = p.apply_action(s, "judge_guess", {"index": 0, "correct": False}, "p1") assert p.validate_action(s, "judge_guess", {"index": 0, "correct": True}, "p1").error_code == "GUESS_ALREADY_JUDGED" s2 = p.apply_action(s, "guess", {"word": "test"}, "p2") s2 = p.apply_action(s2, "judge_guess", {"index": 1, "correct": True}, "p1") assert s2["scores"]["p2"] == 1 assert s2["explainer_id"] == "p2" assert p.allowed_actions(s2, "p2") web = p.render_web(s2, {"p1": "E", "p2": "G"}, "p2") assert web.phase == "Explaining" def test_memo_match_and_game_over(memo): s = memo.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {"pair_count": 2, "seed": 1}) labels = [t["label"] for t in s["board"]] idx_a = labels.index("A") idx_a2 = next(i for i, label in enumerate(labels) if label == "A" and i != idx_a) s = memo.apply_action(s, "flip_tile", {"index": idx_a}, "p1") s = memo.apply_action(s, "flip_tile", {"index": idx_a2}, "p1") assert s["pairs_found"]["p1"] == 1 assert s["current_player_id"] == "p1" idx_c = next(i for i, t in enumerate(s["board"]) if t["state"] == "hidden") idx_d = next( i for i, t in enumerate(s["board"]) if t["state"] == "hidden" and i != idx_c and s["board"][i]["label"] == s["board"][idx_c]["label"] ) s = memo.apply_action(s, "flip_tile", {"index": idx_c}, "p1") s = memo.apply_action(s, "flip_tile", {"index": idx_d}, "p1") assert s["phase"] == "GameOver" assert s["winner_id"] == "p1" def test_memo_validation_errors(memo): s = memo.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {"seed": 1}) assert memo.validate_action(s, "bad", {}, "p1").error_code == "UNKNOWN_ACTION" assert memo.validate_action(s, "flip_tile", {"index": 0}, "p2").error_code == "NOT_YOUR_TURN" assert memo.validate_action(s, "flip_tile", {"index": -1}, "p1").error_code == "INVALID_INDEX" assert memo.validate_action(s, "flip_tile", {"index": 99}, "p1").error_code == "INVALID_INDEX" s = memo.apply_action(s, "flip_tile", {"index": 0}, "p1") assert memo.validate_action(s, "flip_tile", {"index": 0}, "p1").error_code == "ALREADY_REVEALED" s["winner_id"] = "p1" assert memo.validate_action(s, "flip_tile", {"index": 1}, "p1").error_code == "GAME_FINISHED" def test_memo_render(memo): s = memo.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {"seed": 1}) s["board"][0]["state"] = "matched" s["board"][1]["state"] = "revealed" web = memo.render_web(s, {"p1": "A", "p2": "B"}, "p1") assert web.extra["board"][0]["state"] == "matched" assert web.extra["board"][1]["label"] == s["board"][1]["label"] assert memo.allowed_actions(s, "p1") == ["flip_tile"] assert memo.allowed_actions(s, "p2") == [] tg = memo.render_telegram(s, {"p1": "A", "p2": "B"}) assert "Мемо" in tg.caption def test_koaliciya_validation_errors(koaliciya): s = koaliciya.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) assert koaliciya.validate_action(s, "bad", {}, "p1").error_code == "UNKNOWN_ACTION" s["phase"] = "GameOver" assert koaliciya.validate_action(s, "play_card", {"value": 1}, "p1").error_code == "GAME_FINISHED" s = koaliciya.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) assert koaliciya.validate_action(s, "play_card", {"value": 0}, "p1").error_code == "INVALID_VALUE" hand_val = s["hands"]["p1"][0] assert koaliciya.validate_action(s, "play_card", {"value": hand_val + 1}, "p1").error_code == "CARD_NOT_IN_HAND" def test_koaliciya_stuck_and_render(koaliciya): s = koaliciya.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) s["hands"] = {"p1": [5], "p2": [3]} s["last_played"] = 10 result = koaliciya.apply_action(s, "play_card", {"value": 5}, "p1") assert result["lives"] == 3 web = koaliciya.render_web(result, {"p1": "A", "p2": "B"}, "p1") assert "hand" in web.extra assert koaliciya.allowed_actions(result, "p1") == ["play_card"] s2 = koaliciya.initial_state(["p1", "p2"], {"p1": "A", "p2": "B"}, {}) s2["hands"]["p1"] = [] assert koaliciya.allowed_actions(s2, "p1") == [] assert koaliciya.get_current_player(s2) is None tg = koaliciya.render_telegram(s2, {"p1": "A", "p2": "B"}) assert "Коалиция" in tg.caption assert koaliciya.get_winner({"team_won": False, "player_order": ["p1"]}) is None