Files
dice-counter/tests/test_storage.py
T
gitea-actionsandClaude Opus 5 26338bfa29 Adresy a data podle systému, ne podle Linuxu
Než začneme rozdávat binárky pro macOS a Windows, musí se na nich chovat
rozumně to, co dosud počítalo s Linuxem.

Adresy rozhraní se hledaly linuxovým ioctl. Na Windows chybí fcntl, na
macOS to číslo znamená něco jiného, takže obojí propadlo až na poslední
zálohu přes hostname — a ta na macOS vrátí jednu adresu. Tabule by tam
nabídla jedinou volbu, přesně to, co jsme minule opravovali. Přibyla
mezizáloha přes ifconfig; spouští se jen tam, kde ioctl nic nenašel,
takže na Linuxu se neplatí nic. Parsování je zvlášť jako čistá funkce,
ať jde otestovat i bez macOS pod rukama.

Databáze z binárky mířila do XDG adresáře na všech systémech. Na Windows
by to znamenalo C:\Users\...\.local\share\, což tam nikdo nečeká. Teď se
volí podle systému: LOCALAPPDATA, Library/Application Support, XDG.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 13:13:41 +02:00

185 lines
6.4 KiB
Python

from pathlib import Path
import pytest
import storage
@pytest.fixture
def conn(tmp_path):
connection = storage.connect(tmp_path / "test.db")
yield connection
connection.close()
def test_stejne_jmeno_je_stejny_hrac(conn):
"""Arkádová identita: Adam z jedné hry je Adam i v další."""
first = storage.create_game(conn, ["Adam", "Eva"])
second = storage.create_game(conn, ["adam", "Petr"])
adam_first = [p["id"] for p in storage.seating(conn, first) if p["name"] == "Adam"]
adam_second = [p["id"] for p in storage.seating(conn, second)][0]
assert adam_first[0] == adam_second
def test_normalizace_jmen():
assert storage.normalize(" Adam ") == storage.normalize("adam")
assert storage.normalize("Jan Novák") == storage.normalize("jan novák")
assert storage.normalize("Adam") != storage.normalize("Ádám")
def test_prejmenovani_se_propise_do_starych_her(conn):
game_id = storage.create_game(conn, ["Adam", "Eva"])
adam = storage.seating(conn, game_id)[0]["id"]
storage.rename_player(conn, adam, "Adam Š.")
assert [p["name"] for p in storage.seating(conn, game_id)] == ["Adam Š.", "Eva"]
def test_slouceni_hracu_po_preklepu(conn):
good = storage.create_game(conn, ["Adam", "Eva"])
typo = storage.create_game(conn, ["Adm", "Eva"])
adam = storage.get_or_create_player(conn, "Adam")
adm = storage.get_or_create_player(conn, "Adm")
game = storage.load_game(conn, typo)
storage.add_turn(conn, typo, game.add_score(150).turn)
storage.merge_players(conn, adm, adam)
assert [p["name"] for p in storage.seating(conn, typo)] == ["Adam", "Eva"]
assert storage.load_game(conn, typo).totals()["Adam"] == 150
assert [p["id"] for p in storage.known_players(conn)].count(adm) == 0
assert storage.load_game(conn, good).totals() == {"Adam": 0, "Eva": 0}
def test_hra_se_nacte_zpatky_i_s_tahy(conn):
game_id = storage.create_game(conn, ["Adam", "Eva"], final_score=500)
game = storage.load_game(conn, game_id)
for value in (100, 50, 0, 30):
storage.add_turn(conn, game_id, game.add_score(value).turn)
loaded = storage.load_game(conn, game_id)
assert loaded.names == ["Adam", "Eva"]
assert loaded.final_score == 500
assert loaded.totals() == {"Adam": 100, "Eva": 80}
assert loaded.current_player == "Adam"
assert loaded.round_number == 3
def test_vynulovani_se_uklada_jako_nula_s_priznakem(conn):
game_id = storage.create_game(conn, ["Adam"], final_score=500)
game = storage.load_game(conn, game_id)
for value in (300, 0, 0, 0):
storage.add_turn(conn, game_id, game.add_score(value).turn)
rows = conn.execute("SELECT value, reset FROM turns ORDER BY id").fetchall()
assert [r["value"] for r in rows] == [300, 0, 0, 0]
assert [r["reset"] for r in rows] == [0, 0, 0, 1]
assert storage.load_game(conn, game_id).totals()["Adam"] == 0
def test_rozehrana_hra_se_najde_a_dokonci(conn):
game_id = storage.create_game(conn, ["Adam", "Eva"], final_score=100)
assert storage.running_game(conn) == game_id
game = storage.load_game(conn, game_id)
storage.add_turn(conn, game_id, game.add_score(100).turn)
result = game.add_score(10)
storage.add_turn(conn, game_id, result.turn)
storage.finish_game(conn, game_id, result.winner)
assert storage.running_game(conn) is None
assert storage.game_row(conn, game_id)["status"] == storage.STATUS_FINISHED
assert storage.game_row(conn, game_id)["winner_name"] == "Adam"
def test_undo_smaze_tah_a_vrati_hru_do_hry(conn):
game_id = storage.create_game(conn, ["Adam", "Eva"], final_score=100)
game = storage.load_game(conn, game_id)
storage.add_turn(conn, game_id, game.add_score(100).turn)
result = game.add_score(10)
storage.add_turn(conn, game_id, result.turn)
storage.finish_game(conn, game_id, result.winner)
assert storage.undo_turn(conn, game_id)
row = storage.game_row(conn, game_id)
assert row["status"] == storage.STATUS_RUNNING
assert row["winner_id"] is None
assert storage.load_game(conn, game_id).current_player == "Eva"
def test_opustena_hra(conn):
game_id = storage.create_game(conn, ["Adam", "Eva"])
storage.abandon_game(conn, game_id)
assert storage.running_game(conn) is None
assert storage.game_row(conn, game_id)["status"] == storage.STATUS_ABANDONED
def test_hrac_nesmi_sedet_u_stolu_dvakrat(conn):
with pytest.raises(ValueError):
storage.create_game(conn, ["Adam", "adam"])
def test_prazdne_jmeno(conn):
with pytest.raises(ValueError):
storage.get_or_create_player(conn, " ")
def test_umisteni_databaze_ze_zdrojaku(monkeypatch):
"""Ze zdrojáků se ukládá do pracovního adresáře."""
monkeypatch.delenv("DICE_DB", raising=False)
monkeypatch.delattr(storage.sys, "frozen", raising=False)
assert storage.default_db() == Path("dice.db")
def test_umisteni_databaze_z_binarky(monkeypatch, tmp_path):
"""Binárka se rozbaluje do dočasného adresáře, databáze tam nesmí."""
monkeypatch.delenv("DICE_DB", raising=False)
monkeypatch.setattr(storage.sys, "frozen", True, raising=False)
monkeypatch.setattr(storage.sys, "platform", "linux")
monkeypatch.setenv("XDG_DATA_HOME", str(tmp_path))
assert storage.default_db() == tmp_path / "kostky" / "dice.db"
def test_data_home_podle_systemu(monkeypatch, tmp_path):
"""Každý systém má svůj adresář na data; XDG je jen ten linuxový."""
monkeypatch.setenv("LOCALAPPDATA", str(tmp_path / "AppData" / "Local"))
monkeypatch.setattr(Path, "home", classmethod(lambda cls: tmp_path))
monkeypatch.setattr(storage.sys, "platform", "win32")
assert storage.data_home() == tmp_path / "AppData" / "Local"
monkeypatch.setattr(storage.sys, "platform", "darwin")
assert storage.data_home() == tmp_path / "Library" / "Application Support"
monkeypatch.setattr(storage.sys, "platform", "linux")
monkeypatch.delenv("XDG_DATA_HOME", raising=False)
assert storage.data_home() == tmp_path / ".local" / "share"
def test_dice_db_prebije_oboje(monkeypatch, tmp_path):
monkeypatch.setattr(storage.sys, "frozen", True, raising=False)
monkeypatch.setenv("DICE_DB", str(tmp_path / "jinde.db"))
assert storage.default_db() == tmp_path / "jinde.db"
def test_connect_zalozi_chybejici_adresar(tmp_path):
conn = storage.connect(tmp_path / "novy" / "adresar" / "dice.db")
conn.close()
assert (tmp_path / "novy" / "adresar" / "dice.db").exists()