"""Tests for duty-schedule JSON parser.""" from datetime import date import pytest from importers.duty_schedule import ( DUTY_MARKERS, DutyScheduleParseError, parse_duty_schedule, ) def test_parse_valid_schedule(): raw = ( '{"meta": {"start_date": "2026-02-16", "weeks": 2}, ' '"schedule": [' '{"name": "Ivanov I.I.", "duty": "; ; \u0431 ; \u0411 ; \u0432 ; ;"}, ' '{"name": "Petrov P.P.", "duty": " ; \u041d ; \u041e ; ; ; ;"}' "]}" ).encode("utf-8") result = parse_duty_schedule(raw) assert result.start_date == date(2026, 2, 16) # Petrov has 7 cells -> end = start + 6 assert result.end_date == date(2026, 2, 22) assert len(result.entries) == 2 names = [e[0] for e in result.entries] assert "Ivanov I.I." in names assert "Petrov P.P." in names by_name = {e[0]: e[1] for e in result.entries} # Ivanov: indices 2, 3, 4 are duty (б, Б, в) -> 2026-02-18, 19, 20 ivan_dates = sorted(by_name["Ivanov I.I."]) assert ivan_dates == [date(2026, 2, 18), date(2026, 2, 19), date(2026, 2, 20)] # Petrov: indices 1, 2 (Н, О) -> 2026-02-17, 18 petr_dates = sorted(by_name["Petrov P.P."]) assert petr_dates == [date(2026, 2, 17), date(2026, 2, 18)] def test_parse_empty_duty_string(): raw = b'{"meta": {"start_date": "2026-02-01"}, "schedule": [{"name": "A", "duty": ""}]}' result = parse_duty_schedule(raw) assert result.start_date == date(2026, 2, 1) assert result.end_date == date(2026, 2, 1) assert result.entries == [("A", [])] def test_parse_invalid_json(): with pytest.raises(DutyScheduleParseError, match="Invalid JSON"): parse_duty_schedule(b"not json") def test_parse_missing_meta(): with pytest.raises(DutyScheduleParseError, match="meta"): parse_duty_schedule(b'{"schedule": []}') def test_parse_missing_start_date(): with pytest.raises(DutyScheduleParseError, match="start_date"): parse_duty_schedule(b'{"meta": {"weeks": 1}, "schedule": []}') def test_parse_invalid_start_date(): with pytest.raises(DutyScheduleParseError, match="start_date|Invalid"): parse_duty_schedule(b'{"meta": {"start_date": "not-a-date"}, "schedule": []}') def test_parse_missing_schedule(): with pytest.raises(DutyScheduleParseError, match="schedule"): parse_duty_schedule(b'{"meta": {"start_date": "2026-02-01"}}') def test_parse_schedule_not_array(): with pytest.raises(DutyScheduleParseError, match="schedule"): parse_duty_schedule(b'{"meta": {"start_date": "2026-02-01"}, "schedule": {}}') def test_parse_schedule_item_missing_name(): with pytest.raises(DutyScheduleParseError, match="name"): parse_duty_schedule( b'{"meta": {"start_date": "2026-02-01"}, "schedule": [{"duty": ";"}]}' ) def test_parse_schedule_item_empty_name(): with pytest.raises(DutyScheduleParseError, match="empty"): parse_duty_schedule( b'{"meta": {"start_date": "2026-02-01"}, "schedule": [{"name": " ", "duty": ""}]}' ) def test_duty_markers(): assert "б" in DUTY_MARKERS and "Б" in DUTY_MARKERS and "в" in DUTY_MARKERS