305 lines
9.1 KiB
Python
305 lines
9.1 KiB
Python
|
|
"""
|
|||
|
|
测试文档索引处理的变更
|
|||
|
|
文件: src/knowledge/indexing.py
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
project_root = Path(__file__).parent.parent
|
|||
|
|
sys.path.insert(0, str(project_root))
|
|||
|
|
|
|||
|
|
import pytest
|
|||
|
|
import pandas as pd
|
|||
|
|
from openpyxl import Workbook
|
|||
|
|
from src.knowledge.indexing import process_file_to_markdown, _make_unique_columns
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestMakeUniqueColumns:
|
|||
|
|
"""测试新增的 _make_unique_columns 函数"""
|
|||
|
|
|
|||
|
|
def test_no_duplicates(self):
|
|||
|
|
"""测试没有重复列名的情况"""
|
|||
|
|
columns = ["列A", "列B", "列C", "列D"]
|
|||
|
|
result = _make_unique_columns(columns)
|
|||
|
|
|
|||
|
|
assert result == columns
|
|||
|
|
print(f"✓ 无重复列名处理正确: {result}")
|
|||
|
|
|
|||
|
|
def test_with_duplicates(self):
|
|||
|
|
"""测试有重复列名的情况"""
|
|||
|
|
columns = ["姓名", "年龄", "姓名", "地址", "年龄", "姓名"]
|
|||
|
|
result = _make_unique_columns(columns)
|
|||
|
|
|
|||
|
|
expected = ["姓名", "年龄", "姓名_2", "地址", "年龄_2", "姓名_3"]
|
|||
|
|
assert result == expected
|
|||
|
|
print(f"✓ 重复列名处理正确: {result}")
|
|||
|
|
|
|||
|
|
def test_with_none_values(self):
|
|||
|
|
"""测试包含 None 值的列名"""
|
|||
|
|
columns = ["A", None, "B", None, "C"]
|
|||
|
|
result = _make_unique_columns(columns)
|
|||
|
|
|
|||
|
|
assert result[0] == "A"
|
|||
|
|
assert result[1] == "Unnamed"
|
|||
|
|
assert result[2] == "B"
|
|||
|
|
assert result[3] == "Unnamed_2"
|
|||
|
|
assert result[4] == "C"
|
|||
|
|
print(f"✓ None 值处理正确: {result}")
|
|||
|
|
|
|||
|
|
def test_with_empty_strings(self):
|
|||
|
|
"""测试包含空字符串的列名"""
|
|||
|
|
columns = ["A", "", "B", " ", "C"]
|
|||
|
|
result = _make_unique_columns(columns)
|
|||
|
|
|
|||
|
|
# 空字符串应该被转换为 "Unnamed"
|
|||
|
|
assert result[0] == "A"
|
|||
|
|
assert result[1] == "Unnamed"
|
|||
|
|
assert result[2] == "B"
|
|||
|
|
assert result[3] == "Unnamed_2"
|
|||
|
|
assert result[4] == "C"
|
|||
|
|
print(f"✓ 空字符串处理正确: {result}")
|
|||
|
|
|
|||
|
|
def test_empty_list(self):
|
|||
|
|
"""测试空列表"""
|
|||
|
|
columns = []
|
|||
|
|
result = _make_unique_columns(columns)
|
|||
|
|
|
|||
|
|
assert result == []
|
|||
|
|
print(f"✓ 空列表处理正确")
|
|||
|
|
|
|||
|
|
def test_all_same_names(self):
|
|||
|
|
"""测试所有列名相同的情况"""
|
|||
|
|
columns = ["数据", "数据", "数据", "数据"]
|
|||
|
|
result = _make_unique_columns(columns)
|
|||
|
|
|
|||
|
|
expected = ["数据", "数据_2", "数据_3", "数据_4"]
|
|||
|
|
assert result == expected
|
|||
|
|
print(f"✓ 全部相同列名处理正确: {result}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestExcelProcessingChanges:
|
|||
|
|
"""测试 Excel 处理逻辑的变更"""
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_excel_basic_processing(self, tmp_path):
|
|||
|
|
"""测试基础 Excel 处理"""
|
|||
|
|
# 创建测试 Excel 文件
|
|||
|
|
test_file = tmp_path / "test_basic.xlsx"
|
|||
|
|
wb = Workbook()
|
|||
|
|
ws = wb.active
|
|||
|
|
ws.title = "测试表"
|
|||
|
|
|
|||
|
|
# 添加表头
|
|||
|
|
ws["A1"] = "姓名"
|
|||
|
|
ws["B1"] = "年龄"
|
|||
|
|
ws["C1"] = "城市"
|
|||
|
|
|
|||
|
|
# 添加数据
|
|||
|
|
data = [
|
|||
|
|
["张三", 25, "北京"],
|
|||
|
|
["李四", 30, "上海"],
|
|||
|
|
["王五", 28, "广州"],
|
|||
|
|
]
|
|||
|
|
for i, row in enumerate(data, start=2):
|
|||
|
|
for j, value in enumerate(row, start=1):
|
|||
|
|
ws.cell(row=i, column=j, value=value)
|
|||
|
|
|
|||
|
|
wb.save(test_file)
|
|||
|
|
|
|||
|
|
# 处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果
|
|||
|
|
assert result is not None
|
|||
|
|
assert "测试表" in result
|
|||
|
|
assert "表格标题" in result # 新增的标题列
|
|||
|
|
assert "姓名" in result
|
|||
|
|
assert "张三" in result
|
|||
|
|
print(f"✓ 基础 Excel 处理成功")
|
|||
|
|
print(f"处理结果预览:\n{result[:300]}...")
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_excel_merged_cells(self, tmp_path):
|
|||
|
|
"""测试包含合并单元格的 Excel 处理"""
|
|||
|
|
test_file = tmp_path / "test_merged.xlsx"
|
|||
|
|
wb = Workbook()
|
|||
|
|
ws = wb.active
|
|||
|
|
ws.title = "合并单元格测试"
|
|||
|
|
|
|||
|
|
# 添加表头
|
|||
|
|
ws["A1"] = "部门"
|
|||
|
|
ws["B1"] = "员工"
|
|||
|
|
ws["C1"] = "工资"
|
|||
|
|
|
|||
|
|
# 添加数据并合并单元格
|
|||
|
|
ws["A2"] = "技术部"
|
|||
|
|
ws.merge_cells("A2:A4") # 合并 A2:A4
|
|||
|
|
|
|||
|
|
ws["B2"] = "员工1"
|
|||
|
|
ws["B3"] = "员工2"
|
|||
|
|
ws["B4"] = "员工3"
|
|||
|
|
|
|||
|
|
ws["C2"] = 10000
|
|||
|
|
ws["C3"] = 12000
|
|||
|
|
ws["C4"] = 11000
|
|||
|
|
|
|||
|
|
wb.save(test_file)
|
|||
|
|
|
|||
|
|
# 处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果 - 合并单元格的值应该填充到所有单元格
|
|||
|
|
assert result is not None
|
|||
|
|
assert "合并单元格测试" in result
|
|||
|
|
assert "技术部" in result
|
|||
|
|
assert "员工1" in result
|
|||
|
|
print(f"✓ 合并单元格 Excel 处理成功")
|
|||
|
|
print(f"处理结果预览:\n{result[:400]}...")
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_excel_chunking(self, tmp_path):
|
|||
|
|
"""测试 Excel 每 10 行分块处理"""
|
|||
|
|
test_file = tmp_path / "test_chunking.xlsx"
|
|||
|
|
wb = Workbook()
|
|||
|
|
ws = wb.active
|
|||
|
|
ws.title = "分块测试"
|
|||
|
|
|
|||
|
|
# 添加表头
|
|||
|
|
ws["A1"] = "编号"
|
|||
|
|
ws["B1"] = "数据"
|
|||
|
|
|
|||
|
|
# 添加 25 行数据(应该分成 3 块:10+10+5)
|
|||
|
|
for i in range(1, 26):
|
|||
|
|
ws[f"A{i+1}"] = i
|
|||
|
|
ws[f"B{i+1}"] = f"数据{i}"
|
|||
|
|
|
|||
|
|
wb.save(test_file)
|
|||
|
|
|
|||
|
|
# 处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果 - 应该包含多个数据行块
|
|||
|
|
assert result is not None
|
|||
|
|
assert "数据行 1-10" in result # 第一块
|
|||
|
|
assert "数据行 11-20" in result # 第二块
|
|||
|
|
assert "数据行 21-25" in result # 第三块
|
|||
|
|
print(f"✓ Excel 分块处理成功(25行 -> 3块)")
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_excel_duplicate_columns(self, tmp_path):
|
|||
|
|
"""测试包含重复列名的 Excel 处理"""
|
|||
|
|
test_file = tmp_path / "test_duplicate_cols.xlsx"
|
|||
|
|
wb = Workbook()
|
|||
|
|
ws = wb.active
|
|||
|
|
ws.title = "重复列名"
|
|||
|
|
|
|||
|
|
# 添加重复的表头
|
|||
|
|
ws["A1"] = "数据"
|
|||
|
|
ws["B1"] = "数据"
|
|||
|
|
ws["C1"] = "数据"
|
|||
|
|
|
|||
|
|
# 添加数据
|
|||
|
|
ws["A2"] = "值1"
|
|||
|
|
ws["B2"] = "值2"
|
|||
|
|
ws["C2"] = "值3"
|
|||
|
|
|
|||
|
|
wb.save(test_file)
|
|||
|
|
|
|||
|
|
# 处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果 - 重复列名应该被重命名
|
|||
|
|
assert result is not None
|
|||
|
|
# 检查是否包含原始数据
|
|||
|
|
assert "值1" in result or "值2" in result
|
|||
|
|
print(f"✓ 重复列名 Excel 处理成功")
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_excel_multiple_sheets(self, tmp_path):
|
|||
|
|
"""测试包含多个工作表的 Excel 处理"""
|
|||
|
|
test_file = tmp_path / "test_multi_sheets.xlsx"
|
|||
|
|
wb = Workbook()
|
|||
|
|
|
|||
|
|
# 第一个工作表
|
|||
|
|
ws1 = wb.active
|
|||
|
|
ws1.title = "表1"
|
|||
|
|
ws1["A1"] = "列A"
|
|||
|
|
ws1["A2"] = "数据1"
|
|||
|
|
|
|||
|
|
# 第二个工作表
|
|||
|
|
ws2 = wb.create_sheet("表2")
|
|||
|
|
ws2["A1"] = "列B"
|
|||
|
|
ws2["A2"] = "数据2"
|
|||
|
|
|
|||
|
|
wb.save(test_file)
|
|||
|
|
|
|||
|
|
# 处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果 - 应该包含两个工作表
|
|||
|
|
assert result is not None
|
|||
|
|
assert "表1" in result
|
|||
|
|
assert "表2" in result
|
|||
|
|
assert "数据1" in result
|
|||
|
|
assert "数据2" in result
|
|||
|
|
print(f"✓ 多工作表 Excel 处理成功")
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_excel_with_newlines(self, tmp_path):
|
|||
|
|
"""测试包含换行符的单元格处理"""
|
|||
|
|
test_file = tmp_path / "test_newlines.xlsx"
|
|||
|
|
wb = Workbook()
|
|||
|
|
ws = wb.active
|
|||
|
|
ws.title = "换行测试"
|
|||
|
|
|
|||
|
|
ws["A1"] = "标题"
|
|||
|
|
ws["A2"] = "第一行\n第二行\n第三行"
|
|||
|
|
|
|||
|
|
wb.save(test_file)
|
|||
|
|
|
|||
|
|
# 处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果 - 换行符应该被替换为 <br>
|
|||
|
|
assert result is not None
|
|||
|
|
assert "<br>" in result
|
|||
|
|
print(f"✓ 换行符处理成功(\\n -> <br>)")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestJSONProcessingChanges:
|
|||
|
|
"""测试 JSON 处理的异步变更"""
|
|||
|
|
|
|||
|
|
@pytest.mark.asyncio
|
|||
|
|
async def test_json_processing(self, tmp_path):
|
|||
|
|
"""测试 JSON 文件的异步处理"""
|
|||
|
|
import json
|
|||
|
|
|
|||
|
|
test_file = tmp_path / "test.json"
|
|||
|
|
test_data = {
|
|||
|
|
"name": "测试",
|
|||
|
|
"items": [{"id": 1, "value": "值1"}, {"id": 2, "value": "值2"}],
|
|||
|
|
"nested": {"key": "嵌套数据"},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 写入 JSON 文件
|
|||
|
|
with open(test_file, "w", encoding="utf-8") as f:
|
|||
|
|
json.dump(test_data, f, ensure_ascii=False)
|
|||
|
|
|
|||
|
|
# 异步处理文件
|
|||
|
|
result = await process_file_to_markdown(str(test_file))
|
|||
|
|
|
|||
|
|
# 验证结果
|
|||
|
|
assert result is not None
|
|||
|
|
assert "```json" in result
|
|||
|
|
assert "测试" in result
|
|||
|
|
assert "嵌套数据" in result
|
|||
|
|
print(f"✓ JSON 异步处理成功")
|
|||
|
|
print(f"处理结果预览:\n{result[:200]}...")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
exit_code = pytest.main([__file__, "-v", "-s", "--tb=short", "--color=yes"])
|
|||
|
|
sys.exit(exit_code)
|