[california/wip/725785-create-recurring: 13/16] YEARLY quick-add and tests
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/725785-create-recurring: 13/16] YEARLY quick-add and tests
- Date: Wed, 25 Jun 2014 02:12:57 +0000 (UTC)
commit 91bdf5b343c9a781ab1eb8f3c759865c4fbe396c
Author: Jim Nelson <jim yorba org>
Date: Tue Jun 24 16:27:05 2014 -0700
YEARLY quick-add and tests
src/component/component-details-parser.vala | 86 ++++++-----
src/component/component.vala | 7 +-
src/tests/tests-quick-add-recurring.vala | 215 +++++++++++++++++++++++++++
3 files changed, 267 insertions(+), 41 deletions(-)
---
diff --git a/src/component/component-details-parser.vala b/src/component/component-details-parser.vala
index 88133ae..13b4297 100644
--- a/src/component/component-details-parser.vala
+++ b/src/component/component-details-parser.vala
@@ -451,7 +451,7 @@ public class DetailsParser : BaseObject {
return String.is_numeric(amount.casefolded) ? int.parse(amount.casefolded) : -1;
}
- // Returns negative value if ordinalis invalid
+ // Returns negative value if ordinal is invalid
private int parse_ordinal(Token? ordinal) {
if (ordinal == null)
return -1;
@@ -499,11 +499,18 @@ public class DetailsParser : BaseObject {
return set_rrule_daily(1);
if (specifier.casefolded == WEEKLY) {
- // set the start date to today unless already known
- if (start_date == null)
- start_date = Calendar.System.today;
+ if (start_date != null)
+ set_rrule_weekly(iterate<Calendar.DayOfWeek>(start_date.day_of_week).to_array(), 1);
+ else
+ set_rrule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE, 1);
- return set_rrule_weekly(iterate<Calendar.DayOfWeek>(start_date.day_of_week).to_array(), 1);
+ return true;
+ }
+
+ if (specifier.casefolded == YEARLY) {
+ set_rrule(iCal.icalrecurrencetype_frequency.YEARLY_RECURRENCE, 1);
+
+ return true;
}
if (specifier.casefolded in UNIT_WEEKDAYS)
@@ -562,26 +569,32 @@ public class DetailsParser : BaseObject {
if (unit.casefolded in UNIT_WEEKENDS)
return set_rrule_weekly(Calendar.DayOfWeek.weekend_days, interval);
- // if no start date, then parse for start date, and if so, treat as yearly event
- if (start_date == null) {
- stack.mark();
- {
- Token? second = stack.pop();
- if (second != null) {
- Calendar.Date? date = parse_day_month(unit, second);
- if (date == null)
- date = parse_day_month(second, unit);
-
- if (date != null)
- return set_rrule_yearly(date, interval);
- }
+ //parse for date, and if so, treat as yearly event
+ stack.mark();
+ {
+ if (unit == specifier)
+ unit = stack.pop();
+
+ if (unit != null) {
+ Calendar.Date? date = parse_day_month(specifier, unit);
+ if (date == null)
+ date = parse_day_month(unit, specifier);
+
+ if (date != null)
+ return set_rrule_nth_day_of_year(date, 1);
}
- stack.restore();
}
+ stack.restore();
return false;
}
+ private void set_rrule(iCal.icalrecurrencetype_frequency freq, int interval) {
+ rrule = new RecurrenceRule(freq);
+ rrule.interval = interval;
+ rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
+ }
+
// Using the supplied by days, find the first upcoming start_date that matches one of them
// that is also the week number (unless zero, which means "any")
private void set_byday_start_date(Calendar.DayOfWeek[]? by_days, int week_no) {
@@ -613,22 +626,17 @@ public class DetailsParser : BaseObject {
if (start_date == null)
start_date = Calendar.System.today;
- rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.DAILY_RECURRENCE);
- rrule.interval = interval;
- rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
+ set_rrule(iCal.icalrecurrencetype_frequency.DAILY_RECURRENCE, interval);
return true;
}
// "every tuesday"
private bool set_rrule_weekly(Calendar.DayOfWeek[]? by_days, int interval) {
- if (rrule == null) {
- rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE);
- rrule.interval = interval;
- rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
- } else if (!rrule.is_weekly) {
+ if (rrule == null)
+ set_rrule(iCal.icalrecurrencetype_frequency.WEEKLY_RECURRENCE, interval);
+ else if (!rrule.is_weekly)
return false;
- }
Gee.Map<Calendar.DayOfWeek?, int> map = from_array<Calendar.DayOfWeek>(by_days)
.to_hash_map_as_keys<int>(dow => 0);
@@ -646,12 +654,10 @@ public class DetailsParser : BaseObject {
if (week_no < 1 || week_no > 5)
return false;
- if (rrule == null) {
- rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.MONTHLY_RECURRENCE);
- rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
- } else if (!rrule.is_monthly) {
+ if (rrule == null)
+ set_rrule(iCal.icalrecurrencetype_frequency.MONTHLY_RECURRENCE, 1);
+ else if (!rrule.is_monthly)
return false;
- }
Gee.Map<Calendar.DayOfWeek?, int> map = from_array<Calendar.DayOfWeek>(by_days)
.to_hash_map_as_keys<int>(dow => week_no);
@@ -663,16 +669,16 @@ public class DetailsParser : BaseObject {
}
// "every july 4th"
- private bool set_rrule_yearly(Calendar.Date date, int interval) {
- if (rrule != null)
+ private bool set_rrule_nth_day_of_year(Calendar.Date date, int interval) {
+ if (rrule == null)
+ set_rrule(iCal.icalrecurrencetype_frequency.YEARLY_RECURRENCE, interval);
+ else if (!rrule.is_yearly)
return false;
- start_date = date;
+ if (start_date == null)
+ start_date = date;
- rrule = new RecurrenceRule(iCal.icalrecurrencetype_frequency.YEARLY_RECURRENCE);
- rrule.interval = interval;
- rrule.first_of_week = Calendar.System.first_of_week.as_day_of_week();
- rrule.set_by_rule(RecurrenceRule.ByRule.YEAR_DAY, iterate<int>(date.day_of_year).to_array_list());
+ rrule.add_by_rule(RecurrenceRule.ByRule.YEAR_DAY, iterate<int>(date.day_of_year).to_array_list());
return true;
}
diff --git a/src/component/component.vala b/src/component/component.vala
index 23f49b2..d4521d8 100644
--- a/src/component/component.vala
+++ b/src/component/component.vala
@@ -22,6 +22,7 @@ private string TOMORROW;
private string YESTERDAY;
private string DAILY;
private string WEEKLY;
+private string YEARLY;
private string[] UNIT_WEEKDAYS;
private string[] UNIT_WEEKENDS;
private string[] UNIT_YEARS;
@@ -66,6 +67,10 @@ public void init() throws Error {
// For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
WEEKLY = _("weekly").casefold();
+ // Used by quick-add to indicate the user wants to create a yearly recurring event
+ // For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
+ YEARLY = _("yearly").casefold();
+
// Used by quick-add to indicate the user wants to create an event for every weekday
// (in most Western countries, this means Monday through Friday, i.e. the work week)
// Common abbreviations (without punctuation) should be included. Each word must be separated
@@ -178,7 +183,7 @@ public void terminate() {
TIME_PREPOSITIONS = LOCATION_PREPOSITIONS = DURATION_PREPOSITIONS = ORDINAL_SUFFIXES = null;
COMMON_PREPOSITIONS = DELAY_PREPOSITIONS = RECURRING_PREPOSITIONS = null;
- TODAY = TOMORROW = YESTERDAY = DAILY = WEEKLY = null;
+ TODAY = TOMORROW = YESTERDAY = DAILY = WEEKLY = YEARLY = null;
UNIT_WEEKDAYS = UNIT_WEEKENDS = UNIT_YEARS = UNIT_MONTHS = UNIT_WEEKS = UNIT_DAYS = UNIT_HOURS
= UNIT_MINS = null;
diff --git a/src/tests/tests-quick-add-recurring.vala b/src/tests/tests-quick-add-recurring.vala
index 7c83850..ac0d7a7 100644
--- a/src/tests/tests-quick-add-recurring.vala
+++ b/src/tests/tests-quick-add-recurring.vala
@@ -6,6 +6,11 @@
namespace California.Tests {
+/**
+ * Note that some tests are repeated with different days of the week to avoid false positives when
+ * the current day of the week (at time of execution) matches quick-add details.
+ */
+
private class QuickAddRecurring : UnitTest.Harness {
public QuickAddRecurring() {
// ByRule.DAY encoding/decoding tests
@@ -27,7 +32,11 @@ private class QuickAddRecurring : UnitTest.Harness {
// WEEKLY
add_case("every-tuesday", every_tuesday);
+ add_case("every-friday", every_friday);
+ add_case("weekly-meeting-monday", weekly_meeting_monday);
+ add_case("weekly-meeting-tuesday", weekly_meeting_tuesday);
add_case("tuesday_weekly", tuesday_weekly);
+ add_case("thursday-weekly", thursday_weekly);
add_case("weekdays_to_1pm", weekdays_to_1pm);
add_case("weekends", weekends);
add_case("every_weekend", every_weekend);
@@ -38,6 +47,20 @@ private class QuickAddRecurring : UnitTest.Harness {
// MONTHLY
add_case("every-first-tuesday", every_first_tuesday);
add_case("every-sixth-tuesday", every_sixth_tuesday);
+
+ // YEARLY
+ add_case("every-july-4th", every_july_4th);
+ add_case("every-july-15th", every_july_15th);
+ add_case("every-4th-july", every_4th_july);
+ add_case("every-15th-july", every_15th_july);
+ add_case("july-4th-yearly", july_4th_yearly);
+ add_case("july-15th-yearly", july_15th_yearly);
+ add_case("yearly-july-4th", yearly_july_4th);
+ add_case("yearly-july-15th", yearly_july_15th);
+ add_case("yearly-meeting-july-4th", yearly_meeting_july_4th);
+ add_case("yearly-meeting-july-15th", yearly_meeting_july_15th);
+ add_case("meeting-every-july-4th-15th", meeting_every_july_4th_15th);
+ add_case("every-july-4th-3-years", every_july_4th_3_years);
}
protected override void setup() throws Error {
@@ -261,6 +284,45 @@ private class QuickAddRecurring : UnitTest.Harness {
&& check_byrule_day(event, by_days);
}
+ private bool every_friday(out string? dump) throws Error {
+ Gee.Map<Calendar.DayOfWeek?, int> by_days = iterate<Calendar.DayOfWeek?>(
+ Calendar.DayOfWeek.FRI).to_hash_map_as_keys<int>(dow => 0);
+
+ Component.Event event;
+ return basic("meeting at work at 10am every friday", out event, out dump)
+ && event.rrule.is_weekly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.day_of_week.equal_to(Calendar.DayOfWeek.FRI)
+ && check_byrule_day(event, by_days);
+ }
+
+ private bool weekly_meeting_monday(out string? dump) throws Error {
+ Gee.Map<Calendar.DayOfWeek?, int> by_days = iterate<Calendar.DayOfWeek?>(
+ Calendar.DayOfWeek.MON).to_hash_map_as_keys<int>(dow => 0);
+
+ Component.Event event;
+ return basic("weekly meeting at work monday at 10am", out event, out dump)
+ && event.rrule.is_weekly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.day_of_week.equal_to(Calendar.DayOfWeek.MON)
+ && check_byrule_day(event, by_days);
+ }
+
+ private bool weekly_meeting_tuesday(out string? dump) throws Error {
+ Gee.Map<Calendar.DayOfWeek?, int> by_days = iterate<Calendar.DayOfWeek?>(
+ Calendar.DayOfWeek.TUE).to_hash_map_as_keys<int>(dow => 0);
+
+ Component.Event event;
+ return basic("weekly meeting at work tuesday at 10am", out event, out dump)
+ && event.rrule.is_weekly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.day_of_week.equal_to(Calendar.DayOfWeek.TUE)
+ && check_byrule_day(event, by_days);
+ }
+
private bool tuesday_weekly(out string? dump) throws Error {
Gee.Map<Calendar.DayOfWeek?, int> by_days = iterate<Calendar.DayOfWeek?>(
Calendar.DayOfWeek.TUE).to_hash_map_as_keys<int>(dow => 0);
@@ -274,6 +336,19 @@ private class QuickAddRecurring : UnitTest.Harness {
&& check_byrule_day(event, by_days);
}
+ private bool thursday_weekly(out string? dump) throws Error {
+ Gee.Map<Calendar.DayOfWeek?, int> by_days = iterate<Calendar.DayOfWeek?>(
+ Calendar.DayOfWeek.THU).to_hash_map_as_keys<int>(dow => 0);
+
+ Component.Event event;
+ return basic("meeting at work thursday at 10am weekly", out event, out dump)
+ && event.rrule.is_weekly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.day_of_week.equal_to(Calendar.DayOfWeek.THU)
+ && check_byrule_day(event, by_days);
+ }
+
private bool weekdays_to_1pm(out string? dump) throws Error {
Gee.Map<Calendar.DayOfWeek?, int> by_days = from_array<Calendar.DayOfWeek?>(
Calendar.DayOfWeek.weekdays).to_hash_map_as_keys<int>(dow => 0);
@@ -385,6 +460,146 @@ private class QuickAddRecurring : UnitTest.Harness {
return event.rrule == null
&& event.summary == "meeting at work every 6th";
}
+
+ //
+ // YEARLY
+ //
+
+ private bool check_byrule_yearday(Component.Event event, Gee.Collection<int> by_yeardays) {
+ Gee.SortedSet<int> values = event.rrule.get_by_rule(Component.RecurrenceRule.ByRule.YEAR_DAY);
+ if (values.size != by_yeardays.size)
+ return false;
+
+ return traverse<int>(by_yeardays).all(yearday => values.contains(yearday));
+ }
+
+ private bool every_july_4th(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work at 10am every july 4th", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 4;
+ }
+
+ private bool every_july_15th(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work at 10am every july 15th", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 15;
+ }
+
+ private bool every_4th_july(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work at 10am every 4th july", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 4;
+ }
+
+ private bool every_15th_july(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work at 10am every 15th july", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 15;
+ }
+
+ private bool july_4th_yearly(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work july 4th 10am yearly", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 4;
+ }
+
+ private bool july_15th_yearly(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work july 15th 10am yearly", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 15;
+ }
+
+ private bool yearly_july_4th(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work yearly july 4th 10am", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 4;
+ }
+
+ private bool yearly_july_15th(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work yearly july 15th 10am", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 15;
+ }
+
+ private bool yearly_meeting_july_4th(out string? dump) throws Error {
+ Component.Event event;
+ return basic("yearly meeting at work july 4th 10am", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 4;
+ }
+
+ private bool yearly_meeting_july_15th(out string? dump) throws Error {
+ Component.Event event;
+ return basic("yearly meeting at work july 15th 10am", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 15;
+ }
+
+ private bool meeting_every_july_4th_15th(out string? dump) throws Error {
+ Calendar.Date july4 = new Calendar.Date(Calendar.DayOfMonth.for(4), Calendar.Month.JUL,
+ Calendar.System.today.year);
+ Calendar.Date july15 = new Calendar.Date(Calendar.DayOfMonth.for(15), Calendar.Month.JUL,
+ Calendar.System.today.year);
+
+ Component.Event event;
+ return basic("meeting every july 4th and july 15 10am at work", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && !event.rrule.has_duration
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && (event.exact_time_span.start_date.day_of_month.value == 15
+ || event.exact_time_span.start_date.day_of_month.value == 4)
+ && event.exact_time_span.start_date.equal_to(event.exact_time_span.end_date)
+ && check_byrule_yearday(event, iterate<Calendar.Date>(july4, july15).map<int>(d =>
d.day_of_year).to_array_list());
+ }
+
+ private bool every_july_4th_3_years(out string? dump) throws Error {
+ Component.Event event;
+ return basic("meeting at work at 10am every july 4th for 3 years", out event, out dump)
+ && event.rrule.is_yearly
+ && event.rrule.interval == 1
+ && event.rrule.count == 3
+ && event.exact_time_span.start_date.month == Calendar.Month.JUL
+ && event.exact_time_span.start_date.day_of_month.value == 4;
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]