Files
duty-teller/tests/test_duty_schedule_parser.py
Nikolay Tatarinov ef5dbca5df Implement duty schedule import functionality and enhance user management
- Added a new command `/import_duty_schedule` for importing duty schedules via JSON, restricted to admin users.
- Introduced a two-step import process: specifying handover time and uploading a JSON file.
- Updated the database schema to allow `telegram_user_id` to be nullable for user creation by full name.
- Implemented repository functions for user management, including `get_or_create_user_by_full_name` and `delete_duties_in_range`.
- Enhanced README documentation with details on the new import command and JSON format requirements.
- Added comprehensive tests for the duty schedule parser and integration tests for the import functionality.
2026-02-17 21:45:23 +03:00

93 lines
3.1 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,
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