Files
schedule/tests/test_parsing.py
Vladislav Kopnin 9c9875579c Тесты и инфраструктура
- tests/: 104 теста — lessons (все форматы ячеек), xlsx (мержи/скрытые
  столбцы/красный текст/даты), parsing (группы/недели/индексы), API (TestClient,
  TTL/modified/stale-while-error, 404/400/502)
- xlsx_builder.py: генерация xlsx в памяти для тестов без openpyxl
- docker-compose: healthz-хелскчеки (не блокируют старт), SCHEDULE_LINK
- Makefile: target test
- requirements: закреплённые версии
- .gitignore: __pycache__/, .venv/ и т.д.
2026-09-09 11:33:58 +03:00

174 lines
6.6 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.

"""Тесты разбора листов: группы, дни/пары/чётность, индексы, вспомогательные листы."""
from datetime import date
import pytest
from fixtures import fixture_sheets, make_sheets
from schedule import parsing
from schedule.errors import ScheduleError
@pytest.fixture()
def sheets():
return make_sheets(fixture_sheets())
@pytest.fixture()
def data(sheets):
return parsing.parse_schedule(sheets)
def test_hidden_group_excluded(data):
assert set(data) == {"ИВТ-11БО", "ИТ-12БО"}
def test_semester(data):
assert data["ИВТ-11БО"]["semester_until"] == "11.01.27"
assert data["ИТ-12БО"]["semester_until"] == "29.12.26"
def test_day_period_parity(data):
mon = data["ИВТ-11БО"]["days"]["понедельник"]
p1 = mon[1]
assert p1["time"] == "9:00-10:35"
assert p1["ч"] is not None and p1["з"] is not None
assert "Математика" in p1["ч"]
assert "216" in p1["з"]
def test_empty_parity_slot_kept(data):
mon = data["ИТ-12БО"]["days"]["понедельник"]
assert mon[1]["з"] is None
# время на пустой слот подставлено
assert mon[1]["time"] == "9:00-10:35"
def test_lessons_preparsed(data):
mon = data["ИВТ-11БО"]["days"]["понедельник"]
lesson = mon[1]["lessons"]["ч"][0]
assert lesson["subject"] == "Математика"
assert lesson["teacher"] == "Смирнов А.В."
assert lesson["room"] == "ауд. 215"
assert lesson["note"] == "пара 14.09 не будет"
# пустое parity -> None
assert data["ИТ-12БО"]["days"]["понедельник"][1]["lessons"]["з"] is None
def test_marker_parsed(data):
mon_g1 = data["ИВТ-11БО"]["days"]["понедельник"]
mon_g2 = data["ИТ-12БО"]["days"]["понедельник"]
assert mon_g1[2]["lessons"]["ч"][0]["marker"] == "к.в. - 2"
assert mon_g2[2]["lessons"]["з"][0]["marker"] == "к.в."
def test_tuesday_only_ch(data):
tue = data["ИВТ-11БО"]["days"]["вторник"]
assert tue[1]["ч"] and "Биология" in tue[1]["ч"]
assert tue[1]["з"] is None
def test_missing_main_sheet(sheets):
del sheets[parsing.MAIN_SHEET]
with pytest.raises(ScheduleError):
parsing.parse_schedule(sheets)
def test_odd_day_block_warns(caplog):
sheets = make_sheets(fixture_sheets())
# уберём вторую строку понедельника (пара 1, з) -> нечётное число строк
rows = sheets[parsing.MAIN_SHEET].rows
# строки: 0 header, 1 с/по, 2..5 понедельник, 6..7 вторник
del rows[3]
with caplog.at_level("WARNING"):
result = parsing.parse_schedule(sheets)
assert any("сдвинуться" in r.message for r in caplog.records)
# разбор всё равно завершается
assert "ИВТ-11БО" in result
def test_week_ranges(sheets):
weeks = parsing.extract_week_ranges(sheets)
assert len(weeks) == 8
assert weeks[0] == {"parity": "ч", "start": date(2026, 8, 31), "end": date(2026, 9, 6)}
assert weeks[1]["parity"] == "з"
assert weeks[-2]["parity"] == "ч"
def test_current_parity():
sheets = make_sheets(fixture_sheets())
weeks = parsing.extract_week_ranges(sheets)
assert parsing.current_parity(weeks, date(2026, 9, 1)) == "ч"
assert parsing.current_parity(weeks, date(2026, 9, 9)) == "з"
assert parsing.current_parity(weeks, date(2030, 1, 1)) is None
def test_teacher_room_index(data):
teachers, rooms = parsing.build_teacher_room_index(data)
assert set(teachers) == {"Смирнов А.В.", "Иванов И.И.", "Петров П.П.", "Сидорова С.С."}
smirnov = teachers["Смирнов А.В."]["понедельник"]["1"]
assert len(smirnov["ч"]) == 1 and len(smirnov["з"]) == 1
assert smirnov["ч"][0]["subject"] == "Математика"
assert smirnov["ч"][0]["room"] == "ауд. 215"
assert smirnov["ч"][0]["groups"] == ["ИВТ-11БО"]
petrov_zn = teachers["Петров П.П."]["понедельник"]["2"]["з"]
assert petrov_zn[0]["marker"] == "к.в."
assert set(rooms) == {"ауд. 215", "ауд. 216", "ауд. 301", "ауд. 220", "ауд. 201"}
room_301 = rooms["ауд. 301"]["понедельник"]
assert room_301["1"]["ч"][0]["subject"] == "Физика"
assert room_301["1"]["ч"][0]["teacher"] == "Иванов И.И."
assert room_301["2"]["ч"][0]["groups"] == ["ИВТ-11БО"]
def test_day_times(data):
times = parsing.build_day_times(data)
assert times["понедельник"] == {"1": "9:00-10:35", "2": "10:45-12:20"}
assert times["вторник"] == {"1": "9:00-10:35"}
def test_group_schedule_shape(data):
out = parsing.build_group_schedule(data, "ИВТ-11БО")
assert out["group"] == "ИВТ-11БО"
assert out["semester_until"] == "11.01.27"
p1 = out["days"]["понедельник"]["1"]
assert p1["time"] == "9:00-10:35"
assert "raw" in p1["ч"] and "lessons" in p1["ч"]
assert p1["з"]["lessons"][0]["room"] == "ауд. 216"
assert parsing.build_group_schedule(data, "НЕТ-11БО") is None
def test_rooms_info(sheets):
info = parsing.parse_rooms_info(sheets)
assert info == {
"ауд. 215": {"room": "ауд. 215", "info": "комп.класс, 12 мест"},
"ауд. 301": {"room": "ауд. 301", "info": "интерактивная панель, 24 места"},
"ауд. 220": {"room": "ауд. 220", "info": "20 мест"},
}
def test_teachers_full(sheets):
full = parsing.parse_teachers_full(sheets)
assert full == {
"Смирнов А.В.": "Смирнов Александр Викторович",
"Иванов И.И.": "Иванов Иван Иванович",
}
def test_sort_rooms():
assert parsing.sort_rooms(["ауд. 10", "ауд. 9", "ауд. 100", "зал"]) == [
"ауд. 9", "ауд. 10", "ауд. 100", "зал",
]
def test_build_room_schedule(data):
_, rooms = parsing.build_teacher_room_index(data)
times = parsing.build_day_times(data)
out = parsing.build_room_schedule(rooms, "ауд. 301", times)
# дни с расписанием плюс дни, где есть время пар (даже без занятий)
assert set(out["days"]) == {"понедельник", "вторник"}
assert out["days"]["понедельник"]["1"]["ч"][0]["subject"] == "Физика"
assert parsing.build_room_schedule(rooms, "ауд. 999", times) is None