feat: support safe recurrence additions
Parse, persist, expand, and round-trip compatible RDATE values while preserving whole-series TUI behavior and conservative rewrite guards. Verified: normal, warning-as-error, and ASan/UBSan builds pass all 9 suites; storage failure paths preserve calendar and backup bytes; live PTY restores terminal state.
This commit is contained in:
@@ -72,6 +72,7 @@ bool same_event(const nocal::Event& left, const nocal::Event& right)
|
||||
left.calendar_id == right.calendar_id && left.color == right.color &&
|
||||
left.time_basis == right.time_basis && left.time_zone == right.time_zone &&
|
||||
left.recurrence == right.recurrence &&
|
||||
left.recurrence_additions == right.recurrence_additions &&
|
||||
left.recurrence_exceptions == right.recurrence_exceptions;
|
||||
}
|
||||
|
||||
@@ -819,6 +820,36 @@ void test_recurring_occurrence_navigation_and_whole_series_crud()
|
||||
"undo restores a deleted recurring series");
|
||||
}
|
||||
|
||||
void test_rdate_only_occurrence_identity_and_whole_series_crud()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
const auto selected = nocal::today();
|
||||
const auto previous = nocal::from_sys_days(nocal::to_sys_days(selected) - days{1});
|
||||
auto series = make_event("rdate-only", "Extra date", previous, 9, 0,
|
||||
previous, 10, 0);
|
||||
series.recurrence_additions = {
|
||||
nocal::make_local_time(selected, 9, 0),
|
||||
};
|
||||
std::vector<nocal::Event> events{series};
|
||||
nocal::tui::TuiApp app{events, -1, -1};
|
||||
|
||||
app.dispatch(nocal::tui::Action::next_event);
|
||||
check(focus_starts_with(app, "rdate-only@occ:"),
|
||||
"an RDATE-only occurrence has a source-and-start focus identity");
|
||||
app.dispatch(nocal::tui::Action::edit_event);
|
||||
replace_editor_title(app, "Edited extra-date series");
|
||||
app.handle_input("\x13");
|
||||
check(events.front().title == "Edited extra-date series" &&
|
||||
events.front().recurrence_additions == series.recurrence_additions &&
|
||||
app.state().notification == "Recurring series updated.",
|
||||
"editing an RDATE-only occurrence updates and preserves the whole series");
|
||||
|
||||
app.dispatch(nocal::tui::Action::delete_event);
|
||||
app.handle_input("y");
|
||||
check(events.empty() && app.state().notification == "Recurring series deleted.",
|
||||
"deleting an RDATE-only occurrence removes its entire source series");
|
||||
}
|
||||
|
||||
void test_recurrence_grid_expansion_and_source_zone_display()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
@@ -1241,6 +1272,7 @@ int main()
|
||||
test_narrow_detail_wrapping_without_ansi();
|
||||
test_multiday_segment_labels_and_series_messaging();
|
||||
test_recurring_occurrence_navigation_and_whole_series_crud();
|
||||
test_rdate_only_occurrence_identity_and_whole_series_crud();
|
||||
test_recurrence_grid_expansion_and_source_zone_display();
|
||||
test_search_prompt_results_and_occurrence_jump();
|
||||
test_calendar_visibility_filters_without_partial_saves();
|
||||
|
||||
Reference in New Issue
Block a user