0a5e86c4a0
Expand weekdays in the DTSTART week and advance by Interval weeks from Monday; add unit coverage for MO/WE/FR and mid-week starts.
135 lines
4.6 KiB
Erlang
135 lines
4.6 KiB
Erlang
-module(logic_recurrence_tests).
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
logic_recurrence_test_() ->
|
|
[
|
|
{"Parse RRULE test", fun test_parse_rrule/0},
|
|
{"Validate RRULE test", fun test_validate_rrule/0},
|
|
{"Generate daily occurrences test", fun test_daily_occurrences/0},
|
|
{"Generate weekly occurrences test", fun test_weekly_occurrences/0},
|
|
{"Generate weekly BYDAY occurrences test", fun test_weekly_byday_occurrences/0},
|
|
{"Generate monthly occurrences test", fun test_monthly_occurrences/0},
|
|
{"Generate with count limit test", fun test_count_limit/0},
|
|
{"Generate with until limit test", fun test_until_limit/0}
|
|
].
|
|
|
|
test_parse_rrule() ->
|
|
RRule = #{
|
|
<<"freq">> => <<"WEEKLY">>,
|
|
<<"interval">> => 2,
|
|
<<"until">> => <<"2026-12-31T00:00:00Z">>,
|
|
<<"byday">> => [<<"MO">>, <<"WE">>, <<"FR">>]
|
|
},
|
|
|
|
{ok, Parsed} = logic_recurrence:parse_rrule(RRule),
|
|
?assertEqual(<<"WEEKLY">>, maps:get(freq, Parsed)),
|
|
?assertEqual(2, maps:get(interval, Parsed)),
|
|
?assertEqual(<<"2026-12-31T00:00:00Z">>, maps:get(until, Parsed)),
|
|
?assertEqual([<<"MO">>, <<"WE">>, <<"FR">>], maps:get(byday, Parsed)).
|
|
|
|
test_validate_rrule() ->
|
|
ValidRule = #{
|
|
freq => <<"DAILY">>,
|
|
interval => 1
|
|
},
|
|
?assert(logic_recurrence:validate_rrule(ValidRule)),
|
|
|
|
InvalidFreq = #{
|
|
freq => <<"YEARLY">>,
|
|
interval => 1
|
|
},
|
|
?assertNot(logic_recurrence:validate_rrule(InvalidFreq)),
|
|
|
|
InvalidInterval = #{
|
|
freq => <<"DAILY">>,
|
|
interval => 0
|
|
},
|
|
?assertNot(logic_recurrence:validate_rrule(InvalidInterval)).
|
|
|
|
test_daily_occurrences() ->
|
|
StartTime = {{2026, 4, 20}, {10, 0, 0}},
|
|
RRule = #{
|
|
freq => <<"DAILY">>,
|
|
interval => 1
|
|
},
|
|
RangeEnd = {{2026, 4, 25}, {10, 0, 0}},
|
|
|
|
Occurrences = logic_recurrence:generate_occurrences(StartTime, RRule, RangeEnd),
|
|
?assertEqual(6, length(Occurrences)),
|
|
?assertEqual({{2026, 4, 20}, {10, 0, 0}}, lists:nth(1, Occurrences)),
|
|
?assertEqual({{2026, 4, 25}, {10, 0, 0}}, lists:nth(6, Occurrences)).
|
|
|
|
test_weekly_occurrences() ->
|
|
StartTime = {{2026, 4, 20}, {10, 0, 0}}, % Monday
|
|
RRule = #{
|
|
freq => <<"WEEKLY">>,
|
|
interval => 1
|
|
},
|
|
RangeEnd = {{2026, 5, 11}, {10, 0, 0}},
|
|
|
|
Occurrences = logic_recurrence:generate_occurrences(StartTime, RRule, RangeEnd),
|
|
?assertEqual(4, length(Occurrences)),
|
|
?assertEqual({{2026, 4, 20}, {10, 0, 0}}, lists:nth(1, Occurrences)),
|
|
?assertEqual({{2026, 5, 11}, {10, 0, 0}}, lists:nth(4, Occurrences)).
|
|
|
|
test_weekly_byday_occurrences() ->
|
|
%% Monday start, MO/WE/FR for two weeks → 6 slots
|
|
StartTime = {{2026, 4, 20}, {10, 0, 0}},
|
|
RRule = #{
|
|
freq => <<"WEEKLY">>,
|
|
interval => 1,
|
|
byday => [<<"MO">>, <<"WE">>, <<"FR">>]
|
|
},
|
|
RangeEnd = {{2026, 5, 1}, {10, 0, 0}},
|
|
|
|
Occurrences = logic_recurrence:generate_occurrences(StartTime, RRule, RangeEnd),
|
|
?assertEqual(6, length(Occurrences)),
|
|
?assertEqual({{2026, 4, 20}, {10, 0, 0}}, lists:nth(1, Occurrences)),
|
|
?assertEqual({{2026, 4, 22}, {10, 0, 0}}, lists:nth(2, Occurrences)),
|
|
?assertEqual({{2026, 4, 24}, {10, 0, 0}}, lists:nth(3, Occurrences)),
|
|
?assertEqual({{2026, 4, 27}, {10, 0, 0}}, lists:nth(4, Occurrences)),
|
|
?assertEqual({{2026, 4, 29}, {10, 0, 0}}, lists:nth(5, Occurrences)),
|
|
?assertEqual({{2026, 5, 1}, {10, 0, 0}}, lists:nth(6, Occurrences)),
|
|
|
|
%% Mid-week DTSTART must not emit earlier weekdays of the same week
|
|
WedStart = {{2026, 4, 22}, {10, 0, 0}},
|
|
MidWeek = logic_recurrence:generate_occurrences(WedStart, RRule, {{2026, 4, 24}, {10, 0, 0}}),
|
|
?assertEqual([{{2026, 4, 22}, {10, 0, 0}}, {{2026, 4, 24}, {10, 0, 0}}], MidWeek).
|
|
|
|
test_monthly_occurrences() ->
|
|
StartTime = {{2026, 4, 20}, {10, 0, 0}},
|
|
RRule = #{
|
|
freq => <<"MONTHLY">>,
|
|
interval => 1
|
|
},
|
|
RangeEnd = {{2026, 7, 20}, {10, 0, 0}},
|
|
|
|
Occurrences = logic_recurrence:generate_occurrences(StartTime, RRule, RangeEnd),
|
|
?assertEqual(4, length(Occurrences)),
|
|
?assertEqual({{2026, 4, 20}, {10, 0, 0}}, lists:nth(1, Occurrences)),
|
|
?assertEqual({{2026, 7, 20}, {10, 0, 0}}, lists:nth(4, Occurrences)).
|
|
|
|
test_count_limit() ->
|
|
StartTime = {{2026, 4, 20}, {10, 0, 0}},
|
|
RRule = #{
|
|
freq => <<"DAILY">>,
|
|
interval => 1,
|
|
count => 3
|
|
},
|
|
RangeEnd = {{2026, 12, 31}, {10, 0, 0}},
|
|
|
|
Occurrences = logic_recurrence:generate_occurrences(StartTime, RRule, RangeEnd),
|
|
?assertEqual(3, length(Occurrences)).
|
|
|
|
test_until_limit() ->
|
|
StartTime = {{2026, 4, 20}, {10, 0, 0}},
|
|
RRule = #{
|
|
freq => <<"DAILY">>,
|
|
interval => 1,
|
|
until => <<"2026-04-22T10:00:00Z">>
|
|
},
|
|
RangeEnd = {{2026, 12, 31}, {10, 0, 0}},
|
|
|
|
Occurrences = logic_recurrence:generate_occurrences(StartTime, RRule, RangeEnd),
|
|
% 20, 21, 22 апреля = 3 дня
|
|
?assertEqual(3, length(Occurrences)). |