""" test_models.py - Тесты для моделей и предпочтений Проверяют корректность работы класса OperatorPreferences и связанных функций """ import pytest from datetime import datetime from models import ( OperatorPreferences, PreferencesBuilder, DayOfWeek, PreferenceType, get_days, create_model, solve_model, get_solution ) from config import YEAR, MONTH, SHIFTS, OPERATORS class TestDayOfWeek: """Тесты для enum DayOfWeek""" def test_day_of_week_values(self): """Проверка значений enum""" assert DayOfWeek.MONDAY.value == 0 assert DayOfWeek.TUESDAY.value == 1 assert DayOfWeek.WEDNESDAY.value == 2 assert DayOfWeek.THURSDAY.value == 3 assert DayOfWeek.FRIDAY.value == 4 assert DayOfWeek.SATURDAY.value == 5 assert DayOfWeek.SUNDAY.value == 6 def test_day_of_week_names(self): """Проверка названий enum""" assert DayOfWeek.MONDAY.name == "MONDAY" assert DayOfWeek.SUNDAY.name == "SUNDAY" class TestOperatorPreferences: """Тесты для класса OperatorPreferences""" def test_creation(self): """Тест создания объекта предпочтений""" prefs = OperatorPreferences("Тестовый") assert prefs.operator_name == "Тестовый" assert prefs.work_on_dates == [] assert prefs.work_on_day_of_week == [] assert prefs.work_only_shift is None assert prefs.off_on_dates == [] def test_to_dict_empty(self): """Тест конвертации в словарь для пустых предпочтений""" prefs = OperatorPreferences("Тестовый") result = prefs.to_dict() assert result == {} def test_to_dict_with_dates(self): """Тест конвертации с датами""" prefs = OperatorPreferences("Тестовый") prefs.work_on_dates = [10, 15, 20] result = prefs.to_dict() assert result['dates'] == [10, 15, 20] def test_to_dict_with_shift(self): """Тест конвертации со сменой""" prefs = OperatorPreferences("Тестовый") prefs.work_only_shift = 2 result = prefs.to_dict() assert result['shift'] == 2 def test_to_dict_with_day_of_week(self): """Тест конвертации с днем недели""" prefs = OperatorPreferences("Тестовый") prefs.work_on_day_of_week = [DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY] result = prefs.to_dict() assert result['day_of_week'] == ['monday', 'wednesday'] def test_to_dict_with_off_dates(self): """Тест конвертации с днями отдыха""" prefs = OperatorPreferences("Тестовый") prefs.off_on_dates = [5, 12, 19] result = prefs.to_dict() assert result['off_dates'] == [5, 12, 19] def test_to_dict_all(self): """Тест конвертации всех полей""" prefs = OperatorPreferences("Тестовый") prefs.work_on_dates = [10, 15] prefs.work_on_day_of_week = [DayOfWeek.MONDAY] prefs.work_only_shift = 1 prefs.off_on_dates = [5] result = prefs.to_dict() assert result['dates'] == [10, 15] assert result['day_of_week'] == ['monday'] assert result['shift'] == 1 assert result['off_dates'] == [5] def test_from_dict(self): """Тест создания из словаря""" data = { 'dates': [10, 15], 'day_of_week': ['monday'], 'shift': 1, 'off_dates': [5] } prefs = OperatorPreferences.from_dict("Тестовый", data) assert prefs.work_on_dates == [10, 15] assert prefs.work_on_day_of_week == [DayOfWeek.MONDAY] assert prefs.work_only_shift == 1 assert prefs.off_on_dates == [5] def test_from_dict_partial(self): """Тест создания из словаря с неполными данными""" data = {'dates': [10]} prefs = OperatorPreferences.from_dict("Тестовый", data) assert prefs.work_on_dates == [10] assert prefs.work_on_day_of_week == [] assert prefs.work_only_shift is None assert prefs.off_on_dates == [] def test_from_dict_invalid_day_of_week(self): """Тест обработки невалидного дня недели""" data = {'day_of_week': ['invalid']} prefs = OperatorPreferences.from_dict("Тестовый", data) assert prefs.work_on_day_of_week == [] def test_from_dict_invalid_shift(self): """Тест обработки невалидной смены""" data = {'shift': 5} prefs = OperatorPreferences.from_dict("Тестовый", data) assert prefs.work_only_shift is None def test_from_dict_invalid_dates(self): """Тест обработки невалидных дат""" data = {'dates': [32]} prefs = OperatorPreferences.from_dict("Тестовый", data) assert prefs.work_on_dates == [] def test_from_dict_invalid_off_dates(self): """Тест обработки невалидных дней отдыха""" data = {'off_dates': [32]} prefs = OperatorPreferences.from_dict("Тестовый", data) assert prefs.off_on_dates == [] class TestPreferencesBuilder: """Тесты для класса PreferencesBuilder""" def test_creation(self): """Тест создания объекта""" builder = PreferencesBuilder("Тестовый") assert builder.operator_name == "Тестовый" assert builder._preferences is None def test_add_dates(self): """Тест добавления дат""" builder = PreferencesBuilder("Тестовый") builder.add_dates([10, 15]) assert builder._preferences.work_on_dates == [10, 15] def test_add_day_of_week(self): """Тест добавления дней недели""" builder = PreferencesBuilder("Тестовый") builder.add_day_of_week([DayOfWeek.MONDAY, DayOfWeek.WEDNESDAY]) assert len(builder._preferences.work_on_day_of_week) == 2 def test_add_shift(self): """Тест добавления смены""" builder = PreferencesBuilder("Тестовый") builder.add_shift(2) assert builder._preferences.work_only_shift == 2 def test_add_off_dates(self): """Тест добавления дней отдыха""" builder = PreferencesBuilder("Тестовый") builder.add_off_dates([5, 12]) assert builder._preferences.off_on_dates == [5, 12] def test_to_dict(self): """Тест конвертации в словарь""" builder = PreferencesBuilder("Тестовый") builder.add_dates([10]) builder.add_shift(1) result = builder.to_dict() assert result['dates'] == [10] assert result['shift'] == 1 def test_to_dict_empty(self): """Тест конвертации пустых предпочтений""" builder = PreferencesBuilder("Тестовый") result = builder.to_dict() assert result == {} def test_to_dict_invalid(self): """Тест обработки невалидных данных""" builder = PreferencesBuilder("Тестовый") builder.add_dates([32]) # Невалидная дата result = builder.to_dict() assert result == {} def test_to_dict_invalid_day_of_week(self): """Тест обработки невалидного дня недели""" builder = PreferencesBuilder("Тестовый") builder.add_day_of_week([DayOfWeek.MONDAY, "invalid"]) result = builder.to_dict() assert result['day_of_week'] == ['monday'] def test_to_dict_invalid_shift(self): """Тест обработки невалидной смены""" builder = PreferencesBuilder("Тестовый") builder.add_shift(5) # Невалидная смена result = builder.to_dict() assert result == {} def test_to_dict_invalid_off_dates(self): """Тест обработки невалидных дней отдыха""" builder = PreferencesBuilder("Тестовый") builder.add_off_dates([32]) # Невалидная дата result = builder.to_dict() assert result == {} class TestGetDays: """Тесты для функции get_days""" def test_days_count(self): """Проверка количества дней""" days = get_days() assert len(days) == 30 # Апрель 2026 def test_days_format(self): """Проверка формата дней""" days = get_days() for day in days: assert isinstance(day, str) assert len(day) == 10 # YYYY-MM-DD assert '-' in day def test_days_sorted(self): """Проверка сортировки дней""" days = get_days() assert days == sorted(days) def test_days_start(self): """Проверка первого дня""" days = get_days() assert days[0] == "2026-04-01" def test_days_end(self): """Проверка последнего дня""" days = get_days() assert days[-1] == "2026-04-30" class TestCreateModel: """Тесты для функции create_model""" def test_model_creation(self): """Тест создания модели""" model, variables, operators_set = create_model() assert model is not None assert variables is not None assert operators_set is not None assert len(operators_set) == len(OPERATORS) def test_variables_count(self): """Тест количества переменных""" model, variables, operators_set = create_model() expected_count = len(get_days()) * len(SHIFTS) * len(OPERATORS) assert len(variables) == expected_count def test_operators_set(self): """Тест множества операторов""" model, variables, operators_set = create_model() assert operators_set == set(OPERATORS) def test_model_has_constraints(self): """Тест наличия ограничений""" model, variables, operators_set = create_model() # Модель должна иметь ограничения assert model.NumConstraints() > 0 def test_model_has_hints(self): """Тест наличия подсказок""" model, variables, operators_set = create_model() # Модель должна иметь подсказки assert model.NumHints() > 0 class TestSolveModel: """Тесты для функции solve_model""" def test_solve_returns_bool(self): """Тест возврата булевого значения""" result = solve_model() assert isinstance(result, bool) def test_solve_with_valid_config(self): """Тест решения с валидной конфигурацией""" # Это может занять время, поэтому тестуем только факт вызова try: result = solve_model() # Результат может быть True или False в зависимости от конфигурации assert isinstance(result, bool) except Exception as e: pytest.fail(f"Ошибка при решении модели: {e}") class TestGetSolution: """Тесты для функции get_solution""" def test_solution_structure(self): """Тест структуры решения""" schedule = get_solution() assert isinstance(schedule, dict) assert len(schedule) > 0 def test_solution_days(self): """Тест дней в решении""" schedule = get_solution() days = get_days() assert set(schedule.keys()) == set(days) def test_solution_shifts(self): """Тест смен в решении""" schedule = get_solution() for day, day_shifts in schedule.items(): assert isinstance(day_shifts, dict) assert len(day_shifts) == len(SHIFTS) def test_solution_operators(self): """Тест операторов в решении""" schedule = get_solution() for day, day_shifts in schedule.items(): for shift_idx, shift_data in day_shifts.items(): assert isinstance(shift_data, dict) assert len(shift_data) == len(OPERATORS) def test_solution_values(self): """Тест значений в решении""" schedule = get_solution() for day, day_shifts in schedule.items(): for shift_idx, shift_data in day_shifts.items(): for op_name, value in shift_data.items(): assert isinstance(value, bool) assert value in [True, False] def test_solution_consistency(self): """Тест согласованности решения""" schedule = get_solution() # Каждый день и смена должны иметь ровно одного оператора for day, day_shifts in schedule.items(): for shift_idx, shift_data in day_shifts.items(): active_operators = [op for op, value in shift_data.items() if value] assert len(active_operators) == 1