1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
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.
6  *
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
10  * for more details.
11  *
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/>.
14  *
15  */
16 
17 #include <stdlib.h>
18 #include <locale.h>
19 #include <libebook/libebook.h>
20 
21 #include "e-test-server-utils.h"
22 #include "test-book-cache-utils.h"
23 
24 static TCUCursorClosure ascending_closure = {
25 	{ NULL },
26 	NULL, E_BOOK_CURSOR_SORT_ASCENDING
27 };
28 
29 static TCUCursorClosure descending_closure = {
30 	{ NULL },
31 	NULL, E_BOOK_CURSOR_SORT_DESCENDING
32 };
33 
34 static void
test_cursor_calculate_initial(TCUCursorFixture * fixture,gconstpointer user_data)35 test_cursor_calculate_initial (TCUCursorFixture *fixture,
36 			       gconstpointer user_data)
37 {
38 	GError *error = NULL;
39 	gint position = 0, total = 0;
40 
41 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
42 					     fixture->cursor, &total, &position, NULL, &error))
43 	    g_error ("Error calculating cursor: %s", error->message);
44 
45 	g_assert_cmpint (position, ==, 0);
46 	g_assert_cmpint (total, ==, 20);
47 }
48 
49 static void
test_cursor_calculate_move_forward(TCUCursorFixture * fixture,gconstpointer user_data)50 test_cursor_calculate_move_forward (TCUCursorFixture *fixture,
51 				    gconstpointer user_data)
52 {
53 	GSList *results = NULL;
54 	GError *error = NULL;
55 	gint position = 0, total = 0;
56 
57 	/* Move cursor */
58 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
59 				       fixture->cursor,
60 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
61 				       E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
62 				       5,
63 				       &results, NULL, &error) < 0)
64 		g_error ("Error fetching cursor results: %s", error->message);
65 
66 	/* Assert the first 5 contacts in en_US order */
67 	g_assert_cmpint (g_slist_length (results), ==, 5);
68 	tcu_assert_contacts_order (
69 		results,
70 		"sorted-11",
71 		"sorted-1",
72 		"sorted-2",
73 		"sorted-5",
74 		"sorted-6",
75 		NULL);
76 	g_slist_free_full (results, e_book_cache_search_data_free);
77 
78 	/* Check new position */
79 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
80 					     fixture->cursor, &total, &position, NULL, &error))
81 		g_error ("Error calculating cursor: %s", error->message);
82 
83 	/* results 0 + 5 = position 5, result index 4 (results[0, 1, 2, 3, 4]) */
84 	g_assert_cmpint (position, ==, 5);
85 	g_assert_cmpint (total, ==, 20);
86 }
87 
88 static void
test_cursor_calculate_move_backwards(TCUCursorFixture * fixture,gconstpointer user_data)89 test_cursor_calculate_move_backwards (TCUCursorFixture *fixture,
90 				      gconstpointer user_data)
91 {
92 	GSList *results = NULL;
93 	GError *error = NULL;
94 	gint position = 0, total = 0;
95 
96 	/* Move cursor */
97 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
98 				       fixture->cursor,
99 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
100 				       E_BOOK_CACHE_CURSOR_ORIGIN_END,
101 				       -5,
102 				       &results, NULL, &error) < 0)
103 		g_error ("Error fetching cursor results: %s", error->message);
104 
105 	/* Assert the last 5 contacts in en_US order */
106 	g_assert_cmpint (g_slist_length (results), ==, 5);
107 	tcu_assert_contacts_order (
108 		results,
109 		"sorted-20",
110 		"sorted-19",
111 		"sorted-9",
112 		"sorted-13",
113 		"sorted-12",
114 		NULL);
115 	g_slist_free_full (results, e_book_cache_search_data_free);
116 
117 	/* Check new position */
118 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
119 					     fixture->cursor, &total, &position, NULL, &error))
120 	    g_error ("Error calculating cursor: %s", error->message);
121 
122 	/* results 20 - 5 = position 16 result index 15 (results[20, 19, 18, 17, 16]) */
123 	g_assert_cmpint (position, ==, 16);
124 	g_assert_cmpint (total, ==, 20);
125 }
126 
127 static void
test_cursor_calculate_back_and_forth(TCUCursorFixture * fixture,gconstpointer user_data)128 test_cursor_calculate_back_and_forth (TCUCursorFixture *fixture,
129 				      gconstpointer user_data)
130 {
131 	GSList *results = NULL;
132 	GError *error = NULL;
133 	gint position = 0, total = 0;
134 
135 	/* Move cursor */
136 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
137 				       fixture->cursor,
138 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
139 				       E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
140 				       7,
141 				       &results, NULL, &error) < 0)
142 		g_error ("Error fetching cursor results: %s", error->message);
143 
144 	g_assert_cmpint (g_slist_length (results), ==, 7);
145 	g_slist_free_full (results, e_book_cache_search_data_free);
146 	results = NULL;
147 
148 	/* Check new position */
149 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
150 					     fixture->cursor, &total, &position, NULL, &error))
151 		g_error ("Error calculating cursor: %s", error->message);
152 
153 	/* results 0 + 7 = position 7 result index 6 (results[0, 1, 2, 3, 4, 5, 6]) */
154 	g_assert_cmpint (position, ==, 7);
155 	g_assert_cmpint (total, ==, 20);
156 
157 	/* Move cursor */
158 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
159 				       fixture->cursor,
160 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
161 				       E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
162 				       -4,
163 				       &results, NULL, &error) < 0)
164 		g_error ("Error fetching cursor results: %s", error->message);
165 
166 	g_assert_cmpint (g_slist_length (results), ==, 4);
167 	g_slist_free_full (results, e_book_cache_search_data_free);
168 	results = NULL;
169 
170 	/* Check new position */
171 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
172 					     fixture->cursor, &total, &position, NULL, &error))
173 		g_error ("Error calculating cursor: %s", error->message);
174 
175 	/* results 7 - 4 = position 3 result index 2 (results[5, 4, 3, 2]) */
176 	g_assert_cmpint (position, ==, 3);
177 	g_assert_cmpint (total, ==, 20);
178 
179 	/* Move cursor */
180 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
181 				       fixture->cursor,
182 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
183 				       E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
184 				       5,
185 				       &results, NULL, &error) < 0)
186 		g_error ("Error fetching cursor results: %s", error->message);
187 
188 	g_assert_cmpint (g_slist_length (results), ==, 5);
189 	g_slist_free_full (results, e_book_cache_search_data_free);
190 	results = NULL;
191 
192 	/* Check new position */
193 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
194 					     fixture->cursor, &total, &position, NULL, &error))
195 		g_error ("Error calculating cursor: %s", error->message);
196 
197 	/* results 3 + 5 = position 8 result index 7 (results[3, 4, 5, 6, 7]) */
198 	g_assert_cmpint (position, ==, 8);
199 	g_assert_cmpint (total, ==, 20);
200 }
201 
202 static void
test_cursor_calculate_partial_target(TCUCursorFixture * fixture,gconstpointer user_data)203 test_cursor_calculate_partial_target (TCUCursorFixture *fixture,
204 				      gconstpointer user_data)
205 {
206 	GError *error = NULL;
207 	gint position = 0, total = 0;
208 	ECollator *collator;
209 	gint n_labels;
210 	const gchar *const *labels;
211 
212 	/* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
213 	collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
214 	labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
215 	g_assert_cmpstr (labels[3], ==, "C");
216 	e_collator_unref (collator);
217 
218 	/* Set the cursor at the start of family names beginning with 'C' */
219 	e_book_cache_cursor_set_target_alphabetic_index (
220 		((TCUFixture *) fixture)->book_cache,
221 		fixture->cursor, 3);
222 
223 	/* Check new position */
224 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
225 					     fixture->cursor, &total, &position, NULL, &error))
226 		g_error ("Error calculating cursor: %s", error->message);
227 
228 	/* Position is 13, there are 13 contacts before the letter 'C' in en_US locale */
229 	g_assert_cmpint (position, ==, 13);
230 	g_assert_cmpint (total, ==, 20);
231 }
232 
233 static void
test_cursor_calculate_after_modification(TCUCursorFixture * fixture,gconstpointer user_data)234 test_cursor_calculate_after_modification (TCUCursorFixture *fixture,
235 					  gconstpointer user_data)
236 {
237 	GError *error = NULL;
238 	gint position = 0, total = 0;
239 
240 	/* Set the cursor to point exactly 'blackbird' (which is the 12th contact) */
241 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
242 				       fixture->cursor,
243 				       E_BOOK_CACHE_CURSOR_STEP_MOVE,
244 				       E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
245 				       12, NULL, NULL, &error) < 0)
246 		g_error ("Error fetching cursor results: %s", error->message);
247 
248 	/* Check new position */
249 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
250 					     fixture->cursor, &total, &position, NULL, &error))
251 		g_error ("Error calculating cursor: %s", error->message);
252 
253 	/* blackbird is at position 12 in en_US locale */
254 	g_assert_cmpint (position, ==, 12);
255 	g_assert_cmpint (total, ==, 20);
256 
257 	/* Rename Muffler -> Jacob Appelbaum */
258 	e_contact_set (fixture->contacts[19 - 1], E_CONTACT_FAMILY_NAME, "Appelbaum");
259 	e_contact_set (fixture->contacts[19 - 1], E_CONTACT_GIVEN_NAME, "Jacob");
260 	if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
261 					fixture->contacts[19 - 1],
262 					e_contact_get_const (fixture->contacts[19 - 1], E_CONTACT_UID),
263 					0, E_CACHE_IS_ONLINE, NULL, &error))
264 		g_error ("Failed to modify contact: %s", error->message);
265 
266 	/* Rename Müller -> Sade Adu */
267 	e_contact_set (fixture->contacts[20 - 1], E_CONTACT_FAMILY_NAME, "Adu");
268 	e_contact_set (fixture->contacts[20 - 1], E_CONTACT_GIVEN_NAME, "Sade");
269 	if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
270 					fixture->contacts[20 - 1],
271 					e_contact_get_const (fixture->contacts[20 - 1], E_CONTACT_UID),
272 					0, E_CACHE_IS_ONLINE, NULL, &error))
273 		g_error ("Failed to modify contact: %s", error->message);
274 
275 	/* Check new position */
276 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
277 					     fixture->cursor, &total, &position, NULL, &error))
278 		g_error ("Error calculating cursor: %s", error->message);
279 
280 	/* blackbird is now at position 14 after moving 2 later contacts to begin with 'A' */
281 	g_assert_cmpint (position, ==, 14);
282 	g_assert_cmpint (total, ==, 20);
283 }
284 
285 static void
test_cursor_calculate_filtered_initial(TCUCursorFixture * fixture,gconstpointer user_data)286 test_cursor_calculate_filtered_initial (TCUCursorFixture *fixture,
287 					gconstpointer user_data)
288 {
289 	GError *error = NULL;
290 	gint position = 0, total = 0;
291 
292 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
293 					     fixture->cursor, &total, &position, NULL, &error))
294 	    g_error ("Error calculating cursor: %s", error->message);
295 
296 	g_assert_cmpint (position, ==, 0);
297 	g_assert_cmpint (total, ==, 13);
298 }
299 
300 static void
test_cursor_calculate_filtered_move_forward(TCUCursorFixture * fixture,gconstpointer user_data)301 test_cursor_calculate_filtered_move_forward (TCUCursorFixture *fixture,
302 					     gconstpointer user_data)
303 {
304 	GSList *results = NULL;
305 	GError *error = NULL;
306 	gint position = 0, total = 0;
307 
308 	/* Move cursor */
309 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
310 				       fixture->cursor,
311 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
312 				       E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
313 				       5, &results, NULL, &error) < 0)
314 		g_error ("Error fetching cursor results: %s", error->message);
315 
316 	g_assert_cmpint (g_slist_length (results), ==, 5);
317 	g_slist_free_full (results, e_book_cache_search_data_free);
318 	results = NULL;
319 
320 	/* Check new position */
321 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
322 					     fixture->cursor, &total, &position, NULL, &error))
323 	    g_error ("Error calculating cursor: %s", error->message);
324 
325 	/* results 0 + 5 = position 5, result index 4 (results[0, 1, 2, 3, 4]) */
326 	g_assert_cmpint (position, ==, 5);
327 	g_assert_cmpint (total, ==, 13);
328 }
329 
330 static void
test_cursor_calculate_filtered_move_backwards(TCUCursorFixture * fixture,gconstpointer user_data)331 test_cursor_calculate_filtered_move_backwards (TCUCursorFixture *fixture,
332 					       gconstpointer user_data)
333 {
334 	GSList *results = NULL;
335 	GError *error = NULL;
336 	gint position = 0, total = 0;
337 
338 	/* Move cursor */
339 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
340 				       fixture->cursor,
341 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
342 				       E_BOOK_CACHE_CURSOR_ORIGIN_END,
343 				       -5,
344 				       &results, NULL, &error) < 0)
345 		g_error ("Error fetching cursor results: %s", error->message);
346 
347 	g_assert_cmpint (g_slist_length (results), ==, 5);
348 	g_slist_free_full (results, e_book_cache_search_data_free);
349 	results = NULL;
350 
351 	/* Check new position */
352 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
353 					     fixture->cursor, &total, &position, NULL, &error))
354 		g_error ("Error calculating cursor: %s", error->message);
355 
356 	/* results 13 - 5 = position 9 (results[13, 12, 11, 10, 9]) */
357 	g_assert_cmpint (position, ==, 9);
358 	g_assert_cmpint (total, ==, 13);
359 }
360 
361 static void
test_cursor_calculate_filtered_partial_target(TCUCursorFixture * fixture,gconstpointer user_data)362 test_cursor_calculate_filtered_partial_target (TCUCursorFixture *fixture,
363 					       gconstpointer user_data)
364 {
365 	GError *error = NULL;
366 	gint position = 0, total = 0;
367 	ECollator *collator;
368 	gint n_labels;
369 	const gchar *const *labels;
370 
371 	/* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
372 	collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
373 	labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
374 	g_assert_cmpstr (labels[3], ==, "C");
375 	e_collator_unref (collator);
376 
377 	/* Set the cursor at the start of family names beginning with 'C' */
378 	e_book_cache_cursor_set_target_alphabetic_index (
379 		((TCUFixture *) fixture)->book_cache,
380 		fixture->cursor, 3);
381 
382 	/* Check new position */
383 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
384 					     fixture->cursor, &total, &position, NULL, &error))
385 		g_error ("Error calculating cursor: %s", error->message);
386 
387 	/* There are 9 contacts before the letter 'C' in the en_US locale */
388 	g_assert_cmpint (position, ==, 9);
389 	g_assert_cmpint (total, ==, 13);
390 }
391 
392 static void
test_cursor_calculate_filtered_after_modification(TCUCursorFixture * fixture,gconstpointer user_data)393 test_cursor_calculate_filtered_after_modification (TCUCursorFixture *fixture,
394 						   gconstpointer user_data)
395 {
396 	GError *error = NULL;
397 	gint position = 0, total = 0;
398 
399 	/* Set the cursor to point exactly 'blackbird' (which is the 8th contact when filtered) */
400 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
401 				       fixture->cursor,
402 				       E_BOOK_CACHE_CURSOR_STEP_MOVE,
403 				       E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
404 				       8, NULL, NULL, &error) < 0)
405 		g_error ("Error fetching cursor results: %s", error->message);
406 
407 	/* 'blackbirds' -> Jacob Appelbaum */
408 	e_contact_set (fixture->contacts[18 - 1], E_CONTACT_FAMILY_NAME, "Appelbaum");
409 	e_contact_set (fixture->contacts[18 - 1], E_CONTACT_GIVEN_NAME, "Jacob");
410 	if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
411 					fixture->contacts[18 - 1],
412 					e_contact_get_const (fixture->contacts[18 - 1], E_CONTACT_UID),
413 					0, E_CACHE_IS_ONLINE, NULL, &error))
414 		g_error ("Failed to modify contact: %s", error->message);
415 
416 	/* 'black-birds' -> Sade Adu */
417 	e_contact_set (fixture->contacts[17 - 1], E_CONTACT_FAMILY_NAME, "Adu");
418 	e_contact_set (fixture->contacts[17 - 1], E_CONTACT_GIVEN_NAME, "Sade");
419 	if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
420 					fixture->contacts[17 - 1],
421 					e_contact_get_const (fixture->contacts[17 - 1], E_CONTACT_UID),
422 					0, E_CACHE_IS_ONLINE, NULL, &error))
423 		g_error ("Failed to modify contact: %s", error->message);
424 
425 	/* Check new position */
426 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
427 					     fixture->cursor, &total, &position, NULL, &error))
428 		g_error ("Error calculating cursor: %s", error->message);
429 
430 	/* blackbird is now at position 11 after moving 2 later contacts to begin with 'A' */
431 	g_assert_cmpint (position, ==, 9);
432 	g_assert_cmpint (total, ==, 13);
433 }
434 
435 static void
test_cursor_calculate_descending_move_forward(TCUCursorFixture * fixture,gconstpointer user_data)436 test_cursor_calculate_descending_move_forward (TCUCursorFixture *fixture,
437                                                gconstpointer user_data)
438 {
439 	GSList *results = NULL;
440 	GError *error = NULL;
441 	gint position = 0, total = 0;
442 
443 	/* Move cursor */
444 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
445 				       fixture->cursor,
446 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
447 				       E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
448 				       5,
449 				       &results, NULL, &error) < 0)
450 		g_error ("Error fetching cursor results: %s", error->message);
451 
452 	/* Assert the first 5 contacts in en_US order */
453 	g_assert_cmpint (g_slist_length (results), ==, 5);
454 	tcu_assert_contacts_order (
455 		results,
456 		"sorted-20",
457 		"sorted-19",
458 		"sorted-9",
459 		"sorted-13",
460 		"sorted-12",
461 		NULL);
462 	g_slist_free_full (results, e_book_cache_search_data_free);
463 	results = NULL;
464 
465 	/* Check new position */
466 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
467 					     fixture->cursor, &total, &position, NULL, &error))
468 	    g_error ("Error calculating cursor: %s", error->message);
469 
470 	/* results 0 + 5 = position 5, result index 4 (results[0, 1, 2, 3, 4]) */
471 	g_assert_cmpint (position, ==, 5);
472 	g_assert_cmpint (total, ==, 20);
473 }
474 
475 static void
test_cursor_calculate_descending_move_backwards(TCUCursorFixture * fixture,gconstpointer user_data)476 test_cursor_calculate_descending_move_backwards (TCUCursorFixture *fixture,
477 						 gconstpointer user_data)
478 {
479 	GSList *results = NULL;
480 	GError *error = NULL;
481 	gint position = 0, total = 0;
482 
483 	/* Move cursor */
484 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
485 				       fixture->cursor,
486 				       E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
487 				       E_BOOK_CACHE_CURSOR_ORIGIN_END,
488 				       -5, &results, NULL, &error) < 0)
489 		g_error ("Error fetching cursor results: %s", error->message);
490 
491 	/* Assert the last 5 contacts in en_US order */
492 	g_assert_cmpint (g_slist_length (results), ==, 5);
493 	tcu_assert_contacts_order (
494 		results,
495 		"sorted-11",
496 		"sorted-1",
497 		"sorted-2",
498 		"sorted-5",
499 		"sorted-6",
500 		NULL);
501 	g_slist_free_full (results, e_book_cache_search_data_free);
502 	results = NULL;
503 
504 	/* Check new position */
505 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
506 					     fixture->cursor, &total, &position, NULL, &error))
507 	    g_error ("Error calculating cursor: %s", error->message);
508 
509 	/* results 20 - 5 = position 16 result index 15 (results[20, 19, 18, 17, 16]) */
510 	g_assert_cmpint (position, ==, 16);
511 	g_assert_cmpint (total, ==, 20);
512 }
513 
514 static void
test_cursor_calculate_descending_partial_target(TCUCursorFixture * fixture,gconstpointer user_data)515 test_cursor_calculate_descending_partial_target (TCUCursorFixture *fixture,
516 						 gconstpointer user_data)
517 {
518 	GError *error = NULL;
519 	gint position = 0, total = 0;
520 	ECollator *collator;
521 	gint n_labels;
522 	const gchar *const *labels;
523 
524 	/* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
525 	collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
526 	labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
527 	g_assert_cmpstr (labels[3], ==, "C");
528 	e_collator_unref (collator);
529 
530 	/* Set the cursor at the start of family names beginning with 'C' */
531 	e_book_cache_cursor_set_target_alphabetic_index (
532 		((TCUFixture *) fixture)->book_cache,
533 		fixture->cursor, 3);
534 
535 	/* Check new position */
536 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
537 					     fixture->cursor, &total, &position, NULL, &error))
538 		g_error ("Error calculating cursor: %s", error->message);
539 
540 	/* Position is 7, there are 7 contacts leading up to the last 'C' in en_US locale
541 	 * (when sorting in descending order) */
542 	g_assert_cmpint (position, ==, 7);
543 	g_assert_cmpint (total, ==, 20);
544 }
545 
546 static void
test_cursor_calculate_descending_after_modification(TCUCursorFixture * fixture,gconstpointer user_data)547 test_cursor_calculate_descending_after_modification (TCUCursorFixture *fixture,
548 						     gconstpointer user_data)
549 {
550 	GError *error = NULL;
551 	gint position = 0, total = 0;
552 
553 	/* Set the cursor to point exactly 'Bät' (which is the 12th contact in descending order) */
554 	if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
555 				       fixture->cursor,
556 				       E_BOOK_CACHE_CURSOR_STEP_MOVE,
557 				       E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
558 				       12, NULL, NULL, &error) < 0)
559 		g_error ("Error fetching cursor results: %s", error->message);
560 
561 	/* Check new position */
562 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
563 					     fixture->cursor, &total, &position, NULL, &error))
564 		g_error ("Error calculating cursor: %s", error->message);
565 
566 	/* 'Bät' is at position 12 in en_US locale (descending order) */
567 	g_assert_cmpint (position, ==, 12);
568 	g_assert_cmpint (total, ==, 20);
569 
570 	/* Rename Muffler -> Jacob Appelbaum */
571 	e_contact_set (fixture->contacts[19 - 1], E_CONTACT_FAMILY_NAME, "Appelbaum");
572 	e_contact_set (fixture->contacts[19 - 1], E_CONTACT_GIVEN_NAME, "Jacob");
573 	if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
574 					fixture->contacts[19 - 1],
575 					e_contact_get_const (fixture->contacts[19 - 1], E_CONTACT_UID),
576 					0, E_CACHE_IS_ONLINE, NULL, &error))
577 		g_error ("Failed to modify contact: %s", error->message);
578 
579 	/* Rename Müller -> Sade Adu */
580 	e_contact_set (fixture->contacts[20 - 1], E_CONTACT_FAMILY_NAME, "Adu");
581 	e_contact_set (fixture->contacts[20 - 1], E_CONTACT_GIVEN_NAME, "Sade");
582 	if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
583 					fixture->contacts[20 - 1],
584 					e_contact_get_const (fixture->contacts[20 - 1], E_CONTACT_UID),
585 					0, E_CACHE_IS_ONLINE, NULL, &error))
586 		g_error ("Failed to modify contact: %s", error->message);
587 
588 	/* Check new position */
589 	if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
590 					     fixture->cursor, &total, &position, NULL, &error))
591 		g_error ("Error calculating cursor: %s", error->message);
592 
593 	/* 'Bät' is now at position 10 in descending order after moving 2 contacts to begin with 'A' */
594 	g_assert_cmpint (position, ==, 10);
595 	g_assert_cmpint (total, ==, 20);
596 }
597 
598 gint
main(gint argc,gchar ** argv)599 main (gint argc,
600       gchar **argv)
601 {
602 #if !GLIB_CHECK_VERSION (2, 35, 1)
603 	g_type_init ();
604 #endif
605 	g_test_init (&argc, &argv, NULL);
606 	g_test_bug_base ("https://gitlab.gnome.org/GNOME/evolution-data-server/");
607 
608 	tcu_read_args (argc, argv);
609 
610 	g_test_add (
611 		"/EBookCacheCursor/Calculate/Initial", TCUCursorFixture, &ascending_closure,
612 		tcu_cursor_fixture_setup,
613 		test_cursor_calculate_initial,
614 		tcu_cursor_fixture_teardown);
615 	g_test_add (
616 		"/EBookCacheCursor/Calculate/MoveForward", TCUCursorFixture, &ascending_closure,
617 		tcu_cursor_fixture_setup,
618 		test_cursor_calculate_move_forward,
619 		tcu_cursor_fixture_teardown);
620 	g_test_add (
621 		"/EBookCacheCursor/Calculate/MoveBackwards", TCUCursorFixture, &ascending_closure,
622 		tcu_cursor_fixture_setup,
623 		test_cursor_calculate_move_backwards,
624 		tcu_cursor_fixture_teardown);
625 	g_test_add (
626 		"/EBookCacheCursor/Calculate/BackAndForth", TCUCursorFixture, &ascending_closure,
627 		tcu_cursor_fixture_setup,
628 		test_cursor_calculate_back_and_forth,
629 		tcu_cursor_fixture_teardown);
630 	g_test_add (
631 		"/EBookCacheCursor/Calculate/AlphabeticTarget", TCUCursorFixture, &ascending_closure,
632 		tcu_cursor_fixture_setup,
633 		test_cursor_calculate_partial_target,
634 		tcu_cursor_fixture_teardown);
635 	g_test_add (
636 		"/EBookCacheCursor/Calculate/AfterModification", TCUCursorFixture, &ascending_closure,
637 		tcu_cursor_fixture_setup,
638 		test_cursor_calculate_after_modification,
639 		tcu_cursor_fixture_teardown);
640 
641 	g_test_add (
642 		"/EBookCacheCursor/Calculate/Filtered/Initial", TCUCursorFixture, &ascending_closure,
643 		tcu_cursor_fixture_filtered_setup,
644 		test_cursor_calculate_filtered_initial,
645 		tcu_cursor_fixture_teardown);
646 	g_test_add (
647 		"/EBookCacheCursor/Calculate/Filtered/MoveForward", TCUCursorFixture, &ascending_closure,
648 		tcu_cursor_fixture_filtered_setup,
649 		test_cursor_calculate_filtered_move_forward,
650 		tcu_cursor_fixture_teardown);
651 	g_test_add (
652 		"/EBookCacheCursor/Calculate/Filtered/MoveBackwards", TCUCursorFixture, &ascending_closure,
653 		tcu_cursor_fixture_filtered_setup,
654 		test_cursor_calculate_filtered_move_backwards,
655 		tcu_cursor_fixture_teardown);
656 	g_test_add (
657 		"/EBookCacheCursor/Calculate/Filtered/AlphabeticTarget", TCUCursorFixture, &ascending_closure,
658 		tcu_cursor_fixture_filtered_setup,
659 		test_cursor_calculate_filtered_partial_target,
660 		tcu_cursor_fixture_teardown);
661 	g_test_add (
662 		"/EBookCacheCursor/Calculate/Filtered/AfterModification", TCUCursorFixture, &ascending_closure,
663 		tcu_cursor_fixture_filtered_setup,
664 		test_cursor_calculate_filtered_after_modification,
665 		tcu_cursor_fixture_teardown);
666 
667 	g_test_add (
668 		"/EBookCacheCursor/Calculate/Descending/Initial", TCUCursorFixture, &descending_closure,
669 		tcu_cursor_fixture_setup,
670 		test_cursor_calculate_initial,
671 		tcu_cursor_fixture_teardown);
672 	g_test_add (
673 		"/EBookCacheCursor/Calculate/Descending/MoveForward", TCUCursorFixture, &descending_closure,
674 		tcu_cursor_fixture_setup,
675 		test_cursor_calculate_descending_move_forward,
676 		tcu_cursor_fixture_teardown);
677 	g_test_add (
678 		"/EBookCacheCursor/Calculate/Descending/MoveBackwards", TCUCursorFixture, &descending_closure,
679 		tcu_cursor_fixture_setup,
680 		test_cursor_calculate_descending_move_backwards,
681 		tcu_cursor_fixture_teardown);
682 	g_test_add (
683 		"/EBookCacheCursor/Calculate/Descending/BackAndForth", TCUCursorFixture, &descending_closure,
684 		tcu_cursor_fixture_setup,
685 		test_cursor_calculate_back_and_forth,
686 		tcu_cursor_fixture_teardown);
687 	g_test_add (
688 		"/EBookCacheCursor/Calculate/Descending/AlphabeticTarget", TCUCursorFixture, &descending_closure,
689 		tcu_cursor_fixture_setup,
690 		test_cursor_calculate_descending_partial_target,
691 		tcu_cursor_fixture_teardown);
692 	g_test_add (
693 		"/EBookCacheCursor/Calculate/Descending/AfterModification", TCUCursorFixture, &descending_closure,
694 		tcu_cursor_fixture_setup,
695 		test_cursor_calculate_descending_after_modification,
696 		tcu_cursor_fixture_teardown);
697 
698 	return e_test_server_utils_run_full (argc, argv, 0);
699 }
700