1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * This program is free software: you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * You should have received a copy of the GNU Lesser General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <libecal/libecal.h>
21 #include "test-cal-cache-utils.h"
23 #define NUM_INTERVALS_CLOSED 100
24 #define NUM_INTERVALS_OPEN 100
25 #define NUM_SEARCHES 500
26 #define DELETE_PROBABILITY 0.3
27 #define _TIME_MIN ((time_t) 0) /* Min valid time_t */
28 #define _TIME_MAX ((time_t) INT_MAX) /* Max valid time_t */
30 typedef struct _IntervalData
{
37 interval_data_free (gpointer ptr
)
39 IntervalData
*id
= ptr
;
42 g_object_unref (id
->comp
);
48 compare_intervals (time_t x_start
,
53 /* assumption: x_start <= x_end */
54 /* assumption: y_start <= y_end */
69 search_in_intervals (ETimezoneCache
*zone_cache
,
74 ECalBackendSExp
*sexp
;
75 struct icaltimetype itt_start
, itt_end
;
80 itt_start
= icaltime_from_timet_with_zone (start
, FALSE
, NULL
);
81 itt_end
= icaltime_from_timet_with_zone (end
, FALSE
, NULL
);
83 expr
= g_strdup_printf ("(occur-in-time-range? (make-time \"%04d%02d%02dT%02d%02d%02dZ\") (make-time \"%04d%02d%02dT%02d%02d%02dZ\"))",
84 itt_start
.year
, itt_start
.month
, itt_start
.day
, itt_start
.hour
, itt_start
.minute
, itt_start
.second
,
85 itt_end
.year
, itt_end
.month
, itt_end
.day
, itt_end
.hour
, itt_end
.minute
, itt_end
.second
);
87 sexp
= e_cal_backend_sexp_new (expr
);
91 g_assert_nonnull (sexp
);
93 res
= g_hash_table_new_full ((GHashFunc
) e_cal_component_id_hash
, (GEqualFunc
) e_cal_component_id_equal
,
94 (GDestroyNotify
) e_cal_component_free_id
, g_object_unref
);
96 for (link
= intervals
; link
; link
= g_slist_next (link
)) {
97 IntervalData
*data
= link
->data
;
99 if (compare_intervals (start
, end
, data
->start
, data
->end
) == 0 &&
100 e_cal_backend_sexp_match_comp (sexp
, data
->comp
, zone_cache
)) {
101 ECalComponentId
*id
= NULL
;
103 id
= e_cal_component_get_id (data
->comp
);
104 g_assert_nonnull (id
);
106 g_hash_table_insert (res
, id
, g_object_ref (data
->comp
));
110 g_object_unref (sexp
);
116 check_search_results (GSList
*ecalcomps
,
117 GHashTable
*from_intervals
)
121 g_assert_cmpint (g_slist_length (ecalcomps
), ==, g_hash_table_size (from_intervals
));
123 for (link
= ecalcomps
; link
; link
= g_slist_next (link
)) {
124 ECalComponent
*comp
= link
->data
;
125 ECalComponentId
*id
= NULL
;
127 id
= e_cal_component_get_id (comp
);
128 g_assert_nonnull (id
);
130 g_assert (g_hash_table_contains (from_intervals
, id
));
132 e_cal_component_free_id (id
);
136 static ECalComponent
*
137 create_test_component (time_t start
,
141 ECalComponentText summary
;
142 struct icaltimetype current
, ittstart
, ittend
;
144 comp
= e_cal_component_new ();
146 e_cal_component_set_new_vtype (comp
, E_CAL_COMPONENT_EVENT
);
148 ittstart
= icaltime_from_timet_with_zone (start
, 0, NULL
);
149 ittend
= icaltime_from_timet_with_zone (end
, 0, NULL
);
151 icalcomponent_set_dtstart (e_cal_component_get_icalcomponent (comp
), ittstart
);
152 if (end
!= _TIME_MAX
)
153 icalcomponent_set_dtend (e_cal_component_get_icalcomponent (comp
), ittend
);
155 summary
.value
= g_strdup_printf ("%s - %s", icaltime_as_ical_string (ittstart
), icaltime_as_ical_string (ittend
));
156 summary
.altrep
= NULL
;
158 e_cal_component_set_summary (comp
, &summary
);
160 g_free ((gchar
*) summary
.value
);
162 current
= icaltime_from_timet_with_zone (time (NULL
), 0, NULL
);
163 e_cal_component_set_created (comp
, ¤t
);
164 e_cal_component_set_last_modified (comp
, ¤t
);
166 e_cal_component_rescan (comp
);
172 test_intervals (TCUFixture
*fixture
,
173 gconstpointer user_data
)
177 * 1. create new tree and empty list of intervals
178 * 2. insert some intervals into tree and list
179 * 3. do various searches, compare results of both structures
180 * 4. delete some intervals
181 * 5. do various searches, compare results of both structures
185 IntervalData
*interval
;
187 ETimezoneCache
*zone_cache
;
188 GSList
*l1
, *intervals
= NULL
;
189 GHashTable
*from_intervals
;
190 gint num_deleted
= 0;
193 GError
*error
= NULL
;
195 zone_cache
= E_TIMEZONE_CACHE (fixture
->cal_cache
);
197 myrand
= g_rand_new ();
199 for (ii
= 0; ii
< NUM_INTERVALS_CLOSED
; ii
++) {
200 start
= g_rand_int_range (myrand
, 0, 1000);
201 end
= g_rand_int_range (myrand
, start
, 2000);
202 comp
= create_test_component (start
, end
);
203 g_assert (comp
!= NULL
);
205 interval
= g_new (IntervalData
, 1);
206 interval
->start
= start
;
208 interval
->comp
= comp
;
210 intervals
= g_slist_prepend (intervals
, interval
);
212 success
= e_cal_cache_put_component (fixture
->cal_cache
, comp
, NULL
, E_CACHE_IS_ONLINE
, NULL
, &error
);
213 g_assert_no_error (error
);
219 /* insert open ended intervals */
220 for (ii
= 0; ii
< NUM_INTERVALS_OPEN
; ii
++) {
221 start
= g_rand_int_range (myrand
, 0, 1000);
222 comp
= create_test_component (start
, end
);
223 g_assert (comp
!= NULL
);
225 interval
= g_new (IntervalData
, 1);
226 interval
->start
= start
;
228 interval
->comp
= comp
;
230 intervals
= g_slist_prepend (intervals
, interval
);
232 success
= e_cal_cache_put_component (fixture
->cal_cache
, comp
, NULL
, E_CACHE_IS_ONLINE
, NULL
, &error
);
233 g_assert_no_error (error
);
237 for (ii
= 0; ii
< NUM_SEARCHES
; ii
++) {
238 start
= g_rand_int_range (myrand
, 0, 1000);
239 end
= g_rand_int_range (myrand
, 2000, _TIME_MAX
);
243 success
= e_cal_cache_get_components_in_range (fixture
->cal_cache
, start
, end
, &l1
, NULL
, &error
);
244 g_assert_no_error (error
);
247 from_intervals
= search_in_intervals (zone_cache
, intervals
, start
, end
);
249 check_search_results (l1
, from_intervals
);
251 g_slist_free_full (l1
, g_object_unref
);
252 g_hash_table_destroy (from_intervals
);
255 /* open-ended intervals */
256 for (ii
= 0; ii
< 20; ii
++) {
257 start
= g_rand_int_range (myrand
, 0, 1000);
262 success
= e_cal_cache_get_components_in_range (fixture
->cal_cache
, start
, end
, &l1
, NULL
, &error
);
263 g_assert_no_error (error
);
266 from_intervals
= search_in_intervals (zone_cache
, intervals
, start
, end
);
268 check_search_results (l1
, from_intervals
);
270 g_slist_free_full (l1
, g_object_unref
);
271 g_hash_table_destroy (from_intervals
);
277 /* perhaps we will delete l1 */
278 GSList
*next
= l1
->next
;
280 if (g_rand_double (myrand
) < DELETE_PROBABILITY
) {
285 comp
= interval
->comp
;
287 id
= e_cal_component_get_id (comp
);
288 g_assert (id
!= NULL
);
290 success
= e_cal_cache_remove_component (fixture
->cal_cache
, id
->uid
, id
->rid
, E_CACHE_IS_ONLINE
, NULL
, &error
);
291 g_assert_no_error (error
);
294 e_cal_component_free_id (id
);
296 interval_data_free (interval
);
297 intervals
= g_slist_delete_link (intervals
, l1
);
305 for (ii
= 0; ii
< NUM_SEARCHES
; ii
++) {
306 start
= g_rand_int_range (myrand
, 0, 1000);
307 end
= g_rand_int_range (myrand
, start
+ 1, 2000);
311 success
= e_cal_cache_get_components_in_range (fixture
->cal_cache
, start
, end
, &l1
, NULL
, &error
);
312 g_assert_no_error (error
);
315 from_intervals
= search_in_intervals (zone_cache
, intervals
, start
, end
);
317 check_search_results (l1
, from_intervals
);
319 g_slist_free_full (l1
, g_object_unref
);
320 g_hash_table_destroy (from_intervals
);
323 g_slist_free_full (intervals
, interval_data_free
);
324 g_rand_free (myrand
);
331 #if !GLIB_CHECK_VERSION (2, 35, 1)
334 g_test_init (&argc
, &argv
, NULL
);
336 /* Ensure that the client and server get the same locale */
337 g_assert (g_setenv ("LC_ALL", "en_US.UTF-8", TRUE
));
338 setlocale (LC_ALL
, "");
340 g_test_add ("/ECalCache/Intervals", TCUFixture
, NULL
,
341 tcu_fixture_setup
, test_intervals
, tcu_fixture_teardown
);
343 return g_test_run ();