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