[evolution-data-server/wip/mcrha/libical-glib] Add a test for e-cal-recur and fix recurrence generation through ECalClient



commit d80f7907712143e6b2806085fe1a1c7872d898d4
Author: Milan Crha <mcrha redhat com>
Date:   Thu Apr 18 13:54:53 2019 +0200

    Add a test for e-cal-recur and fix recurrence generation through ECalClient

 src/calendar/libecal/e-cal-client.c | 281 +++++--------------------
 tests/libecal/CMakeLists.txt        |   1 +
 tests/libecal/test-cal-recur.c      | 407 ++++++++++++++++++++++++++++++++++++
 3 files changed, 461 insertions(+), 228 deletions(-)
---
diff --git a/src/calendar/libecal/e-cal-client.c b/src/calendar/libecal/e-cal-client.c
index 38dc2cc43..998fddeda 100644
--- a/src/calendar/libecal/e-cal-client.c
+++ b/src/calendar/libecal/e-cal-client.c
@@ -2159,15 +2159,25 @@ e_cal_client_check_recurrences_no_master (ECalClient *client)
 
 struct comp_instance {
        ECalComponent *comp;
-       time_t start;
-       time_t end;
+       ICalTime *start;
+       ICalTime *end;
 };
 
+static void
+comp_instance_free (gpointer ptr)
+{
+       struct comp_instance *ci = ptr;
+
+       if (ci) {
+               g_clear_object (&ci->comp);
+               g_clear_object (&ci->start);
+               g_clear_object (&ci->end);
+               g_free (ci);
+       }
+}
+
 struct instances_info {
        GSList **instances;
-       ICalTimezone *start_zone;
-       ICalTimezone *end_zone;
-       ICalTimezone *default_zone;
 };
 
 /* Called from cal_recur_generate_instances(); adds an instance to the list */
@@ -2186,49 +2196,23 @@ add_instance_cb (ICalComponent *icomp,
        instances_hold = user_data;
        list = instances_hold->instances;
 
-       ci = g_new (struct comp_instance, 1);
+       ci = g_new0 (struct comp_instance, 1);
 
        /* add the instance to the list */
        ci->comp = e_cal_component_new_from_icalcomponent (i_cal_component_new_clone (icomp));
        if (!ci->comp) {
-               g_free (ci);
+               comp_instance_free (ci);
                return FALSE;
        }
 
        /* make sure we return an instance */
        if (e_cal_component_has_recurrences (ci->comp) &&
            !e_cal_component_is_instance (ci->comp)) {
-               ECalComponentRange *range;
-               ICalTime *itt;
                ECalComponentDateTime *dtstart, *dtend;
+               ECalComponentRange *range;
 
-               dtstart = e_cal_component_get_dtstart (ci->comp);
-
-               if (instances_hold->start_zone) {
-                       itt = i_cal_time_from_timet_with_zone (i_cal_time_as_timet (start),
-                               dtstart && e_cal_component_datetime_get_value (dtstart) && i_cal_time_is_date 
(e_cal_component_datetime_get_value (dtstart)),
-                               instances_hold->start_zone);
-                       if (dtstart)
-                               e_cal_component_datetime_set_tzid (dtstart, i_cal_timezone_get_tzid 
(instances_hold->start_zone));
-               } else if (dtstart && instances_hold->default_zone &&
-                          e_cal_component_datetime_get_value (dtstart) &&
-                          i_cal_time_is_date (e_cal_component_datetime_get_value (dtstart)) &&
-                          !e_cal_component_datetime_get_tzid (dtstart)) {
-                       /* Floating date, set in the default zone */
-                       itt = i_cal_time_from_timet_with_zone (i_cal_time_as_timet (start), TRUE, 
instances_hold->default_zone);
-               } else {
-                       itt = i_cal_time_from_timet_with_zone (i_cal_time_as_timet (start),
-                               dtstart && e_cal_component_datetime_get_value (dtstart) && i_cal_time_is_date 
(e_cal_component_datetime_get_value (dtstart)),
-                               NULL);
-                       if (dtstart)
-                               e_cal_component_datetime_set_tzid (dtstart, NULL);
-               }
-
-               if (dtstart)
-                       e_cal_component_datetime_set_value (dtstart, itt);
-               else
-                       dtstart = e_cal_component_datetime_new (itt, instances_hold->start_zone ? 
i_cal_timezone_get_tzid (instances_hold->start_zone) : NULL);
-
+               /* Update DTSTART */
+               dtstart = e_cal_component_datetime_new (start, i_cal_time_get_tzid (start));
                e_cal_component_set_dtstart (ci->comp, dtstart);
 
                /* set the RECUR-ID for the instance */
@@ -2238,45 +2222,15 @@ add_instance_cb (ICalComponent *icomp,
 
                e_cal_component_datetime_free (dtstart);
                e_cal_component_range_free (range);
-               g_clear_object (&itt);
 
                /* Update DTEND */
-
-               dtend = e_cal_component_get_dtend (ci->comp);
-
-               if (instances_hold->end_zone) {
-                       itt = i_cal_time_from_timet_with_zone (i_cal_time_as_timet (end),
-                               dtend && e_cal_component_datetime_get_value (dtend) && i_cal_time_is_date 
(e_cal_component_datetime_get_value (dtend)),
-                               instances_hold->end_zone);
-                       if (dtend)
-                               e_cal_component_datetime_set_tzid (dtend, i_cal_timezone_get_tzid 
(instances_hold->end_zone));
-               } else if (dtend && instances_hold->default_zone &&
-                          e_cal_component_datetime_get_value (dtend) &&
-                          i_cal_time_is_date (e_cal_component_datetime_get_value (dtend)) &&
-                          !e_cal_component_datetime_get_tzid (dtend)) {
-                       /* Floating date, set in the default zone */
-                       itt = i_cal_time_from_timet_with_zone (i_cal_time_as_timet (end), TRUE, 
instances_hold->default_zone);
-               } else {
-                       itt = i_cal_time_from_timet_with_zone (i_cal_time_as_timet (end),
-                               dtend && e_cal_component_datetime_get_value (dtend) && i_cal_time_is_date 
(e_cal_component_datetime_get_value (dtend)),
-                               NULL);
-                       if (dtend)
-                               e_cal_component_datetime_set_tzid (dtend, NULL);
-               }
-
-               if (dtend)
-                       e_cal_component_datetime_set_value (dtend, itt);
-               else
-                       dtend = e_cal_component_datetime_new (itt, instances_hold->end_zone ? 
i_cal_timezone_get_tzid (instances_hold->end_zone) : NULL);
-
+               dtend = e_cal_component_datetime_new (end, i_cal_time_get_tzid (end));
                e_cal_component_set_dtend (ci->comp, dtend);
-
                e_cal_component_datetime_free (dtend);
-               g_clear_object (&itt);
        }
 
-       ci->start = i_cal_time_as_timet (start);
-       ci->end = i_cal_time_as_timet (end);
+       ci->start = i_cal_time_new_clone (start);
+       ci->end = i_cal_time_new_clone (end);
 
        *list = g_slist_prepend (*list, ci);
 
@@ -2289,13 +2243,11 @@ compare_comp_instance (gconstpointer a,
                        gconstpointer b)
 {
        const struct comp_instance *cia, *cib;
-       time_t diff;
 
        cia = a;
        cib = b;
 
-       diff = cia->start - cib->start;
-       return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+       return i_cal_time_compare (cia->start, cib->start);
 }
 
 static time_t
@@ -2390,9 +2342,11 @@ process_detached_instances (GSList *instances,
 
                                if (e_cal_component_range_get_kind (recur_id) == E_CAL_COMPONENT_RANGE_SINGLE 
&& i_rid == d_rid) {
                                        g_object_unref (ci->comp);
+                                       g_clear_object (&ci->start);
+                                       g_clear_object (&ci->end);
                                        ci->comp = g_object_ref (cid->comp);
-                                       ci->start = cid->start;
-                                       ci->end = cid->end;
+                                       ci->start = i_cal_time_new_clone (cid->start);
+                                       ci->end = i_cal_time_new_clone (cid->end);
 
                                        processed = TRUE;
                                } else {
@@ -2426,8 +2380,8 @@ process_detached_instances (GSList *instances,
                cid = unprocessed_instances->data;
                ci = g_new0 (struct comp_instance, 1);
                ci->comp = g_object_ref (cid->comp);
-               ci->start = cid->start;
-               ci->end = cid->end;
+               ci->start = i_cal_time_new_clone (cid->start);
+               ci->end = i_cal_time_new_clone (cid->end);
                instances = g_slist_append (instances, ci);
 
                unprocessed_instances = g_slist_remove (unprocessed_instances, cid);
@@ -2449,6 +2403,7 @@ generate_instances (ECalClient *client,
        GSList *l;
        ECalClientPrivate *priv;
        ICalTimezone *default_zone;
+       ICalTime *starttt, *endtt;
 
        priv = client->priv;
 
@@ -2459,6 +2414,9 @@ generate_instances (ECalClient *client,
        else
                default_zone = i_cal_timezone_get_utc_timezone ();
 
+       starttt = i_cal_time_from_timet_with_zone (start, FALSE, NULL);
+       endtt = i_cal_time_from_timet_with_zone (end, FALSE, NULL);
+
        for (l = objects; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
                ECalComponent *comp;
 
@@ -2466,7 +2424,6 @@ generate_instances (ECalClient *client,
                if (e_cal_component_is_instance (comp)) {
                        struct comp_instance *ci;
                        ECalComponentDateTime *dtstart, *dtend;
-                       ICalTimezone *start_zone = NULL, *end_zone = NULL;
 
                        /* keep the detached instances apart */
                        ci = g_new0 (struct comp_instance, 1);
@@ -2475,97 +2432,47 @@ generate_instances (ECalClient *client,
                        dtstart = e_cal_component_get_dtstart (comp);
                        dtend = e_cal_component_get_dtend (comp);
 
-                       /* For DATE-TIME values with a TZID, we use
-                        * e_cal_resolve_tzid_cb to resolve the TZID.
-                        * For DATE values and DATE-TIME values without a
-                        * TZID (i.e. floating times) we use the default
-                        * timezone. */
-                       if (dtstart && e_cal_component_datetime_get_tzid (dtstart) && 
e_cal_component_datetime_get_value (dtstart) &&
-                           !i_cal_time_is_date (e_cal_component_datetime_get_value (dtstart))) {
-                               start_zone = e_cal_client_tzlookup_cb (e_cal_component_datetime_get_tzid 
(dtstart), client, cancellable, NULL);
-                               if (!start_zone)
-                                       start_zone = default_zone;
-                       } else {
-                               start_zone = default_zone;
-                       }
-
-                       if (dtend && e_cal_component_datetime_get_tzid (dtend) && 
e_cal_component_datetime_get_value (dtend) &&
-                           !i_cal_time_is_date (e_cal_component_datetime_get_value (dtend))) {
-                               end_zone = e_cal_client_tzlookup_cb (e_cal_component_datetime_get_tzid 
(dtend), client, cancellable, NULL);
-                               if (!end_zone)
-                                       end_zone = default_zone;
-                       } else {
-                               end_zone = default_zone;
-                       }
-
                        if (!dtstart || !e_cal_component_datetime_get_value (dtstart)) {
                                g_warn_if_reached ();
 
                                e_cal_component_datetime_free (dtstart);
                                e_cal_component_datetime_free (dtend);
-                               g_object_unref (G_OBJECT (ci->comp));
-                               g_free (ci);
+                               comp_instance_free (ci);
 
                                continue;
                        }
 
-                       ci->start = i_cal_time_as_timet_with_zone (e_cal_component_datetime_get_value 
(dtstart), start_zone);
+                       ci->start = i_cal_time_new_clone (e_cal_component_datetime_get_value (dtstart));
 
                        if (dtend && e_cal_component_datetime_get_value (dtend))
-                               ci->end = i_cal_time_as_timet_with_zone (e_cal_component_datetime_get_value 
(dtend), end_zone);
-                       else if (i_cal_time_is_date (e_cal_component_datetime_get_value (dtstart)))
-                               ci->end = time_day_end (ci->start);
-                       else
-                               ci->end = ci->start;
+                               ci->end = i_cal_time_new_clone (e_cal_component_datetime_get_value (dtend));
+                       else {
+                               ci->end = i_cal_time_new_clone (ci->start);
+
+                               if (i_cal_time_is_date (e_cal_component_datetime_get_value (dtstart)))
+                                       i_cal_time_adjust (ci->end, 1, 0, 0, 0);
+                       }
 
                        e_cal_component_datetime_free (dtstart);
                        e_cal_component_datetime_free (dtend);
 
-                       if (ci->start <= end && ci->end >= start) {
+                       if (i_cal_time_compare (ci->start, endtt) <= 0 && i_cal_time_compare (ci->end, 
starttt) >= 0) {
                                detached_instances = g_slist_prepend (detached_instances, ci);
                        } else {
                                /* it doesn't fit to our time range, thus skip it */
-                               g_object_unref (G_OBJECT (ci->comp));
-                               g_free (ci);
+                               comp_instance_free (ci);
                        }
                } else {
-                       ECalComponentDateTime *datetime;
-                       ICalTimezone *start_zone = NULL, *end_zone = NULL;
-                       ICalTime *starttt, *endtt;
                        struct instances_info *instances_hold;
 
-                       /* Get the start timezone */
-                       datetime = e_cal_component_get_dtstart (comp);
-                       if (datetime && e_cal_component_datetime_get_tzid (datetime))
-                               e_cal_client_get_timezone_sync (client, e_cal_component_datetime_get_tzid 
(datetime), &start_zone, cancellable, NULL);
-                       else
-                               start_zone = NULL;
-                       e_cal_component_datetime_free (datetime);
-
-                       /* Get the end timezone */
-                       datetime = e_cal_component_get_dtend (comp);
-                       if (datetime && e_cal_component_datetime_get_tzid (datetime))
-                               e_cal_client_get_timezone_sync (client, e_cal_component_datetime_get_tzid 
(datetime), &end_zone, cancellable, NULL);
-                       else
-                               end_zone = NULL;
-                       e_cal_component_datetime_free (datetime);
-
                        instances_hold = g_new0 (struct instances_info, 1);
                        instances_hold->instances = &instances;
-                       instances_hold->start_zone = start_zone;
-                       instances_hold->end_zone = end_zone;
-                       instances_hold->default_zone = default_zone;
-
-                       starttt = i_cal_time_from_timet_with_zone (start, FALSE, NULL);
-                       endtt = i_cal_time_from_timet_with_zone (end, FALSE, NULL);
 
                        e_cal_recur_generate_instances_sync (
                                e_cal_component_get_icalcomponent (comp), starttt, endtt, add_instance_cb, 
instances_hold,
                                e_cal_client_tzlookup_cb, client,
                                default_zone, cancellable, NULL);
 
-                       g_clear_object (&starttt);
-                       g_clear_object (&endtt);
                        g_free (instances_hold);
                }
        }
@@ -2582,18 +2489,11 @@ generate_instances (ECalClient *client,
 
        for (l = instances; l && !g_cancellable_is_cancelled (cancellable); l = l->next) {
                struct comp_instance *ci;
-               ICalTime *starttt, *endtt;
                gboolean result;
 
                ci = l->data;
 
-               starttt = i_cal_time_from_timet_with_zone (ci->start, FALSE, default_zone);
-               endtt = i_cal_time_from_timet_with_zone (ci->end, FALSE, default_zone);
-
-               result = (* cb) (e_cal_component_get_icalcomponent (ci->comp), starttt, endtt, cb_data, 
cancellable, NULL);
-
-               g_clear_object (&starttt);
-               g_clear_object (&endtt);
+               result = (* cb) (e_cal_component_get_icalcomponent (ci->comp), ci->start, ci->end, cb_data, 
cancellable, NULL);
 
                if (!result)
                        break;
@@ -2601,25 +2501,10 @@ generate_instances (ECalClient *client,
 
        /* Clean up */
 
-       for (l = instances; l; l = l->next) {
-               struct comp_instance *ci;
-
-               ci = l->data;
-               g_object_unref (G_OBJECT (ci->comp));
-               g_free (ci);
-       }
-
-       g_slist_free (instances);
-
-       for (l = detached_instances; l; l = l->next) {
-               struct comp_instance *ci;
-
-               ci = l->data;
-               g_object_unref (G_OBJECT (ci->comp));
-               g_free (ci);
-       }
-
-       g_slist_free (detached_instances);
+       g_slist_free_full (instances, comp_instance_free);
+       g_slist_free_full (detached_instances, comp_instance_free);
+       g_clear_object (&starttt);
+       g_clear_object (&endtt);
 }
 
 static GSList *
@@ -2687,8 +2572,6 @@ struct get_objects_async_data {
        gchar *query;
        guint tries;
        void (* ready_cb) (struct get_objects_async_data *goad, GSList *objects);
-       ICalTimezone *start_zone;
-       ICalTimezone *end_zone;
        ECalComponent *comp;
 };
 
@@ -2973,32 +2856,20 @@ process_instances (ECalClient *client,
                ci = instances->data;
 
                if (result) {
-                       ICalTime *starttt = NULL, *endtt = NULL;
-
                        instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
 
                        if (rid && *rid) {
                                if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0) {
-                                       starttt = i_cal_time_from_timet_with_zone (ci->start, FALSE, 
client->priv->default_zone);
-                                       endtt = i_cal_time_from_timet_with_zone (ci->end, FALSE, 
client->priv->default_zone);
-
-                                       result = (* cb) (e_cal_component_get_icalcomponent (ci->comp), 
starttt, endtt, cb_data, NULL, NULL);
+                                       result = (* cb) (e_cal_component_get_icalcomponent (ci->comp), 
ci->start, ci->end, cb_data, NULL, NULL);
                                }
                        } else {
-                               starttt = i_cal_time_from_timet_with_zone (ci->start, FALSE, 
client->priv->default_zone);
-                               endtt = i_cal_time_from_timet_with_zone (ci->end, FALSE, 
client->priv->default_zone);
-
-                               result = (* cb) (e_cal_component_get_icalcomponent (ci->comp), starttt, 
endtt, cb_data, NULL, NULL);
+                               result = (* cb) (e_cal_component_get_icalcomponent (ci->comp), ci->start, 
ci->end, cb_data, NULL, NULL);
                        }
-
-                       g_clear_object (&starttt);
-                       g_clear_object (&endtt);
                }
 
                /* remove instance from list */
                instances = g_slist_remove (instances, ci);
-               g_object_unref (ci->comp);
-               g_free (ci);
+               comp_instance_free (ci);
                g_free (instance_rid);
        }
 
@@ -3017,9 +2888,6 @@ generate_instances_for_object_got_objects_cb (struct get_objects_async_data *goa
 
        instances_hold = g_new0 (struct instances_info, 1);
        instances_hold->instances = &instances;
-       instances_hold->start_zone = goad->start_zone;
-       instances_hold->end_zone = goad->end_zone;
-       instances_hold->default_zone = e_cal_client_get_default_timezone (goad->client);
 
        /* generate all instances in the given time range */
        generate_instances (
@@ -3072,8 +2940,6 @@ e_cal_client_generate_instances_for_object (ECalClient *client,
 {
        ECalComponent *comp;
        const gchar *uid;
-       ECalComponentDateTime *datetime;
-       ICalTimezone *start_zone = NULL, *end_zone = NULL;
        struct get_objects_async_data *goad;
        GCancellable *use_cancellable;
 
@@ -3107,24 +2973,6 @@ e_cal_client_generate_instances_for_object (ECalClient *client,
 
        uid = e_cal_component_get_uid (comp);
 
-       /* Get the start timezone */
-       datetime = e_cal_component_get_dtstart (comp);
-       if (datetime && e_cal_component_datetime_get_tzid (datetime))
-               e_cal_client_get_timezone_sync (
-                       client, e_cal_component_datetime_get_tzid (datetime), &start_zone, cancellable, NULL);
-       else
-               start_zone = NULL;
-       e_cal_component_datetime_free (datetime);
-
-       /* Get the end timezone */
-       datetime = e_cal_component_get_dtend (comp);
-       if (datetime && e_cal_component_datetime_get_tzid (datetime))
-               e_cal_client_get_timezone_sync (
-                       client, e_cal_component_datetime_get_tzid (datetime), &end_zone, cancellable, NULL);
-       else
-               end_zone = NULL;
-       e_cal_component_datetime_free (datetime);
-
        use_cancellable = cancellable;
        if (!use_cancellable)
                use_cancellable = g_cancellable_new ();
@@ -3137,8 +2985,6 @@ e_cal_client_generate_instances_for_object (ECalClient *client,
        goad->cb = cb;
        goad->cb_data = cb_data;
        goad->destroy_cb_data = destroy_cb_data;
-       goad->start_zone = start_zone;
-       goad->end_zone = end_zone;
        goad->comp = comp;
        goad->uid = g_strdup (uid);
 
@@ -3180,8 +3026,6 @@ e_cal_client_generate_instances_for_object_sync (ECalClient *client,
        ECalComponent *comp;
        const gchar *uid;
        GSList *instances = NULL;
-       ECalComponentDateTime *datetime;
-       ICalTimezone *start_zone = NULL, *end_zone = NULL;
        struct instances_info *instances_hold;
 
        g_return_if_fail (E_IS_CAL_CLIENT (client));
@@ -3212,27 +3056,8 @@ e_cal_client_generate_instances_for_object_sync (ECalClient *client,
 
        uid = e_cal_component_get_uid (comp);
 
-       /* Get the start timezone */
-       datetime = e_cal_component_get_dtstart (comp);
-       if (datetime && e_cal_component_datetime_get_tzid (datetime))
-               e_cal_client_get_timezone_sync (client, e_cal_component_datetime_get_tzid (datetime), 
&start_zone, cancellable, NULL);
-       else
-               start_zone = NULL;
-       e_cal_component_datetime_free (datetime);
-
-       /* Get the end timezone */
-       datetime = e_cal_component_get_dtend (comp);
-       if (datetime && e_cal_component_datetime_get_tzid (datetime))
-               e_cal_client_get_timezone_sync (client, e_cal_component_datetime_get_tzid (datetime), 
&end_zone, cancellable, NULL);
-       else
-               end_zone = NULL;
-       e_cal_component_datetime_free (datetime);
-
        instances_hold = g_new0 (struct instances_info, 1);
        instances_hold->instances = &instances;
-       instances_hold->start_zone = start_zone;
-       instances_hold->end_zone = end_zone;
-       instances_hold->default_zone = e_cal_client_get_default_timezone (client);
 
        /* generate all instances in the given time range */
        generate_instances (
diff --git a/tests/libecal/CMakeLists.txt b/tests/libecal/CMakeLists.txt
index 8d69e5924..5575e53cc 100644
--- a/tests/libecal/CMakeLists.txt
+++ b/tests/libecal/CMakeLists.txt
@@ -33,6 +33,7 @@ set(TESTS
        test-cal-client-get-revision
        test-cal-client-get-free-busy
        test-cal-component
+       test-cal-recur
 )
 
 foreach(_test ${TESTS})
diff --git a/tests/libecal/test-cal-recur.c b/tests/libecal/test-cal-recur.c
new file mode 100644
index 000000000..b9d26097d
--- /dev/null
+++ b/tests/libecal/test-cal-recur.c
@@ -0,0 +1,407 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libecal/libecal.h>
+
+#include "e-test-server-utils.h"
+
+static ETestServerClosure test_closure = { E_TEST_SERVER_CALENDAR, NULL, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, 
FALSE, NULL, FALSE };
+
+static ICalComponent *
+create_component (const gchar *tz_location)
+{
+       const gchar *comp_str =
+               "BEGIN:VEVENT\r\n"
+               "SUMMARY:recurs\r\n"
+               "UID:recurs-id\r\n"
+               "DTSTART%s:20190107T080000%s\r\n"
+               "DTEND%s:20190107T090000%s\r\n"
+               "DTSTAMP:20190101T050000Z\r\n"
+               "CREATED:20190101T050000Z\r\n"
+               "LAST-MODIFIED:20190101T050000Z\r\n"
+               "RRULE:FREQ=DAILY;COUNT=5\r\n"
+               "END:VEVENT\r\n";
+       gchar *tzref = NULL, tzsuffix[2] = { 0, 0};
+       gchar *str;
+       ICalComponent *icomp;
+       ICalTimezone *zone = NULL;
+       ICalTime *itt;
+
+       if (tz_location) {
+               if (g_ascii_strcasecmp (tz_location, "UTC") == 0) {
+                       tzsuffix[0] = 'Z';
+                       zone = i_cal_timezone_get_utc_timezone ();
+               } else {
+                       const gchar *tzid;
+
+                       zone = i_cal_timezone_get_builtin_timezone (tz_location);
+                       g_assert_nonnull (zone);
+
+                       tzid = i_cal_timezone_get_tzid (zone);
+                       g_assert_nonnull (tzid);
+
+                       tzref = g_strconcat (";TZID=", tzid, NULL);
+               }
+       }
+
+       str = g_strdup_printf (comp_str, tzref ? tzref : "", tzsuffix, tzref ? tzref : "", tzsuffix);
+       icomp = i_cal_component_new_from_string (str);
+       g_assert_nonnull (icomp);
+
+       g_free (tzref);
+       g_free (str);
+
+       itt = i_cal_component_get_dtstart (icomp);
+       g_assert_nonnull (itt);
+       g_assert (i_cal_time_get_timezone (itt) == zone);
+       g_object_unref (itt);
+
+       itt = i_cal_component_get_dtend (icomp);
+       g_assert_nonnull (itt);
+       g_assert (i_cal_time_get_timezone (itt) == zone);
+       g_object_unref (itt);
+
+       return icomp;
+}
+
+static void
+setup_cal (ECalClient *cal_client,
+          const gchar *tz_location)
+{
+       ICalComponent *icomp;
+       gboolean success;
+       gchar *uid = NULL;
+       GError *error = NULL;
+
+       icomp = create_component (tz_location);
+
+       /* Ignore errors, it'll fail the first time, but will succeed all other times */
+       e_cal_client_remove_object_sync (cal_client, i_cal_component_get_uid (icomp), NULL, 
E_CAL_OBJ_MOD_ALL, E_CAL_OPERATION_FLAG_NONE, NULL, NULL);
+
+       success = e_cal_client_create_object_sync (cal_client, icomp, E_CAL_OPERATION_FLAG_NONE, &uid, NULL, 
&error);
+       g_assert_no_error (error);
+       g_assert (success);
+       g_assert_nonnull (uid);
+
+       g_object_unref (icomp);
+       g_free (uid);
+}
+
+typedef struct _Instance {
+       ICalTime *start;
+       ICalTime *end;
+       ICalComponent *icomp;
+} Instance;
+
+static Instance *
+instance_new (ICalTime *start,
+             ICalTime *end,
+             ICalComponent *icomp)
+{
+       Instance *ins;
+
+       ins = g_new0 (Instance, 1);
+       ins->start = i_cal_time_new_clone (start);
+       ins->end = i_cal_time_new_clone (end);
+       ins->icomp = i_cal_component_new_clone (icomp);
+
+       return ins;
+}
+
+static void
+instance_free (gpointer ptr)
+{
+       Instance *ins = ptr;
+
+       if (ins) {
+               g_clear_object (&ins->start);
+               g_clear_object (&ins->end);
+               g_clear_object (&ins->icomp);
+               g_free (ins);
+       }
+}
+
+static guint
+instance_hash (gconstpointer ptr)
+{
+       /* Place everything into a single basket */
+       return 0;
+}
+
+static gboolean
+instance_equal (gconstpointer ptr1,
+               gconstpointer ptr2)
+{
+       Instance *ins1 = (Instance *) ptr1;
+       Instance *ins2 = (Instance *) ptr2;
+
+       if (!ins1 || !ins2)
+               return ins1 == ins2;
+
+       return i_cal_time_compare (ins1->start, ins2->start) == 0;
+}
+
+static void
+verify_received_instances (GHashTable *instances,
+                          ICalTimezone *comp_zone)
+{
+       const gchar *expected_times[] = {
+               "20190107T080000",
+               "20190108T080000",
+               "20190109T080000",
+               "20190110T080000",
+               "20190111T080000"
+       };
+       gint ii;
+
+       g_assert_nonnull (instances);
+
+       for (ii = 0; ii < G_N_ELEMENTS (expected_times); ii++) {
+               ICalTime *expected_start;
+               Instance ins = { 0, };
+
+               expected_start = i_cal_time_from_string (expected_times[ii]);
+               g_assert_nonnull (expected_start);
+
+               ins.start = expected_start;
+               g_assert (g_hash_table_remove (instances, &ins));
+
+               g_object_unref (expected_start);
+       }
+
+       g_assert_cmpint (g_hash_table_size (instances), ==, 0);
+}
+
+typedef struct _RecurData {
+       GHashTable *instances;
+} RecurData;
+
+static gboolean
+recur_instance_cb (ICalComponent *icomp,
+                  ICalTime *instance_start,
+                  ICalTime *instance_end,
+                  gpointer user_data,
+                  GCancellable *cancellable,
+                  GError **error)
+{
+       RecurData *rd = user_data;
+       Instance *ins;
+       gsize pre;
+
+       g_assert_nonnull (rd);
+
+       ins = instance_new (instance_start, instance_end, icomp);
+
+       pre = g_hash_table_size (rd->instances);
+       g_hash_table_insert (rd->instances, ins, NULL);
+
+       g_assert_cmpint (pre + 1, ==, g_hash_table_size (rd->instances));
+
+       return TRUE;
+}
+
+static void
+test_recur_plain_run (ECalClient *client,
+                     const gchar *default_tz,
+                     const gchar *comp_tz)
+{
+       ICalTimezone *default_zone, *comp_zone;
+       ICalComponent *icomp;
+       ICalTime *start, *end;
+       RecurData rd;
+       gboolean success;
+       GError *error = NULL;
+
+       default_zone = default_tz ? i_cal_timezone_get_builtin_timezone (default_tz) : NULL;
+       if (default_tz)
+               g_assert_nonnull (default_zone);
+
+       comp_zone = comp_tz ? i_cal_timezone_get_builtin_timezone (comp_tz) : NULL;
+       if (comp_tz)
+               g_assert_nonnull (comp_zone);
+
+       icomp = create_component (comp_tz);
+       start = i_cal_time_from_string ("20190103T080000Z");
+       end = i_cal_time_from_string ("20190115T080000Z");
+
+       rd.instances = g_hash_table_new_full (instance_hash, instance_equal, instance_free, NULL);
+
+       success = e_cal_recur_generate_instances_sync (icomp, start, end,
+               recur_instance_cb, &rd,
+               e_cal_client_tzlookup_cb, client,
+               default_zone, NULL, &error);
+       g_assert_no_error (error);
+       g_assert (success);
+
+       g_assert_cmpint (g_hash_table_size (rd.instances), ==, 5);
+
+       verify_received_instances (rd.instances, comp_zone);
+
+       g_hash_table_destroy (rd.instances);
+       g_clear_object (&icomp);
+       g_clear_object (&start);
+       g_clear_object (&end);
+}
+
+static void
+test_recur_client_run (ECalClient *client,
+                      const gchar *default_tz,
+                      const gchar *comp_tz)
+{
+       ICalTimezone *default_zone, *comp_zone;
+       ICalTime *start, *end;
+       ICalComponent *icomp;
+       RecurData rd;
+
+       default_zone = default_tz ? i_cal_timezone_get_builtin_timezone (default_tz) : NULL;
+       if (default_tz)
+               g_assert_nonnull (default_zone);
+
+       comp_zone = comp_tz ? i_cal_timezone_get_builtin_timezone (comp_tz) : NULL;
+       if (comp_tz)
+               g_assert_nonnull (comp_zone);
+
+       e_cal_client_set_default_timezone (client, default_zone);
+       setup_cal (client, comp_tz);
+
+       start = i_cal_time_from_string ("20190103T080000Z");
+       end = i_cal_time_from_string ("20190115T080000Z");
+
+       rd.instances = g_hash_table_new_full (instance_hash, instance_equal, instance_free, NULL);
+
+       e_cal_client_generate_instances_sync (client,
+               i_cal_time_as_timet (start),
+               i_cal_time_as_timet (end),
+               NULL, /* GCancellable * */
+               recur_instance_cb, &rd);
+
+       g_assert_cmpint (g_hash_table_size (rd.instances), ==, 5);
+
+       verify_received_instances (rd.instances, comp_zone);
+
+       g_hash_table_destroy (rd.instances);
+
+       icomp = create_component (comp_tz);
+       rd.instances = g_hash_table_new_full (instance_hash, instance_equal, instance_free, NULL);
+
+       e_cal_client_generate_instances_for_object_sync (client,
+               icomp,
+               i_cal_time_as_timet (start),
+               i_cal_time_as_timet (end),
+               NULL, /* GCancellable * */
+               recur_instance_cb, &rd);
+
+       g_assert_cmpint (g_hash_table_size (rd.instances), ==, 5);
+
+       verify_received_instances (rd.instances, comp_zone);
+
+       g_hash_table_destroy (rd.instances);
+       g_clear_object (&icomp);
+       g_clear_object (&start);
+       g_clear_object (&end);
+}
+
+static const gchar *timezones[] = {
+       NULL,                   /* floating time */
+       "Pacific/Midway",       /* UTC-11 */
+       "Pacific/Honolulu",     /* UTC-10 */
+       "America/Adak",         /* UTC-9 */
+       "America/Yakutat",      /* UTC-8 */
+       "America/Vancouver",    /* UTC-7 */
+       "America/Boise",        /* UTC-6 */
+       "America/Cancun",       /* UTC-5 */
+       "America/New_York",     /* UTC-4 */
+       "Atlantic/Bermuda",     /* UTC-3 */
+       "America/Noronha",      /* UTC-2 */
+       "Atlantic/Cape_Verde",  /* UTC-1 */
+       "Atlantic/Azores",      /* UTC */
+       "UTC",                  /* UTC */
+       "Africa/Casablanca",    /* UTC+1 */
+       "Europe/Malta",         /* UTC+2 */
+       "Europe/Athens",        /* UTC+3 */
+       "Asia/Baku",            /* UTC+4 */
+       "Asia/Qyzylorda",       /* UTC+5 */
+       "Asia/Urumqi",          /* UTC+6 */
+       "Asia/Hovd",            /* UTC+7 */
+       "Asia/Irkutsk",         /* UTC+8 */
+       "Asia/Seoul",           /* UTC+9 */
+       "Asia/Vladivostok",     /* UTC+10 */
+       "Asia/Sakhalin",        /* UTC+11 */
+       "Asia/Kamchatka",       /* UTC+12 */
+       "Pacific/Enderbury",    /* UTC+13 */
+       "Pacific/Kiritimati"    /* UTC+14 */
+};
+
+static void
+test_recur_plain (ETestServerFixture *fixture,
+                 gconstpointer user_data)
+{
+       ECalClient *cal;
+       gint deftz_ii, comptz_ii;
+
+       cal = E_TEST_SERVER_UTILS_SERVICE (fixture, ECalClient);
+
+       for (deftz_ii = 0; deftz_ii < G_N_ELEMENTS (timezones); deftz_ii++) {
+               for (comptz_ii = 0; comptz_ii < G_N_ELEMENTS (timezones); comptz_ii++) {
+                       test_recur_plain_run (cal, timezones[deftz_ii], timezones[comptz_ii]);
+               }
+       }
+}
+
+static void
+test_recur_client (ETestServerFixture *fixture,
+                  gconstpointer user_data)
+{
+       ECalClient *cal;
+       gint deftz_ii, comptz_ii;
+
+       cal = E_TEST_SERVER_UTILS_SERVICE (fixture, ECalClient);
+
+       for (deftz_ii = 0; deftz_ii < G_N_ELEMENTS (timezones); deftz_ii++) {
+               for (comptz_ii = 0; comptz_ii < G_N_ELEMENTS (timezones); comptz_ii++) {
+                       /* Skip the floating time for the client's default timezone */
+                       if (timezones[deftz_ii])
+                               test_recur_client_run (cal, timezones[deftz_ii], timezones[comptz_ii]);
+               }
+       }
+}
+
+gint
+main (gint argc,
+      gchar **argv)
+{
+       g_test_init (&argc, &argv, NULL);
+       g_test_bug_base ("http://bugzilla.gnome.org/";);
+
+       g_test_add (
+               "/ECalRecur/Plain",
+               ETestServerFixture,
+               &test_closure,
+               e_test_server_utils_setup,
+               test_recur_plain,
+               e_test_server_utils_teardown);
+       g_test_add (
+               "/ECalRecur/Client",
+               ETestServerFixture,
+               &test_closure,
+               e_test_server_utils_setup,
+               test_recur_client,
+               e_test_server_utils_teardown);
+
+       return e_test_server_utils_run ();
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]