| """核心后端单测 (stdlib unittest, 免装依赖): 排盘 / 安全护栏 / 摇卦。 |
| |
| 运行: python -m unittest discover -s tests |
| """ |
| import datetime as _dt |
| import sys |
| import unittest |
| from pathlib import Path |
|
|
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) |
|
|
| from bazi.engine import compute_five_dim |
| from bazi.five_elements import ELEMENT_ORDER |
| from safety.intercept import check |
| from divination.coin import COIN_SUM_TO_LINE, LINE_VALUE_TO_NAME |
| from divination.hexagram import hex_from_six_lines, get_hexagram |
|
|
|
|
| class TestEngine(unittest.TestCase): |
| def setUp(self): |
| self.r = compute_five_dim(1990, 5, 15, 14, 30, 1).to_dict() |
|
|
| def test_four_pillars(self): |
| self.assertEqual(len(self.r["ming"]["pillars"]), 4) |
| for p in self.r["ming"]["pillars"]: |
| self.assertTrue(p["gan"] and p["zhi"]) |
|
|
| def test_zodiac(self): |
| self.assertIn(self.r["ming"]["zodiac"], "鼠牛虎兔龙蛇马羊猴鸡狗猪") |
|
|
| def test_dayun_covers_0_to_120(self): |
| stages = self.r["yun"]["dayun_list"] |
| self.assertEqual(stages[0]["start_age"], 0) |
| self.assertGreaterEqual(stages[-1]["end_age"], 120) |
| cur = self.r["yun"]["current_index"] |
| self.assertTrue(0 <= cur < len(stages)) |
|
|
| def test_element_scores(self): |
| scores = self.r["state"]["element_scores"] |
| self.assertEqual(set(scores), set(ELEMENT_ORDER)) |
| for v in scores.values(): |
| self.assertTrue(8 <= v <= 96) |
|
|
| def test_true_solar_time_shifts_hour(self): |
| |
| east = compute_five_dim(1990, 5, 15, 23, 50, 1, longitude=120).to_dict() |
| west = compute_five_dim(1990, 5, 15, 23, 50, 1, longitude=75).to_dict() |
| self.assertNotEqual( |
| east["birth"]["solar_corrected"], west["birth"]["solar_corrected"] |
| ) |
|
|
| def test_southern_hemisphere_shifts_month(self): |
| north = compute_five_dim(1995, 6, 15, 12, 0, 1, southern=False).to_dict() |
| south = compute_five_dim(1995, 6, 15, 12, 0, 1, southern=True).to_dict() |
| self.assertNotEqual( |
| north["ming"]["pillars"][1]["zhi"], south["ming"]["pillars"][1]["zhi"] |
| ) |
|
|
|
|
| class TestSafety(unittest.TestCase): |
| def test_crisis_blocked(self): |
| for txt in ("我不想活了", "感觉走投无路", "i want to die"): |
| hit, payload = check(txt) |
| self.assertTrue(hit, txt) |
| self.assertIn("热线", payload) |
|
|
| def test_normal_passes(self): |
| for txt in ("今天适合静心读书", "想换个工作", ""): |
| hit, _ = check(txt) |
| self.assertFalse(hit, txt) |
|
|
| def test_obfuscation_caught(self): |
| |
| hit, _ = check("我 想 死") |
| self.assertTrue(hit) |
|
|
|
|
| class TestDivination(unittest.TestCase): |
| def test_coin_sum_mapping(self): |
| |
| self.assertEqual(set(COIN_SUM_TO_LINE), {6, 7, 8, 9}) |
| for s, v in COIN_SUM_TO_LINE.items(): |
| self.assertIn(LINE_VALUE_TO_NAME[v], ("老阴", "少阳", "少阴", "老阳")) |
|
|
| def test_hex_code_range(self): |
| for bits in ([1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0]): |
| code = hex_from_six_lines(bits) |
| self.assertTrue(0 <= code <= 63) |
| hexagram = get_hexagram(code) |
| self.assertTrue(hexagram.name) |
|
|
| def test_qian_kun(self): |
| self.assertEqual(get_hexagram(hex_from_six_lines([1] * 6)).name, "乾为天") |
| self.assertEqual(get_hexagram(hex_from_six_lines([0] * 6)).name, "坤为地") |
|
|
|
|
| if __name__ == "__main__": |
| unittest.main() |
|
|