v1.5.4 Bug 修复:模板文件名修正 + 布局重设计
BUG-005: 模板文件名改为 PinMAP-Template.xlsx / PinList-Template.xlsx BUG-006: 布局改为 Number 外侧 + Name 里侧(v1.5.4 最终版) - 从边界往中心:第1圈=Number,第2圈=Name - 上边角点例外处理,15种网格无冲突 - 18/18 单元测试 + 37/37 集成测试全部通过
This commit is contained in:
BIN
Test/fixtures/sample_4x4.xlsx
vendored
BIN
Test/fixtures/sample_4x4.xlsx
vendored
Binary file not shown.
@@ -84,19 +84,27 @@ def create_pinmap_fixture(data: dict, path: str):
|
||||
def test_map_to_list(r: TestRunner):
|
||||
fixture_dir = os.path.join(os.path.dirname(__file__), 'fixtures')
|
||||
|
||||
# TC-MAP-001: 标准 4x4 PinMAP 转换
|
||||
# TC-MAP-001: 标准 4x4 PinMAP 转换 (v1.5.4 布局)
|
||||
def _tc_map_001(result):
|
||||
filepath = os.path.join(fixture_dir, 'sample_4x4.xlsx')
|
||||
cells = read_xlsx_cells(filepath)
|
||||
pinmap = parse_pinmap(cells)
|
||||
validation = validate_pinmap(pinmap)
|
||||
pinlist = generate_pinlist(pinmap, validation)
|
||||
assert pinlist.package_info, "package_info 不应为空"
|
||||
assert len(pinlist.rows) > 0, "应有引脚数据"
|
||||
# 封装信息 (v1.5.4 布局)
|
||||
assert pinlist.package_info == "QFP-16", f"封装应为 QFP-16,实际: {pinlist.package_info}"
|
||||
# 引脚数 (4x4 网格: (4+4)*2 = 16)
|
||||
assert len(pinlist.rows) == 16, f"应有 16 个引脚,实际: {len(pinlist.rows)}"
|
||||
# 验证递增排序
|
||||
nums = [num for _, num in pinlist.rows]
|
||||
assert nums == sorted(nums), f"序号应递增,实际: {nums}"
|
||||
result.ok(f"封装={pinlist.package_info}, Pin数={len(pinlist.rows)}, 序号递增")
|
||||
assert nums == list(range(1, 17)), f"序号应为 1-16,实际: {nums}"
|
||||
# 验证引脚名不是数字(确保 Name/Number 未错位)
|
||||
names = [name for name, _ in pinlist.rows]
|
||||
for name in names:
|
||||
assert not name.isdigit(), f"引脚名 '{name}' 不应为纯数字"
|
||||
assert all(name.startswith("Pin") for name in names), f"所有引脚名应以 Pin 开头: {names}"
|
||||
result.ok(f"封装={pinlist.package_info}, Pin数={len(pinlist.rows)}, 序号 1-16, 引脚名=Pin1..Pin16")
|
||||
|
||||
r.run("TC-MAP-001: 标准4x4 PinMAP转换", _tc_map_001)
|
||||
|
||||
@@ -570,19 +578,19 @@ def test_v15_styles(r: TestRunner):
|
||||
from xlsx_writer import write_xlsx_with_style
|
||||
|
||||
try:
|
||||
# ── TC-v1.5-001: MAP→List 加载 BallList 模板 ──
|
||||
# ── TC-v1.5-001: MAP→List 加载 PinList 模板 ──
|
||||
def _tc_v15_001(result):
|
||||
template_path = os.path.join(fixture_dir, 'BallList-Template.xlsx')
|
||||
assert os.path.exists(template_path), f"BallList 模板文件不存在: {template_path}"
|
||||
template_path = os.path.join(fixture_dir, 'PinList-Template.xlsx')
|
||||
assert os.path.exists(template_path), f"PinList 模板文件不存在: {template_path}"
|
||||
|
||||
style = read_template_styles(template_path)
|
||||
assert style is not None, "BallList 模板样式应成功读取"
|
||||
assert style is not None, "PinList 模板样式应成功读取"
|
||||
assert len(style.fonts) > 0, "应有字体定义"
|
||||
assert len(style.borders) > 0, "应有边框定义"
|
||||
assert 0 in style.column_widths, "应有列宽定义"
|
||||
result.ok(f"模板加载成功: fonts={len(style.fonts)}, borders={len(style.borders)}, width_A={style.column_widths.get(0)}")
|
||||
|
||||
r.run("TC-v1.5-001: MAP->List 加载 BallList 模板", _tc_v15_001)
|
||||
r.run("TC-v1.5-001: MAP->List 加载 PinList 模板", _tc_v15_001)
|
||||
|
||||
# ── TC-v1.5-002: MAP→List 无模板降级 ──
|
||||
def _tc_v15_002(result):
|
||||
@@ -592,19 +600,19 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
r.run("TC-v1.5-002: MAP->List 无模板降级", _tc_v15_002)
|
||||
|
||||
# ── TC-v1.5-003: List→MAP 加载 BallMAP 模板 ──
|
||||
# ── TC-v1.5-003: List→MAP 加载 PinMAP 模板 ──
|
||||
def _tc_v15_003(result):
|
||||
template_path = os.path.join(fixture_dir, 'BallMAP-Template.xlsx')
|
||||
assert os.path.exists(template_path), f"BallMAP 模板文件不存在: {template_path}"
|
||||
template_path = os.path.join(fixture_dir, 'PinMAP-Template.xlsx')
|
||||
assert os.path.exists(template_path), f"PinMAP 模板文件不存在: {template_path}"
|
||||
|
||||
style = read_template_styles(template_path)
|
||||
assert style is not None, "BallMAP 模板样式应成功读取"
|
||||
assert style is not None, "PinMAP 模板样式应成功读取"
|
||||
assert len(style.fonts) > 0, "应有字体定义"
|
||||
assert len(style.borders) > 0, "应有边框定义"
|
||||
assert 0 in style.row_heights, "应有行高定义"
|
||||
result.ok(f"模板加载成功: fonts={len(style.fonts)}, borders={len(style.borders)}, row_height={style.row_heights.get(0)}")
|
||||
|
||||
r.run("TC-v1.5-003: List->MAP 加载 BallMAP 模板", _tc_v15_003)
|
||||
r.run("TC-v1.5-003: List->MAP 加载 PinMAP 模板", _tc_v15_003)
|
||||
|
||||
# ── TC-v1.5-004: List→MAP 无模板降级 ──
|
||||
def _tc_v15_004(result):
|
||||
@@ -616,19 +624,19 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
# ── TC-v1.5-005: 两个方向独立使用各自模板 ──
|
||||
def _tc_v15_005(result):
|
||||
bl_path = os.path.join(fixture_dir, 'BallList-Template.xlsx')
|
||||
bm_path = os.path.join(fixture_dir, 'BallMAP-Template.xlsx')
|
||||
bl_path = os.path.join(fixture_dir, 'PinList-Template.xlsx')
|
||||
bm_path = os.path.join(fixture_dir, 'PinMAP-Template.xlsx')
|
||||
|
||||
style_bl = read_template_styles(bl_path)
|
||||
style_bm = read_template_styles(bm_path)
|
||||
|
||||
assert style_bl is not None, "BallList 模板应成功加载"
|
||||
assert style_bm is not None, "BallMAP 模板应成功加载"
|
||||
assert style_bl is not None, "PinList 模板应成功加载"
|
||||
assert style_bm is not None, "PinMAP 模板应成功加载"
|
||||
|
||||
# BallList 有列宽,BallMAP 有行高
|
||||
assert 0 in style_bl.column_widths, "BallList 应有列宽"
|
||||
assert 0 in style_bm.row_heights, "BallMAP 应有行高"
|
||||
result.ok(f"两个模板独立: BL fonts={len(style_bl.fonts)}, BM fonts={len(style_bm.fonts)}")
|
||||
# PinList 有列宽,PinMAP 有行高
|
||||
assert 0 in style_bl.column_widths, "PinList 应有列宽"
|
||||
assert 0 in style_bm.row_heights, "PinMAP 应有行高"
|
||||
result.ok(f"两个模板独立: PL fonts={len(style_bl.fonts)}, PM fonts={len(style_bm.fonts)}")
|
||||
|
||||
r.run("TC-v1.5-005: 两个方向独立使用各自模板", _tc_v15_005)
|
||||
|
||||
@@ -645,7 +653,7 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
# ── TC-v1.5-007: 模板字体应用到输出文件 ──
|
||||
def _tc_v15_007(result):
|
||||
template_path = os.path.join(fixture_dir, 'BallMAP-Template.xlsx')
|
||||
template_path = os.path.join(fixture_dir, 'PinMAP-Template.xlsx')
|
||||
style = read_template_styles(template_path)
|
||||
|
||||
assert style is not None, "模板样式应成功读取"
|
||||
@@ -669,7 +677,7 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
# ── TC-v1.5-008: 模板列宽应用到输出文件 ──
|
||||
def _tc_v15_008(result):
|
||||
template_path = os.path.join(fixture_dir, 'BallList-Template.xlsx')
|
||||
template_path = os.path.join(fixture_dir, 'PinList-Template.xlsx')
|
||||
style = read_template_styles(template_path)
|
||||
assert style is not None, "模板样式应成功读取"
|
||||
|
||||
@@ -700,7 +708,7 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
# ── TC-v1.5-009: 模板行高应用到输出文件 ──
|
||||
def _tc_v15_009(result):
|
||||
template_path = os.path.join(fixture_dir, 'BallMAP-Template.xlsx')
|
||||
template_path = os.path.join(fixture_dir, 'PinMAP-Template.xlsx')
|
||||
style = read_template_styles(template_path)
|
||||
assert style is not None, "模板样式应成功读取"
|
||||
|
||||
@@ -732,19 +740,19 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
# ── TC-v1.5-010: 两个方向使用不同模板各自的格式 ──
|
||||
def _tc_v15_010(result):
|
||||
bl_path = os.path.join(fixture_dir, 'BallList-Template.xlsx')
|
||||
bm_path = os.path.join(fixture_dir, 'BallMAP-Template.xlsx')
|
||||
bl_path = os.path.join(fixture_dir, 'PinList-Template.xlsx')
|
||||
bm_path = os.path.join(fixture_dir, 'PinMAP-Template.xlsx')
|
||||
|
||||
style_bl = read_template_styles(bl_path)
|
||||
style_bm = read_template_styles(bm_path)
|
||||
assert style_bl and style_bm, "两个模板都应该成功加载"
|
||||
|
||||
# MAP->List 方向:用 BallList 模板
|
||||
# MAP->List 方向:用 PinList 模板
|
||||
pinlist_data = {'A1': 'QFP-44', 'A2': 'Pin1', 'B2': '1'}
|
||||
pinlist_path = os.path.join(tmpdir, 'v15_010_pinlist.xlsx')
|
||||
write_xlsx_with_style(pinlist_data, pinlist_path, style_bl)
|
||||
|
||||
# List->MAP 方向:用 BallMAP 模板
|
||||
# List->MAP 方向:用 PinMAP 模板
|
||||
entries = [PinListEntry(number=i+1, name=f"PIN{i+1:02d}") for i in range(12)]
|
||||
pinmap_path = os.path.join(tmpdir, 'v15_010_pinmap.xlsx')
|
||||
generate_pinmap(entries, 3, 3, "QFP-12", template_style=style_bm, output_path=pinmap_path)
|
||||
@@ -755,17 +763,17 @@ def test_v15_styles(r: TestRunner):
|
||||
with zipfile.ZipFile(pinmap_path, 'r') as zf:
|
||||
pm_styles = zf.read('xl/styles.xml').decode('utf-8')
|
||||
|
||||
assert '楷体' in pl_styles, "BallList 输出应包含楷体"
|
||||
assert '宋体' in pm_styles, "BallMAP 输出应包含宋体"
|
||||
assert '楷体' in pl_styles, "PinList 输出应包含楷体"
|
||||
assert '宋体' in pm_styles, "PinMAP 输出应包含宋体"
|
||||
|
||||
result.ok("两个方向输出字体不同: BL->楷体, BM->宋体")
|
||||
result.ok("两个方向输出字体不同: PinList->楷体, PinMAP->宋体")
|
||||
|
||||
r.run("TC-v1.5-010: 两个方向不同模板各自的格式", _tc_v15_010)
|
||||
|
||||
# ── TC-v1.5-011: 完整往返+模板隔离 ──
|
||||
# ── TC-v1.5-011: 完整往返+模板隔离 (4×4 网格) ──
|
||||
def _tc_v15_011(result):
|
||||
bl_path = os.path.join(fixture_dir, 'BallList-Template.xlsx')
|
||||
bm_path = os.path.join(fixture_dir, 'BallMAP-Template.xlsx')
|
||||
bl_path = os.path.join(fixture_dir, 'PinList-Template.xlsx')
|
||||
bm_path = os.path.join(fixture_dir, 'PinMAP-Template.xlsx')
|
||||
|
||||
style_bl = read_template_styles(bl_path)
|
||||
style_bm = read_template_styles(bm_path)
|
||||
@@ -786,7 +794,8 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
pkg2, entries2 = parse_pinlist(pinlist_path)
|
||||
pinmap_path = os.path.join(tmpdir, 'v15_011_pinmap.xlsx')
|
||||
generate_pinmap(entries2, 3, 3, pkg2, template_style=style_bm, output_path=pinmap_path)
|
||||
# 4×4 网格: (4+4)×2 = 16 引脚
|
||||
generate_pinmap(entries2, 4, 4, pkg2, template_style=style_bm, output_path=pinmap_path)
|
||||
|
||||
rt_cells = read_xlsx_cells(pinmap_path)
|
||||
rt_pinmap = parse_pinmap(rt_cells)
|
||||
@@ -800,8 +809,8 @@ def test_v15_styles(r: TestRunner):
|
||||
pl_xml = zf.read('xl/styles.xml').decode('utf-8')
|
||||
with zipfile.ZipFile(pinmap_path, 'r') as zf:
|
||||
pm_xml = zf.read('xl/styles.xml').decode('utf-8')
|
||||
assert '楷体' in pl_xml, "中间 PinList 应使用 BallList 的楷体"
|
||||
assert '宋体' in pm_xml, "最终 PinMAP 应使用 BallMAP 的宋体"
|
||||
assert '楷体' in pl_xml, "中间 PinList 应使用 PinList 模板的楷体"
|
||||
assert '宋体' in pm_xml, "最终 PinMAP 应使用 PinMAP 模板的宋体"
|
||||
|
||||
result.ok(f"往返成功: {len(pinmap.pins)} pins, 楷体->PinList, 宋体->PinMAP")
|
||||
|
||||
@@ -828,7 +837,8 @@ def test_v15_styles(r: TestRunner):
|
||||
|
||||
pkg2, entries2 = parse_pinlist(pinlist_path)
|
||||
pinmap_path = os.path.join(tmpdir, 'v15_012_pinmap.xlsx')
|
||||
generate_pinmap(entries2, 3, 3, pkg2, template_style=None, output_path=pinmap_path)
|
||||
# sample_4x4 有 16 pins,需用 4×4 网格
|
||||
generate_pinmap(entries2, 4, 4, pkg2, template_style=None, output_path=pinmap_path)
|
||||
assert os.path.exists(pinmap_path), "PinMAP 输出文件应存在"
|
||||
|
||||
result.ok("无模板完整流程正常")
|
||||
|
||||
@@ -1,51 +1,19 @@
|
||||
# PinMAP ↔ PinList 双向转换器 测试报告 (v1.5.0)
|
||||
# PinMAP ↔ PinList 双向转换器 测试报告
|
||||
|
||||
> **版本**: v1.5.0
|
||||
> **日期**: 2026-06-06
|
||||
> **测试类型**: 单元测试 + 集成测试 + 端到端测试
|
||||
> **日期**: 2026-06-09
|
||||
> **测试类型**: 集成测试 + 端到端测试
|
||||
> **测试环境**: Python 3.x, Linux x64
|
||||
|
||||
---
|
||||
|
||||
## v1.5.0 变更覆盖
|
||||
|
||||
v1.5.0 引入三项核心变更:
|
||||
- **F009**: MAP→List 使用 BallList-Template.xlsx(独立模板)
|
||||
- **F010**: List→MAP 使用 BallMAP-Template.xlsx(独立模板)
|
||||
- **F011**: 模板格式提取式应用(字体/边框/填充/对齐/列宽/行高)
|
||||
- **F012**: PinName 位置确认(bottom=max_row-1, top=min_row+1)
|
||||
|
||||
## 测试覆盖矩阵
|
||||
|
||||
| 特性 | 单元测试 | 集成测试 | 状态 |
|
||||
|------|---------|---------|------|
|
||||
| F009 — BallList 模板加载 | ✅ `test_template_path_generation` | ✅ TC-v1.5-001/002/005 | ✅ |
|
||||
| F010 — BallMAP 模板加载 | ✅ `test_template_path_generation` | ✅ TC-v1.5-003/004/005 | ✅ |
|
||||
| F011 — 模板字体应用 | ✅ `test_f011_template_fonts_in_styles_xml` | ✅ TC-v1.5-007/010/013 | ✅ |
|
||||
| F011 — 模板边框应用 | ✅ `test_f011_template_borders_in_styles_xml` | ✅ TC-v1.5-007/010 | ✅ |
|
||||
| F011 — 模板填充应用 | ✅ `test_f011_template_fills_in_styles_xml` | ✅ TC-v1.5-010 | ✅ |
|
||||
| F011 — 默认样式降级 | ✅ `test_f011_default_styles_xml` | ✅ TC-v1.5-002/004/012 | ✅ |
|
||||
| F011 — 输出 dim 由 Pin 决定 | ✅ `test_f011_output_dims_determined_by_pins` | ✅ TC-v1.5-014 | ✅ |
|
||||
| F011 — 列宽应用 | — | ✅ TC-v1.5-008/014 | ✅ |
|
||||
| F011 — 行高应用 | — | ✅ TC-v1.5-009 | ✅ |
|
||||
| F012 — PinName 位置 | ✅ `test_f012_pinname_position` | — | ✅ |
|
||||
| 损坏模板优雅降级 | — | ✅ TC-v1.5-006 | ✅ |
|
||||
| 极简模板 | — | ✅ TC-v1.5-013 | ✅ |
|
||||
| 无模板完整流程 | — | ✅ TC-v1.5-012 | ✅ |
|
||||
| 完整往返+模板隔离 | — | ✅ TC-v1.5-011 | ✅ |
|
||||
| 空 fonts/样式回退 | ✅ `test_template_empty_fonts_fallback` | — | ✅ |
|
||||
| FF 颜色前缀补全 | ✅ `test_template_color_prefix_auto_fix` | — | ✅ |
|
||||
| 缺失 styles.xml 降级 | ✅ `test_template_no_styles_xml` | — | ✅ |
|
||||
|
||||
## 测试概览
|
||||
|
||||
| 类别 | 用例数 | 通过 | 失败 |
|
||||
|------|--------|------|------|
|
||||
| 单元测试 (test_pinmap.py) | **18** | **18** | **0** |
|
||||
| MAP->List 回归 | 6 | 6 | 0 |
|
||||
| List->MAP 新增 | 17 | 17 | 0 |
|
||||
| v1.5 模板/样式集成 | 14 | 14 | 0 |
|
||||
| **总计** | **55** | **55** | **0** |
|
||||
| **总计** | **37** | **37** | **0** |
|
||||
|
||||
---
|
||||
|
||||
@@ -53,7 +21,7 @@ v1.5.0 引入三项核心变更:
|
||||
|
||||
### TC-MAP-001: 标准4x4 PinMAP转换
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 封装=QFP12, Pin数=12, 序号递增
|
||||
- **详情**: 封装=QFP-16, Pin数=16, 序号 1-16, 引脚名=Pin1..Pin16
|
||||
|
||||
### TC-MAP-002: 长方形PinMAP转换
|
||||
- **结果**: ✅ 通过
|
||||
@@ -147,7 +115,7 @@ v1.5.0 引入三项核心变更:
|
||||
|
||||
## Part 3: v1.5 模板/样式集成测试
|
||||
|
||||
### TC-v1.5-001: MAP->List 加载 BallList 模板
|
||||
### TC-v1.5-001: MAP->List 加载 PinList 模板
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 模板加载成功: fonts=2, borders=2, width_A=25.0
|
||||
|
||||
@@ -155,7 +123,7 @@ v1.5.0 引入三项核心变更:
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 无模板文件时优雅返回 None
|
||||
|
||||
### TC-v1.5-003: List->MAP 加载 BallMAP 模板
|
||||
### TC-v1.5-003: List->MAP 加载 PinMAP 模板
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 模板加载成功: fonts=2, borders=2, row_height=25.0
|
||||
|
||||
@@ -165,7 +133,7 @@ v1.5.0 引入三项核心变更:
|
||||
|
||||
### TC-v1.5-005: 两个方向独立使用各自模板
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 两个模板独立: BL fonts=2, BM fonts=2
|
||||
- **详情**: 两个模板独立: PL fonts=2, PM fonts=2
|
||||
|
||||
### TC-v1.5-006: 模板损坏优雅降级
|
||||
- **结果**: ✅ 通过
|
||||
@@ -185,11 +153,11 @@ v1.5.0 引入三项核心变更:
|
||||
|
||||
### TC-v1.5-010: 两个方向不同模板各自的格式
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 两个方向输出字体不同: BL->楷体, BM->宋体
|
||||
- **详情**: 两个方向输出字体不同: PinList->楷体, PinMAP->宋体
|
||||
|
||||
### TC-v1.5-011: 完整往返+模板隔离
|
||||
- **结果**: ✅ 通过
|
||||
- **详情**: 往返成功: 12 pins, 楷体->PinList, 宋体->PinMAP
|
||||
- **详情**: 往返成功: 16 pins, 楷体->PinList, 宋体->PinMAP
|
||||
|
||||
### TC-v1.5-012: 无模板完整流程
|
||||
- **结果**: ✅ 通过
|
||||
|
||||
Reference in New Issue
Block a user