Files
duty-teller/tests/test_duty_schedule_parser.py
Nikolay Tatarinov 7a963eccd1 Add event type handling for duties in the system
- Introduced a new `event_type` column in the `duties` table to categorize duties as 'duty', 'unavailable', or 'vacation'.
- Updated the duty schedule import functionality to parse and store event types from the JSON input.
- Enhanced the API response to include event types for each duty, improving the calendar display logic.
- Modified the web application to visually differentiate between duty types in the calendar and duty list.
- Updated tests to cover new event type functionality and ensure correct parsing and storage of duties.
- Revised README documentation to reflect changes in duty event types and their representation in the system.
2026-02-17 23:01:07 +03:00

118 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.

"""Tests for duty-schedule JSON parser."""
from datetime import date
import pytest
from importers.duty_schedule import (
DUTY_MARKERS,
UNAVAILABLE_MARKER,
VACATION_MARKER,
DutyScheduleParseError,
DutyScheduleEntry,
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
by_name = {e.full_name: e for e in result.entries}
assert "Ivanov I.I." in by_name
assert "Petrov P.P." in by_name
# Ivanov: only duty (б, Б, в) -> 2026-02-18, 19, 20
ivan = by_name["Ivanov I.I."]
assert sorted(ivan.duty_dates) == [date(2026, 2, 18), date(2026, 2, 19), date(2026, 2, 20)]
assert ivan.unavailable_dates == []
assert ivan.vacation_dates == []
# Petrov: one Н (unavailable), one О (vacation) -> 2026-02-17, 18
petr = by_name["Petrov P.P."]
assert petr.duty_dates == []
assert petr.unavailable_dates == [date(2026, 2, 17)]
assert petr.vacation_dates == [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 len(result.entries) == 1
assert result.entries[0].full_name == "A"
assert result.entries[0].duty_dates == []
assert result.entries[0].unavailable_dates == []
assert result.entries[0].vacation_dates == []
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 DUTY_MARKERS == frozenset({"б", "Б", "в", "В"})
assert "Н" not in DUTY_MARKERS and "О" not in DUTY_MARKERS
def test_unavailable_and_vacation_markers():
assert UNAVAILABLE_MARKER == "Н"
assert VACATION_MARKER == "О"
raw = (
'{"meta": {"start_date": "2026-02-01"}, "schedule": ['
'{"name": "X", "duty": "\u041d; \u041e; \u0432"}]}'
).encode("utf-8")
result = parse_duty_schedule(raw)
entry = result.entries[0]
assert entry.unavailable_dates == [date(2026, 2, 1)]
assert entry.vacation_dates == [date(2026, 2, 2)]
assert entry.duty_dates == [date(2026, 2, 3)]