116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
from copy import copy
|
||
|
||
from openpyxl import Workbook
|
||
from openpyxl.comments import Comment
|
||
|
||
from genesis.data_models import CellComment, CellFormatting
|
||
from genesis.parsers.formatting_detector import (
|
||
cell_comment, cell_formatting, collect_comments,
|
||
)
|
||
|
||
|
||
def make_wb():
|
||
wb = Workbook()
|
||
ws = wb.active
|
||
ws.title = "機能一覧"
|
||
ws["A1"] = "F001"
|
||
font = copy(ws["A1"].font)
|
||
font.strike = True
|
||
ws["A1"].font = font
|
||
ws["A2"] = "F002"
|
||
ws["A2"].comment = Comment("要確認", "reviewer")
|
||
return wb
|
||
|
||
|
||
def test_cell_formatting_detects_strike():
|
||
fmt = cell_formatting(make_wb().active["A1"])
|
||
assert fmt is not None
|
||
assert fmt.strikethrough is True
|
||
|
||
|
||
def test_cell_formatting_none_when_plain():
|
||
wb = Workbook()
|
||
ws = wb.active
|
||
ws["A1"] = "x"
|
||
assert cell_formatting(ws["A1"]) is None
|
||
|
||
|
||
def test_cell_formatting_detects_font_color():
|
||
from openpyxl.styles import Font
|
||
wb = Workbook()
|
||
ws = wb.active
|
||
ws["A1"] = "x"
|
||
f = copy(ws["A1"].font)
|
||
f.color = Font(color="FF0000FF").color
|
||
ws["A1"].font = f
|
||
fmt = cell_formatting(ws["A1"])
|
||
assert fmt is not None
|
||
assert fmt.font_color is not None
|
||
|
||
|
||
def test_cell_comment_returns_obj():
|
||
wb = make_wb()
|
||
cm = cell_comment(wb.active["A2"], "f.xlsx")
|
||
assert isinstance(cm, CellComment)
|
||
assert cm.author == "reviewer"
|
||
assert cm.text == "要確認"
|
||
assert cm.source_uri == "f.xlsx#機能一覧!A2"
|
||
|
||
|
||
def test_collect_comments():
|
||
comments = collect_comments(make_wb().active, "f.xlsx")
|
||
assert len(comments) == 1
|
||
|
||
|
||
def test_to_rgb_hex_accepts_6_digit_hex():
|
||
from types import SimpleNamespace
|
||
from genesis.parsers.formatting_detector import _to_rgb_hex
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="FF3333")) == "FF3333"
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="00FF00FF")) == "00FF00FF"
|
||
|
||
|
||
def test_to_rgb_hex_rejects_black_and_theme():
|
||
from types import SimpleNamespace
|
||
from genesis.parsers.formatting_detector import _to_rgb_hex
|
||
# 纯黑(默认色)与主题色(rgb 为空/异常/非 hex)→ None
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="00000000")) is None
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="FF000000")) is None
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="")) is None
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="ZZZZZZ")) is None
|
||
assert _to_rgb_hex(SimpleNamespace(rgb="FFFFF")) is None # 长度不足
|
||
|
||
|
||
class _ExplodingRgb:
|
||
@property
|
||
def rgb(self):
|
||
raise Exception("boom")
|
||
|
||
|
||
def test_to_rgb_hex_rgb_access_exception_returns_none():
|
||
from genesis.parsers.formatting_detector import _to_rgb_hex
|
||
# L15-16:color.rgb 访问抛异常 → 返回 None(防御分支)
|
||
assert _to_rgb_hex(_ExplodingRgb()) is None
|
||
|
||
|
||
def test_cell_formatting_fills_only_color():
|
||
from copy import copy
|
||
from openpyxl.styles import PatternFill
|
||
from genesis.parsers.formatting_detector import cell_formatting
|
||
wb = Workbook()
|
||
ws = wb.active
|
||
ws["A1"] = "x"
|
||
# 仅背景色(无 strikethrough / 无字体色)→ 返回 CellFormatting 含 bg_color
|
||
f = copy(ws["A1"].fill)
|
||
f.fgColor = PatternFill(start_color="00CC00").fgColor
|
||
ws["A1"].fill = f
|
||
fmt = cell_formatting(ws["A1"])
|
||
assert fmt is not None
|
||
assert fmt.bg_color is not None
|
||
|
||
|
||
def test_cell_formatting_fill_none_branch():
|
||
# 覆盖 L31 防御分支:fill 为 None(无样式对象)时直接返回 None
|
||
from types import SimpleNamespace
|
||
from genesis.parsers.formatting_detector import cell_formatting
|
||
fake = SimpleNamespace(font=SimpleNamespace(strike=False), fill=None)
|
||
assert cell_formatting(fake) is None |