1c8a86594f
Dos funciones nuevas del grupo de capacidad `dav`: - expand_rrule_py_infra (pure): expande una RRULE iCalendar a las fechas de cada ocurrencia dentro de un rango [from, to]. Solo stdlib (datetime, re). Soporta FREQ DAILY/WEEKLY/MONTHLY/YEARLY, INTERVAL, COUNT, UNTIL, BYDAY. 9 tests. - dav_make_calendar_py_infra (impure): crea una coleccion de calendario nueva via MKCALENDAR + PROPPATCH de nombre/color. Idempotente si ya existe. 11 tests. Consumidas por la app osint_web (eventos recurrentes + creacion de agendas). Pagina del grupo dav actualizada con ambas. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
145 lines
3.5 KiB
Python
145 lines
3.5 KiB
Python
"""Tests para expand_rrule."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
|
|
|
|
from functions.infra.expand_rrule import expand_rrule
|
|
|
|
|
|
def test_golden_weekly_count_4():
|
|
# FREQ=WEEKLY;COUNT=4 a partir del 2026-01-05 (lunes) -> 4 fechas a 7 dias.
|
|
got = expand_rrule(
|
|
"20260105T090000",
|
|
"FREQ=WEEKLY;COUNT=4",
|
|
"20260101",
|
|
"20261231",
|
|
)
|
|
assert got == [
|
|
"20260105T090000",
|
|
"20260112T090000",
|
|
"20260119T090000",
|
|
"20260126T090000",
|
|
]
|
|
|
|
|
|
def test_edge_monthly_interval_2():
|
|
# INTERVAL=2 mensual: cada dos meses, dia 15.
|
|
got = expand_rrule(
|
|
"20260115",
|
|
"FREQ=MONTHLY;INTERVAL=2;COUNT=4",
|
|
"20260101",
|
|
"20261231",
|
|
all_day=True,
|
|
)
|
|
assert got == ["20260115", "20260315", "20260515", "20260715"]
|
|
|
|
|
|
def test_edge_weekly_byday_two_days():
|
|
# BYDAY con 2 dias en WEEKLY: MO y WE, dentro de cada semana del intervalo.
|
|
# dtstart 2026-01-05 (lunes). COUNT=4 -> MO,WE de la sem 1 y MO,WE de la sem 2.
|
|
got = expand_rrule(
|
|
"20260105",
|
|
"FREQ=WEEKLY;BYDAY=MO,WE;COUNT=4",
|
|
"20260101",
|
|
"20261231",
|
|
all_day=True,
|
|
)
|
|
assert got == ["20260105", "20260107", "20260112", "20260114"]
|
|
|
|
|
|
def test_edge_all_day_vs_with_time():
|
|
# all_day=True -> YYYYMMDD; all_day=False conserva la hora del dtstart.
|
|
all_day = expand_rrule(
|
|
"20260105T143000",
|
|
"FREQ=DAILY;COUNT=2",
|
|
"20260101",
|
|
"20261231",
|
|
all_day=True,
|
|
)
|
|
assert all_day == ["20260105", "20260106"]
|
|
|
|
with_time = expand_rrule(
|
|
"20260105T143000",
|
|
"FREQ=DAILY;COUNT=2",
|
|
"20260101",
|
|
"20261231",
|
|
all_day=False,
|
|
)
|
|
assert with_time == ["20260105T143000", "20260106T143000"]
|
|
|
|
|
|
def test_until_recorta():
|
|
# UNTIL=20260120 recorta la serie semanal inclusive en esa fecha.
|
|
got = expand_rrule(
|
|
"20260105T090000",
|
|
"FREQ=WEEKLY;UNTIL=20260120T235959Z",
|
|
"20260101",
|
|
"20261231",
|
|
)
|
|
assert got == [
|
|
"20260105T090000",
|
|
"20260112T090000",
|
|
"20260119T090000",
|
|
]
|
|
|
|
|
|
def test_filtro_por_rango_excluye_fuera():
|
|
# COUNT=10 semanal, pero el rango solo cubre 3 ocurrencias intermedias.
|
|
got = expand_rrule(
|
|
"20260105T090000",
|
|
"FREQ=WEEKLY;COUNT=10",
|
|
"20260112",
|
|
"20260131",
|
|
)
|
|
assert got == [
|
|
"20260112T090000",
|
|
"20260119T090000",
|
|
"20260126T090000",
|
|
]
|
|
|
|
|
|
def test_dtstart_anterior_al_rango_pero_serie_entra():
|
|
# dtstart en 2025-12-29 (antes del rango), serie semanal entra en enero 2026.
|
|
got = expand_rrule(
|
|
"20251229T090000",
|
|
"FREQ=WEEKLY;COUNT=8",
|
|
"20260101",
|
|
"20260115",
|
|
)
|
|
assert got == [
|
|
"20260105T090000",
|
|
"20260112T090000",
|
|
]
|
|
|
|
|
|
def test_componente_no_soportado_se_ignora():
|
|
# BYMONTHDAY no soportado -> se ignora, no falla. Serie mensual normal.
|
|
got = expand_rrule(
|
|
"20260110",
|
|
"FREQ=MONTHLY;BYMONTHDAY=10;COUNT=3",
|
|
"20260101",
|
|
"20261231",
|
|
all_day=True,
|
|
)
|
|
assert got == ["20260110", "20260210", "20260310"]
|
|
|
|
|
|
def test_sin_count_ni_until_acota_a_range_end():
|
|
# Sin COUNT ni UNTIL: la generacion debe acotarse por range_end.
|
|
got = expand_rrule(
|
|
"20260101",
|
|
"FREQ=DAILY",
|
|
"20260101",
|
|
"20260105",
|
|
all_day=True,
|
|
)
|
|
assert got == [
|
|
"20260101",
|
|
"20260102",
|
|
"20260103",
|
|
"20260104",
|
|
"20260105",
|
|
]
|