DazedTL/tests/test_wolf_db_classify.py
2026-07-09 08:10:55 -05:00

242 lines
8.1 KiB
Python

#!/usr/bin/env python3
"""Unit tests for WolfDawn database classification in util/wolfdawn/db_classify.py."""
from __future__ import annotations
import json
import os
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
os.chdir(ROOT)
sys.path.insert(0, str(ROOT))
from util.wolfdawn import db_classify as wdb # noqa: E402
STANDARD_DB = {
"file": "DataBase.project",
"kind": "db",
"groups": [
{
"type": 0,
"typeName": "Skill · 技能",
"lines": [
{
"row": 2,
"field": 1,
"fieldName": "Description · 説明",
"source": "味方一人のHPを回復",
"text": "味方一人のHPを回復",
},
],
},
{
"type": 1,
"typeName": "Item · アイテム",
"lines": [
{
"row": 0,
"field": 1,
"fieldName": "Description · 説明",
"source": "HPを回復",
"text": "HPを回復",
},
],
},
],
}
NARRATIVE_DB = {
"file": "DataBase.project",
"kind": "db",
"groups": [
{
"type": 10,
"typeName": "■イベント(セルリア)",
"lines": [
{
"row": 0,
"field": 3,
"fieldName": "セリフ_メッセージ",
"source": "こんにちは",
"text": "こんにちは",
},
{
"row": 0,
"field": 4,
"fieldName": "直前の相手_コメント",
"source": "誰か",
"text": "誰か",
},
],
},
{
"type": 11,
"typeName": "├■プロフィール(元数値)",
"lines": [
{
"row": 1,
"field": 2,
"fieldName": "好きなもの_コメント",
"source": "甘いもの",
"text": "甘いもの",
},
],
},
],
}
class TestClassifyGroupTier(unittest.TestCase):
def test_standard_skill_sheet_is_foundation(self):
tier = wdb.classify_group_tier(
"Skill · 技能",
STANDARD_DB["groups"][0]["lines"],
)
self.assertEqual(tier, wdb.TIER_FOUNDATION)
def test_custom_event_sheet_is_narrative(self):
tier = wdb.classify_group_tier(
"■イベント(セルリア)",
NARRATIVE_DB["groups"][0]["lines"],
)
self.assertEqual(tier, wdb.TIER_NARRATIVE)
def test_profile_sheet_is_narrative(self):
tier = wdb.classify_group_tier(
"├■プロフィール(元数値)",
NARRATIVE_DB["groups"][1]["lines"],
)
self.assertEqual(tier, wdb.TIER_NARRATIVE)
class TestClassifyDbDocument(unittest.TestCase):
def test_standard_doc_groups(self):
groups = wdb.classify_db_document(STANDARD_DB)
self.assertEqual(len(groups), 2)
self.assertTrue(all(g.tier == wdb.TIER_FOUNDATION for g in groups))
self.assertTrue(all(g.default_checked for g in groups))
def test_narrative_doc_groups(self):
groups = wdb.classify_db_document(NARRATIVE_DB)
self.assertEqual(len(groups), 2)
self.assertTrue(all(g.tier == wdb.TIER_NARRATIVE for g in groups))
self.assertTrue(all(not g.default_checked for g in groups))
class TestContentDistribution(unittest.TestCase):
def test_analyze_mixed_files_dir(self):
with tempfile.TemporaryDirectory() as tmp:
base = Path(tmp)
(base / "DataBase.project.json").write_text(
json.dumps({**STANDARD_DB, **NARRATIVE_DB, "groups": (
STANDARD_DB["groups"] + NARRATIVE_DB["groups"]
)}, ensure_ascii=False),
encoding="utf-8",
)
(base / "OP.mps.json").write_text(
json.dumps({
"file": "OP.mps",
"kind": "map",
"scenes": [{"lines": [{"source": "a", "text": "a"}]}],
}),
encoding="utf-8",
)
dist = wdb.analyze_content_distribution(base)
self.assertGreater(dist.db_lines, 0)
self.assertGreater(dist.db_foundation_lines, 0)
self.assertGreater(dist.db_narrative_lines, 0)
self.assertEqual(dist.map_files, 1)
self.assertEqual(dist.map_lines, 1)
def test_skips_rpgmaker_array_json(self):
"""files/ may hold RPGMaker list JSON; must not crash Wolf discovery."""
with tempfile.TemporaryDirectory() as tmp:
base = Path(tmp)
(base / "Actors.json").write_text(
json.dumps([{"id": 1, "name": "Hero"}]),
encoding="utf-8",
)
(base / "DataBase.project.json").write_text(
json.dumps(NARRATIVE_DB, ensure_ascii=False),
encoding="utf-8",
)
dist = wdb.analyze_content_distribution(base)
self.assertGreater(dist.db_lines, 0)
def test_discovery_summary_mentions_database(self):
with tempfile.TemporaryDirectory() as tmp:
base = Path(tmp)
(base / "DataBase.project.json").write_text(
json.dumps(NARRATIVE_DB, ensure_ascii=False),
encoding="utf-8",
)
dist = wdb.analyze_content_distribution(base)
summary = wdb.format_discovery_summary(dist)
self.assertIn("Database:", summary)
self.assertIn("Recommended order:", summary)
class TestGroupFilter(unittest.TestCase):
def test_group_key_format(self):
key = wdb.group_key("DataBase.project.json", "Skill · 技能")
self.assertEqual(key, "DataBase.project.json|Skill · 技能")
def test_filter_by_groups(self):
groups = frozenset({"DataBase.project.json|Skill · 技能"})
self.assertTrue(
wdb.group_matches_filter(
"DataBase.project.json", "Skill · 技能", frozenset(), groups
)
)
self.assertFalse(
wdb.group_matches_filter(
"DataBase.project.json", "■イベント(セルリア)", frozenset(), groups
)
)
def test_empty_filter_matches_all(self):
self.assertTrue(
wdb.group_matches_filter(
"DataBase.project.json", "■イベント(セルリア)", frozenset(), frozenset()
)
)
class TestDbProfile(unittest.TestCase):
def test_save_and_load_profile(self):
with tempfile.TemporaryDirectory() as tmp:
work = Path(tmp)
profile = {
"archetype": "simulation_db_heavy",
"foundation_groups": ["DataBase.project.json|Skill · 技能"],
"narrative_groups": ["DataBase.project.json|■イベント(セルリア)"],
"defer_groups": [],
"notes": "Test note",
}
wdb.save_db_profile(work, profile)
loaded = wdb.load_db_profile(work)
self.assertEqual(loaded["archetype"], "simulation_db_heavy")
self.assertEqual(len(loaded["foundation_groups"]), 1)
def test_import_ai_profile_strips_fences(self):
raw = '```json\n{"archetype": "hybrid", "foundation_groups": []}\n```'
data = wdb.import_ai_profile(raw)
self.assertEqual(data["archetype"], "hybrid")
def test_merge_profile_checks(self):
groups = wdb.classify_db_document(NARRATIVE_DB)
checks = wdb.merge_profile_with_groups(
{"narrative_groups": [groups[0].key]},
groups,
)
self.assertTrue(checks[groups[0].key])
self.assertFalse(checks[groups[1].key])
if __name__ == "__main__":
unittest.main()