from genesis.data_models import CellValue, ExcelTable, ExtractionMethod, SheetType from genesis.parsers.merge_fill import forward_fill from genesis.parsers.table_extractor import column_letter, extract_table def test_forward_fill_vertical(): matrix = [ ["機能ID", "機能名", "備考"], ["A001", "", ""], ["", "", "メモ"], ] filled = forward_fill(matrix, [(1, 2, 2, 2)]) # B1:B2 纵向合并 assert filled[1][1] == "機能名" assert filled[2][2] == "メモ" def test_forward_fill_horizontal(): matrix = [["A", "B"], ["x", ""]] filled = forward_fill(matrix, [(2, 1, 2, 2)]) # A2:B2 横向合并 assert filled[1][1] == "x" assert filled[1][0] == "x" def test_column_letter(): assert column_letter(1) == "A" assert column_letter(27) == "AA" def test_extract_table_basic(): matrix = [["ID", "名前"], ["1", "田中"], ["2", "佐藤"]] table = extract_table("社員一覧", matrix, "f.xlsx", SheetType.FUNCTION) assert isinstance(table, ExcelTable) assert table.headers == ["ID", "名前"] assert table.extraction_method == "openpyxl" assert len(table.rows) == 2 first = table.rows[0] assert isinstance(first["ID"], CellValue) assert first["ID"].value == "1" assert first["ID"].provenance.sheet_name == "社員一覧" assert first["ID"].provenance.column == "A" def test_extract_table_uses_enum_value(): matrix = [["ID"], ["1"]] table = extract_table("社員", matrix, "f.xlsx", SheetType.FUNCTION) assert table.extraction_method == ExtractionMethod.OPENPYXL.value def test_forward_fill_ignores_invalid_range(): matrix = [["A"], ["B"]] assert forward_fill(matrix, [(0, 1, 2, 1)]) == matrix # min_row=0 非法 → 不崩溃不改数据 assert forward_fill(matrix, [(9, 9, 9, 9)]) == matrix # 越界 → 不崩溃 def test_extract_table_empty_matrix(): # 空矩阵 → 返回空表(headers/rows 均为空),不崩溃(L 空矩阵分支) table = extract_table("空シート", [], "f.xlsx", SheetType.FUNCTION) assert table.headers == [] assert table.rows == [] def test_extract_table_header_row_out_of_range(): # header_row 越界/负值 → 回落 0(防御分支) mat = [["ID", "名前"], ["1", "田中"]] t_high = extract_table("社員", mat, "f.xlsx", SheetType.FUNCTION, header_row=9) t_neg = extract_table("社員", mat, "f.xlsx", SheetType.FUNCTION, header_row=-1) assert t_high.headers == ["ID", "名前"] assert t_neg.headers == ["ID", "名前"]