Merge lp:~charlesk/indicator-datetime/lp-1456281-fix-15.04-alarm-regression into lp:indicator-datetime/15.04
- lp-1456281-fix-15.04-alarm-regression
- Merge into trunk.15.04
Status: | Merged |
---|---|
Approved by: | Ted Gould |
Approved revision: | 428 |
Merged at revision: | 414 |
Proposed branch: | lp:~charlesk/indicator-datetime/lp-1456281-fix-15.04-alarm-regression |
Merge into: | lp:indicator-datetime/15.04 |
Diff against target: |
1442 lines (+809/-433) 17 files modified
src/engine-eds.cpp (+348/-200) tests/CMakeLists.txt (+15/-14) tests/print-to.h (+10/-1) tests/run-eds-ics-test.sh (+10/-0) tests/test-eds-ics-all-day-events.cpp (+91/-0) tests/test-eds-ics-all-day-events.ics (+19/-0) tests/test-eds-ics-config-files/.config/evolution/sources/system-proxy.source (+21/-0) tests/test-eds-ics-nonrepeating-events.cpp (+93/-0) tests/test-eds-ics-nonrepeating-events.ics (+27/-0) tests/test-eds-ics-repeating-events.cpp (+100/-0) tests/test-eds-ics-repeating-events.ics (+28/-0) tests/test-eds-ics-repeating-valarms.ics (+47/-0) tests/test-eds-tasks-config-files/.config/evolution/sources/system-proxy.source (+0/-21) tests/test-eds-tasks-config-files/.local/share/evolution/tasks/system/tasks.ics (+0/-28) tests/test-eds-tasks.cpp (+0/-101) tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source (+0/-21) tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics (+0/-47) |
To merge this branch: | bzr merge lp:~charlesk/indicator-datetime/lp-1456281-fix-15.04-alarm-regression |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ted Gould (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+259713@code.launchpad.net |
Commit message
Fix regression that caused nonrepeating alarms to go off at the wrong time.
Description of the change
== Description of the Change
So, for the purposes of this description there are two kinds of ECalComponents: the primary one for an event, and instance components that are what you get when you have a repeating event.
Timezones for "floating" times (e.g., an alarm that goes off at 6:30 AM regardless of the current timezone) get distorted when you call e_cal_util_
So, the old code flow was
for (instance : e_cal_client_
for (alarm : e_cal_util_
The new flow is:
for (component : e_cal_client_
for (alarm : e_cal_util_
...if only the actual code were that easy :-)
Also, ensure EDS regression tests exist for both repeating and nonrepeating alarms.
== Checklist
> Are there any related MPs required for this MP to build/function as expected? Please list.
No
> Is your branch in sync with latest trunk? (e.g. bzr pull lp:trunk -> no changes)
In sync with indicator-
> Did the code build without warnings?
Yes
> Did the tests run successfully?
Yes
> Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
> If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
> What device (or emulator) has your component test plan been executed successfully on?
krillin ubuntu-
> What manual tests are relevant for this MP?
indicator-
> Did you include a link to the MR Review Checklist Template to make your reviewer's life easier?
https:/
- 424. By Charles Kerr
-
remove a little more leftover code from the false starts
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:424
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 425. By Charles Kerr
-
in engine-eds.cpp's get_appointments(), clear the begin_str and end_str variables as soon as we're done with them.
- 426. By Charles Kerr
-
in engine-eds.cpp's on_object_
list_ready( ), always mark the subtask as finished even if the dbus call failed. - 427. By Charles Kerr
-
in run-eds-
ics-test. sh, slightly cleaner ics file copying - 428. By Charles Kerr
-
in eds-engine, add a occur-in-time-range sexp to handle events that are interesting but don't require user notification alarms
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:427
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Ted Gould (ted) wrote : | # |
Looks like good updates. I really like moving the deleter function into the class, makes it way more readable and easier to track the memory.
Preview Diff
1 | === modified file 'src/engine-eds.cpp' | |||
2 | --- src/engine-eds.cpp 2015-05-08 00:10:37 +0000 | |||
3 | +++ src/engine-eds.cpp 2015-05-21 12:47:48 +0000 | |||
4 | @@ -79,9 +79,6 @@ | |||
5 | 79 | const Timezone& timezone, | 79 | const Timezone& timezone, |
6 | 80 | std::function<void(const std::vector<Appointment>&)> func) | 80 | std::function<void(const std::vector<Appointment>&)> func) |
7 | 81 | { | 81 | { |
8 | 82 | const auto begin_timet = begin.to_unix(); | ||
9 | 83 | const auto end_timet = end.to_unix(); | ||
10 | 84 | |||
11 | 85 | const auto b_str = begin.format("%F %T"); | 82 | const auto b_str = begin.format("%F %T"); |
12 | 86 | const auto e_str = end.format("%F %T"); | 83 | const auto e_str = end.format("%F %T"); |
13 | 87 | g_debug("getting all appointments from [%s ... %s]", b_str.c_str(), e_str.c_str()); | 84 | g_debug("getting all appointments from [%s ... %s]", b_str.c_str(), e_str.c_str()); |
14 | @@ -106,42 +103,51 @@ | |||
15 | 106 | *** walk through the sources to build the appointment list | 103 | *** walk through the sources to build the appointment list |
16 | 107 | **/ | 104 | **/ |
17 | 108 | 105 | ||
29 | 109 | auto task_deleter = [](Task* task){ | 106 | auto gtz = default_timezone != nullptr |
30 | 110 | // give the caller the (sorted) finished product | 107 | ? g_time_zone_new(icaltimezone_get_location(default_timezone)) |
31 | 111 | auto& a = task->appointments; | 108 | : g_time_zone_new_local(); |
32 | 112 | std::sort(a.begin(), a.end(), [](const Appointment& a, const Appointment& b){return a.begin < b.begin;}); | 109 | auto main_task = std::make_shared<Task>(this, func, default_timezone, gtz, begin, end); |
22 | 113 | task->func(a); | ||
23 | 114 | // we're done; delete the task | ||
24 | 115 | g_debug("time to delete task %p", (void*)task); | ||
25 | 116 | delete task; | ||
26 | 117 | }; | ||
27 | 118 | |||
28 | 119 | std::shared_ptr<Task> main_task(new Task(this, func), task_deleter); | ||
33 | 120 | 110 | ||
34 | 121 | for (auto& kv : m_clients) | 111 | for (auto& kv : m_clients) |
35 | 122 | { | 112 | { |
36 | 123 | auto& client = kv.second; | 113 | auto& client = kv.second; |
37 | 124 | if (default_timezone != nullptr) | 114 | if (default_timezone != nullptr) |
38 | 125 | e_cal_client_set_default_timezone(client, default_timezone); | 115 | e_cal_client_set_default_timezone(client, default_timezone); |
39 | 116 | g_debug("calling e_cal_client_generate_instances for %p", (void*)client); | ||
40 | 126 | 117 | ||
41 | 127 | // start a new subtask to enumerate all the components in this client. | ||
42 | 128 | auto& source = kv.first; | 118 | auto& source = kv.first; |
43 | 129 | auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR); | 119 | auto extension = e_source_get_extension(source, E_SOURCE_EXTENSION_CALENDAR); |
44 | 130 | const auto color = e_source_selectable_get_color(E_SOURCE_SELECTABLE(extension)); | 120 | const auto color = e_source_selectable_get_color(E_SOURCE_SELECTABLE(extension)); |
59 | 131 | g_debug("calling e_cal_client_generate_instances for %p", (void*)client); | 121 | |
60 | 132 | auto subtask = new AppointmentSubtask(main_task, | 122 | auto begin_str = isodate_from_time_t(begin.to_unix()); |
61 | 133 | client, | 123 | auto end_str = isodate_from_time_t(end.to_unix()); |
62 | 134 | color, | 124 | auto sexp_fmt = g_strdup_printf("(%%s? (make-time \"%s\") (make-time \"%s\"))", begin_str, end_str); |
63 | 135 | default_timezone, | 125 | g_clear_pointer(&begin_str, g_free); |
64 | 136 | begin_timet, | 126 | g_clear_pointer(&end_str, g_free); |
65 | 137 | end_timet); | 127 | |
66 | 138 | e_cal_client_generate_instances(client, | 128 | // ask EDS about alarms that occur in this window... |
67 | 139 | begin_timet, | 129 | auto sexp = g_strdup_printf(sexp_fmt, "has-alarms-in-range"); |
68 | 140 | end_timet, | 130 | g_debug("%s alarm sexp is %s", G_STRLOC, sexp); |
69 | 141 | m_cancellable, | 131 | e_cal_client_get_object_list_as_comps( |
70 | 142 | my_get_appointments_foreach, | 132 | client, |
71 | 143 | subtask, | 133 | sexp, |
72 | 144 | [](gpointer g){delete static_cast<AppointmentSubtask*>(g);}); | 134 | m_cancellable, |
73 | 135 | on_alarm_component_list_ready, | ||
74 | 136 | new ClientSubtask(main_task, client, color)); | ||
75 | 137 | g_clear_pointer(&sexp, g_free); | ||
76 | 138 | |||
77 | 139 | // ask EDS about events that occur in this window... | ||
78 | 140 | sexp = g_strdup_printf(sexp_fmt, "occur-in-time-range"); | ||
79 | 141 | g_debug("%s event sexp is %s", G_STRLOC, sexp); | ||
80 | 142 | e_cal_client_get_object_list_as_comps( | ||
81 | 143 | client, | ||
82 | 144 | sexp, | ||
83 | 145 | m_cancellable, | ||
84 | 146 | on_event_component_list_ready, | ||
85 | 147 | new ClientSubtask(main_task, client, color)); | ||
86 | 148 | g_clear_pointer(&sexp, g_free); | ||
87 | 149 | |||
88 | 150 | g_clear_pointer(&sexp_fmt, g_free); | ||
89 | 145 | } | 151 | } |
90 | 146 | } | 152 | } |
91 | 147 | 153 | ||
92 | @@ -409,30 +415,45 @@ | |||
93 | 409 | { | 415 | { |
94 | 410 | Impl* p; | 416 | Impl* p; |
95 | 411 | appointment_func func; | 417 | appointment_func func; |
96 | 418 | icaltimezone* default_timezone; // pointer owned by libical | ||
97 | 419 | GTimeZone* gtz; | ||
98 | 412 | std::vector<Appointment> appointments; | 420 | std::vector<Appointment> appointments; |
100 | 413 | Task(Impl* p_in, const appointment_func& func_in): p(p_in), func(func_in) {} | 421 | const DateTime begin; |
101 | 422 | const DateTime end; | ||
102 | 423 | |||
103 | 424 | Task(Impl* p_in, | ||
104 | 425 | appointment_func func_in, | ||
105 | 426 | icaltimezone* tz_in, | ||
106 | 427 | GTimeZone* gtz_in, | ||
107 | 428 | const DateTime& begin_in, | ||
108 | 429 | const DateTime& end_in): | ||
109 | 430 | p{p_in}, | ||
110 | 431 | func{func_in}, | ||
111 | 432 | default_timezone{tz_in}, | ||
112 | 433 | gtz{gtz_in}, | ||
113 | 434 | begin{begin_in}, | ||
114 | 435 | end{end_in} {} | ||
115 | 436 | |||
116 | 437 | ~Task() { | ||
117 | 438 | g_clear_pointer(>z, g_time_zone_unref); | ||
118 | 439 | // give the caller the sorted finished product | ||
119 | 440 | auto& a = appointments; | ||
120 | 441 | std::sort(a.begin(), a.end(), [](const Appointment& a, const Appointment& b){return a.begin < b.begin;}); | ||
121 | 442 | func(a); | ||
122 | 443 | }; | ||
123 | 414 | }; | 444 | }; |
124 | 415 | 445 | ||
126 | 416 | struct AppointmentSubtask | 446 | struct ClientSubtask |
127 | 417 | { | 447 | { |
128 | 418 | std::shared_ptr<Task> task; | 448 | std::shared_ptr<Task> task; |
129 | 419 | ECalClient* client; | 449 | ECalClient* client; |
130 | 420 | std::string color; | 450 | std::string color; |
131 | 421 | icaltimezone* default_timezone; | ||
132 | 422 | time_t begin; | ||
133 | 423 | time_t end; | ||
134 | 424 | 451 | ||
141 | 425 | AppointmentSubtask(const std::shared_ptr<Task>& task_in, | 452 | ClientSubtask(const std::shared_ptr<Task>& task_in, |
142 | 426 | ECalClient* client_in, | 453 | ECalClient* client_in, |
143 | 427 | const char* color_in, | 454 | const char* color_in): |
138 | 428 | icaltimezone* default_tz, | ||
139 | 429 | time_t begin_, | ||
140 | 430 | time_t end_): | ||
144 | 431 | task(task_in), | 455 | task(task_in), |
149 | 432 | client(client_in), | 456 | client(client_in) |
146 | 433 | default_timezone(default_tz), | ||
147 | 434 | begin(begin_), | ||
148 | 435 | end(end_) | ||
150 | 436 | { | 457 | { |
151 | 437 | if (color_in) | 458 | if (color_in) |
152 | 438 | color = color_in; | 459 | color = color_in; |
153 | @@ -482,163 +503,290 @@ | |||
154 | 482 | return ret; | 503 | return ret; |
155 | 483 | } | 504 | } |
156 | 484 | 505 | ||
163 | 485 | static gboolean | 506 | static void |
164 | 486 | my_get_appointments_foreach(ECalComponent* component, | 507 | on_alarm_component_list_ready(GObject * oclient, |
165 | 487 | time_t begin, | 508 | GAsyncResult * res, |
166 | 488 | time_t end, | 509 | gpointer gsubtask) |
167 | 489 | gpointer gsubtask) | 510 | { |
168 | 490 | { | 511 | GError * error = NULL; |
169 | 512 | GSList * comps_slist = NULL; | ||
170 | 513 | auto subtask = static_cast<ClientSubtask*>(gsubtask); | ||
171 | 514 | |||
172 | 515 | if (e_cal_client_get_object_list_as_comps_finish(E_CAL_CLIENT(oclient), | ||
173 | 516 | res, | ||
174 | 517 | &comps_slist, | ||
175 | 518 | &error)) | ||
176 | 519 | { | ||
177 | 520 | // _generate_alarms takes a GList, so make a shallow one | ||
178 | 521 | GList * comps_list = nullptr; | ||
179 | 522 | for (auto l=comps_slist; l!=nullptr; l=l->next) | ||
180 | 523 | comps_list = g_list_prepend(comps_list, l->data); | ||
181 | 524 | |||
182 | 525 | constexpr std::array<ECalComponentAlarmAction,1> omit = { | ||
183 | 526 | (ECalComponentAlarmAction)-1 | ||
184 | 527 | }; // list of action types to omit, terminated with -1 | ||
185 | 528 | GSList * comp_alarms = nullptr; | ||
186 | 529 | e_cal_util_generate_alarms_for_list( | ||
187 | 530 | comps_list, | ||
188 | 531 | subtask->task->begin.to_unix(), | ||
189 | 532 | subtask->task->end.to_unix(), | ||
190 | 533 | const_cast<ECalComponentAlarmAction*>(omit.data()), | ||
191 | 534 | &comp_alarms, | ||
192 | 535 | e_cal_client_resolve_tzid_cb, | ||
193 | 536 | oclient, | ||
194 | 537 | subtask->task->default_timezone); | ||
195 | 538 | |||
196 | 539 | // walk the alarms & add them | ||
197 | 540 | for (auto l=comp_alarms; l!=nullptr; l=l->next) | ||
198 | 541 | add_alarms_to_subtask(static_cast<ECalComponentAlarms*>(l->data), subtask, subtask->task->gtz); | ||
199 | 542 | |||
200 | 543 | // cleanup | ||
201 | 544 | e_cal_free_alarms(comp_alarms); | ||
202 | 545 | g_list_free(comps_list); | ||
203 | 546 | e_cal_client_free_ecalcomp_slist(comps_slist); | ||
204 | 547 | } | ||
205 | 548 | else if (error != nullptr) | ||
206 | 549 | { | ||
207 | 550 | if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | ||
208 | 551 | g_warning("can't get ecalcomponent list: %s", error->message); | ||
209 | 552 | |||
210 | 553 | g_error_free(error); | ||
211 | 554 | } | ||
212 | 555 | |||
213 | 556 | delete subtask; | ||
214 | 557 | } | ||
215 | 558 | |||
216 | 559 | static void | ||
217 | 560 | on_event_component_list_ready(GObject * oclient, | ||
218 | 561 | GAsyncResult * res, | ||
219 | 562 | gpointer gsubtask) | ||
220 | 563 | { | ||
221 | 564 | GError * error = NULL; | ||
222 | 565 | GSList * comps_slist = NULL; | ||
223 | 566 | auto subtask = static_cast<ClientSubtask*>(gsubtask); | ||
224 | 567 | |||
225 | 568 | if (e_cal_client_get_object_list_as_comps_finish(E_CAL_CLIENT(oclient), | ||
226 | 569 | res, | ||
227 | 570 | &comps_slist, | ||
228 | 571 | &error)) | ||
229 | 572 | { | ||
230 | 573 | for (auto l=comps_slist; l!=nullptr; l=l->next) | ||
231 | 574 | add_event_to_subtask(static_cast<ECalComponent*>(l->data), subtask, subtask->task->gtz); | ||
232 | 575 | |||
233 | 576 | e_cal_client_free_ecalcomp_slist(comps_slist); | ||
234 | 577 | } | ||
235 | 578 | else if (error != nullptr) | ||
236 | 579 | { | ||
237 | 580 | if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) | ||
238 | 581 | g_warning("can't get ecalcomponent list: %s", error->message); | ||
239 | 582 | |||
240 | 583 | g_error_free(error); | ||
241 | 584 | } | ||
242 | 585 | |||
243 | 586 | delete subtask; | ||
244 | 587 | } | ||
245 | 588 | |||
246 | 589 | static DateTime | ||
247 | 590 | datetime_from_component_date_time(const ECalComponentDateTime & in, | ||
248 | 591 | GTimeZone * default_timezone) | ||
249 | 592 | { | ||
250 | 593 | DateTime out; | ||
251 | 594 | |||
252 | 595 | g_return_val_if_fail(in.value != nullptr, out); | ||
253 | 596 | |||
254 | 597 | auto gtz = in.tzid == nullptr ? g_time_zone_ref(default_timezone) | ||
255 | 598 | : g_time_zone_new(in.tzid); | ||
256 | 599 | out = DateTime(gtz, | ||
257 | 600 | in.value->year, | ||
258 | 601 | in.value->month, | ||
259 | 602 | in.value->day, | ||
260 | 603 | in.value->hour, | ||
261 | 604 | in.value->minute, | ||
262 | 605 | in.value->second); | ||
263 | 606 | g_time_zone_unref(gtz); | ||
264 | 607 | return out; | ||
265 | 608 | } | ||
266 | 609 | |||
267 | 610 | static bool | ||
268 | 611 | is_component_interesting(ECalComponent * component) | ||
269 | 612 | { | ||
270 | 613 | // we only want calendar events and vtodos | ||
271 | 491 | const auto vtype = e_cal_component_get_vtype(component); | 614 | const auto vtype = e_cal_component_get_vtype(component); |
422 | 492 | auto subtask = static_cast<AppointmentSubtask*>(gsubtask); | 615 | if ((vtype != E_CAL_COMPONENT_EVENT) && |
423 | 493 | 616 | (vtype != E_CAL_COMPONENT_TODO)) | |
424 | 494 | if ((vtype == E_CAL_COMPONENT_EVENT) || (vtype == E_CAL_COMPONENT_TODO)) | 617 | return false; |
425 | 495 | { | 618 | |
426 | 496 | const gchar* uid = nullptr; | 619 | // we're not interested in completed or cancelled components |
427 | 497 | e_cal_component_get_uid(component, &uid); | 620 | auto status = ICAL_STATUS_NONE; |
428 | 498 | 621 | e_cal_component_get_status(component, &status); | |
429 | 499 | auto status = ICAL_STATUS_NONE; | 622 | if ((status == ICAL_STATUS_COMPLETED) || |
430 | 500 | e_cal_component_get_status(component, &status); | 623 | (status == ICAL_STATUS_CANCELLED)) |
431 | 501 | 624 | return false; | |
432 | 502 | // get the timezone we want to use for generated Appointments/Alarms | 625 | |
433 | 503 | const char * location = icaltimezone_get_location(subtask->default_timezone); | 626 | // we don't want disabled alarms |
434 | 504 | auto gtz = g_time_zone_new(location); | 627 | bool disabled = false; |
435 | 505 | g_debug("timezone abbreviation is %s", g_time_zone_get_abbreviation (gtz, 0)); | 628 | GSList * categ_list = nullptr; |
436 | 506 | 629 | e_cal_component_get_categories_list (component, &categ_list); | |
437 | 507 | const DateTime begin_dt { gtz, begin }; | 630 | for (GSList * l=categ_list; l!=nullptr; l=l->next) { |
438 | 508 | const DateTime end_dt { gtz, end }; | 631 | auto tag = static_cast<const char*>(l->data); |
439 | 509 | g_debug ("got appointment from %s to %s, uid %s status %d", | 632 | if (!g_strcmp0(tag, TAG_DISABLED)) |
440 | 510 | begin_dt.format("%F %T %z").c_str(), | 633 | disabled = true; |
441 | 511 | end_dt.format("%F %T %z").c_str(), | 634 | } |
442 | 512 | uid, | 635 | e_cal_component_free_categories_list(categ_list); |
443 | 513 | (int)status); | 636 | if (disabled) |
444 | 514 | 637 | return false; | |
445 | 515 | // look for the in-house tags | 638 | |
446 | 516 | bool disabled = false; | 639 | return true; |
447 | 517 | Appointment::Type type = Appointment::EVENT; | 640 | } |
448 | 518 | GSList * categ_list = nullptr; | 641 | |
449 | 519 | e_cal_component_get_categories_list (component, &categ_list); | 642 | static Appointment |
450 | 520 | for (GSList * l=categ_list; l!=nullptr; l=l->next) { | 643 | get_appointment(ECalComponent * component, GTimeZone * gtz) |
451 | 521 | auto tag = static_cast<const char*>(l->data); | 644 | { |
452 | 522 | if (!g_strcmp0(tag, TAG_ALARM)) | 645 | Appointment baseline; |
453 | 523 | type = Appointment::UBUNTU_ALARM; | 646 | |
454 | 524 | if (!g_strcmp0(tag, TAG_DISABLED)) | 647 | // get appointment.uid |
455 | 525 | disabled = true; | 648 | const gchar* uid = nullptr; |
456 | 526 | } | 649 | e_cal_component_get_uid(component, &uid); |
457 | 527 | e_cal_component_free_categories_list(categ_list); | 650 | if (uid != nullptr) |
458 | 528 | 651 | baseline.uid = uid; | |
459 | 529 | if ((uid != nullptr) && | 652 | |
460 | 530 | (!disabled) && | 653 | // get appointment.summary |
461 | 531 | (status != ICAL_STATUS_COMPLETED) && | 654 | ECalComponentText text {}; |
462 | 532 | (status != ICAL_STATUS_CANCELLED)) | 655 | e_cal_component_get_summary(component, &text); |
463 | 533 | { | 656 | if (text.value) |
464 | 534 | constexpr std::array<ECalComponentAlarmAction,1> omit = { (ECalComponentAlarmAction)-1 }; // list of action types to omit, terminated with -1 | 657 | baseline.summary = text.value; |
465 | 535 | Appointment appointment; | 658 | |
466 | 536 | 659 | // get appointment.begin | |
467 | 537 | ECalComponentText text {}; | 660 | ECalComponentDateTime eccdt_tmp {}; |
468 | 538 | e_cal_component_get_summary(component, &text); | 661 | e_cal_component_get_dtstart(component, &eccdt_tmp); |
469 | 539 | if (text.value) | 662 | baseline.begin = datetime_from_component_date_time(eccdt_tmp, gtz); |
470 | 540 | appointment.summary = text.value; | 663 | e_cal_component_free_datetime(&eccdt_tmp); |
471 | 541 | 664 | ||
472 | 542 | auto icc = e_cal_component_get_icalcomponent(component); // component owns icc | 665 | // get appointment.end |
473 | 543 | if (icc) | 666 | e_cal_component_get_dtend(component, &eccdt_tmp); |
474 | 544 | { | 667 | baseline.end = eccdt_tmp.value != nullptr |
475 | 545 | g_debug("%s", icalcomponent_as_ical_string(icc)); // libical owns this string; no leak | 668 | ? datetime_from_component_date_time(eccdt_tmp, gtz) |
476 | 546 | 669 | : baseline.begin; | |
477 | 547 | auto icalprop = icalcomponent_get_first_property(icc, ICAL_X_PROPERTY); | 670 | e_cal_component_free_datetime(&eccdt_tmp); |
478 | 548 | while (icalprop) | 671 | |
479 | 549 | { | 672 | // get appointment.activation_url from x-props |
480 | 550 | const char * x_name = icalproperty_get_x_name(icalprop); | 673 | auto icc = e_cal_component_get_icalcomponent(component); // icc owned by component |
481 | 551 | if ((x_name != nullptr) && !g_ascii_strcasecmp(x_name, X_PROP_ACTIVATION_URL)) | 674 | auto icalprop = icalcomponent_get_first_property(icc, ICAL_X_PROPERTY); |
482 | 552 | { | 675 | while (icalprop != nullptr) { |
483 | 553 | const char * url = icalproperty_get_value_as_string(icalprop); | 676 | const char * x_name = icalproperty_get_x_name(icalprop); |
484 | 554 | if ((url != nullptr) && appointment.activation_url.empty()) | 677 | if ((x_name != nullptr) && !g_ascii_strcasecmp(x_name, X_PROP_ACTIVATION_URL)) { |
485 | 555 | appointment.activation_url = url; | 678 | const char * url = icalproperty_get_value_as_string(icalprop); |
486 | 556 | } | 679 | if ((url != nullptr) && baseline.activation_url.empty()) |
487 | 557 | 680 | baseline.activation_url = url; | |
488 | 558 | icalprop = icalcomponent_get_next_property(icc, ICAL_X_PROPERTY); | 681 | } |
489 | 559 | } | 682 | icalprop = icalcomponent_get_next_property(icc, ICAL_X_PROPERTY); |
490 | 560 | } | 683 | } |
491 | 561 | 684 | ||
492 | 562 | appointment.begin = begin_dt; | 685 | // get appointment.type |
493 | 563 | appointment.end = end_dt; | 686 | baseline.type = Appointment::EVENT; |
494 | 564 | appointment.color = subtask->color; | 687 | GSList * categ_list = nullptr; |
495 | 565 | appointment.uid = uid; | 688 | e_cal_component_get_categories_list (component, &categ_list); |
496 | 566 | appointment.type = type; | 689 | for (GSList * l=categ_list; l!=nullptr; l=l->next) { |
497 | 567 | 690 | auto tag = static_cast<const char*>(l->data); | |
498 | 568 | auto e_alarms = e_cal_util_generate_alarms_for_comp(component, | 691 | if (!g_strcmp0(tag, TAG_ALARM)) |
499 | 569 | subtask->begin, | 692 | baseline.type = Appointment::UBUNTU_ALARM; |
500 | 570 | subtask->end, | 693 | } |
501 | 571 | const_cast<ECalComponentAlarmAction*>(omit.data()), | 694 | e_cal_component_free_categories_list(categ_list); |
502 | 572 | e_cal_client_resolve_tzid_cb, | 695 | |
503 | 573 | subtask->client, | 696 | g_debug("%s got appointment from %s to %s: %s", G_STRLOC, |
504 | 574 | nullptr); | 697 | baseline.begin.format("%F %T %z").c_str(), |
505 | 575 | 698 | baseline.end.format("%F %T %z").c_str(), | |
506 | 576 | std::map<DateTime,Alarm> alarms; | 699 | icalcomponent_as_ical_string(icc) /* string owned by ical */); |
507 | 577 | 700 | ||
508 | 578 | if (e_alarms != nullptr) | 701 | return baseline; |
509 | 579 | { | 702 | } |
510 | 580 | for (auto l=e_alarms->alarms; l!=nullptr; l=l->next) | 703 | |
511 | 581 | { | 704 | static void |
512 | 582 | auto ai = static_cast<ECalComponentAlarmInstance*>(l->data); | 705 | add_event_to_subtask(ECalComponent * component, |
513 | 583 | auto a = e_cal_component_get_alarm(component, ai->auid); | 706 | ClientSubtask * subtask, |
514 | 584 | 707 | GTimeZone * gtz) | |
515 | 585 | if (a != nullptr) | 708 | { |
516 | 586 | { | 709 | // events with alarms are covered by add_alarm_to_subtask(), |
517 | 587 | const DateTime alarm_begin{gtz, ai->trigger}; | 710 | // so skip them here |
518 | 588 | auto& alarm = alarms[alarm_begin]; | 711 | auto auids = e_cal_component_get_alarm_uids(component); |
519 | 589 | 712 | const bool has_alarms = auids != nullptr; | |
520 | 590 | if (alarm.text.empty()) | 713 | cal_obj_uid_list_free(auids); |
521 | 591 | alarm.text = get_alarm_text(a); | 714 | if (has_alarms) |
522 | 592 | if (alarm.audio_url.empty()) | 715 | return; |
523 | 593 | alarm.audio_url = get_alarm_sound_url(a); | 716 | |
524 | 594 | if (!alarm.time.is_set()) | 717 | // add it. simple, eh? |
525 | 595 | alarm.time = alarm_begin; | 718 | if (is_component_interesting(component)) |
526 | 596 | 719 | { | |
527 | 597 | e_cal_component_alarm_free(a); | 720 | Appointment appointment = get_appointment(component, gtz); |
528 | 598 | } | 721 | appointment.color = subtask->color; |
529 | 599 | } | 722 | subtask->task->appointments.push_back(appointment); |
530 | 600 | 723 | } | |
531 | 601 | e_cal_component_alarms_free(e_alarms); | 724 | } |
532 | 602 | } | 725 | |
533 | 603 | // Hm, no alarm triggers? | 726 | static void |
534 | 604 | // That's a bug in alarms created by some versions of ubuntu-ui-toolkit. | 727 | add_alarms_to_subtask(ECalComponentAlarms * comp_alarms, |
535 | 605 | // If that's what's happening here, let's handle those alarms anyway | 728 | ClientSubtask * subtask, |
536 | 606 | // by effectively injecting a TRIGGER;VALUE=DURATION;RELATED=START:PT0S | 729 | GTimeZone * gtz) |
537 | 607 | else if (appointment.is_ubuntu_alarm()) | 730 | { |
538 | 608 | { | 731 | auto& component = comp_alarms->comp; |
539 | 609 | Alarm tmp; | 732 | |
540 | 610 | tmp.time = appointment.begin; | 733 | if (!is_component_interesting(component)) |
541 | 611 | 734 | return; | |
542 | 612 | auto auids = e_cal_component_get_alarm_uids(component); | 735 | |
543 | 613 | for(auto l=auids; l!=nullptr; l=l->next) | 736 | Appointment baseline = get_appointment(component, gtz); |
544 | 614 | { | 737 | baseline.color = subtask->color; |
545 | 615 | const auto auid = static_cast<const char*>(l->data); | 738 | |
546 | 616 | auto a = e_cal_component_get_alarm(component, auid); | 739 | /** |
547 | 617 | if (a != nullptr) | 740 | *** Now loop through comp_alarms to get information that we need |
548 | 618 | { | 741 | *** to build the instance appointments and their alarms. |
549 | 619 | if (tmp.text.empty()) | 742 | *** |
550 | 620 | tmp.text = get_alarm_text(a); | 743 | *** Outer map key is the instance component's start + end time. |
551 | 621 | if (tmp.audio_url.empty()) | 744 | *** We build Appointment.begin and .end from that. |
552 | 622 | tmp.audio_url = get_alarm_sound_url(a); | 745 | *** |
553 | 623 | e_cal_component_alarm_free(a); | 746 | *** inner map key is the alarm trigger, we build Alarm.time from that. |
554 | 624 | } | 747 | *** |
555 | 625 | } | 748 | *** inner map value is the Alarm. |
556 | 626 | cal_obj_uid_list_free(auids); | 749 | *** |
557 | 627 | 750 | *** We map the alarms based on their trigger time so that we | |
558 | 628 | alarms[tmp.time] = tmp; | 751 | *** can fold together multiple valarms that trigger for the |
559 | 629 | } | 752 | *** same componeng at the same time. This is commonplace; |
560 | 630 | 753 | *** e.g. one valarm will have a display action and another | |
561 | 631 | appointment.alarms.reserve(alarms.size()); | 754 | *** will specify a sound to be played. |
562 | 632 | for (const auto& it : alarms) | 755 | */ |
563 | 633 | appointment.alarms.push_back(it.second); | 756 | std::map<std::pair<DateTime,DateTime>,std::map<DateTime,Alarm>> alarms; |
564 | 634 | 757 | for (auto l=comp_alarms->alarms; l!=nullptr; l=l->next) | |
565 | 635 | subtask->task->appointments.push_back(appointment); | 758 | { |
566 | 636 | } | 759 | auto ai = static_cast<ECalComponentAlarmInstance*>(l->data); |
567 | 637 | 760 | auto a = e_cal_component_get_alarm(component, ai->auid); | |
568 | 638 | g_time_zone_unref(gtz); | 761 | if (a == nullptr) |
569 | 639 | } | 762 | continue; |
570 | 640 | 763 | ||
571 | 641 | return G_SOURCE_CONTINUE; | 764 | auto instance_time = std::make_pair(DateTime{gtz, ai->occur_start}, |
572 | 765 | DateTime{gtz, ai->occur_end}); | ||
573 | 766 | auto trigger_time = DateTime{gtz, ai->trigger}; | ||
574 | 767 | |||
575 | 768 | auto& alarm = alarms[instance_time][trigger_time]; | ||
576 | 769 | |||
577 | 770 | if (alarm.text.empty()) | ||
578 | 771 | alarm.text = get_alarm_text(a); | ||
579 | 772 | if (alarm.audio_url.empty()) | ||
580 | 773 | alarm.audio_url = get_alarm_sound_url(a); | ||
581 | 774 | if (!alarm.time.is_set()) | ||
582 | 775 | alarm.time = trigger_time; | ||
583 | 776 | |||
584 | 777 | e_cal_component_alarm_free(a); | ||
585 | 778 | } | ||
586 | 779 | |||
587 | 780 | for (auto& i : alarms) | ||
588 | 781 | { | ||
589 | 782 | Appointment appointment = baseline; | ||
590 | 783 | appointment.begin = i.first.first; | ||
591 | 784 | appointment.end = i.first.second; | ||
592 | 785 | appointment.alarms.reserve(i.second.size()); | ||
593 | 786 | for (auto& j : i.second) | ||
594 | 787 | appointment.alarms.push_back(j.second); | ||
595 | 788 | subtask->task->appointments.push_back(appointment); | ||
596 | 789 | } | ||
597 | 642 | } | 790 | } |
598 | 643 | 791 | ||
599 | 644 | /*** | 792 | /*** |
600 | 645 | 793 | ||
601 | === modified file 'tests/CMakeLists.txt' | |||
602 | --- tests/CMakeLists.txt 2015-05-08 00:08:13 +0000 | |||
603 | +++ tests/CMakeLists.txt 2015-05-21 12:47:48 +0000 | |||
604 | @@ -78,25 +78,26 @@ | |||
605 | 78 | set(EVOLUTION_SOURCE_SERVICE_NAME "org.gnome.evolution.dataserver.Sources3") | 78 | set(EVOLUTION_SOURCE_SERVICE_NAME "org.gnome.evolution.dataserver.Sources3") |
606 | 79 | endif() | 79 | endif() |
607 | 80 | 80 | ||
609 | 81 | function(add_eds_test_by_name name) | 81 | function(add_eds_ics_test_by_name name) |
610 | 82 | set (TEST_NAME ${name}) | 82 | set (TEST_NAME ${name}) |
611 | 83 | add_executable(${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled) | 83 | add_executable(${TEST_NAME} ${TEST_NAME}.cpp gschemas.compiled) |
612 | 84 | target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) | 84 | target_link_libraries (${TEST_NAME} indicatordatetimeservice gtest ${DBUSTEST_LIBRARIES} ${SERVICE_DEPS_LIBRARIES} ${GTEST_LIBS}) |
613 | 85 | add_test (${TEST_NAME} | 85 | add_test (${TEST_NAME} |
623 | 86 | ${CMAKE_CURRENT_SOURCE_DIR}/run-eds-test.sh | 86 | ${CMAKE_CURRENT_SOURCE_DIR}/run-eds-ics-test.sh |
624 | 87 | ${DBUS_RUNNER} # arg1: dbus-test-runner exec | 87 | ${DBUS_RUNNER} # arg1: dbus-test-runner exec |
625 | 88 | ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} # arg2: test executable path | 88 | ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} # arg2: test executable path |
626 | 89 | ${TEST_NAME} # arg3: test name | 89 | ${TEST_NAME} # arg3: test name |
627 | 90 | ${EVOLUTION_CALENDAR_FACTORY} # arg4: evolution-calendar-factory exec | 90 | ${EVOLUTION_CALENDAR_FACTORY} # arg4: evolution-calendar-factory exec |
628 | 91 | ${EVOLUTION_SOURCE_SERVICE_NAME} # arg5: dbus name for source registry | 91 | ${EVOLUTION_SOURCE_SERVICE_NAME} # arg5: dbus name for source registry |
629 | 92 | ${EVOLUTION_SOURCE_REGISTRY} # arg6: evolution-source-registry exec | 92 | ${EVOLUTION_SOURCE_REGISTRY} # arg6: evolution-source-registry exec |
630 | 93 | ${GVFSD} # arg7: gvfsd exec | 93 | ${GVFSD} # arg7: gvfsd exec |
631 | 94 | ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_NAME}-config-files) # arg8: canned config files | 94 | ${CMAKE_CURRENT_SOURCE_DIR}/test-eds-ics-config-files # arg8: base directory for config file template |
632 | 95 | ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_NAME}.ics) # arg9: the ical file for this test | ||
633 | 95 | endfunction() | 96 | endfunction() |
638 | 96 | add_eds_test_by_name(test-eds-tasks) | 97 | add_eds_ics_test_by_name(test-eds-ics-all-day-events) |
639 | 97 | add_eds_test_by_name(test-eds-valarms) | 98 | add_eds_ics_test_by_name(test-eds-ics-repeating-events) |
640 | 98 | 99 | add_eds_ics_test_by_name(test-eds-ics-nonrepeating-events) | |
641 | 99 | 100 | add_eds_ics_test_by_name(test-eds-ics-repeating-valarms) | |
642 | 100 | 101 | ||
643 | 101 | 102 | ||
644 | 102 | # disabling the timezone unit tests because they require | 103 | # disabling the timezone unit tests because they require |
645 | 103 | 104 | ||
646 | === modified file 'tests/print-to.h' | |||
647 | --- tests/print-to.h 2015-04-06 15:20:49 +0000 | |||
648 | +++ tests/print-to.h 2015-05-21 12:47:48 +0000 | |||
649 | @@ -33,9 +33,18 @@ | |||
650 | 33 | ***/ | 33 | ***/ |
651 | 34 | 34 | ||
652 | 35 | void | 35 | void |
653 | 36 | PrintTo(const DateTime& datetime, std::ostream* os) | ||
654 | 37 | { | ||
655 | 38 | *os << "{time:'" << datetime.format("%F %T %z") << '}'; | ||
656 | 39 | } | ||
657 | 40 | |||
658 | 41 | void | ||
659 | 36 | PrintTo(const Alarm& alarm, std::ostream* os) | 42 | PrintTo(const Alarm& alarm, std::ostream* os) |
660 | 37 | { | 43 | { |
662 | 38 | *os << "{text:'" << alarm.text << "', audio_url:'" << alarm.audio_url << "', time:'"<<alarm.time.format("%F %T")<<"'}"; | 44 | *os << '{'; |
663 | 45 | *os << "{text:" << alarm.text << '}'; | ||
664 | 46 | PrintTo(alarm.time, os); | ||
665 | 47 | *os << '}'; | ||
666 | 39 | } | 48 | } |
667 | 40 | 49 | ||
668 | 41 | } // namespace datetime | 50 | } // namespace datetime |
669 | 42 | 51 | ||
670 | === renamed file 'tests/run-eds-test.sh' => 'tests/run-eds-ics-test.sh' | |||
671 | --- tests/run-eds-test.sh 2015-04-06 20:09:16 +0000 | |||
672 | +++ tests/run-eds-ics-test.sh 2015-05-21 12:47:48 +0000 | |||
673 | @@ -9,6 +9,7 @@ | |||
674 | 9 | echo ARG6=$6 # full exectuable path of evolution-source-registry | 9 | echo ARG6=$6 # full exectuable path of evolution-source-registry |
675 | 10 | echo ARG7=$7 # full executable path of gvfs | 10 | echo ARG7=$7 # full executable path of gvfs |
676 | 11 | echo ARG8=$8 # config files | 11 | echo ARG8=$8 # config files |
677 | 12 | echo ARG8=$9 # ics file | ||
678 | 12 | 13 | ||
679 | 13 | # set up the tmpdir and tell the shell to purge it when we exit | 14 | # set up the tmpdir and tell the shell to purge it when we exit |
680 | 14 | export TEST_TMP_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d $3-XXXXXXXXXX) || exit 1 | 15 | export TEST_TMP_DIR=$(mktemp -p "${TMPDIR:-/tmp}" -d $3-XXXXXXXXXX) || exit 1 |
681 | @@ -32,6 +33,9 @@ | |||
682 | 32 | export QORGANIZER_EDS_DEBUG=On | 33 | export QORGANIZER_EDS_DEBUG=On |
683 | 33 | export GIO_USE_VFS=local # needed to ensure GVFS shuts down cleanly after the test is over | 34 | export GIO_USE_VFS=local # needed to ensure GVFS shuts down cleanly after the test is over |
684 | 34 | 35 | ||
685 | 36 | export G_MESSAGES_DEBUG=all | ||
686 | 37 | export G_DBUS_DEBUG=messages | ||
687 | 38 | |||
688 | 35 | echo HOMEDIR=${HOME} | 39 | echo HOMEDIR=${HOME} |
689 | 36 | rm -rf ${XDG_DATA_HOME} | 40 | rm -rf ${XDG_DATA_HOME} |
690 | 37 | 41 | ||
691 | @@ -41,6 +45,12 @@ | |||
692 | 41 | cp --verbose --archive $8/. $HOME | 45 | cp --verbose --archive $8/. $HOME |
693 | 42 | fi | 46 | fi |
694 | 43 | 47 | ||
695 | 48 | # if there's a specific ics file to test, copy it on top of the canned confilg files | ||
696 | 49 | if [ -e $9 ]; then | ||
697 | 50 | echo "copying $9 into $HOME" | ||
698 | 51 | cp --verbose --archive $9 ${XDG_DATA_HOME}/evolution/tasks/system/tasks.ics | ||
699 | 52 | fi | ||
700 | 53 | |||
701 | 44 | # run dbus-test-runner | 54 | # run dbus-test-runner |
702 | 45 | $1 --keep-env --max-wait=90 \ | 55 | $1 --keep-env --max-wait=90 \ |
703 | 46 | --task $2 --task-name $3 --wait-until-complete --wait-for=org.gnome.evolution.dataserver.Calendar4 \ | 56 | --task $2 --task-name $3 --wait-until-complete --wait-for=org.gnome.evolution.dataserver.Calendar4 \ |
704 | 47 | 57 | ||
705 | === added file 'tests/test-eds-ics-all-day-events.cpp' | |||
706 | --- tests/test-eds-ics-all-day-events.cpp 1970-01-01 00:00:00 +0000 | |||
707 | +++ tests/test-eds-ics-all-day-events.cpp 2015-05-21 12:47:48 +0000 | |||
708 | @@ -0,0 +1,91 @@ | |||
709 | 1 | /* | ||
710 | 2 | * Copyright 2015 Canonical Ltd. | ||
711 | 3 | * | ||
712 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
713 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
714 | 6 | * by the Free Software Foundation. | ||
715 | 7 | * | ||
716 | 8 | * This program is distributed in the hope that it will be useful, but | ||
717 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
718 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
719 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
720 | 12 | * | ||
721 | 13 | * You should have received a copy of the GNU General Public License along | ||
722 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
723 | 15 | * | ||
724 | 16 | * Authors: | ||
725 | 17 | * Charles Kerr <charles.kerr@canonical.com> | ||
726 | 18 | */ | ||
727 | 19 | |||
728 | 20 | #include <algorithm> | ||
729 | 21 | |||
730 | 22 | #include <datetime/alarm-queue-simple.h> | ||
731 | 23 | #include <datetime/clock-mock.h> | ||
732 | 24 | #include <datetime/engine-eds.h> | ||
733 | 25 | #include <datetime/planner-range.h> | ||
734 | 26 | |||
735 | 27 | #include <gtest/gtest.h> | ||
736 | 28 | |||
737 | 29 | #include "glib-fixture.h" | ||
738 | 30 | #include "print-to.h" | ||
739 | 31 | #include "timezone-mock.h" | ||
740 | 32 | #include "wakeup-timer-mock.h" | ||
741 | 33 | |||
742 | 34 | using namespace unity::indicator::datetime; | ||
743 | 35 | using VAlarmFixture = GlibFixture; | ||
744 | 36 | |||
745 | 37 | /*** | ||
746 | 38 | **** | ||
747 | 39 | ***/ | ||
748 | 40 | |||
749 | 41 | TEST_F(VAlarmFixture, MultipleAppointments) | ||
750 | 42 | { | ||
751 | 43 | // start the EDS engine | ||
752 | 44 | auto engine = std::make_shared<EdsEngine>(); | ||
753 | 45 | |||
754 | 46 | // we need a consistent timezone for the planner and our local DateTimes | ||
755 | 47 | constexpr char const * zone_str {"America/Chicago"}; | ||
756 | 48 | auto tz = std::make_shared<MockTimezone>(zone_str); | ||
757 | 49 | auto gtz = g_time_zone_new(zone_str); | ||
758 | 50 | |||
759 | 51 | // make a planner that looks at the first half of 2015 in EDS | ||
760 | 52 | auto planner = std::make_shared<SimpleRangePlanner>(engine, tz); | ||
761 | 53 | const DateTime range_begin {gtz, 2015,1, 1, 0, 0, 0.0}; | ||
762 | 54 | const DateTime range_end {gtz, 2015,6,31,23,59,59.5}; | ||
763 | 55 | planner->range().set(std::make_pair(range_begin, range_end)); | ||
764 | 56 | |||
765 | 57 | // give EDS a moment to load | ||
766 | 58 | if (planner->appointments().get().empty()) { | ||
767 | 59 | g_message("waiting a moment for EDS to load..."); | ||
768 | 60 | auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){ | ||
769 | 61 | g_message("ah, they loaded"); | ||
770 | 62 | if (!appointments.empty()) | ||
771 | 63 | g_main_loop_quit(loop); | ||
772 | 64 | }; | ||
773 | 65 | core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed)); | ||
774 | 66 | constexpr int max_wait_sec = 10; | ||
775 | 67 | wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND); | ||
776 | 68 | } | ||
777 | 69 | |||
778 | 70 | // what we expect to get... | ||
779 | 71 | Appointment expected_appt; | ||
780 | 72 | expected_appt.uid = "20150521T111538Z-7449-1000-3572-0@ghidorah"; | ||
781 | 73 | expected_appt.color = "#becedd"; | ||
782 | 74 | expected_appt.summary = "Memorial Day"; | ||
783 | 75 | expected_appt.begin = DateTime{gtz,2015,5,25,0,0,0}; | ||
784 | 76 | expected_appt.end = DateTime{gtz,2015,5,26,0,0,0}; | ||
785 | 77 | |||
786 | 78 | // compare it to what we actually loaded... | ||
787 | 79 | const auto appts = planner->appointments().get(); | ||
788 | 80 | ASSERT_EQ(1, appts.size()); | ||
789 | 81 | const auto& appt = appts[0]; | ||
790 | 82 | EXPECT_EQ(expected_appt.begin, appt.begin); | ||
791 | 83 | EXPECT_EQ(expected_appt.end, appt.end); | ||
792 | 84 | EXPECT_EQ(expected_appt.uid, appt.uid); | ||
793 | 85 | EXPECT_EQ(expected_appt.color, appt.color); | ||
794 | 86 | EXPECT_EQ(expected_appt.summary, appt.summary); | ||
795 | 87 | EXPECT_EQ(0, appt.alarms.size()); | ||
796 | 88 | |||
797 | 89 | // cleanup | ||
798 | 90 | g_time_zone_unref(gtz); | ||
799 | 91 | } | ||
800 | 0 | 92 | ||
801 | === added file 'tests/test-eds-ics-all-day-events.ics' | |||
802 | --- tests/test-eds-ics-all-day-events.ics 1970-01-01 00:00:00 +0000 | |||
803 | +++ tests/test-eds-ics-all-day-events.ics 2015-05-21 12:47:48 +0000 | |||
804 | @@ -0,0 +1,19 @@ | |||
805 | 1 | BEGIN:VCALENDAR | ||
806 | 2 | CALSCALE:GREGORIAN | ||
807 | 3 | PRODID:-//Ximian//NONSGML Evolution Calendar//EN | ||
808 | 4 | VERSION:2.0 | ||
809 | 5 | X-EVOLUTION-DATA-REVISION:2015-05-07T21:14:49.315443Z(0) | ||
810 | 6 | BEGIN:VEVENT | ||
811 | 7 | UID:20150521T111538Z-7449-1000-3572-0@ghidorah | ||
812 | 8 | DTSTAMP:20150521T001128Z | ||
813 | 9 | DTSTART;VALUE=DATE:20150525 | ||
814 | 10 | DTEND;VALUE=DATE:20150526 | ||
815 | 11 | TRANSP:TRANSPARENT | ||
816 | 12 | SEQUENCE:2 | ||
817 | 13 | SUMMARY:Memorial Day | ||
818 | 14 | DESCRIPTION:Today is Memorial Day | ||
819 | 15 | CLASS:PUBLIC | ||
820 | 16 | CREATED:20150521T111638Z | ||
821 | 17 | LAST-MODIFIED:20150521T111638Z | ||
822 | 18 | END:VEVENT | ||
823 | 19 | END:VCALENDAR | ||
824 | 0 | 20 | ||
825 | === added directory 'tests/test-eds-ics-config-files' | |||
826 | === added directory 'tests/test-eds-ics-config-files/.config' | |||
827 | === added directory 'tests/test-eds-ics-config-files/.config/evolution' | |||
828 | === added directory 'tests/test-eds-ics-config-files/.config/evolution/sources' | |||
829 | === added file 'tests/test-eds-ics-config-files/.config/evolution/sources/system-proxy.source' | |||
830 | --- tests/test-eds-ics-config-files/.config/evolution/sources/system-proxy.source 1970-01-01 00:00:00 +0000 | |||
831 | +++ tests/test-eds-ics-config-files/.config/evolution/sources/system-proxy.source 2015-05-21 12:47:48 +0000 | |||
832 | @@ -0,0 +1,21 @@ | |||
833 | 1 | |||
834 | 2 | [Data Source] | ||
835 | 3 | DisplayName=Default Proxy Settings | ||
836 | 4 | Enabled=true | ||
837 | 5 | Parent= | ||
838 | 6 | |||
839 | 7 | [Proxy] | ||
840 | 8 | Method=default | ||
841 | 9 | IgnoreHosts=localhost;127.0.0.0/8;::1; | ||
842 | 10 | AutoconfigUrl= | ||
843 | 11 | FtpHost= | ||
844 | 12 | FtpPort=0 | ||
845 | 13 | HttpAuthPassword= | ||
846 | 14 | HttpAuthUser= | ||
847 | 15 | HttpHost= | ||
848 | 16 | HttpPort=8080 | ||
849 | 17 | HttpUseAuth=false | ||
850 | 18 | HttpsHost= | ||
851 | 19 | HttpsPort=0 | ||
852 | 20 | SocksHost= | ||
853 | 21 | SocksPort=0 | ||
854 | 0 | 22 | ||
855 | === added directory 'tests/test-eds-ics-config-files/.local' | |||
856 | === added directory 'tests/test-eds-ics-config-files/.local/share' | |||
857 | === added directory 'tests/test-eds-ics-config-files/.local/share/evolution' | |||
858 | === added directory 'tests/test-eds-ics-config-files/.local/share/evolution/calendar' | |||
859 | === added directory 'tests/test-eds-ics-config-files/.local/share/evolution/calendar/system' | |||
860 | === added directory 'tests/test-eds-ics-config-files/.local/share/evolution/tasks' | |||
861 | === added directory 'tests/test-eds-ics-config-files/.local/share/evolution/tasks/system' | |||
862 | === added file 'tests/test-eds-ics-nonrepeating-events.cpp' | |||
863 | --- tests/test-eds-ics-nonrepeating-events.cpp 1970-01-01 00:00:00 +0000 | |||
864 | +++ tests/test-eds-ics-nonrepeating-events.cpp 2015-05-21 12:47:48 +0000 | |||
865 | @@ -0,0 +1,93 @@ | |||
866 | 1 | /* | ||
867 | 2 | * Copyright 2015 Canonical Ltd. | ||
868 | 3 | * | ||
869 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
870 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
871 | 6 | * by the Free Software Foundation. | ||
872 | 7 | * | ||
873 | 8 | * This program is distributed in the hope that it will be useful, but | ||
874 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
875 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
876 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
877 | 12 | * | ||
878 | 13 | * You should have received a copy of the GNU General Public License along | ||
879 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
880 | 15 | * | ||
881 | 16 | * Authors: | ||
882 | 17 | * Charles Kerr <charles.kerr@canonical.com> | ||
883 | 18 | */ | ||
884 | 19 | |||
885 | 20 | #include <algorithm> | ||
886 | 21 | |||
887 | 22 | #include <datetime/alarm-queue-simple.h> | ||
888 | 23 | #include <datetime/clock-mock.h> | ||
889 | 24 | #include <datetime/engine-eds.h> | ||
890 | 25 | #include <datetime/planner-range.h> | ||
891 | 26 | |||
892 | 27 | #include <gtest/gtest.h> | ||
893 | 28 | |||
894 | 29 | #include "glib-fixture.h" | ||
895 | 30 | #include "print-to.h" | ||
896 | 31 | #include "timezone-mock.h" | ||
897 | 32 | #include "wakeup-timer-mock.h" | ||
898 | 33 | |||
899 | 34 | using namespace unity::indicator::datetime; | ||
900 | 35 | using VAlarmFixture = GlibFixture; | ||
901 | 36 | |||
902 | 37 | /*** | ||
903 | 38 | **** | ||
904 | 39 | ***/ | ||
905 | 40 | |||
906 | 41 | TEST_F(VAlarmFixture, MultipleAppointments) | ||
907 | 42 | { | ||
908 | 43 | // start the EDS engine | ||
909 | 44 | auto engine = std::make_shared<EdsEngine>(); | ||
910 | 45 | |||
911 | 46 | // we need a consistent timezone for the planner and our local DateTimes | ||
912 | 47 | constexpr char const * zone_str {"America/Chicago"}; | ||
913 | 48 | auto tz = std::make_shared<MockTimezone>(zone_str); | ||
914 | 49 | auto gtz = g_time_zone_new(zone_str); | ||
915 | 50 | |||
916 | 51 | // make a planner that looks at the first half of 2015 in EDS | ||
917 | 52 | auto planner = std::make_shared<SimpleRangePlanner>(engine, tz); | ||
918 | 53 | const DateTime range_begin {gtz, 2015,1, 1, 0, 0, 0.0}; | ||
919 | 54 | const DateTime range_end {gtz, 2015,6,31,23,59,59.5}; | ||
920 | 55 | planner->range().set(std::make_pair(range_begin, range_end)); | ||
921 | 56 | |||
922 | 57 | // give EDS a moment to load | ||
923 | 58 | if (planner->appointments().get().empty()) { | ||
924 | 59 | g_message("waiting a moment for EDS to load..."); | ||
925 | 60 | auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){ | ||
926 | 61 | g_message("ah, they loaded"); | ||
927 | 62 | if (!appointments.empty()) | ||
928 | 63 | g_main_loop_quit(loop); | ||
929 | 64 | }; | ||
930 | 65 | core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed)); | ||
931 | 66 | constexpr int max_wait_sec = 10; | ||
932 | 67 | wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND); | ||
933 | 68 | } | ||
934 | 69 | |||
935 | 70 | // what we expect to get... | ||
936 | 71 | Appointment expected_appt; | ||
937 | 72 | expected_appt.uid = "20150520T000726Z-3878-32011-1770-81@ubuntu-phablet"; | ||
938 | 73 | expected_appt.color = "#becedd"; | ||
939 | 74 | expected_appt.summary = "Alarm"; | ||
940 | 75 | std::array<Alarm,1> expected_alarms = { | ||
941 | 76 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,20,20,00,0)}) | ||
942 | 77 | }; | ||
943 | 78 | |||
944 | 79 | // compare it to what we actually loaded... | ||
945 | 80 | const auto appts = planner->appointments().get(); | ||
946 | 81 | EXPECT_EQ(expected_alarms.size(), appts.size()); | ||
947 | 82 | for (size_t i=0, n=expected_alarms.size(); i<n; i++) { | ||
948 | 83 | const auto& appt = appts[i]; | ||
949 | 84 | EXPECT_EQ(expected_appt.uid, appt.uid); | ||
950 | 85 | EXPECT_EQ(expected_appt.color, appt.color); | ||
951 | 86 | EXPECT_EQ(expected_appt.summary, appt.summary); | ||
952 | 87 | EXPECT_EQ(1, appt.alarms.size()); | ||
953 | 88 | EXPECT_EQ(expected_alarms[i], appt.alarms[0]); | ||
954 | 89 | } | ||
955 | 90 | |||
956 | 91 | // cleanup | ||
957 | 92 | g_time_zone_unref(gtz); | ||
958 | 93 | } | ||
959 | 0 | 94 | ||
960 | === added file 'tests/test-eds-ics-nonrepeating-events.ics' | |||
961 | --- tests/test-eds-ics-nonrepeating-events.ics 1970-01-01 00:00:00 +0000 | |||
962 | +++ tests/test-eds-ics-nonrepeating-events.ics 2015-05-21 12:47:48 +0000 | |||
963 | @@ -0,0 +1,27 @@ | |||
964 | 1 | BEGIN:VCALENDAR | ||
965 | 2 | CALSCALE:GREGORIAN | ||
966 | 3 | PRODID:-//Ximian//NONSGML Evolution Calendar//EN | ||
967 | 4 | VERSION:2.0 | ||
968 | 5 | X-EVOLUTION-DATA-REVISION:2015-05-20T22:39:32.685099Z(1) | ||
969 | 6 | BEGIN:VTODO | ||
970 | 7 | UID:20150520T000726Z-3878-32011-1770-81@ubuntu-phablet | ||
971 | 8 | DTSTAMP:20150520T223932Z | ||
972 | 9 | DTSTART:20150520T200000 | ||
973 | 10 | SUMMARY:Alarm | ||
974 | 11 | CATEGORIES:x-canonical-alarm | ||
975 | 12 | SEQUENCE:1 | ||
976 | 13 | LAST-MODIFIED:20150520T223932Z | ||
977 | 14 | BEGIN:VALARM | ||
978 | 15 | X-EVOLUTION-ALARM-UID:20150520T223932Z-22506-32011-1771-2@ubuntu-phablet | ||
979 | 16 | ACTION:AUDIO | ||
980 | 17 | ATTACH:file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg | ||
981 | 18 | TRIGGER;VALUE=DURATION;RELATED=START:PT0S | ||
982 | 19 | END:VALARM | ||
983 | 20 | BEGIN:VALARM | ||
984 | 21 | X-EVOLUTION-ALARM-UID:20150520T223932Z-22506-32011-1771-3@ubuntu-phablet | ||
985 | 22 | ACTION:DISPLAY | ||
986 | 23 | DESCRIPTION:Alarm | ||
987 | 24 | TRIGGER;VALUE=DURATION;RELATED=START:PT0S | ||
988 | 25 | END:VALARM | ||
989 | 26 | END:VTODO | ||
990 | 27 | END:VCALENDAR | ||
991 | 0 | 28 | ||
992 | === added file 'tests/test-eds-ics-repeating-events.cpp' | |||
993 | --- tests/test-eds-ics-repeating-events.cpp 1970-01-01 00:00:00 +0000 | |||
994 | +++ tests/test-eds-ics-repeating-events.cpp 2015-05-21 12:47:48 +0000 | |||
995 | @@ -0,0 +1,100 @@ | |||
996 | 1 | /* | ||
997 | 2 | * Copyright 2015 Canonical Ltd. | ||
998 | 3 | * | ||
999 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1000 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
1001 | 6 | * by the Free Software Foundation. | ||
1002 | 7 | * | ||
1003 | 8 | * This program is distributed in the hope that it will be useful, but | ||
1004 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1005 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
1006 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
1007 | 12 | * | ||
1008 | 13 | * You should have received a copy of the GNU General Public License along | ||
1009 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1010 | 15 | * | ||
1011 | 16 | * Authors: | ||
1012 | 17 | * Charles Kerr <charles.kerr@canonical.com> | ||
1013 | 18 | */ | ||
1014 | 19 | |||
1015 | 20 | #include <algorithm> | ||
1016 | 21 | |||
1017 | 22 | #include <datetime/alarm-queue-simple.h> | ||
1018 | 23 | #include <datetime/clock-mock.h> | ||
1019 | 24 | #include <datetime/engine-eds.h> | ||
1020 | 25 | #include <datetime/planner-range.h> | ||
1021 | 26 | |||
1022 | 27 | #include <gtest/gtest.h> | ||
1023 | 28 | |||
1024 | 29 | #include "glib-fixture.h" | ||
1025 | 30 | #include "print-to.h" | ||
1026 | 31 | #include "timezone-mock.h" | ||
1027 | 32 | #include "wakeup-timer-mock.h" | ||
1028 | 33 | |||
1029 | 34 | using namespace unity::indicator::datetime; | ||
1030 | 35 | using VAlarmFixture = GlibFixture; | ||
1031 | 36 | |||
1032 | 37 | /*** | ||
1033 | 38 | **** | ||
1034 | 39 | ***/ | ||
1035 | 40 | |||
1036 | 41 | TEST_F(VAlarmFixture, MultipleAppointments) | ||
1037 | 42 | { | ||
1038 | 43 | // start the EDS engine | ||
1039 | 44 | auto engine = std::make_shared<EdsEngine>(); | ||
1040 | 45 | |||
1041 | 46 | // we need a consistent timezone for the planner and our local DateTimes | ||
1042 | 47 | constexpr char const * zone_str {"America/Chicago"}; | ||
1043 | 48 | auto tz = std::make_shared<MockTimezone>(zone_str); | ||
1044 | 49 | auto gtz = g_time_zone_new(zone_str); | ||
1045 | 50 | |||
1046 | 51 | // make a planner that looks at the first half of 2015 in EDS | ||
1047 | 52 | auto planner = std::make_shared<SimpleRangePlanner>(engine, tz); | ||
1048 | 53 | const DateTime range_begin {gtz, 2015,1, 1, 0, 0, 0.0}; | ||
1049 | 54 | const DateTime range_end {gtz, 2015,6,31,23,59,59.5}; | ||
1050 | 55 | planner->range().set(std::make_pair(range_begin, range_end)); | ||
1051 | 56 | |||
1052 | 57 | // give EDS a moment to load | ||
1053 | 58 | if (planner->appointments().get().empty()) { | ||
1054 | 59 | g_message("waiting a moment for EDS to load..."); | ||
1055 | 60 | auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){ | ||
1056 | 61 | g_message("ah, they loaded"); | ||
1057 | 62 | if (!appointments.empty()) | ||
1058 | 63 | g_main_loop_quit(loop); | ||
1059 | 64 | }; | ||
1060 | 65 | core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed)); | ||
1061 | 66 | constexpr int max_wait_sec = 10; | ||
1062 | 67 | wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND); | ||
1063 | 68 | } | ||
1064 | 69 | |||
1065 | 70 | // what we expect to get... | ||
1066 | 71 | Appointment expected_appt; | ||
1067 | 72 | expected_appt.uid = "20150507T211449Z-4262-32011-1418-1@ubuntu-phablet"; | ||
1068 | 73 | expected_appt.color = "#becedd"; | ||
1069 | 74 | expected_appt.summary = "Alarm"; | ||
1070 | 75 | std::array<Alarm,8> expected_alarms = { | ||
1071 | 76 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5, 8,16,40,0)}), | ||
1072 | 77 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,15,16,40,0)}), | ||
1073 | 78 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,22,16,40,0)}), | ||
1074 | 79 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,29,16,40,0)}), | ||
1075 | 80 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6, 5,16,40,0)}), | ||
1076 | 81 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6,12,16,40,0)}), | ||
1077 | 82 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6,19,16,40,0)}), | ||
1078 | 83 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6,26,16,40,0)}) | ||
1079 | 84 | }; | ||
1080 | 85 | |||
1081 | 86 | // compare it to what we actually loaded... | ||
1082 | 87 | const auto appts = planner->appointments().get(); | ||
1083 | 88 | EXPECT_EQ(expected_alarms.size(), appts.size()); | ||
1084 | 89 | for (size_t i=0, n=expected_alarms.size(); i<n; i++) { | ||
1085 | 90 | const auto& appt = appts[i]; | ||
1086 | 91 | EXPECT_EQ(expected_appt.uid, appt.uid); | ||
1087 | 92 | EXPECT_EQ(expected_appt.color, appt.color); | ||
1088 | 93 | EXPECT_EQ(expected_appt.summary, appt.summary); | ||
1089 | 94 | EXPECT_EQ(1, appt.alarms.size()); | ||
1090 | 95 | EXPECT_EQ(expected_alarms[i], appt.alarms[0]); | ||
1091 | 96 | } | ||
1092 | 97 | |||
1093 | 98 | // cleanup | ||
1094 | 99 | g_time_zone_unref(gtz); | ||
1095 | 100 | } | ||
1096 | 0 | 101 | ||
1097 | === added file 'tests/test-eds-ics-repeating-events.ics' | |||
1098 | --- tests/test-eds-ics-repeating-events.ics 1970-01-01 00:00:00 +0000 | |||
1099 | +++ tests/test-eds-ics-repeating-events.ics 2015-05-21 12:47:48 +0000 | |||
1100 | @@ -0,0 +1,28 @@ | |||
1101 | 1 | BEGIN:VCALENDAR | ||
1102 | 2 | CALSCALE:GREGORIAN | ||
1103 | 3 | PRODID:-//Ximian//NONSGML Evolution Calendar//EN | ||
1104 | 4 | VERSION:2.0 | ||
1105 | 5 | X-EVOLUTION-DATA-REVISION:2015-05-07T21:14:49.315443Z(0) | ||
1106 | 6 | BEGIN:VTODO | ||
1107 | 7 | UID:20150507T211449Z-4262-32011-1418-1@ubuntu-phablet | ||
1108 | 8 | DTSTAMP:20150508T211449Z | ||
1109 | 9 | DTSTART:20150508T164000 | ||
1110 | 10 | RRULE:FREQ=WEEKLY;BYDAY=FR | ||
1111 | 11 | SUMMARY:Alarm | ||
1112 | 12 | CATEGORIES:x-canonical-alarm | ||
1113 | 13 | CREATED:20150507T211449Z | ||
1114 | 14 | LAST-MODIFIED:20150507T211449Z | ||
1115 | 15 | BEGIN:VALARM | ||
1116 | 16 | X-EVOLUTION-ALARM-UID:20150507T211449Z-4262-32011-1418-2@ubuntu-phablet | ||
1117 | 17 | ACTION:AUDIO | ||
1118 | 18 | ATTACH:file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg | ||
1119 | 19 | TRIGGER;VALUE=DURATION;RELATED=START:PT0S | ||
1120 | 20 | END:VALARM | ||
1121 | 21 | BEGIN:VALARM | ||
1122 | 22 | X-EVOLUTION-ALARM-UID:20150507T211449Z-4262-32011-1418-3@ubuntu-phablet | ||
1123 | 23 | ACTION:DISPLAY | ||
1124 | 24 | DESCRIPTION:Alarm | ||
1125 | 25 | TRIGGER;VALUE=DURATION;RELATED=START:PT0S | ||
1126 | 26 | END:VALARM | ||
1127 | 27 | END:VTODO | ||
1128 | 28 | END:VCALENDAR | ||
1129 | 0 | 29 | ||
1130 | === renamed file 'tests/test-eds-valarms.cpp' => 'tests/test-eds-ics-repeating-valarms.cpp' | |||
1131 | === added file 'tests/test-eds-ics-repeating-valarms.ics' | |||
1132 | --- tests/test-eds-ics-repeating-valarms.ics 1970-01-01 00:00:00 +0000 | |||
1133 | +++ tests/test-eds-ics-repeating-valarms.ics 2015-05-21 12:47:48 +0000 | |||
1134 | @@ -0,0 +1,47 @@ | |||
1135 | 1 | BEGIN:VCALENDAR | ||
1136 | 2 | CALSCALE:GREGORIAN | ||
1137 | 3 | PRODID:-//Ximian//NONSGML Evolution Calendar//EN | ||
1138 | 4 | VERSION:2.0 | ||
1139 | 5 | X-EVOLUTION-DATA-REVISION:2015-04-05T21:32:47.354433Z(2) | ||
1140 | 6 | BEGIN:VEVENT | ||
1141 | 7 | UID:20150405T213247Z-4371-32011-1698-1@ubuntu-phablet | ||
1142 | 8 | DTSTAMP:20150405T213247Z | ||
1143 | 9 | DTSTART:20150424T183500Z | ||
1144 | 10 | DTEND:20150424T193554Z | ||
1145 | 11 | X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:Can't parse as RECUR value | ||
1146 | 12 | in RRULE property. Removing entire property: ERROR: No Value | ||
1147 | 13 | SUMMARY:London Sprint Flight | ||
1148 | 14 | CREATED:20150405T213247Z | ||
1149 | 15 | LAST-MODIFIED:20150405T213247Z | ||
1150 | 16 | BEGIN:VALARM | ||
1151 | 17 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-2@ubuntu-phablet | ||
1152 | 18 | ACTION:AUDIO | ||
1153 | 19 | TRIGGER;VALUE=DURATION;RELATED=START:-P1D | ||
1154 | 20 | REPEAT:3 | ||
1155 | 21 | DURATION:PT2M | ||
1156 | 22 | END:VALARM | ||
1157 | 23 | BEGIN:VALARM | ||
1158 | 24 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-3@ubuntu-phablet | ||
1159 | 25 | ACTION:DISPLAY | ||
1160 | 26 | DESCRIPTION:Time to pack! | ||
1161 | 27 | TRIGGER;VALUE=DURATION;RELATED=START:-P1D | ||
1162 | 28 | REPEAT:3 | ||
1163 | 29 | DURATION:PT2M | ||
1164 | 30 | END:VALARM | ||
1165 | 31 | BEGIN:VALARM | ||
1166 | 32 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-5@ubuntu-phablet | ||
1167 | 33 | ACTION:AUDIO | ||
1168 | 34 | TRIGGER;VALUE=DURATION;RELATED=START:-PT3H | ||
1169 | 35 | REPEAT:3 | ||
1170 | 36 | DURATION:PT2M | ||
1171 | 37 | END:VALARM | ||
1172 | 38 | BEGIN:VALARM | ||
1173 | 39 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-6@ubuntu-phablet | ||
1174 | 40 | ACTION:DISPLAY | ||
1175 | 41 | DESCRIPTION:Go to the airport! | ||
1176 | 42 | TRIGGER;VALUE=DURATION;RELATED=START:-PT3H | ||
1177 | 43 | REPEAT:3 | ||
1178 | 44 | DURATION:PT2M | ||
1179 | 45 | END:VALARM | ||
1180 | 46 | END:VEVENT | ||
1181 | 47 | END:VCALENDAR | ||
1182 | 0 | 48 | ||
1183 | === removed directory 'tests/test-eds-tasks-config-files' | |||
1184 | === removed directory 'tests/test-eds-tasks-config-files/.config' | |||
1185 | === removed directory 'tests/test-eds-tasks-config-files/.config/evolution' | |||
1186 | === removed directory 'tests/test-eds-tasks-config-files/.config/evolution/sources' | |||
1187 | === removed file 'tests/test-eds-tasks-config-files/.config/evolution/sources/system-proxy.source' | |||
1188 | --- tests/test-eds-tasks-config-files/.config/evolution/sources/system-proxy.source 2015-05-08 00:08:13 +0000 | |||
1189 | +++ tests/test-eds-tasks-config-files/.config/evolution/sources/system-proxy.source 1970-01-01 00:00:00 +0000 | |||
1190 | @@ -1,21 +0,0 @@ | |||
1191 | 1 | |||
1192 | 2 | [Data Source] | ||
1193 | 3 | DisplayName=Default Proxy Settings | ||
1194 | 4 | Enabled=true | ||
1195 | 5 | Parent= | ||
1196 | 6 | |||
1197 | 7 | [Proxy] | ||
1198 | 8 | Method=default | ||
1199 | 9 | IgnoreHosts=localhost;127.0.0.0/8;::1; | ||
1200 | 10 | AutoconfigUrl= | ||
1201 | 11 | FtpHost= | ||
1202 | 12 | FtpPort=0 | ||
1203 | 13 | HttpAuthPassword= | ||
1204 | 14 | HttpAuthUser= | ||
1205 | 15 | HttpHost= | ||
1206 | 16 | HttpPort=8080 | ||
1207 | 17 | HttpUseAuth=false | ||
1208 | 18 | HttpsHost= | ||
1209 | 19 | HttpsPort=0 | ||
1210 | 20 | SocksHost= | ||
1211 | 21 | SocksPort=0 | ||
1212 | 22 | 0 | ||
1213 | === removed directory 'tests/test-eds-tasks-config-files/.local' | |||
1214 | === removed directory 'tests/test-eds-tasks-config-files/.local/share' | |||
1215 | === removed directory 'tests/test-eds-tasks-config-files/.local/share/evolution' | |||
1216 | === removed directory 'tests/test-eds-tasks-config-files/.local/share/evolution/tasks' | |||
1217 | === removed directory 'tests/test-eds-tasks-config-files/.local/share/evolution/tasks/system' | |||
1218 | === removed file 'tests/test-eds-tasks-config-files/.local/share/evolution/tasks/system/tasks.ics' | |||
1219 | --- tests/test-eds-tasks-config-files/.local/share/evolution/tasks/system/tasks.ics 2015-05-08 00:08:13 +0000 | |||
1220 | +++ tests/test-eds-tasks-config-files/.local/share/evolution/tasks/system/tasks.ics 1970-01-01 00:00:00 +0000 | |||
1221 | @@ -1,28 +0,0 @@ | |||
1222 | 1 | BEGIN:VCALENDAR | ||
1223 | 2 | CALSCALE:GREGORIAN | ||
1224 | 3 | PRODID:-//Ximian//NONSGML Evolution Calendar//EN | ||
1225 | 4 | VERSION:2.0 | ||
1226 | 5 | X-EVOLUTION-DATA-REVISION:2015-05-07T21:14:49.315443Z(0) | ||
1227 | 6 | BEGIN:VTODO | ||
1228 | 7 | UID:20150507T211449Z-4262-32011-1418-1@ubuntu-phablet | ||
1229 | 8 | DTSTAMP:20150508T211449Z | ||
1230 | 9 | DTSTART:20150508T164000 | ||
1231 | 10 | RRULE:FREQ=WEEKLY;BYDAY=FR | ||
1232 | 11 | SUMMARY:Alarm | ||
1233 | 12 | CATEGORIES:x-canonical-alarm | ||
1234 | 13 | CREATED:20150507T211449Z | ||
1235 | 14 | LAST-MODIFIED:20150507T211449Z | ||
1236 | 15 | BEGIN:VALARM | ||
1237 | 16 | X-EVOLUTION-ALARM-UID:20150507T211449Z-4262-32011-1418-2@ubuntu-phablet | ||
1238 | 17 | ACTION:AUDIO | ||
1239 | 18 | ATTACH:file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg | ||
1240 | 19 | TRIGGER;VALUE=DURATION;RELATED=START:PT0S | ||
1241 | 20 | END:VALARM | ||
1242 | 21 | BEGIN:VALARM | ||
1243 | 22 | X-EVOLUTION-ALARM-UID:20150507T211449Z-4262-32011-1418-3@ubuntu-phablet | ||
1244 | 23 | ACTION:DISPLAY | ||
1245 | 24 | DESCRIPTION:Alarm | ||
1246 | 25 | TRIGGER;VALUE=DURATION;RELATED=START:PT0S | ||
1247 | 26 | END:VALARM | ||
1248 | 27 | END:VTODO | ||
1249 | 28 | END:VCALENDAR | ||
1250 | 29 | 0 | ||
1251 | === removed file 'tests/test-eds-tasks.cpp' | |||
1252 | --- tests/test-eds-tasks.cpp 2015-05-08 00:08:13 +0000 | |||
1253 | +++ tests/test-eds-tasks.cpp 1970-01-01 00:00:00 +0000 | |||
1254 | @@ -1,101 +0,0 @@ | |||
1255 | 1 | /* | ||
1256 | 2 | * Copyright 2015 Canonical Ltd. | ||
1257 | 3 | * | ||
1258 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1259 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
1260 | 6 | * by the Free Software Foundation. | ||
1261 | 7 | * | ||
1262 | 8 | * This program is distributed in the hope that it will be useful, but | ||
1263 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1264 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
1265 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
1266 | 12 | * | ||
1267 | 13 | * You should have received a copy of the GNU General Public License along | ||
1268 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1269 | 15 | * | ||
1270 | 16 | * Authors: | ||
1271 | 17 | * Charles Kerr <charles.kerr@canonical.com> | ||
1272 | 18 | */ | ||
1273 | 19 | |||
1274 | 20 | #include <algorithm> | ||
1275 | 21 | |||
1276 | 22 | #include <datetime/alarm-queue-simple.h> | ||
1277 | 23 | #include <datetime/clock-mock.h> | ||
1278 | 24 | #include <datetime/engine-eds.h> | ||
1279 | 25 | #include <datetime/planner-range.h> | ||
1280 | 26 | |||
1281 | 27 | #include <gtest/gtest.h> | ||
1282 | 28 | |||
1283 | 29 | #include "glib-fixture.h" | ||
1284 | 30 | #include "print-to.h" | ||
1285 | 31 | #include "timezone-mock.h" | ||
1286 | 32 | #include "wakeup-timer-mock.h" | ||
1287 | 33 | |||
1288 | 34 | using namespace unity::indicator::datetime; | ||
1289 | 35 | using VAlarmFixture = GlibFixture; | ||
1290 | 36 | |||
1291 | 37 | /*** | ||
1292 | 38 | **** | ||
1293 | 39 | ***/ | ||
1294 | 40 | |||
1295 | 41 | TEST_F(VAlarmFixture, MultipleAppointments) | ||
1296 | 42 | { | ||
1297 | 43 | // start the EDS engine | ||
1298 | 44 | auto engine = std::make_shared<EdsEngine>(); | ||
1299 | 45 | |||
1300 | 46 | // we need a consistent timezone for the planner and our local DateTimes | ||
1301 | 47 | constexpr char const * zone_str {"America/Chicago"}; | ||
1302 | 48 | auto tz = std::make_shared<MockTimezone>(zone_str); | ||
1303 | 49 | auto gtz = g_time_zone_new(zone_str); | ||
1304 | 50 | |||
1305 | 51 | // make a planner that looks at the first half of 2015 in EDS | ||
1306 | 52 | auto planner = std::make_shared<SimpleRangePlanner>(engine, tz); | ||
1307 | 53 | const DateTime range_begin {gtz, 2015,1, 1, 0, 0, 0.0}; | ||
1308 | 54 | const DateTime range_end {gtz, 2015,6,31,23,59,59.5}; | ||
1309 | 55 | planner->range().set(std::make_pair(range_begin, range_end)); | ||
1310 | 56 | |||
1311 | 57 | // give EDS a moment to load | ||
1312 | 58 | if (planner->appointments().get().empty()) { | ||
1313 | 59 | g_message("waiting a moment for EDS to load..."); | ||
1314 | 60 | auto on_appointments_changed = [this](const std::vector<Appointment>& appointments){ | ||
1315 | 61 | g_message("ah, they loaded"); | ||
1316 | 62 | if (!appointments.empty()) | ||
1317 | 63 | g_main_loop_quit(loop); | ||
1318 | 64 | }; | ||
1319 | 65 | core::ScopedConnection conn(planner->appointments().changed().connect(on_appointments_changed)); | ||
1320 | 66 | constexpr int max_wait_sec = 10; | ||
1321 | 67 | wait_msec(max_wait_sec * G_TIME_SPAN_MILLISECOND); | ||
1322 | 68 | } | ||
1323 | 69 | |||
1324 | 70 | // what we expect to get... | ||
1325 | 71 | Appointment expected_appt; | ||
1326 | 72 | expected_appt.uid = "20150507T211449Z-4262-32011-1418-1@ubuntu-phablet"; | ||
1327 | 73 | expected_appt.color = "#becedd"; | ||
1328 | 74 | expected_appt.summary = "Alarm"; | ||
1329 | 75 | std::array<Alarm,8> expected_alarms = { | ||
1330 | 76 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5, 8,16,40,0)}), | ||
1331 | 77 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,15,16,40,0)}), | ||
1332 | 78 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,22,16,40,0)}), | ||
1333 | 79 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,5,29,16,40,0)}), | ||
1334 | 80 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6, 5,16,40,0)}), | ||
1335 | 81 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6,12,16,40,0)}), | ||
1336 | 82 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6,19,16,40,0)}), | ||
1337 | 83 | Alarm({"Alarm", "file:///usr/share/sounds/ubuntu/ringtones/Suru arpeggio.ogg", DateTime(gtz,2015,6,26,16,40,0)}) | ||
1338 | 84 | }; | ||
1339 | 85 | |||
1340 | 86 | // compare it to what we actually loaded... | ||
1341 | 87 | const auto appts = planner->appointments().get(); | ||
1342 | 88 | EXPECT_EQ(expected_alarms.size(), appts.size()); | ||
1343 | 89 | for (size_t i=0, n=expected_alarms.size(); i<n; i++) { | ||
1344 | 90 | const auto& appt = appts[i]; | ||
1345 | 91 | EXPECT_EQ(expected_appt.uid, appt.uid); | ||
1346 | 92 | EXPECT_EQ(expected_appt.color, appt.color); | ||
1347 | 93 | EXPECT_EQ(expected_appt.summary, appt.summary); | ||
1348 | 94 | EXPECT_EQ(1, appt.alarms.size()); | ||
1349 | 95 | EXPECT_EQ(expected_alarms[i], appt.alarms[0]); | ||
1350 | 96 | } | ||
1351 | 97 | |||
1352 | 98 | |||
1353 | 99 | // cleanup | ||
1354 | 100 | g_time_zone_unref(gtz); | ||
1355 | 101 | } | ||
1356 | 102 | 0 | ||
1357 | === removed directory 'tests/test-eds-valarms-config-files' | |||
1358 | === removed directory 'tests/test-eds-valarms-config-files/.config' | |||
1359 | === removed directory 'tests/test-eds-valarms-config-files/.config/evolution' | |||
1360 | === removed directory 'tests/test-eds-valarms-config-files/.config/evolution/sources' | |||
1361 | === removed file 'tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source' | |||
1362 | --- tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source 2015-04-06 00:19:01 +0000 | |||
1363 | +++ tests/test-eds-valarms-config-files/.config/evolution/sources/system-proxy.source 1970-01-01 00:00:00 +0000 | |||
1364 | @@ -1,21 +0,0 @@ | |||
1365 | 1 | |||
1366 | 2 | [Data Source] | ||
1367 | 3 | DisplayName=Default Proxy Settings | ||
1368 | 4 | Enabled=true | ||
1369 | 5 | Parent= | ||
1370 | 6 | |||
1371 | 7 | [Proxy] | ||
1372 | 8 | Method=default | ||
1373 | 9 | IgnoreHosts=localhost;127.0.0.0/8;::1; | ||
1374 | 10 | AutoconfigUrl= | ||
1375 | 11 | FtpHost= | ||
1376 | 12 | FtpPort=0 | ||
1377 | 13 | HttpAuthPassword= | ||
1378 | 14 | HttpAuthUser= | ||
1379 | 15 | HttpHost= | ||
1380 | 16 | HttpPort=8080 | ||
1381 | 17 | HttpUseAuth=false | ||
1382 | 18 | HttpsHost= | ||
1383 | 19 | HttpsPort=0 | ||
1384 | 20 | SocksHost= | ||
1385 | 21 | SocksPort=0 | ||
1386 | 22 | 0 | ||
1387 | === removed directory 'tests/test-eds-valarms-config-files/.local' | |||
1388 | === removed directory 'tests/test-eds-valarms-config-files/.local/share' | |||
1389 | === removed directory 'tests/test-eds-valarms-config-files/.local/share/evolution' | |||
1390 | === removed directory 'tests/test-eds-valarms-config-files/.local/share/evolution/calendar' | |||
1391 | === removed directory 'tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system' | |||
1392 | === removed file 'tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics' | |||
1393 | --- tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics 2015-04-06 00:19:01 +0000 | |||
1394 | +++ tests/test-eds-valarms-config-files/.local/share/evolution/calendar/system/calendar.ics 1970-01-01 00:00:00 +0000 | |||
1395 | @@ -1,47 +0,0 @@ | |||
1396 | 1 | BEGIN:VCALENDAR | ||
1397 | 2 | CALSCALE:GREGORIAN | ||
1398 | 3 | PRODID:-//Ximian//NONSGML Evolution Calendar//EN | ||
1399 | 4 | VERSION:2.0 | ||
1400 | 5 | X-EVOLUTION-DATA-REVISION:2015-04-05T21:32:47.354433Z(2) | ||
1401 | 6 | BEGIN:VEVENT | ||
1402 | 7 | UID:20150405T213247Z-4371-32011-1698-1@ubuntu-phablet | ||
1403 | 8 | DTSTAMP:20150405T213247Z | ||
1404 | 9 | DTSTART:20150424T183500Z | ||
1405 | 10 | DTEND:20150424T193554Z | ||
1406 | 11 | X-LIC-ERROR;X-LIC-ERRORTYPE=VALUE-PARSE-ERROR:Can't parse as RECUR value | ||
1407 | 12 | in RRULE property. Removing entire property: ERROR: No Value | ||
1408 | 13 | SUMMARY:London Sprint Flight | ||
1409 | 14 | CREATED:20150405T213247Z | ||
1410 | 15 | LAST-MODIFIED:20150405T213247Z | ||
1411 | 16 | BEGIN:VALARM | ||
1412 | 17 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-2@ubuntu-phablet | ||
1413 | 18 | ACTION:AUDIO | ||
1414 | 19 | TRIGGER;VALUE=DURATION;RELATED=START:-P1D | ||
1415 | 20 | REPEAT:3 | ||
1416 | 21 | DURATION:PT2M | ||
1417 | 22 | END:VALARM | ||
1418 | 23 | BEGIN:VALARM | ||
1419 | 24 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-3@ubuntu-phablet | ||
1420 | 25 | ACTION:DISPLAY | ||
1421 | 26 | DESCRIPTION:Time to pack! | ||
1422 | 27 | TRIGGER;VALUE=DURATION;RELATED=START:-P1D | ||
1423 | 28 | REPEAT:3 | ||
1424 | 29 | DURATION:PT2M | ||
1425 | 30 | END:VALARM | ||
1426 | 31 | BEGIN:VALARM | ||
1427 | 32 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-5@ubuntu-phablet | ||
1428 | 33 | ACTION:AUDIO | ||
1429 | 34 | TRIGGER;VALUE=DURATION;RELATED=START:-PT3H | ||
1430 | 35 | REPEAT:3 | ||
1431 | 36 | DURATION:PT2M | ||
1432 | 37 | END:VALARM | ||
1433 | 38 | BEGIN:VALARM | ||
1434 | 39 | X-EVOLUTION-ALARM-UID:20150405T213247Z-4371-32011-1698-6@ubuntu-phablet | ||
1435 | 40 | ACTION:DISPLAY | ||
1436 | 41 | DESCRIPTION:Go to the airport! | ||
1437 | 42 | TRIGGER;VALUE=DURATION;RELATED=START:-PT3H | ||
1438 | 43 | REPEAT:3 | ||
1439 | 44 | DURATION:PT2M | ||
1440 | 45 | END:VALARM | ||
1441 | 46 | END:VEVENT | ||
1442 | 47 | END:VCALENDAR |
There seems to be a small object leak, but otherwise I can only find faults in the EDS API :-)