102 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Модель листа `Sheet`: merged-диапазоны, порядок ячеек строки, пустота, буквы колонок для диагностики."""
import datetime
from decimal import Decimal
import pytest
from src.parser.grid import EMPTY_CELL, Cell, MergedRange, Sheet, cell_ref, column_letter
def _sheet(
cells: dict[tuple[int, int], Cell],
merged: tuple[MergedRange, ...] = (),
row_outline: dict[int, int] | None = None,
) -> Sheet:
n_rows = max((row for row, _ in cells), default=0)
n_cols = max((col for _, col in cells), default=0)
return Sheet(name="ОСВ", cells=cells, merged=merged, row_outline=row_outline or {}, n_rows=n_rows, n_cols=n_cols)
def test_text_at_inside_merged_range_takes_origin_value() -> None:
sheet = _sheet(
{(1, 2): Cell("Сальдо на начало периода", "text"), (2, 2): Cell("Дебет", "text")},
merged=(MergedRange(top=1, left=2, bottom=1, right=3),),
)
assert sheet.text_at(1, 3) == "Сальдо на начало периода"
assert sheet.text_at(1, 2) == "Сальдо на начало периода"
assert sheet.cell(1, 3) is EMPTY_CELL
assert sheet.merged_origin(1, 3) == (1, 2)
assert sheet.merged_span(1, 3) == MergedRange(1, 2, 1, 3)
assert sheet.text_at(2, 3) == ""
assert sheet.merged_origin(2, 3) == (2, 3)
assert sheet.merged_span(2, 3) is None
def test_large_merged_range_is_resolved_without_cell_index() -> None:
# Диапазон на весь столбец: индекс «ячейка → диапазон» для него не строится, поиск всё равно работает
big = MergedRange(top=1, left=1, bottom=1_048_576, right=16_384)
sheet = _sheet({(1, 1): Cell("Шапка", "text")}, merged=(big,))
assert sheet.merged_origin(500_000, 10_000) == (1, 1)
assert sheet.text_at(1_048_576, 16_384) == "Шапка"
def test_row_cells_are_ordered_by_column_and_skip_blank_text() -> None:
sheet = _sheet(
{
(3, 5): Cell(Decimal("10.5"), "number"),
(3, 1): Cell("60.01", "text"),
(3, 3): Cell(" ", "text"),
(4, 1): Cell("62", "text"),
}
)
assert sheet.row_cells(3) == [(1, Cell("60.01", "text")), (5, Cell(Decimal("10.5"), "number"))]
assert sheet.row_cells(7) == []
def test_row_of_spaces_is_empty() -> None:
sheet = _sheet({(2, 1): Cell(" ", "text"), (2, 4): Cell("\xa0 ", "text"), (3, 1): Cell(False, "bool")})
assert sheet.is_row_empty(2)
assert sheet.is_row_empty(10)
assert not sheet.is_row_empty(3)
def test_cell_text_strips_and_treats_spaces_as_empty() -> None:
assert Cell(" ", "text").text == ""
assert Cell(" Контрагент ", "text").text == "Контрагент"
assert Cell(None, "empty").text == ""
assert EMPTY_CELL.text == ""
assert Cell(Decimal("1250.00"), "number").text == "1250.00"
assert Cell(datetime.date(2024, 9, 30), "date").text == "2024-09-30"
def test_outline_defaults_to_zero() -> None:
sheet = _sheet({(1, 1): Cell("62", "text")}, row_outline={2: 1, 3: 2})
assert [sheet.outline(row) for row in (1, 2, 3)] == [0, 1, 2]
@pytest.mark.parametrize(
("index", "letter"),
[(1, "A"), (26, "Z"), (27, "AA"), (52, "AZ"), (703, "AAA"), (16_384, "XFD")],
)
def test_column_letter(index: int, letter: str) -> None:
assert column_letter(index) == letter
def test_column_letter_rejects_non_positive_index() -> None:
with pytest.raises(ValueError, match="1-based"):
column_letter(0)
def test_cell_ref_quotes_sheet_name_by_excel_rule() -> None:
assert cell_ref("Баланс", 27, 3) == "Баланс!C27"
assert cell_ref("Лист_1", 2, 2) == "Лист_1!B2"
assert cell_ref("Бухгалтерский баланс. Лист 1", 14, 3) == "'Бухгалтерский баланс. Лист 1'!C14"
assert cell_ref("2024", 1, 1) == "'2024'!A1"
assert cell_ref("Отчёт д'Артаньяна", 1, 28) == "'Отчёт д''Артаньяна'!AB1"