Files
ZiPingEightChar/tests/test_chart_shot.py
T
moxiaonian 433c9b4a41 v3.6.0 同步发版
- 交互契约改对话式询问(禁点选工具、一次1~2问、先铺垫再问),规则库 3.6
- 盘面图默认生成+chart_shot 截图;品牌区、大运/流年小卡信息补全、交流群二维码卡
- day_boundary 子正换日;memory_save --update-chart 换盘留痕;share_export 事件简介+城市级地域
- share_push 失败诊断+代理引导;_runtime_guard;修 STAR_ORDER 三奇贵人 KeyError
- README 规则计数 541→542;manifest 重建(1275 文件);测试 142 项全绿
2026-10-10 13:13:41 +08:00

114 lines
4.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""chart_shot.py 与 cast_chart --shot:HTML → PNG 截图的分级回退与优雅失败。"""
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
SKILL_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(SKILL_ROOT / "scripts"))
import chart_shot # noqa: E402
CHROME_OK = Path(chart_shot.CHROME).is_file()
try:
import playwright # noqa: F401
PLAYWRIGHT_OK = True
except ImportError:
PLAYWRIGHT_OK = False
SHOT_OK = CHROME_OK or PLAYWRIGHT_OK
HTML = "<!DOCTYPE html><html><body><h1>命盘</h1></body></html>"
class ShootUnitTest(unittest.TestCase):
def test_missing_html_exit_2(self):
r = subprocess.run(
[sys.executable, str(SKILL_ROOT / "scripts" / "chart_shot.py"),
"/nonexistent/x.html"], capture_output=True, text=True, timeout=30)
self.assertEqual(r.returncode, 2)
self.assertIn("ERROR", r.stderr)
def test_no_tools_fails_gracefully(self):
"""playwright 与 Chrome 都不可用时:shoot 返回 None,CLI 退出码 2 并给提示。"""
with tempfile.TemporaryDirectory() as td:
html = Path(td) / "p.html"
html.write_text(HTML, encoding="utf-8")
with mock.patch.object(chart_shot, "_shot_playwright",
return_value=False), \
mock.patch.object(chart_shot, "_shot_chrome",
return_value=False):
self.assertIsNone(chart_shot.shoot(html))
self.assertFalse(html.with_suffix(".png").exists())
with mock.patch.object(sys, "argv",
["chart_shot.py", str(html)]):
with mock.patch("sys.stderr") as err:
self.assertEqual(chart_shot.main(), 2)
err.write.assert_called()
def test_content_height_bounds(self):
"""高度估算不越界:空页夹到下限,超长页夹到上限。"""
with tempfile.TemporaryDirectory() as td:
empty = Path(td) / "e.html"
empty.write_text(HTML, encoding="utf-8")
self.assertEqual(chart_shot._content_height(empty), 1300)
big = Path(td) / "b.html"
big.write_text(
'<div class="strip">' + '<div class="cell"></div>' * 5000
+ "</div>", encoding="utf-8")
self.assertEqual(chart_shot._content_height(big), 4200)
@unittest.skipUnless(SHOT_OK, "环境无 playwright 与 Chrome,跳过真实截图")
class ShootRealTest(unittest.TestCase):
def test_real_png(self):
"""真实截图:PNG 非空、宽 2200(1100 窗口 × 2 倍分辨率)。"""
import struct
with tempfile.TemporaryDirectory() as td:
html = Path(td) / "p.html"
html.write_text(HTML, encoding="utf-8")
png = chart_shot.shoot(html)
self.assertIsNotNone(png)
data = png.read_bytes()
self.assertGreater(len(data), 1000)
self.assertEqual(data[:8], b"\x89PNG\r\n\x1a\n")
w, _h = struct.unpack(">II", data[16:24])
self.assertEqual(w, 2200)
def test_cli_success(self):
with tempfile.TemporaryDirectory() as td:
html = Path(td) / "p.html"
html.write_text(HTML, encoding="utf-8")
out = Path(td) / "o.png"
r = subprocess.run(
[sys.executable, str(SKILL_ROOT / "scripts" / "chart_shot.py"),
str(html), "-o", str(out)],
capture_output=True, text=True, timeout=120)
self.assertEqual(r.returncode, 0, r.stderr)
self.assertIn(str(out), r.stdout)
self.assertGreater(out.stat().st_size, 0)
@unittest.skipUnless(SHOT_OK, "环境无 playwright 与 Chrome,跳过 --shot 端到端")
class CastShotE2ETest(unittest.TestCase):
def test_shot_flag_outputs_paths(self):
with tempfile.TemporaryDirectory() as td:
html = Path(td) / "p.html"
r = subprocess.run(
[sys.executable, str(SKILL_ROOT / "scripts" / "cast_chart.py"),
"--name", "张三", "--gender", "男", "--birth", "1990-05-14 08:30",
"--place", "四川省成都市", "--html", str(html), "--shot"],
capture_output=True, text=True, timeout=120,
cwd=str(SKILL_ROOT / "scripts"))
self.assertEqual(r.returncode, 0, r.stderr)
self.assertTrue(r.stdout.startswith("# 命盘:张三"))
self.assertIn(f"HTML 盘面:{html.resolve()}", r.stdout)
png = html.with_suffix(".png")
self.assertIn(f"盘面截图:{png.resolve()}", r.stdout)
self.assertGreater(png.stat().st_size, 0)
if __name__ == "__main__":
unittest.main()