Files

109 lines
4.3 KiB
Python

"""End-to-end tests for the dependency-free EQL spell CLI."""
from __future__ import annotations
import json
import shutil
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
CLI = ROOT / "scripts" / "eql-spells"
FIXTURE = ROOT / "tests" / "fixtures" / "eql-spells"
class EqlSpellsCliTests(unittest.TestCase):
def setUp(self) -> None:
self.temporary = tempfile.TemporaryDirectory()
self.work = Path(self.temporary.name)
self.game = self.work / "game"
shutil.copytree(FIXTURE, self.game)
self.db = self.work / "cache" / "spells.sqlite"
def tearDown(self) -> None:
self.temporary.cleanup()
def run_cli(self, *arguments: str) -> subprocess.CompletedProcess[str]:
return subprocess.run(
[sys.executable, str(CLI), "--game-path", str(self.game), "--db", str(self.db), *arguments],
cwd=ROOT,
text=True,
capture_output=True,
check=False,
)
def json_stdout(self, *arguments: str) -> dict:
result = self.run_cli(*arguments)
self.assertEqual(result.returncode, 0, result.stderr)
return json.loads(result.stdout)
def test_build_and_exact_lookup_by_id_and_name(self) -> None:
built = self.json_stdout("build")
self.assertEqual(built["built"], {"descriptions": 3, "messages": 3, "spells": 3})
self.assertTrue(self.db.is_file())
by_id = self.json_stdout("get", "1")
self.assertEqual(by_id["spell"]["name"], "Fire Bolt")
self.assertEqual(by_id["spell"]["description"], "Launches a bolt of fire at your target.")
self.assertEqual(by_id["spell"]["messages"]["caster_me"], "You cast Fire Bolt.")
self.assertIn("fingerprint", by_id["source"])
by_name = self.json_stdout("get", "water breathing")
self.assertEqual(by_name["spell"]["id"], 2)
def test_find_search_and_raw_output(self) -> None:
found = self.json_stdout("find", "fire")
self.assertEqual([spell["name"] for spell in found["results"]], ["Fire Bolt", "Fireball"])
searched = self.json_stdout("search", "breathing underwater")
self.assertEqual([spell["id"] for spell in searched["results"]], [2])
raw = self.json_stdout("get", "1", "--raw")
self.assertEqual(raw["spell"]["raw"]["line"], "1^Fire Bolt^0^alpha")
self.assertEqual(raw["spell"]["raw"]["fields"], ["1", "Fire Bolt", "0", "alpha"])
def test_query_automatically_rebuilds_after_source_change(self) -> None:
self.json_stdout("build")
descriptions = self.game / "dbstr_us.txt"
with descriptions.open("a", encoding="utf-8") as handle:
handle.write("2^6^Lets your target breathe underwater indefinitely.^0^\n")
result = self.run_cli("search", "indefinitely")
self.assertEqual(result.returncode, 1)
self.assertIn("Duplicate spell description", json.loads(result.stderr)["error"]["message"])
# Replace the existing description rather than adding a duplicate.
descriptions.write_text(
"1^6^Launches a bolt of fire at your target.^0^\n"
"2^6^Lets your target breathe underwater indefinitely.^0^\n"
"3^6^Launches a ball of fire at your target.^0^\n"
"1^5^Fire^0^\n",
encoding="utf-8",
)
rebuilt = self.json_stdout("search", "indefinitely")
self.assertTrue(rebuilt["index_rebuilt"])
self.assertEqual(rebuilt["results"][0]["id"], 2)
def test_malformed_data_and_invalid_query_return_structured_errors(self) -> None:
(self.game / "spells_us.txt").write_text("bad row\n", encoding="utf-8")
malformed = self.run_cli("build")
self.assertEqual(malformed.returncode, 1)
self.assertEqual(json.loads(malformed.stderr)["error"]["code"], "data")
shutil.copy2(FIXTURE / "spells_us.txt", self.game / "spells_us.txt")
invalid_limit = self.run_cli("find", "fire", "--limit", "101")
self.assertEqual(invalid_limit.returncode, 2)
self.assertEqual(json.loads(invalid_limit.stderr)["error"]["code"], "usage")
missing = self.run_cli("get", "999")
self.assertEqual(missing.returncode, 1)
self.assertEqual(json.loads(missing.stderr)["error"]["code"], "data")
if __name__ == "__main__":
unittest.main()