76 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""内容级快照泄露审计的纯函数测试。"""
from __future__ import annotations
import json
import pathlib
import sys
import unittest
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent))
from audit_leakage import audit_snapshot # noqa: E402
def target_facts():
"""提供只供审计侧使用的目标章事实,不进入规划器上下文。"""
return {
"targetChapter": 489,
"forbiddenFacts": [
{
"id": "betrayal-489",
"firstChapter": 489,
"text": "阿铎反水击毙加特朗",
}
],
}
class LeakageAuditTest(unittest.TestCase):
def test_safe_snapshot_is_ready(self):
result = audit_snapshot(
{"events": [{"chapter": 488, "fact": "环星防御仍在"}]},
target_facts(),
as_of=488,
target=489,
)
self.assertTrue(result["ok"])
self.assertEqual(result["status"], "ready")
self.assertEqual(result["findingCount"], 0)
def test_future_nested_record_blocks_snapshot(self):
result = audit_snapshot(
{"events": [{"chapter": 489, "fact": "未来事件"}]},
target_facts(),
as_of=488,
target=489,
)
self.assertFalse(result["ok"])
self.assertEqual(result["status"], "invalid_snapshot")
self.assertEqual(result["findings"][0]["reason"], "future_or_crosses_as_of")
def test_mislabelled_target_fact_blocks_snapshot_without_echoing_text(self):
result = audit_snapshot(
{"events": [{"chapter": 488, "fact": "阿铎反水击毙加特朗"}]},
target_facts(),
as_of=488,
target=489,
)
encoded = json.dumps(result, ensure_ascii=False)
self.assertFalse(result["ok"])
self.assertEqual(result["status"], "invalid_snapshot")
self.assertNotIn("阿铎反水击毙加特朗", encoded)
self.assertEqual(result["findings"][0]["reason"], "target_fact_match")
self.assertIn("factHash", result["findings"][0])
self.assertIn("valueHash", result["findings"][0])
def test_target_and_as_of_must_form_next_chapter_pair(self):
result = audit_snapshot({}, target_facts(), as_of=487, target=489)
self.assertFalse(result["ok"])
self.assertEqual(result["status"], "invalid_audit_input")
if __name__ == "__main__":
unittest.main()