supervisor-simulator/tools/ndbs/server/tests/test_api.py
2026-01-17 20:59:45 +08:00

168 lines
4.9 KiB
Python

import json
import sys
from pathlib import Path
import pytest
SERVER_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(SERVER_ROOT))
from ndbs_core import ( # noqa: E402
NdbsPaths,
create_rule,
ensure_within_root,
infer_schema,
list_definition_files,
list_rule_files,
load_definition_file,
parse_tres_array,
parse_tres_value,
resolve_paths,
update_tres_resource,
write_definition_file,
)
def make_paths(tmp_path: Path) -> NdbsPaths:
project_root = tmp_path / "project"
project_root.mkdir()
(project_root / "project.godot").write_text("[gd_project]\n")
definitions_root = project_root / "resources" / "definitions"
definitions_root.mkdir(parents=True)
rules_root = project_root / "scripts" / "Rules" / "Generated"
rules_root.mkdir(parents=True)
backup_root = project_root / "tools" / "ndbs" / "backups"
backup_root.mkdir(parents=True)
web_root = project_root / "tools" / "ndbs" / "server" / "web"
web_root.mkdir(parents=True)
(web_root / "index.html").write_text("<html>ndbs</html>")
return NdbsPaths(
project_root=project_root,
definitions_root=definitions_root,
rules_root=rules_root,
backup_root=backup_root,
web_root=web_root,
)
def seed_definitions(paths: NdbsPaths) -> None:
traits_path = paths.definitions_root / "traits.json"
traits_path.write_text(
json.dumps({"id": "core:trait_test", "value": 1}), encoding="utf-8"
)
tres_path = paths.definitions_root / "discipline_biology.tres"
tres_path.write_text(
"[gd_resource type=\"Resource\" format=3]\n"
"\n"
"[resource]\n"
"Id = \"core:discipline_test\"\n"
"NameFallback = \"Biology\"\n"
"Tags = [ \"discipline\", \"lab\" ]\n",
encoding="utf-8",
)
def test_parse_tres_values() -> None:
assert parse_tres_value("\"hello\"") == "hello"
assert parse_tres_value("true") is True
assert parse_tres_value("42") == 42
assert parse_tres_array('[ "a", "b" ]') == ["a", "b"]
def test_list_definitions_and_schema(tmp_path: Path) -> None:
paths = make_paths(tmp_path)
seed_definitions(paths)
files = list_definition_files(paths)
assert "traits.json" in files
assert "discipline_biology.tres" in files
content = load_definition_file(paths.definitions_root / "traits.json")
assert content["id"] == "core:trait_test"
schema = infer_schema(content)
assert schema["type"] == "object"
assert "id" in schema["fields"]
def test_write_json_creates_backup(tmp_path: Path) -> None:
paths = make_paths(tmp_path)
seed_definitions(paths)
write_definition_file(
paths.definitions_root / "traits.json",
{"id": "core:trait_test", "value": 2},
paths,
)
saved = json.loads(
(paths.definitions_root / "traits.json").read_text(encoding="utf-8")
)
assert saved["value"] == 2
backups = list(paths.backup_root.rglob("traits.json"))
assert backups
def test_tres_roundtrip(tmp_path: Path) -> None:
paths = make_paths(tmp_path)
seed_definitions(paths)
original = load_definition_file(paths.definitions_root / "discipline_biology.tres")
assert original["Tags"] == ["discipline", "lab"]
write_definition_file(
paths.definitions_root / "discipline_biology.tres",
{"Tags": ["alpha", "beta"], "NameFallback": "Bio 2"},
paths,
)
updated = load_definition_file(paths.definitions_root / "discipline_biology.tres")
assert updated["Tags"] == ["alpha", "beta"]
assert updated["NameFallback"] == "Bio 2"
def test_update_tres_resource_adds_keys() -> None:
original = "[resource]\nId = \"core:test\"\n"
updated = update_tres_resource(original, {"NewKey": "Value"})
assert "NewKey" in updated
def test_create_rule(tmp_path: Path) -> None:
paths = make_paths(tmp_path)
filename = create_rule("test_rule", paths)
assert filename.endswith(".cs")
rule_path = paths.rules_root / filename
assert rule_path.exists()
assert "rule:test_rule" in rule_path.read_text(encoding="utf-8")
rules = list_rule_files(paths)
assert filename in rules
def test_ensure_within_root_rejects_traversal(tmp_path: Path) -> None:
paths = make_paths(tmp_path)
with pytest.raises(ValueError):
ensure_within_root(paths.definitions_root, "../evil.json", {".json"})
def test_resolve_paths_defaults(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
project_root = tmp_path / "game"
project_root.mkdir()
(project_root / "project.godot").write_text("[gd_project]\n")
server_root = tmp_path / "server"
server_root.mkdir()
monkeypatch.chdir(server_root)
monkeypatch.setenv("NDBS_PROJECT_ROOT", str(project_root))
resolved = resolve_paths()
assert resolved.project_root == project_root
assert resolved.definitions_root.name == "definitions"