"""Тесты разбора ячеек занятий: каждый найденный в таблице формат.""" import pytest from schedule.lessons import Lesson, parse_lesson_cell R = "\u27EA" # ⟨ Cc = "\u27EB" # ⟩ def lessons(text): return [l.to_dict() for l in parse_lesson_cell(text)] def one(text): ls = parse_lesson_cell(text) assert len(ls) == 1, f"ожидалось 1 занятие, got: {ls}" return ls[0].to_dict() # --- базовые формы ------------------------------------------------------------- def test_simple_three_lines(): assert one("Математика\nСмирнов А.В.\nауд. 215") == { "marker": "", "subject": "Математика", "teacher": "Смирнов А.В.", "room": "ауд. 215", "note": "", } def test_two_lines_no_room(): assert one("ТВИМС\nКоролев Г.К") == { "marker": "", "subject": "ТВИМС", "teacher": "Королев Г.К", "room": "", "note": "", } def test_single_word_subject(): assert one("ДАСП") == { "marker": "", "subject": "ДАСП", "teacher": "", "room": "", "note": "", } def test_acronym_subject_not_org(): for subject in ("МАИС", "БЖД", "ООП", "ЯПМТ", "ТВиМС", "ФТД"): result = one(f"{subject}\nГладков А.Н.\nауд. 207") assert result["subject"] == subject, subject assert result["teacher"] == "Гладков А.Н." def test_multiple_teachers_slash(): result = one("Иностранный язык\nМастакова Н.К./Умнова И.В./Чвягина Т.В.\nауд. 305 / 207") assert result["teacher"] == "Мастакова Н.К./Умнова И.В./Чвягина Т.В." assert result["room"] == "ауд. 305 / 207" def test_subject_lines_join(): result = one("Методы компьютерной лингвистики\nв ИИ - 2\nПарамонов И.В.\nауд. 231") assert result["subject"] == "Методы компьютерной лингвистики в ИИ - 2" assert result["teacher"] == "Парамонов И.В." assert result["room"] == "ауд. 231" # --- маркеры ------------------------------------------------------------------- @pytest.mark.parametrize( "raw, expected", [ ("к.в. - 2\nФизика\nИванов И.И.\nауд. 301", "к.в. - 2"), ("к.в.-7\nСети Петри\nБашкин В.А.\nауд. 224", "к.в. - 7"), ("к.в.\nХимия\nПетров П.П.\nауд. 201", "к.в."), ("к.в. - 1 \nОсновы тестирования\nОкопный Марк Олегович\nонлайн", "к.в. - 1"), ("к.в.-2 Распределенные технологии\nКорсаков С.В.\nауд. 201", "к.в. - 2"), ], ) def test_markers(raw, expected): assert one(raw)["marker"] == expected def test_marker_alone_line_then_blank(): ls = lessons("к.в. \n\nОсновы веб-технологий\nЛавровский В.А.\nауд. 210") assert len(ls) == 1 assert ls[0]["marker"] == "к.в." assert ls[0]["subject"] == "Основы веб-технологий" def test_marker_inherited(): ls = lessons("к.в. - 3\nA\nБелов А.А.\nауд. 1\n\nB\nБелов А.А.\nауд. 2") assert [l["marker"] for l in ls] == ["к.в. - 3", "к.в. - 3"] # --- аудитории и локации --------------------------------------------------------- def test_room_normalization(): result = one("Математика\nСмирнов А.В.\nауд312") assert result["room"] == "ауд. 312" def test_room_with_building(): result = one("Основы права (л)\nКолпазанова Е.В.\nюридический корпус, 3 этаж ауд. 22\nначало в 16:05") assert result["subject"] == "Основы права (л)" assert result["teacher"] == "Колпазанова Е.В." assert result["room"] == "юридический корпус, 3 этаж ауд. 22" assert result["note"] == "начало в 16:05" def test_room_with_time_after(): result = one("Бизнес-аналитика\nЕлин А.С.\nонлайн\nс 17:00 до 20:00\nс 8.09.26") assert result["room"] == "онлайн" assert "с 17:00 до 20:00" in result["note"] assert "с 8.09.26" in result["note"] def test_room_online_with_time_inside(): result = one("Облачные сервисы\nБегунов А.В.\nонлайн (начало в 14:30)") assert result["room"] == "онлайн" assert result["note"] == "начало в 14:30" def test_room_url(): result = one("Физкультура (онлайн)\nhttps://next.uniyar.ac.ru/course/view.php?id=407") assert result["subject"] == "Физкультура (онлайн)" assert result["room"].startswith("https://next.uniyar.ac.ru") assert result["teacher"] == "" def test_location_instead_of_room(): result = one("Прикладная физическая культура\nТкач О.С.\nпервый этаж, восточное крыло") assert result["room"] == "первый этаж, восточное крыло" assert result["note"] == "" def test_room_paren_note(): result = one("Базы данных\nПолетаев А.Ю.\nауд. 223 (возможно и 221)") assert result["room"] == "ауд. 223" assert result["note"] == "возможно и 221" def test_room_paren_alternative_kept(): result = one("Сетевые технологии Huawei\nКорсаков С.В.\nауд.201 (221)") assert result["room"] == "ауд. 201 (221)" assert result["note"] == "" # --- преподаватели --------------------------------------------------------------- def test_full_name_teacher(): result = one("Основы тестирования\nОкопный Марк Олегович (БИФИТ)\nонлайн\nначало в 12:00") assert result["teacher"] == "Окопный Марк Олегович (БИФИТ)" assert result["room"] == "онлайн" assert result["note"] == "начало в 12:00" def test_full_name_with_company(): result = one("Проектный практикум\nЛабеев Игорь Владимирович (Корус консалтинг)\nначало занятия в 18:30 онлайн\nссылка в эл. университете") assert result["teacher"] == "Лабеев Игорь Владимирович (Корус консалтинг)" assert result["room"] == "онлайн" assert "начало занятия в 18:30" in result["note"] assert "ссылка в эл. университете" in result["note"] def test_teacher_with_substitute(): result = one("Параллельное программирование\nМещеряков И.А. (Федулов Д.Д.) (начало пары в 14:05)\nауд.213") assert result["teacher"] == "Мещеряков И.А. (Федулов Д.Д.)" assert result["room"] == "ауд. 213" assert result["note"] == "начало пары в 14:05" def test_teacher_lecture_marker_kept(): result = one("Теория автоматов\nСмирнов А.В. (л)\nауд.312") assert result["teacher"] == "Смирнов А.В. (л)" def test_org_as_teacher(): result = one("Управление ИТ-проектами\nПравоТех\nауд. 309") assert result["teacher"] == "ПравоТех" assert result["subject"] == "Управление ИТ-проектами" def test_single_word_org_in_teacher_position(): result = one("Оценка качества ПО\nХинт") assert result["teacher"] == "Хинт" assert result["subject"] == "Оценка качества ПО" def test_org_as_location(): ls = lessons( "Сети Петри\nБашкин В.А.\nауд. 224\n\nСовременные инструменты промышленной разработки\nКоновал О.В.\nНПО Криста" ) second = ls[1] assert second["teacher"] == "Коновал О.В." assert second["room"] == "НПО Криста" def test_teacher_and_room_on_one_line(): result = one("Логические контроллеры\nКузьмин Е.В.ауд. 301 (начало в 12:30)") assert result["teacher"] == "Кузьмин Е.В." assert result["room"] == "ауд. 301" assert result["note"] == "начало в 12:30" def test_initials_without_space(): result = one("Методы сжатия КрасновМ.В.\nауд.231") assert result["subject"] == "Методы сжатия" assert result["teacher"] == "КрасновМ.В." assert result["room"] == "ауд. 231" def test_inline_subject_teacher_room(): result = one("Сети Петри Башкин В.А. ауд. 224") assert result["subject"] == "Сети Петри" assert result["teacher"] == "Башкин В.А." assert result["room"] == "ауд. 224" # --- заметки --------------------------------------------------------------------- def test_red_note(): assert one(f"Математика\nСмирнов А.В.\nауд. 215\n{R}пара 14.09 не будет{Cc}")["note"] == "пара 14.09 не будет" def test_red_note_on_room_line(): result = one(f"Русский язык\nШаманова М.В.\nауд.312 {R}с 7.09 по 20.09 пары не будет{Cc}") assert result["room"] == "ауд. 312" assert result["note"] == "с 7.09 по 20.09 пары не будет" def test_red_note_multiline_with_embedded_lesson(): raw = ( "Теория автоматов\nСмирнов А.В. (л)\nауд.312\n" f"{R}занятия начнутся с 21.09\nИностранный язык\nБугрова Е.И.\n" f"ауд. 312 у ИТ-22БО 7.09 и 14.09 с 12:30{Cc}" ) result = one(raw) assert result["subject"] == "Теория автоматов" assert result["teacher"] == "Смирнов А.В. (л)" assert result["room"] == "ауд.312" or result["room"] == "ауд. 312" assert "занятия начнутся с 21.09" in result["note"] assert "Бугрова Е.И." in result["note"] def test_red_note_between_teacher_and_room(): raw = f"Математика\nСмирнов А.В.\n{R}(пара 8.09 не будет)\n{Cc}ауд. 203" result = one(raw) assert result["teacher"] == "Смирнов А.В." assert result["room"] == "ауд. 203" assert result["note"] == "пара 8.09 не будет" def test_only_red_text_gives_lesson_with_note(): result = one(f"{R}нет занятий{Cc}") assert result["note"] == "нет занятий" def test_date_note_not_room(): result = one("Практика в НПО Криста\nс 9.09.2026") assert result["subject"] == "Практика в НПО Криста" assert result["room"] == "" assert result["note"] == "с 9.09.2026" # --- несколько занятий в одной ячейке --------------------------------------------- def test_two_lessons_blank_line(): ls = lessons("Сети Петри\nБашкин В.А.\nауд. 224\n\nСовременные инструменты\nКоновал О.В.\nауд. 301") assert [l["subject"] for l in ls] == ["Сети Петри", "Современные инструменты"] assert [l["room"] for l in ls] == ["ауд. 224", "ауд. 301"] def test_two_lessons_room_subject_border(): ls = lessons("Логические контроллеры\nКузьмин Е.В.ауд. 301 (начало в 12:30)\nЧисленные методы\nГлызин С.Д. ауд. 312") assert [l["subject"] for l in ls] == ["Логические контроллеры", "Численные методы"] assert [l["teacher"] for l in ls] == ["Кузьмин Е.В.", "Глызин С.Д."] assert [l["room"] for l in ls] == ["ауд. 301", "ауд. 312"] def test_group_tag_after_room_is_note(): result = one("Алгебра и геометрия\nСедов А.Г.\nауд.219\nИТ-11") assert result["room"] == "ауд. 219" assert result["note"] == "ИТ-11" def test_lesson_with_red_between_lessons(): ls = lessons( "Введение в промышленную разработку\nПарамонов И.В.\n" f"ауд. 220 {R}2.09 пара отменяется{Cc}\n\n" "Язык UML и CASE-системы\nЛарина Ю.А.\nауд.210" ) assert ls[0]["note"] == "2.09 пара отменяется" assert ls[0]["room"] == "ауд. 220" assert ls[1]["subject"] == "Язык UML и CASE-системы" # --- оторвавшиеся пустой строкой преподаватель/аудитория --------------------------- def test_room_detached_by_blank_line(): # ПИЭ-31БО, вторник: «ауд.210» оторвана пустой строкой от предмета result = one("Программная инженерия\nЛарина Ю.А.\n\n ауд.210") assert result["subject"] == "Программная инженерия" assert result["teacher"] == "Ларина Ю.А." assert result["room"] == "ауд. 210" def test_teacher_and_room_detached_by_red_note(): # ИВТ-13БО, четверг: красная заметка снята со своей строки, осталась пустая raw = f"Практикум по матанализу\n{R}пара для тех кто не ТОП{Cc}\nШабаршина Г.В.\nауд. 219" result = one(raw) assert result["subject"] == "Практикум по матанализу" assert result["teacher"] == "Шабаршина Г.В." assert result["room"] == "ауд. 219" assert result["note"] == "пара для тех кто не ТОП" def test_detached_room_inherits_marker(): ls = lessons("к.в. - 2\nФизика\nИванов И.И.\n\nауд. 301") assert len(ls) == 1 assert ls[0]["marker"] == "к.в. - 2" assert ls[0]["room"] == "ауд. 301" def test_detached_room_kept_if_prev_has_room(): ls = lessons("Физика\nСмирнов А.В.\nауд. 221\n\nауд. 222") assert len(ls) == 2 assert ls[0]["room"] == "ауд. 221" def test_detached_teacher_kept_if_prev_has_teacher(): ls = lessons("Физика\nСмирнов А.В.\nауд. 221\n\nПетров П.П.\nауд. 222") assert len(ls) == 2 assert ls[0]["teacher"] == "Смирнов А.В." def test_lesson_after_detached_room_starts_fresh(): ls = lessons("Физика\nСмирнов А.В.\n\nауд. 221\n\nХимия\nПетров П.П.\nауд. 222") assert len(ls) == 2 assert ls[0]["room"] == "ауд. 221" assert ls[1]["subject"] == "Химия" # --- пустые и экзотические ---------------------------------------------------------- def test_empty_cell(): assert parse_lesson_cell("") == [] assert parse_lesson_cell(" \n ") == [] def test_cell_with_underscores_subject(): lesson = one("Промышленное программирование\nПарамонов И.В.\nауд. 220") assert lesson["subject"] == "Промышленное программирование" def test_lesson_subject_only(): result = one(f"{R}не будет{Cc}") assert result["subject"] == "" assert result["note"] == "не будет" def test_unclosed_paren_in_table(): # в таблице не закрыли скобку вокруг красной заметки result = one("Основы веб-технологий\nЛавровский В.А. (" + R + "предмет начнется с 8.09)" + Cc + "\nауд. 210") assert result["teacher"] == "Лавровский В.А." assert result["room"] == "ауд. 210" assert result["note"] == "предмет начнется с 8.09" def test_inline_lesson_after_room_no_blank_line(): raw = ( "к.в. - 2\nАлгоритмы и структуры данных Волченков С.Г. " + R + "(14.09 по 30.09 пары нет) " + Cc + "ауд.219 \nМетоды сжатия КрасновМ.В. ауд.231" ) ls = lessons(raw) assert len(ls) == 2 assert ls[0]["room"] == "ауд. 219" assert "14.09 по 30.09 пары нет" in ls[0]["note"] assert ls[1]["subject"] == "Методы сжатия" assert ls[1]["teacher"] == "КрасновМ.В." assert ls[1]["room"] == "ауд. 231" def test_full_name_three_words_after_subject(): """«Предмет Денис Сергеевич Верховцев (Сигма)» — ФИО не должно попасть в предмет.""" result = one("Основы тестирования веб-приложений Денис Сергеевич Верховцев (Сигма)\nонлайн") assert result["subject"] == "Основы тестирования веб-приложений" assert result["teacher"] == "Денис Сергеевич Верховцев (Сигма)" assert result["room"] == "онлайн" def test_plain_time_paren_line(): result = one("Параллельное программирование (пр)\nМещеряков И.А.\nауд. 213\n(начало пары в 12:30)") assert result["note"] == "начало пары в 12:30" def test_full_name_inline_after_subject(): result = one("Основы тестирования веб-приложений Денис Верховцев (Сигма)\nонлайн") assert result["subject"] == "Основы тестирования веб-приложений" assert result["teacher"] == "Денис Верховцев (Сигма)" assert result["room"] == "онлайн" def test_cell_note_applies_to_all_lessons(): # ПИЭ-13МО, понедельник, 5-я пара: два курса по выбору, заметка о паре raw = ( "к.в. Управление ИТ-проектами\nЕрофеев Александр Александрович (ПравоТех)\nонлайн\n" "к.в. Математические методы и модели принятия решения Наука онлайн\n" + R + "14.09 пары не будет" + Cc ) ls = lessons(raw) assert len(ls) == 2 assert all(l["note"] == "14.09 пары не будет" for l in ls) assert {l["subject"] for l in ls} == { "Управление ИТ-проектами", "Математические методы и модели принятия решения", } def test_inline_note_stays_with_its_lesson(): raw = ( "Русский язык\nШаманова М.В.\nауд. 312 " + R + "с 7.09 по 20.09 пары не будет" + Cc + "\n\nМатематика\nСмирнов А.В.\nауд. 203" ) ls = lessons(raw) assert ls[0]["note"] == "с 7.09 по 20.09 пары не будет" assert ls[1]["note"] == "" @pytest.mark.parametrize( "teacher, expected", [ ("Верховцев Денис Сергеевич", ["Верховцев Д.С."]), ("Денис Сергеевич Верховцев", ["Верховцев Д.С."]), ("Денис Верховцев (Сигма)", ["Верховцев Д."]), ("Лабеев Игорь Владимирович", ["Лабеев И.В."]), ("ПравоТех", ["ПравоТех"]), ], ) def test_teacher_keys_order(teacher, expected): """Ключ преподавателя — «Фамилия И.О.» в любом порядке ФИО в таблице.""" from schedule.lessons import extract_teacher_names assert extract_teacher_names(teacher) == expected