chore: v1.5.0 - 提交测试代码、测试报告,更新 tasks.md 状态
This commit is contained in:
@@ -363,6 +363,227 @@ def test_f012_pinname_position():
|
||||
print(f"✓ test_f012_pinname_position passed (5×5={len(pm.pins)} pins)")
|
||||
|
||||
|
||||
# ── v1.5: Template path generation tests ──────────────────────────
|
||||
|
||||
def test_template_path_generation():
|
||||
"""验证两个模板查找函数返回正确的路径格式。"""
|
||||
from main import _find_balllist_template_path, _find_ballmap_template_path
|
||||
|
||||
result1 = _find_balllist_template_path()
|
||||
result2 = _find_ballmap_template_path()
|
||||
|
||||
# 返回值要么是 str 要么是 None
|
||||
assert result1 is None or isinstance(result1, str)
|
||||
assert result2 is None or isinstance(result2, str)
|
||||
# 两者应该是不同路径
|
||||
if result1 and result2:
|
||||
assert "BallList" in result1
|
||||
assert "BallMAP" in result2
|
||||
assert result1 != result2
|
||||
|
||||
print("✓ test_template_path_generation passed")
|
||||
|
||||
|
||||
def test_f011_default_styles_xml():
|
||||
"""F011: 无模板时 _styles_xml() 返回硬编码默认样式。"""
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
writer = StyledXLSXWriter(style=None)
|
||||
xml = writer._styles_xml()
|
||||
|
||||
# 验证硬编码默认值的存在
|
||||
assert 'Calibri' in xml, "默认字体应为 Calibri"
|
||||
assert 'thin' in xml, "默认边框应为 thin"
|
||||
assert 'center' in xml, "默认对齐应为 center"
|
||||
assert 'cellXfs count="4"' in xml, "应有 4 个 xf"
|
||||
|
||||
print("✓ test_f011_default_styles_xml passed")
|
||||
|
||||
|
||||
def test_f011_template_fonts_in_styles_xml():
|
||||
"""F011: 有模板时 _styles_xml() 使用模板的字体信息。"""
|
||||
from template_reader import TemplateStyle, FontStyle
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
# 构建一个模板样式:微软雅黑 12pt
|
||||
style = TemplateStyle()
|
||||
style.fonts = [
|
||||
FontStyle(name="微软雅黑", size=12.0, bold=False, italic=False, color="FF000000"),
|
||||
FontStyle(name="微软雅黑", size=12.0, bold=True, italic=False, color="FF000000"),
|
||||
]
|
||||
style.fills = []
|
||||
style.borders = []
|
||||
style.cell_xfs = [
|
||||
{'numFmtId': '0', 'fontId': '0', 'fillId': '0', 'borderId': '0', 'xfId': '0'},
|
||||
]
|
||||
|
||||
writer = StyledXLSXWriter(style=style)
|
||||
xml = writer._styles_xml()
|
||||
|
||||
assert '微软雅黑' in xml, f"模板字体名应出现在 styles.xml 中\n{xml[:500]}"
|
||||
assert '12' in xml or '12.0' in xml, f"模板字号 12pt 应出现在 styles.xml 中"
|
||||
|
||||
print("✓ test_f011_template_fonts_in_styles_xml passed")
|
||||
|
||||
|
||||
def test_f011_output_dims_determined_by_pins():
|
||||
"""F011: 输出文件的 dim 由实际 Pin 数量决定,不复制模板的行列结构。"""
|
||||
from template_reader import TemplateStyle, FontStyle
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
style = TemplateStyle()
|
||||
style.fonts = [FontStyle(name="Calibri", size=11.0)]
|
||||
style.column_widths = {i: 20.0 for i in range(100)} # 模板有 100 列
|
||||
style.row_heights = {i: 30.0 for i in range(200)} # 模板有 200 行
|
||||
style.fills = []
|
||||
style.borders = []
|
||||
style.cell_xfs = [
|
||||
{'numFmtId': '0', 'fontId': '0', 'fillId': '0', 'borderId': '0', 'xfId': '0'},
|
||||
]
|
||||
|
||||
# 仅输出 2 行 2 列的数据(模拟 2×2 PinMAP + A1)
|
||||
data = {
|
||||
'A1': 'QFP-8',
|
||||
'A2': '1', 'B2': 'Pin1',
|
||||
'A3': '2', 'B3': 'Pin2',
|
||||
}
|
||||
|
||||
writer = StyledXLSXWriter(style=style)
|
||||
sheet_xml = writer._sheet_xml(data)
|
||||
|
||||
# dim 应该反映实际数据范围(A1:B3),而非模板的 100 列
|
||||
assert 'dimension ref="A1:B3"' in sheet_xml, \
|
||||
f"dim 应由实际数据决定,不应包含模板的 100 列\n{sheet_xml[:500]}"
|
||||
|
||||
# 不应出现 row r="201"(模板的第 200 行)
|
||||
assert 'row r="201"' not in sheet_xml, "不应包含模板的多余行"
|
||||
|
||||
print("✓ test_f011_output_dims_determined_by_pins passed")
|
||||
|
||||
|
||||
def test_f011_template_borders_in_styles_xml():
|
||||
"""F011: 有模板时 _styles_xml() 使用模板的边框样式(而非硬编码 thin)。"""
|
||||
from template_reader import TemplateStyle, BorderStyle, FontStyle
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
style = TemplateStyle()
|
||||
style.fonts = [FontStyle(name="Calibri", size=11.0)]
|
||||
style.borders = [
|
||||
BorderStyle(top="none", bottom="none", left="none", right="none"),
|
||||
BorderStyle(top="medium", bottom="medium", left="medium", right="medium"),
|
||||
]
|
||||
style.fills = []
|
||||
style.cell_xfs = [
|
||||
{'numFmtId': '0', 'fontId': '0', 'fillId': '0', 'borderId': '1', 'xfId': '0',
|
||||
'applyBorder': '1'},
|
||||
]
|
||||
|
||||
writer = StyledXLSXWriter(style=style)
|
||||
xml = writer._styles_xml()
|
||||
|
||||
# 模板的 medium 边框应该存在(不仅仅是 thin)
|
||||
assert 'medium' in xml, f"模板 medium 边框应出现在 styles.xml 中\n{xml[:800]}"
|
||||
|
||||
print("✓ test_f011_template_borders_in_styles_xml passed")
|
||||
|
||||
|
||||
def test_f011_template_fills_in_styles_xml():
|
||||
"""F011: 有模板时 _styles_xml() 使用模板的填充色。"""
|
||||
from template_reader import TemplateStyle, FillStyle, FontStyle
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
style = TemplateStyle()
|
||||
style.fonts = [FontStyle(name="Calibri", size=11.0)]
|
||||
style.borders = []
|
||||
style.fills = [
|
||||
FillStyle(pattern_type="none", fg_color=""),
|
||||
FillStyle(pattern_type="solid", fg_color="FFFF00"), # 黄色
|
||||
]
|
||||
style.cell_xfs = [
|
||||
{'numFmtId': '0', 'fontId': '0', 'fillId': '0', 'borderId': '0', 'xfId': '0'},
|
||||
{'numFmtId': '0', 'fontId': '0', 'fillId': '1', 'borderId': '0', 'xfId': '0',
|
||||
'applyFill': '1'},
|
||||
]
|
||||
|
||||
writer = StyledXLSXWriter(style=style)
|
||||
xml = writer._styles_xml()
|
||||
|
||||
assert 'FFFF00' in xml, f"模板黄色填充应出现在 styles.xml 中\n{xml[:800]}"
|
||||
|
||||
print("✓ test_f011_template_fills_in_styles_xml passed")
|
||||
|
||||
|
||||
def test_template_empty_fonts_fallback():
|
||||
"""边界测试:空 fonts 回退到默认字体。"""
|
||||
from template_reader import TemplateStyle
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
style = TemplateStyle()
|
||||
style.fonts = [] # 空 fonts
|
||||
style.fills = []
|
||||
style.borders = []
|
||||
style.cell_xfs = []
|
||||
|
||||
writer = StyledXLSXWriter(style=style)
|
||||
xml = writer._styles_xml()
|
||||
|
||||
# 应回退到默认样式:Calibri 11pt
|
||||
assert 'Calibri' in xml, "空 fonts 应回退到默认 Calibri"
|
||||
assert 'thin' in xml, "空 borders 应回退到默认 thin"
|
||||
assert 'cellXfs count="4"' in xml, "应有 4 个 xf"
|
||||
|
||||
print("✓ test_template_empty_fonts_fallback passed")
|
||||
|
||||
|
||||
def test_template_color_prefix_auto_fix():
|
||||
"""边界测试:FF 前缀补全。"""
|
||||
from template_reader import TemplateStyle, FontStyle, FillStyle
|
||||
from xlsx_writer import StyledXLSXWriter
|
||||
|
||||
style = TemplateStyle()
|
||||
# color 缺少 FF 前缀
|
||||
style.fonts = [FontStyle(name="Calibri", size=11.0, color="000000")]
|
||||
style.fills = [
|
||||
FillStyle(pattern_type="none"),
|
||||
FillStyle(pattern_type="solid", fg_color="FFFF00"), # 已有 FF
|
||||
]
|
||||
style.borders = []
|
||||
style.cell_xfs = [
|
||||
{'numFmtId': '0', 'fontId': '0', 'fillId': '0', 'borderId': '0', 'xfId': '0'},
|
||||
]
|
||||
|
||||
writer = StyledXLSXWriter(style=style)
|
||||
xml = writer._styles_xml()
|
||||
|
||||
# 即使原始 color 是 "000000",输出也应是 "FF000000"
|
||||
assert 'FF000000' in xml, f"color 应自动补全 FF 前缀\n{xml[:800]}"
|
||||
|
||||
print("✓ test_template_color_prefix_auto_fix passed")
|
||||
|
||||
|
||||
def test_template_no_styles_xml():
|
||||
"""边界测试:缺失 styles.xml 时优雅降级。"""
|
||||
from template_reader import read_template_styles
|
||||
import tempfile, os
|
||||
import zipfile
|
||||
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
bad_path = os.path.join(tmpdir, "no_styles.xlsx")
|
||||
with zipfile.ZipFile(bad_path, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||||
zf.writestr('[Content_Types].xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/xml"/></Types>')
|
||||
zf.writestr('xl/worksheets/sheet1.xml', '<?xml version="1.0"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData/></worksheet>')
|
||||
|
||||
style = read_template_styles(bad_path)
|
||||
assert style is not None, "缺失 styles.xml 不应导致 read_template_styles 返回 None"
|
||||
assert len(style.fonts) == 0, "无 styles.xml,font 列表应为空"
|
||||
assert len(style.fills) == 0, "无 styles.xml,fill 列表应为空"
|
||||
print("✓ test_template_no_styles_xml passed")
|
||||
finally:
|
||||
import shutil
|
||||
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_4x4_parse()
|
||||
test_4x4_validate()
|
||||
@@ -373,4 +594,14 @@ if __name__ == "__main__":
|
||||
test_no_pins()
|
||||
test_12pin_square()
|
||||
test_f012_pinname_position()
|
||||
# v1.5 新增测试
|
||||
test_template_path_generation()
|
||||
test_f011_default_styles_xml()
|
||||
test_f011_template_fonts_in_styles_xml()
|
||||
test_f011_output_dims_determined_by_pins()
|
||||
test_f011_template_borders_in_styles_xml()
|
||||
test_f011_template_fills_in_styles_xml()
|
||||
test_template_empty_fonts_fallback()
|
||||
test_template_color_prefix_auto_fix()
|
||||
test_template_no_styles_xml()
|
||||
print("\n✅ All tests passed!")
|
||||
|
||||
Reference in New Issue
Block a user