[evolution-data-server/wip/offline-cache] Copy Tristan's EBookSqlite tests and use then with EBookCache
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/wip/offline-cache] Copy Tristan's EBookSqlite tests and use then with EBookCache
- Date: Tue, 21 Mar 2017 17:31:43 +0000 (UTC)
commit e50bad9fe5306a7979aefd21f533d61c8f25c3f6
Author: Milan Crha <mcrha redhat com>
Date: Wed Feb 1 22:34:42 2017 +0100
Copy Tristan's EBookSqlite tests and use then with EBookCache
src/addressbook/libedata-book/e-book-cache.c | 242 +++++++-
src/addressbook/libedata-book/e-book-cache.h | 5 +
src/libebackend/e-cache.c | 11 +-
tests/libedata-book/CMakeLists.txt | 12 +
tests/libedata-book/test-cache-create-cursor.c | 125 ++++
tests/libedata-book/test-cache-cursor-calculate.c | 695 ++++++++++++++++++++
.../test-cache-cursor-change-locale.c | 102 +++
.../test-cache-cursor-move-by-de-DE.c | 82 +++
.../test-cache-cursor-move-by-en-US.c | 100 +++
.../test-cache-cursor-move-by-fr-CA.c | 82 +++
.../test-cache-cursor-move-by-posix.c | 82 +++
tests/libedata-book/test-cache-cursor-set-sexp.c | 151 +++++
tests/libedata-book/test-cache-cursor-set-target.c | 225 +++++++
tests/libedata-book/test-cache-get-contact.c | 78 +++
tests/libedata-book/test-cache-utils.c | 691 +++++++++++++++++++
tests/libedata-book/test-cache-utils.h | 174 +++++
16 files changed, 2829 insertions(+), 28 deletions(-)
---
diff --git a/src/addressbook/libedata-book/e-book-cache.c b/src/addressbook/libedata-book/e-book-cache.c
index 881bff8..f80f6af 100644
--- a/src/addressbook/libedata-book/e-book-cache.c
+++ b/src/addressbook/libedata-book/e-book-cache.c
@@ -129,6 +129,13 @@ enum {
PROP_LOCALE
};
+enum {
+ E164_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE_WITH_CODE (EBookCache, e_book_cache, E_TYPE_CACHE,
G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
@@ -266,6 +273,9 @@ column_info_new (SummaryField *field,
g_return_val_if_fail (column_name != NULL, NULL);
+ if (field->type == E_TYPE_CONTACT_ATTR_LIST)
+ column_name = "value";
+
if (!column_type) {
if (field->type == G_TYPE_STRING)
column_type = "TEXT";
@@ -1009,7 +1019,7 @@ ebc_run_multi_insert_one (ECache *cache,
normal = e_util_utf8_normalize (value);
- e_cache_sqlite_stmt_append_printf (stmt, "INSERT INTO %Q (uid, %s", field->aux_table, field->dbname);
+ e_cache_sqlite_stmt_append_printf (stmt, "INSERT INTO %Q (uid, value", field->aux_table);
if ((field->index & INDEX_FLAG (SUFFIX)) != 0) {
g_string_append (stmt, ", value_" EBC_SUFFIX_REVERSE);
@@ -1237,26 +1247,10 @@ ebc_upgrade_cb (ECache *cache,
g_clear_object (&contact);
- if (g_hash_table_size (other_columns) > 0) {
- gint ii;
-
- for (ii = 0; ii < ncols; ii++) {
- if (!column_names[ii] ||
- !g_hash_table_contains (other_columns, column_names[ii]))
- continue;
-
- if (g_strcmp0 (g_hash_table_lookup (other_columns, column_names[ii]),
column_values[ii]) == 0) {
- /* Do not try to store values which did not change */
- g_hash_table_remove (other_columns, column_names[ii]);
- }
- }
- }
-
- if (g_hash_table_size (other_columns) > 0) {
- *out_other_columns = other_columns;
- } else {
- g_hash_table_destroy (other_columns);
- }
+ /* This will cause rewrite even when no values changed, but it's
+ necessary, because the locale changed, which can influence
+ other tables, not only the other columns. */
+ *out_other_columns = other_columns;
return TRUE;
}
@@ -3891,6 +3885,178 @@ cursor_count_position_locked (EBookCache *book_cache,
return success;
}
+typedef struct {
+ gint country_code;
+ gchar *national;
+} E164Number;
+
+static E164Number *
+ebc_e164_number_new (gint country_code,
+ const gchar *national)
+{
+ E164Number *number = g_slice_new (E164Number);
+
+ number->country_code = country_code;
+ number->national = g_strdup (national);
+
+ return number;
+}
+
+static void
+ebc_e164_number_free (E164Number *number)
+{
+ if (number) {
+ g_free (number->national);
+ g_slice_free (E164Number, number);
+ }
+}
+
+static gint
+ebc_e164_number_find (E164Number *number_a,
+ E164Number *number_b)
+{
+ gint ret;
+
+ ret = number_a->country_code - number_b->country_code;
+
+ if (ret == 0) {
+ ret = g_strcmp0 (
+ number_a->national,
+ number_b->national);
+ }
+
+ return ret;
+}
+
+static GList *
+extract_e164_attribute_params (EContact *contact)
+{
+ EVCard *vcard = E_VCARD (contact);
+ GList *extracted = NULL;
+ GList *attr_list;
+
+ for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
+ EVCardAttribute *const attr = attr_list->data;
+ EVCardAttributeParam *param = NULL;
+ GList *param_list, *values, *l;
+ gchar *this_national = NULL;
+ gint this_country = 0;
+
+ /* We only attach E164 parameters to TEL attributes. */
+ if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
+ continue;
+
+ /* Find already exisiting parameter, so that we can reuse it. */
+ for (param_list = e_vcard_attribute_get_params (attr); param_list; param_list =
param_list->next) {
+ if (strcmp (e_vcard_attribute_param_get_name (param_list->data), EVC_X_E164) == 0) {
+ param = param_list->data;
+ break;
+ }
+ }
+
+ if (!param)
+ continue;
+
+ values = e_vcard_attribute_param_get_values (param);
+ for (l = values; l; l = l->next) {
+ const gchar *value = l->data;
+
+ if (value[0] == '+')
+ this_country = g_ascii_strtoll (&value[1], NULL, 10);
+ else if (this_national == NULL)
+ this_national = g_strdup (value);
+ }
+
+ if (this_national) {
+ E164Number *number;
+
+ number = ebc_e164_number_new (this_country, this_national);
+ extracted = g_list_prepend (extracted, number);
+ }
+
+ g_free (this_national);
+
+ /* Clear the values, we'll insert new ones */
+ e_vcard_attribute_param_remove_values (param);
+ e_vcard_attribute_remove_param (attr, EVC_X_E164);
+ }
+
+ return extracted;
+}
+
+static gboolean
+update_e164_attribute_params (EBookCache *book_cache,
+ EContact *contact,
+ const gchar *default_region)
+{
+ GList *original_numbers = NULL;
+ GList *attr_list;
+ gboolean changed = FALSE;
+ gint n_numbers = 0;
+ EVCard *vcard = E_VCARD (contact);
+
+ original_numbers = extract_e164_attribute_params (contact);
+
+ for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
+ EVCardAttribute *const attr = attr_list->data;
+ EVCardAttributeParam *param = NULL;
+ const gchar *original_number = NULL;
+ gchar *country_string;
+ GList *values;
+ E164Number number = { 0, NULL };
+
+ /* We only attach E164 parameters to TEL attributes. */
+ if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
+ continue;
+
+ /* Fetch the TEL value */
+ values = e_vcard_attribute_get_values (attr);
+
+ /* Compute E164 number based on the TEL value */
+ if (values && values->data) {
+ original_number = (const gchar *) values->data;
+ number.national = convert_phone (original_number, book_cache->priv->region_code,
&(number.country_code));
+ }
+
+ if (number.national == NULL)
+ continue;
+
+ /* Count how many we successfully parsed in this region code */
+ n_numbers++;
+
+ /* Check if we have a differing e164 number, if there is no match
+ * in the old existing values then the vcard changed
+ */
+ if (!g_list_find_custom (original_numbers, &number, (GCompareFunc) ebc_e164_number_find))
+ changed = TRUE;
+
+ if (number.country_code != 0)
+ country_string = g_strdup_printf ("+%d", number.country_code);
+ else
+ country_string = g_strdup ("");
+
+ param = e_vcard_attribute_param_new (EVC_X_E164);
+ e_vcard_attribute_add_param (attr, param);
+
+ /* Assign the parameter values. It seems odd that we revert
+ * the order of NN and CC, but at least EVCard's parser doesn't
+ * permit an empty first param value. Which of course could be
+ * fixed - in order to create a nice potential IOP problem with
+ ** other vCard parsers. */
+ e_vcard_attribute_param_add_values (param, number.national, country_string, NULL);
+
+ g_free (number.national);
+ g_free (country_string);
+ }
+
+ if (!changed && n_numbers != g_list_length (original_numbers))
+ changed = TRUE;
+
+ g_list_free_full (original_numbers, (GDestroyNotify) ebc_e164_number_free);
+
+ return changed;
+}
+
static gboolean
e_book_cache_get_string (ECache *cache,
gint ncols,
@@ -5580,16 +5746,38 @@ e_book_cache_put_locked (ECache *cache,
GCancellable *cancellable,
GError **error)
{
+ EBookCache *book_cache;
+ EContact *contact;
+ gchar *updated_vcard = NULL;
+ gboolean e164_changed;
gboolean success;
g_return_val_if_fail (E_IS_BOOK_CACHE (cache), FALSE);
g_return_val_if_fail (E_CACHE_CLASS (e_book_cache_parent_class)->put_locked != NULL, FALSE);
+ book_cache = E_BOOK_CACHE (cache);
+
+ contact = e_contact_new_from_vcard_with_uid (object, uid);
+
+ /* Update E.164 parameters in vcard if needed */
+ e164_changed = update_e164_attribute_params (book_cache, contact, book_cache->priv->region_code);
+
+ if (e164_changed) {
+ updated_vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+ object = updated_vcard;
+ }
+
success = E_CACHE_CLASS (e_book_cache_parent_class)->put_locked (cache, uid, revision, object,
other_columns, offline_state,
is_replace, cancellable, error);
success = success && ebc_update_aux_tables (cache, uid, revision, object, cancellable, error);
+ if (success && e164_changed)
+ g_signal_emit (book_cache, signals[E164_CHANGED], 0, contact, is_replace);
+
+ g_clear_object (&contact);
+ g_free (updated_vcard);
+
return success;
}
@@ -5693,6 +5881,18 @@ e_book_cache_class_init (EBookCacheClass *class)
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
+
+ signals[E164_CHANGED] = g_signal_new (
+ "e164-changed",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EBookCacheClass, e164_changed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 2,
+ E_TYPE_CONTACT,
+ G_TYPE_BOOLEAN);
}
static void
diff --git a/src/addressbook/libedata-book/e-book-cache.h b/src/addressbook/libedata-book/e-book-cache.h
index c8ad69c..6fcfdb4 100644
--- a/src/addressbook/libedata-book/e-book-cache.h
+++ b/src/addressbook/libedata-book/e-book-cache.h
@@ -112,6 +112,11 @@ struct _EBookCacheClass {
/*< private >*/
ECacheClass parent_class;
+ /* Signals */
+ void (* e164_changed) (EBookCache *book_cache,
+ EContact *contact,
+ gboolean is_replace);
+
/* Padding for future expansion */
gpointer reserved[10];
};
diff --git a/src/libebackend/e-cache.c b/src/libebackend/e-cache.c
index 7fe3762..e5d47f0 100644
--- a/src/libebackend/e-cache.c
+++ b/src/libebackend/e-cache.c
@@ -54,7 +54,7 @@
#define E_CACHE_CANCEL_BATCH_SIZE 200
/* How many rows to read when e_cache_foreach_update() */
-#define E_CACHE_UPDATE_BATCH_SIZE 200
+#define E_CACHE_UPDATE_BATCH_SIZE 100
struct _ECachePrivate {
gchar *filename;
@@ -999,7 +999,6 @@ e_cache_put_locked (ECache *cache,
g_return_val_if_fail (E_IS_CACHE (cache), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
- g_return_val_if_fail (revision != NULL, FALSE);
g_return_val_if_fail (object != NULL, FALSE);
if (!other_columns) {
@@ -1034,7 +1033,7 @@ e_cache_put_locked (ECache *cache,
* e_cache_put:
* @cache: an #ECache
* @uid: a unique identifier of an object
- * @revision: a revision of the object
+ * @revision: (nullable): a revision of the object
* @object: the object itself
* @other_columns: (nullable) (element-type utf8 utf8): what other columns to set; can be %NULL
* @cancellable: optional #GCancellable object, or %NULL
@@ -1063,7 +1062,6 @@ e_cache_put (ECache *cache,
g_return_val_if_fail (E_IS_CACHE (cache), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
- g_return_val_if_fail (revision != NULL, FALSE);
g_return_val_if_fail (object != NULL, FALSE);
g_rec_mutex_lock (&cache->priv->lock);
@@ -2336,7 +2334,7 @@ e_cache_sqlite_stmt_append_printf (GString *stmt,
g_string_append (stmt, tmp_stmt);
- g_free (tmp_stmt);
+ sqlite3_free (tmp_stmt);
}
/**
@@ -2444,7 +2442,6 @@ e_cache_put_locked_default (ECache *cache,
g_return_val_if_fail (E_IS_CACHE (cache), FALSE);
g_return_val_if_fail (uid != NULL, FALSE);
- g_return_val_if_fail (revision != NULL, FALSE);
g_return_val_if_fail (object != NULL, FALSE);
statement = g_string_sized_new (255);
@@ -2485,7 +2482,7 @@ e_cache_put_locked_default (ECache *cache,
g_string_append (statement, ") VALUES (");
- e_cache_sqlite_stmt_append_printf (statement, "%Q,%Q,%Q,%d", uid, revision, object, offline_state);
+ e_cache_sqlite_stmt_append_printf (statement, "%Q,%Q,%Q,%d", uid, revision ? revision : "", object,
offline_state);
if (other_values)
g_string_append (statement, other_values->str);
diff --git a/tests/libedata-book/CMakeLists.txt b/tests/libedata-book/CMakeLists.txt
index 347196d..d8677d2 100644
--- a/tests/libedata-book/CMakeLists.txt
+++ b/tests/libedata-book/CMakeLists.txt
@@ -37,6 +37,8 @@ set(extra_ldflags
set(SOURCES
data-test-utils.c
data-test-utils.h
+ test-cache-utils.c
+ test-cache-utils.h
)
add_library(data-test-utils STATIC
@@ -94,6 +96,16 @@ set(extra_defines)
# This is because each migrated test changes the
# locale and reloads the same addressbook of the previous test.
set(TESTS
+ test-cache-get-contact
+ test-cache-create-cursor
+ test-cache-cursor-move-by-posix
+ test-cache-cursor-move-by-en-US
+ test-cache-cursor-move-by-fr-CA
+ test-cache-cursor-move-by-de-DE
+ test-cache-cursor-set-target
+ test-cache-cursor-calculate
+ test-cache-cursor-set-sexp
+ test-cache-cursor-change-locale
test-sqlite-get-contact
test-sqlite-create-cursor
test-sqlite-cursor-move-by-posix
diff --git a/tests/libedata-book/test-cache-create-cursor.c b/tests/libedata-book/test-cache-create-cursor.c
new file mode 100644
index 0000000..9ef9d15
--- /dev/null
+++ b/tests/libedata-book/test-cache-create-cursor.c
@@ -0,0 +1,125 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+static TCUClosure closure = { NULL };
+
+static void
+test_create_cursor_empty_query (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ EBookCacheCursor *cursor;
+ EContactField sort_fields[] = { E_CONTACT_FAMILY_NAME, E_CONTACT_GIVEN_NAME };
+ EBookCursorSortType sort_types[] = { E_BOOK_CURSOR_SORT_ASCENDING, E_BOOK_CURSOR_SORT_ASCENDING };
+ GError *error = NULL;
+
+ cursor = e_book_cache_cursor_new (
+ fixture->book_cache, NULL,
+ sort_fields, sort_types, 2, &error);
+
+ g_assert (cursor != NULL);
+ e_book_cache_cursor_free (fixture->book_cache, cursor);
+}
+
+static void
+test_create_cursor_valid_query (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ EBookCacheCursor *cursor;
+ EContactField sort_fields[] = { E_CONTACT_FAMILY_NAME, E_CONTACT_GIVEN_NAME };
+ EBookCursorSortType sort_types[] = { E_BOOK_CURSOR_SORT_ASCENDING, E_BOOK_CURSOR_SORT_ASCENDING };
+ EBookQuery *query;
+ gchar *sexp;
+ GError *error = NULL;
+
+ query = e_book_query_field_test (E_CONTACT_FULL_NAME, E_BOOK_QUERY_IS, "James Brown");
+ sexp = e_book_query_to_string (query);
+
+ cursor = e_book_cache_cursor_new (
+ fixture->book_cache, sexp,
+ sort_fields, sort_types, 2, &error);
+
+ g_assert (cursor != NULL);
+ e_book_cache_cursor_free (fixture->book_cache, cursor);
+ g_free (sexp);
+ e_book_query_unref (query);
+}
+
+static void
+test_create_cursor_invalid_sort (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ EBookCacheCursor *cursor;
+ EContactField sort_fields[] = { E_CONTACT_TEL };
+ EBookCursorSortType sort_types[] = { E_BOOK_CURSOR_SORT_ASCENDING };
+ GError *error = NULL;
+
+ cursor = e_book_cache_cursor_new (
+ fixture->book_cache, NULL,
+ sort_fields, sort_types, 1, &error);
+
+ g_assert (cursor == NULL);
+ g_assert (error);
+ g_assert (g_error_matches (error, E_CACHE_ERROR, E_CACHE_ERROR_INVALID_QUERY));
+}
+
+static void
+test_create_cursor_missing_sort (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ EBookCacheCursor *cursor;
+ GError *error = NULL;
+
+ cursor = e_book_cache_cursor_new (fixture->book_cache, NULL, NULL, NULL, 0, &error);
+
+ g_assert (cursor == NULL);
+ g_assert (error);
+ g_assert (g_error_matches (error, E_CACHE_ERROR, E_CACHE_ERROR_INVALID_QUERY));
+}
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ /* Ensure that the client and server get the same locale */
+ g_assert (g_setenv ("LC_ALL", "en_US.UTF-8", TRUE));
+ setlocale (LC_ALL, "");
+
+ g_test_add (
+ "/EBookCacheCursor/Create/EmptyQuery", TCUFixture, &closure,
+ tcu_fixture_setup, test_create_cursor_empty_query, tcu_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Create/ValidQuery", TCUFixture, &closure,
+ tcu_fixture_setup, test_create_cursor_valid_query, tcu_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Create/InvalidSort", TCUFixture, &closure,
+ tcu_fixture_setup, test_create_cursor_invalid_sort, tcu_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Create/MissingSort", TCUFixture, &closure,
+ tcu_fixture_setup, test_create_cursor_missing_sort, tcu_fixture_teardown);
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-calculate.c
b/tests/libedata-book/test-cache-cursor-calculate.c
new file mode 100644
index 0000000..cf7172a
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-calculate.c
@@ -0,0 +1,695 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+static TCUCursorClosure ascending_closure = {
+ { NULL },
+ NULL, E_BOOK_CURSOR_SORT_ASCENDING
+};
+
+static TCUCursorClosure descending_closure = {
+ { NULL },
+ NULL, E_BOOK_CURSOR_SORT_DESCENDING
+};
+
+static void
+test_cursor_calculate_initial (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ g_assert_cmpint (position, ==, 0);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_move_forward (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ 5,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Assert the first 5 contacts in en_US order */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-11",
+ "sorted-1",
+ "sorted-2",
+ "sorted-5",
+ "sorted-6",
+ NULL);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 0 + 5 = position 5, result index 4 (results[0, 1, 2, 3, 4]) */
+ g_assert_cmpint (position, ==, 5);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_move_backwards (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_END,
+ -5,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Assert the last 5 contacts in en_US order */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-20",
+ "sorted-19",
+ "sorted-9",
+ "sorted-13",
+ "sorted-12",
+ NULL);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 20 - 5 = position 16 result index 15 (results[20, 19, 18, 17, 16]) */
+ g_assert_cmpint (position, ==, 16);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_back_and_forth (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 7,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ g_assert_cmpint (g_slist_length (results), ==, 7);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 0 + 7 = position 7 result index 6 (results[0, 1, 2, 3, 4, 5, 6]) */
+ g_assert_cmpint (position, ==, 7);
+ g_assert_cmpint (total, ==, 20);
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ -4,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ g_assert_cmpint (g_slist_length (results), ==, 4);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 7 - 4 = position 3 result index 2 (results[5, 4, 3, 2]) */
+ g_assert_cmpint (position, ==, 3);
+ g_assert_cmpint (total, ==, 20);
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ 5,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 3 + 5 = position 8 result index 7 (results[3, 4, 5, 6, 7]) */
+ g_assert_cmpint (position, ==, 8);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_partial_target (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+ ECollator *collator;
+ gint n_labels;
+ const gchar *const *labels;
+
+ /* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
+ collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
+ labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
+ g_assert_cmpstr (labels[3], ==, "C");
+ e_collator_unref (collator);
+
+ /* Set the cursor at the start of family names beginning with 'C' */
+ e_book_cache_cursor_set_target_alphabetic_index (
+ ((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, 3);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* Position is 13, there are 13 contacts before the letter 'C' in en_US locale */
+ g_assert_cmpint (position, ==, 13);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_after_modification (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Set the cursor to point exactly 'blackbird' (which is the 12th contact) */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ 12, NULL, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* blackbird is at position 12 in en_US locale */
+ g_assert_cmpint (position, ==, 12);
+ g_assert_cmpint (total, ==, 20);
+
+ /* Rename Muffler -> Jacob Appelbaum */
+ e_contact_set (fixture->contacts[19 - 1], E_CONTACT_FAMILY_NAME, "Appelbaum");
+ e_contact_set (fixture->contacts[19 - 1], E_CONTACT_GIVEN_NAME, "Jacob");
+ if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
+ fixture->contacts[19 - 1],
+ e_contact_get_const (fixture->contacts[19 - 1], E_CONTACT_UID),
+ FALSE, NULL, &error))
+ g_error ("Failed to modify contact: %s", error->message);
+
+ /* Rename Müller -> Sade Adu */
+ e_contact_set (fixture->contacts[20 - 1], E_CONTACT_FAMILY_NAME, "Adu");
+ e_contact_set (fixture->contacts[20 - 1], E_CONTACT_GIVEN_NAME, "Sade");
+ if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
+ fixture->contacts[20 - 1],
+ e_contact_get_const (fixture->contacts[20 - 1], E_CONTACT_UID),
+ FALSE, NULL, &error))
+ g_error ("Failed to modify contact: %s", error->message);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* blackbird is now at position 14 after moving 2 later contacts to begin with 'A' */
+ g_assert_cmpint (position, ==, 14);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_filtered_initial (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ g_assert_cmpint (position, ==, 0);
+ g_assert_cmpint (total, ==, 13);
+}
+
+static void
+test_cursor_calculate_filtered_move_forward (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ 5, &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 0 + 5 = position 5, result index 4 (results[0, 1, 2, 3, 4]) */
+ g_assert_cmpint (position, ==, 5);
+ g_assert_cmpint (total, ==, 13);
+}
+
+static void
+test_cursor_calculate_filtered_move_backwards (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_END,
+ -5,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 13 - 5 = position 9 (results[13, 12, 11, 10, 9]) */
+ g_assert_cmpint (position, ==, 9);
+ g_assert_cmpint (total, ==, 13);
+}
+
+static void
+test_cursor_calculate_filtered_partial_target (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+ ECollator *collator;
+ gint n_labels;
+ const gchar *const *labels;
+
+ /* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
+ collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
+ labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
+ g_assert_cmpstr (labels[3], ==, "C");
+ e_collator_unref (collator);
+
+ /* Set the cursor at the start of family names beginning with 'C' */
+ e_book_cache_cursor_set_target_alphabetic_index (
+ ((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, 3);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* There are 9 contacts before the letter 'C' in the en_US locale */
+ g_assert_cmpint (position, ==, 9);
+ g_assert_cmpint (total, ==, 13);
+}
+
+static void
+test_cursor_calculate_filtered_after_modification (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Set the cursor to point exactly 'blackbird' (which is the 8th contact when filtered) */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 8, NULL, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* 'blackbirds' -> Jacob Appelbaum */
+ e_contact_set (fixture->contacts[18 - 1], E_CONTACT_FAMILY_NAME, "Appelbaum");
+ e_contact_set (fixture->contacts[18 - 1], E_CONTACT_GIVEN_NAME, "Jacob");
+ if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
+ fixture->contacts[18 - 1],
+ e_contact_get_const (fixture->contacts[18 - 1], E_CONTACT_UID),
+ FALSE, NULL, &error))
+ g_error ("Failed to modify contact: %s", error->message);
+
+ /* 'black-birds' -> Sade Adu */
+ e_contact_set (fixture->contacts[17 - 1], E_CONTACT_FAMILY_NAME, "Adu");
+ e_contact_set (fixture->contacts[17 - 1], E_CONTACT_GIVEN_NAME, "Sade");
+ if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
+ fixture->contacts[17 - 1],
+ e_contact_get_const (fixture->contacts[17 - 1], E_CONTACT_UID),
+ FALSE, NULL, &error))
+ g_error ("Failed to modify contact: %s", error->message);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* blackbird is now at position 11 after moving 2 later contacts to begin with 'A' */
+ g_assert_cmpint (position, ==, 9);
+ g_assert_cmpint (total, ==, 13);
+}
+
+static void
+test_cursor_calculate_descending_move_forward (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 5,
+ &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Assert the first 5 contacts in en_US order */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-20",
+ "sorted-19",
+ "sorted-9",
+ "sorted-13",
+ "sorted-12",
+ NULL);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 0 + 5 = position 5, result index 4 (results[0, 1, 2, 3, 4]) */
+ g_assert_cmpint (position, ==, 5);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_descending_move_backwards (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Move cursor */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_END,
+ -5, &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Assert the last 5 contacts in en_US order */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-11",
+ "sorted-1",
+ "sorted-2",
+ "sorted-5",
+ "sorted-6",
+ NULL);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* results 20 - 5 = position 16 result index 15 (results[20, 19, 18, 17, 16]) */
+ g_assert_cmpint (position, ==, 16);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_descending_partial_target (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+ ECollator *collator;
+ gint n_labels;
+ const gchar *const *labels;
+
+ /* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
+ collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
+ labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
+ g_assert_cmpstr (labels[3], ==, "C");
+ e_collator_unref (collator);
+
+ /* Set the cursor at the start of family names beginning with 'C' */
+ e_book_cache_cursor_set_target_alphabetic_index (
+ ((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, 3);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* Position is 7, there are 7 contacts leading up to the last 'C' in en_US locale
+ * (when sorting in descending order) */
+ g_assert_cmpint (position, ==, 7);
+ g_assert_cmpint (total, ==, 20);
+}
+
+static void
+test_cursor_calculate_descending_after_modification (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ gint position = 0, total = 0;
+
+ /* Set the cursor to point exactly 'Bät' (which is the 12th contact in descending order) */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 12, NULL, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* 'Bät' is at position 12 in en_US locale (descending order) */
+ g_assert_cmpint (position, ==, 12);
+ g_assert_cmpint (total, ==, 20);
+
+ /* Rename Muffler -> Jacob Appelbaum */
+ e_contact_set (fixture->contacts[19 - 1], E_CONTACT_FAMILY_NAME, "Appelbaum");
+ e_contact_set (fixture->contacts[19 - 1], E_CONTACT_GIVEN_NAME, "Jacob");
+ if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
+ fixture->contacts[19 - 1],
+ e_contact_get_const (fixture->contacts[19 - 1], E_CONTACT_UID),
+ FALSE, NULL, &error))
+ g_error ("Failed to modify contact: %s", error->message);
+
+ /* Rename Müller -> Sade Adu */
+ e_contact_set (fixture->contacts[20 - 1], E_CONTACT_FAMILY_NAME, "Adu");
+ e_contact_set (fixture->contacts[20 - 1], E_CONTACT_GIVEN_NAME, "Sade");
+ if (!e_book_cache_put_contact (((TCUFixture *) fixture)->book_cache,
+ fixture->contacts[20 - 1],
+ e_contact_get_const (fixture->contacts[20 - 1], E_CONTACT_UID),
+ FALSE, NULL, &error))
+ g_error ("Failed to modify contact: %s", error->message);
+
+ /* Check new position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* 'Bät' is now at position 10 in descending order after moving 2 contacts to begin with 'A' */
+ g_assert_cmpint (position, ==, 10);
+ g_assert_cmpint (total, ==, 20);
+}
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Initial", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_initial,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/MoveForward", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_move_forward,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/MoveBackwards", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_move_backwards,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/BackAndForth", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_back_and_forth,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/AlphabeticTarget", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_partial_target,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/AfterModification", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_after_modification,
+ tcu_cursor_fixture_teardown);
+
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Filtered/Initial", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_filtered_setup,
+ test_cursor_calculate_filtered_initial,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Filtered/MoveForward", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_filtered_setup,
+ test_cursor_calculate_filtered_move_forward,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Filtered/MoveBackwards", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_filtered_setup,
+ test_cursor_calculate_filtered_move_backwards,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Filtered/AlphabeticTarget", TCUCursorFixture, &ascending_closure,
+ tcu_cursor_fixture_filtered_setup,
+ test_cursor_calculate_filtered_partial_target,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Filtered/AfterModification", TCUCursorFixture,
&ascending_closure,
+ tcu_cursor_fixture_filtered_setup,
+ test_cursor_calculate_filtered_after_modification,
+ tcu_cursor_fixture_teardown);
+
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Descending/Initial", TCUCursorFixture, &descending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_initial,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Descending/MoveForward", TCUCursorFixture, &descending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_descending_move_forward,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Descending/MoveBackwards", TCUCursorFixture, &descending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_descending_move_backwards,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Descending/BackAndForth", TCUCursorFixture, &descending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_back_and_forth,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Descending/AlphabeticTarget", TCUCursorFixture,
&descending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_descending_partial_target,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/Calculate/Descending/AfterModification", TCUCursorFixture,
&descending_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_calculate_descending_after_modification,
+ tcu_cursor_fixture_teardown);
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-change-locale.c
b/tests/libedata-book/test-cache-cursor-change-locale.c
new file mode 100644
index 0000000..2445652
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-change-locale.c
@@ -0,0 +1,102 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+struct {
+ gboolean empty_book;
+ const gchar *path;
+} params[] = {
+ { FALSE, "/EBookCacheCursor/DefaultSummary" },
+ { TRUE, "/EBookCacheCursor/EmptySummary" }
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ TCUStepData *data;
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ for (ii = 0; ii < G_N_ELEMENTS (params); ii++) {
+
+ data = tcu_step_test_new (
+ params[ii].path, "/ChangeLocale/POSIX/en_US", "POSIX",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 2, 6, 3, 8);
+ tcu_step_test_add_assertion (data, 5, 1, 5, 4, 7, 15);
+ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);
+ tcu_step_test_add_assertion (data, 5, 12, 13, 9, 19, 20);
+
+ tcu_step_test_change_locale (data, "en_US.UTF-8", 0);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 5, 4, 3, 7, 8, 15);
+ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);
+ tcu_step_test_add_assertion (data, 5, 12, 13, 9, 19, 20);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/ChangeLocale/en_US/fr_CA", "en_US.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 5, 4, 3, 7, 8, 15);
+ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);
+ tcu_step_test_add_assertion (data, 5, 12, 13, 9, 19, 20);
+
+ tcu_step_test_change_locale (data, "fr_CA.UTF-8", 0);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 5, 4, 3, 7, 8, 15);
+ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);
+ tcu_step_test_add_assertion (data, 5, 13, 12, 9, 19, 20);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/ChangeLocale/fr_CA/de_DE", "fr_CA.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 5, 4, 3, 7, 8, 15);
+ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);
+ tcu_step_test_add_assertion (data, 5, 13, 12, 9, 19, 20);
+
+ /* When changing from fr_CA to de_DE, two numbers change:
+ *
+ * sorted-5:
+ * 049-2459-4393 is now parsed with the national number as 4924594393
+ *
+ * sorted-4:
+ * 12 245999 is now parsed with national number 12245999 instead of 2245999
+ *
+ */
+ tcu_step_test_change_locale (data, "de_DE.UTF-8", 2);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 5, 7, 8, 4, 3, 15);
+ tcu_step_test_add_assertion (data, 5, 17, 16, 18, 10, 14);
+ tcu_step_test_add_assertion (data, 5, 12, 13, 9, 20, 19);
+ tcu_step_test_add (data, FALSE);
+ }
+
+ /* On this case, we want to delete the work directory and start fresh */
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-move-by-de-DE.c
b/tests/libedata-book/test-cache-cursor-move-by-de-DE.c
new file mode 100644
index 0000000..b4bfb2c
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-move-by-de-DE.c
@@ -0,0 +1,82 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+struct {
+ gboolean empty_book;
+ const gchar *path;
+} params[] = {
+ { FALSE, "/EBookCacheCursor/DefaultSummary" },
+ { TRUE, "/EBookCacheCursor/EmptySummary" }
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ TCUStepData *data;
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ for (ii = 0; ii < G_N_ELEMENTS (params); ii++) {
+
+ data = tcu_step_test_new (
+ params[ii].path, "/de_DE/Move/Forward", "de_DE.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 6, 7, 8, 4, 3, 15, 17);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/de_DE/Move/ForwardOnNameless", "de_DE.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 1, 11);
+ tcu_step_test_add_assertion (data, 3, 1, 2, 5);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/de_DE/Move/Backwards", "de_DE.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 19, 20, 9, 13, 12);
+ tcu_step_test_add_assertion (data, -8, 14, 10, 18, 16, 17, 15, 3, 4);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/de_DE/Filtered/Move/Forward", "de_DE.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 8);
+ tcu_step_test_add_assertion (data, 8, 3, 17, 16, 18, 10, 14, 12, 9);
+ tcu_step_test_add (data, TRUE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/de_DE/Filtered/Move/Backwards", "de_DE.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 9, 12, 14, 10, 18);
+ tcu_step_test_add_assertion (data, -8, 16, 17, 3, 8, 5, 2, 1, 11);
+ tcu_step_test_add (data, TRUE);
+ }
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-move-by-en-US.c
b/tests/libedata-book/test-cache-cursor-move-by-en-US.c
new file mode 100644
index 0000000..6f969e7
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-move-by-en-US.c
@@ -0,0 +1,100 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+struct {
+ gboolean empty_book;
+ const gchar *path;
+} params[] = {
+ { FALSE, "/EBookCacheCursor/DefaultSummary" },
+ { TRUE, "/EBookCacheCursor/EmptySummary" }
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ TCUStepData *data;
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ for (ii = 0; ii < G_N_ELEMENTS (params); ii++) {
+
+ data = tcu_step_test_new (
+ params[ii].path, "/en_US/Move/Forward", "en_US.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 6, 4, 3, 7, 8, 15, 17);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/en_US/Move/ForwardOnNameless", "en_US.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 1, 11);
+ tcu_step_test_add_assertion (data, 3, 1, 2, 5);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/en_US/Move/Backwards", "en_US.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 20, 19, 9, 13, 12);
+ tcu_step_test_add_assertion (data, -8, 14, 10, 18, 16, 17, 15, 8, 7);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/en_US/Filtered/Move/Forward", "en_US.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 3);
+ tcu_step_test_add_assertion (data, 8, 8, 17, 16, 18, 10, 14, 12, 9);
+ tcu_step_test_add (data, TRUE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/en_US/Filtered/Move/Backwards", "en_US.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 9, 12, 14, 10, 18);
+ tcu_step_test_add_assertion (data, -8, 16, 17, 8, 3, 5, 2, 1, 11);
+ tcu_step_test_add (data, TRUE);
+
+ data = tcu_step_test_new_full (
+ params[ii].path, "/en_US/Move/Descending/Forward", "en_US.UTF-8",
+ params[ii].empty_book,
+ E_BOOK_CURSOR_SORT_DESCENDING);
+ tcu_step_test_add_assertion (data, 5, 20, 19, 9, 13, 12);
+ tcu_step_test_add_assertion (data, 5, 14, 10, 18, 16, 17);
+ tcu_step_test_add_assertion (data, 5, 15, 8, 7, 3, 4);
+ tcu_step_test_add_assertion (data, 5, 6, 5, 2, 1, 11);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new_full (
+ params[ii].path, "/en_US/Move/Descending/Backwards", "en_US.UTF-8",
+ params[ii].empty_book,
+ E_BOOK_CURSOR_SORT_DESCENDING);
+ tcu_step_test_add_assertion (data, -10, 11, 1, 2, 5, 6, 4, 3, 7, 8, 15);
+ tcu_step_test_add_assertion (data, -10, 17, 16, 18, 10, 14, 12, 13, 9, 19, 20);
+ tcu_step_test_add (data, FALSE);
+ }
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-move-by-fr-CA.c
b/tests/libedata-book/test-cache-cursor-move-by-fr-CA.c
new file mode 100644
index 0000000..7bfb435
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-move-by-fr-CA.c
@@ -0,0 +1,82 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+struct {
+ gboolean empty_book;
+ const gchar *path;
+} params[] = {
+ { FALSE, "/EBookCacheCursor/DefaultSummary" },
+ { TRUE, "/EBookCacheCursor/EmptySummary" }
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ TCUStepData *data;
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ for (ii = 0; ii < G_N_ELEMENTS (params); ii++) {
+
+ data = tcu_step_test_new (
+ params[ii].path, "/fr_CA/Move/Forward", "fr_CA.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 6);
+ tcu_step_test_add_assertion (data, 6, 4, 3, 7, 8, 15, 17);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/fr_CA/Move/ForwardOnNameless", "fr_CA.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 1, 11);
+ tcu_step_test_add_assertion (data, 3, 1, 2, 5);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/fr_CA/Move/Backwards", "fr_CA.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 20, 19, 9, 12, 13);
+ tcu_step_test_add_assertion (data, -8, 14, 10, 18, 16, 17, 15, 8, 7);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/fr_CA/Filtered/Move/Forward", "fr_CA.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 1, 2, 5, 3);
+ tcu_step_test_add_assertion (data, 8, 8, 17, 16, 18, 10, 14, 12, 9);
+ tcu_step_test_add (data, TRUE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/fr_CA/Filtered/Move/Backwards", "fr_CA.UTF-8",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 9, 12, 14, 10, 18);
+ tcu_step_test_add_assertion (data, -8, 16, 17, 8, 3, 5, 2, 1, 11);
+ tcu_step_test_add (data, TRUE);
+ }
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-move-by-posix.c
b/tests/libedata-book/test-cache-cursor-move-by-posix.c
new file mode 100644
index 0000000..93d4e05
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-move-by-posix.c
@@ -0,0 +1,82 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+struct {
+ gboolean empty_book;
+ const gchar *path;
+} params[] = {
+ { FALSE, "/EBookCacheCursor/DefaultSummary" },
+ { TRUE, "/EBookCacheCursor/EmptySummary" }
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ TCUStepData *data;
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ for (ii = 0; ii < G_N_ELEMENTS (params); ii++) {
+
+ data = tcu_step_test_new (
+ params[ii].path, "/POSIX/Move/Forward", "POSIX",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 2, 6, 3, 8);
+ tcu_step_test_add_assertion (data, 6, 1, 5, 4, 7, 15, 17);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/POSIX/Move/ForwardOnNameless", "POSIX",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 1, 11);
+ tcu_step_test_add_assertion (data, 3, 2, 6, 3);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/POSIX/Move/Backwards", "POSIX",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 20, 19, 9, 13, 12);
+ tcu_step_test_add_assertion (data, -12, 14, 10, 18, 16, 17, 15, 7, 4, 5, 1, 8, 3);
+ tcu_step_test_add (data, FALSE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/POSIX/Filtered/Move/Forward", "POSIX",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, 5, 11, 2, 3, 8, 1);
+ tcu_step_test_add_assertion (data, 8, 5, 17, 16, 18, 10, 14, 12, 9);
+ tcu_step_test_add (data, TRUE);
+
+ data = tcu_step_test_new (
+ params[ii].path, "/POSIX/Filtered/Move/Backwards", "POSIX",
+ params[ii].empty_book);
+ tcu_step_test_add_assertion (data, -5, 9, 12, 14, 10, 18);
+ tcu_step_test_add_assertion (data, -8, 16, 17, 5, 1, 8, 3, 2, 11);
+ tcu_step_test_add (data, TRUE);
+ }
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-set-sexp.c
b/tests/libedata-book/test-cache-cursor-set-sexp.c
new file mode 100644
index 0000000..94bc247
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-set-sexp.c
@@ -0,0 +1,151 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+static TCUCursorClosure book_closure = { { NULL }, NULL, E_BOOK_CURSOR_SORT_ASCENDING };
+
+static void
+test_cursor_sexp_calculate_position (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ EBookQuery *query;
+ gint position = 0, total = 0;
+ gchar *sexp = NULL;
+ GSList *results = NULL, *node;
+ EBookCacheSearchData *data;
+
+ /* Set the cursor to point exactly to 'blackbirds', which is the 12th contact in en_US */
+ if (!e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 12, &results, NULL, &error))
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Ensure we moved to the right contact */
+ node = g_slist_last (results);
+ g_assert (node);
+ data = node->data;
+ g_assert_cmpstr (data->uid, ==, "sorted-16");
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+
+ /* Check position */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* blackbird is at position 12 in an unfiltered en_US locale */
+ g_assert_cmpint (position, ==, 12);
+ g_assert_cmpint (total, ==, 20);
+
+ /* Set new sexp, only contacts with .com email addresses */
+ query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_ENDS_WITH, ".com");
+ sexp = e_book_query_to_string (query);
+ e_book_query_unref (query);
+
+ if (!e_book_cache_cursor_set_sexp (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, sexp, &error))
+ g_error ("Failed to set sexp: %s", error->message);
+
+ /* Check new position after modified sexp */
+ if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, &total, &position, NULL, &error))
+ g_error ("Error calculating cursor: %s", error->message);
+
+ /* 'blackbird' is now at position 8 out of 13, with a filtered set of contacts in en_US locale */
+ g_assert_cmpint (position, ==, 8);
+ g_assert_cmpint (total, ==, 13);
+}
+
+static void
+test_cursor_sexp_and_step (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GError *error = NULL;
+ EBookQuery *query;
+ gchar *sexp = NULL;
+ GSList *results = NULL, *node;
+ EBookCacheSearchData *data;
+
+ /* Set new sexp, only contacts with .com email addresses */
+ query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_ENDS_WITH, ".com");
+ sexp = e_book_query_to_string (query);
+ e_book_query_unref (query);
+
+ if (!e_book_cache_cursor_set_sexp (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, sexp, &error))
+ g_error ("Failed to set sexp: %s", error->message);
+
+ /* Step 6 results from the beginning of the filtered list, gets up to contact 'sorted-8' */
+ if (!e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 6, &results, NULL, &error))
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Ensure we moved to the right contact */
+ node = g_slist_last (results);
+ g_assert (node);
+ data = node->data;
+ g_assert_cmpstr (data->uid, ==, "sorted-8");
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Step 6 results more, gets up to contact 'sorted-12' */
+ if (!e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ 6, &results, NULL, &error))
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ /* Ensure we moved to the right contact */
+ node = g_slist_last (results);
+ g_assert (node);
+ data = node->data;
+ g_assert_cmpstr (data->uid, ==, "sorted-12");
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+}
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add (
+ "/EBookCacheCursor/SetSexp/CalculatePosition", TCUCursorFixture, &book_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_sexp_calculate_position,
+ tcu_cursor_fixture_teardown);
+ g_test_add (
+ "/EBookCacheCursor/SetSexp/Step", TCUCursorFixture, &book_closure,
+ tcu_cursor_fixture_setup,
+ test_cursor_sexp_and_step,
+ tcu_cursor_fixture_teardown);
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-cursor-set-target.c
b/tests/libedata-book/test-cache-cursor-set-target.c
new file mode 100644
index 0000000..ade53c5
--- /dev/null
+++ b/tests/libedata-book/test-cache-cursor-set-target.c
@@ -0,0 +1,225 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+/*****************************************************
+ * Expect the same results twice *
+ *****************************************************/
+static void
+test_cursor_set_target_reset_cursor (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+
+ /* First batch */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 5, &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ tcu_print_results (results);
+
+ /* Assert the first 5 contacts in en_US order */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-11",
+ "sorted-1",
+ "sorted-2",
+ "sorted-5",
+ "sorted-6",
+ NULL);
+
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Second batch reset (same results) */
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN,
+ 5, &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ tcu_print_results (results);
+
+ /* Assert the first 5 contacts in en_US order again */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-11",
+ "sorted-1",
+ "sorted-2",
+ "sorted-5",
+ "sorted-6",
+ NULL);
+
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+}
+
+/*****************************************************
+ * Expect results with family name starting with 'C' *
+ *****************************************************/
+static void
+test_cursor_set_target_c_next_results (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ ECollator *collator;
+ gint n_labels;
+ const gchar *const *labels;
+
+ /* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
+ collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
+ labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
+ g_assert_cmpstr (labels[3], ==, "C");
+ e_collator_unref (collator);
+
+ /* Set the cursor at the start of family names beginning with 'C' */
+ e_book_cache_cursor_set_target_alphabetic_index (
+ ((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, 3);
+
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ 5, &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ tcu_print_results (results);
+
+ /* Assert that we got the results starting at C */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-10",
+ "sorted-14",
+ "sorted-12",
+ "sorted-13",
+ "sorted-9",
+ NULL);
+
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+}
+
+/*****************************************************
+ * Expect results before the letter 'C' *
+ *****************************************************/
+static void
+test_cursor_set_target_c_prev_results (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ GSList *results = NULL;
+ GError *error = NULL;
+ ECollator *collator;
+ gint n_labels;
+ const gchar *const *labels;
+
+ /* First verify our test... in en_US locale the label 'C' should exist with the index 3 */
+ collator = e_book_cache_ref_collator (((TCUFixture *) fixture)->book_cache);
+ labels = e_collator_get_index_labels (collator, &n_labels, NULL, NULL, NULL);
+ g_assert_cmpstr (labels[3], ==, "C");
+ e_collator_unref (collator);
+
+ /* Set the cursor at the start of family names beginning with 'C' */
+ e_book_cache_cursor_set_target_alphabetic_index (
+ ((TCUFixture *) fixture)->book_cache,
+ fixture->cursor, 3);
+
+ if (e_book_cache_cursor_step (((TCUFixture *) fixture)->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE | E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT,
+ -5, &results, NULL, &error) < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ tcu_print_results (results);
+
+ /* Assert that we got the results before C */
+ g_assert_cmpint (g_slist_length (results), ==, 5);
+ tcu_assert_contacts_order (
+ results,
+ "sorted-18",
+ "sorted-16",
+ "sorted-17",
+ "sorted-15",
+ "sorted-8",
+ NULL);
+
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+}
+
+static TCUCursorClosure closures[] = {
+ { { NULL }, NULL, E_BOOK_CURSOR_SORT_ASCENDING },
+ { { tcu_setup_empty_book }, NULL, E_BOOK_CURSOR_SORT_ASCENDING }
+};
+
+static const gchar *prefixes[] = {
+ "/EBookCache/DefaultSummary",
+ "/EBookCache/EmptySummary"
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ for (ii = 0; ii < G_N_ELEMENTS (closures); ii++) {
+ gchar *path;
+
+ path = g_strconcat (prefixes[ii], "/SetTarget/ResetCursor", NULL);
+ g_test_add (
+ path, TCUCursorFixture, &closures[ii],
+ tcu_cursor_fixture_setup,
+ test_cursor_set_target_reset_cursor,
+ tcu_cursor_fixture_teardown);
+ g_free (path);
+
+ path = g_strconcat (prefixes[ii], "/SetTarget/Alphabetic/C/NextResults", NULL);
+ g_test_add (
+ path, TCUCursorFixture, &closures[ii],
+ tcu_cursor_fixture_setup,
+ test_cursor_set_target_c_next_results,
+ tcu_cursor_fixture_teardown);
+ g_free (path);
+
+ path = g_strconcat (prefixes[ii], "/SetTarget/Alphabetic/C/PreviousResults", NULL);
+ g_test_add (
+ path, TCUCursorFixture, &closures[ii],
+ tcu_cursor_fixture_setup,
+ test_cursor_set_target_c_prev_results,
+ tcu_cursor_fixture_teardown);
+ g_free (path);
+ }
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-get-contact.c b/tests/libedata-book/test-cache-get-contact.c
new file mode 100644
index 0000000..d48faed
--- /dev/null
+++ b/tests/libedata-book/test-cache-get-contact.c
@@ -0,0 +1,78 @@
+/* -*- 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 <locale.h>
+#include <libebook/libebook.h>
+
+#include "test-cache-utils.h"
+
+static void
+test_get_contact (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ EContact *contact = NULL;
+ EContact *other = NULL;
+ GError *error = NULL;
+
+ tcu_add_contact_from_test_case (fixture, "simple-1", &contact);
+
+ if (!e_book_cache_get_contact (fixture->book_cache,
+ (const gchar *) e_contact_get_const (contact, E_CONTACT_UID),
+ FALSE, &other, NULL, &error)) {
+ g_error (
+ "Failed to get contact with uid '%s': %s",
+ (const gchar *) e_contact_get_const (contact, E_CONTACT_UID),
+ error->message);
+ }
+
+ g_object_unref (contact);
+ g_object_unref (other);
+}
+
+static TCUClosure closures[] = {
+ { NULL },
+ { tcu_setup_empty_book }
+};
+
+static const gchar *paths[] = {
+ "/EBookCache/DefaultSummary/GetContact",
+ "/EBookCache/EmptySummary/GetContact",
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ gint ii;
+
+#if !GLIB_CHECK_VERSION (2, 35, 1)
+ g_type_init ();
+#endif
+ g_test_init (&argc, &argv, NULL);
+
+ /* Ensure that the client and server get the same locale */
+ g_assert (g_setenv ("LC_ALL", "en_US.UTF-8", TRUE));
+ setlocale (LC_ALL, "");
+
+ for (ii = 0; ii < G_N_ELEMENTS (closures); ii++) {
+ g_test_add (
+ paths[ii], TCUFixture, &closures[ii],
+ tcu_fixture_setup, test_get_contact, tcu_fixture_teardown);
+ }
+
+ return g_test_run ();
+}
diff --git a/tests/libedata-book/test-cache-utils.c b/tests/libedata-book/test-cache-utils.c
new file mode 100644
index 0000000..70a74d4
--- /dev/null
+++ b/tests/libedata-book/test-cache-utils.c
@@ -0,0 +1,691 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2013, Openismus GmbH
+ *
+ * This library 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 library 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 library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Tristan Van Berkom <tristanvb openismus com>
+ */
+
+#include "evolution-data-server-config.h"
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "test-cache-utils.h"
+
+gchar *
+tcu_new_vcard_from_test_case (const gchar *case_name)
+{
+ gchar *filename;
+ gchar *case_filename;
+ GFile * file;
+ GError *error = NULL;
+ gchar *vcard;
+
+ case_filename = g_strdup_printf ("%s.vcf", case_name);
+
+ /* In the case of installed tests, they run in ${pkglibexecdir}/installed-tests
+ * and the vcards are installed in ${pkglibexecdir}/installed-tests/vcards
+ */
+ if (g_getenv ("TEST_INSTALLED_SERVICES") != NULL)
+ filename = g_build_filename (INSTALLED_TEST_DIR, "vcards", case_filename, NULL);
+ else
+ filename = g_build_filename (SRCDIR, "..", "libebook", "data", "vcards", case_filename, NULL);
+
+ file = g_file_new_for_path (filename);
+ if (!g_file_load_contents (file, NULL, &vcard, NULL, NULL, &error))
+ g_error (
+ "failed to read test contact file '%s': %s",
+ filename, error->message);
+
+ g_free (case_filename);
+ g_free (filename);
+ g_object_unref (file);
+
+ return vcard;
+}
+
+EContact *
+tcu_new_contact_from_test_case (const gchar *case_name)
+{
+ gchar *vcard;
+ EContact *contact = NULL;
+
+ vcard = tcu_new_vcard_from_test_case (case_name);
+ if (vcard)
+ contact = e_contact_new_from_vcard (vcard);
+ g_free (vcard);
+
+ if (!contact)
+ g_error (
+ "failed to construct contact from test case '%s'",
+ case_name);
+
+ return contact;
+}
+
+void
+tcu_add_contact_from_test_case (TCUFixture *fixture,
+ const gchar *case_name,
+ EContact **ret_contact)
+{
+ EContact *contact;
+ GError *error = NULL;
+
+ contact = tcu_new_contact_from_test_case (case_name);
+
+ if (!e_book_cache_put_contact (fixture->book_cache, contact, case_name, FALSE, NULL, &error))
+ g_error ("Failed to add contact: %s", error->message);
+
+ if (ret_contact)
+ *ret_contact = g_object_ref (contact);
+}
+
+static void
+delete_work_directory (const gchar *filename)
+{
+ /* XXX Instead of complex error checking here, we should ideally use
+ * a recursive GDir / g_unlink() function.
+ *
+ * We cannot use GFile and the recursive delete function without
+ * corrupting our contained D-Bus environment with service files
+ * from the OS.
+ */
+ const gchar *argv[] = { "/bin/rm", "-rf", filename, NULL };
+ gboolean spawn_succeeded;
+ gint exit_status;
+
+ spawn_succeeded = g_spawn_sync (
+ NULL, (gchar **) argv, NULL, 0, NULL, NULL,
+ NULL, NULL, &exit_status, NULL);
+
+ g_assert (spawn_succeeded);
+ #ifndef G_OS_WIN32
+ g_assert (WIFEXITED (exit_status));
+ g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
+ #else
+ g_assert_cmpint (exit_status, ==, 0);
+ #endif
+}
+
+ESourceBackendSummarySetup *
+tcu_setup_empty_book (void)
+{
+ ESourceBackendSummarySetup *setup;
+ ESource *scratch;
+ GError *error = NULL;
+
+ scratch = e_source_new_with_uid ("test-source", NULL, &error);
+ if (!scratch)
+ g_error ("Error creating scratch source: %s", error ? error->message : "Unknown error");
+
+ /* This is a bit of a cheat */
+ setup = g_object_new (E_TYPE_SOURCE_BACKEND_SUMMARY_SETUP, "source", scratch, NULL);
+ e_source_backend_summary_setup_set_summary_fields (
+ setup,
+ /* We don't use this field in our tests anyway */
+ E_CONTACT_FILE_AS,
+ 0);
+
+ g_object_unref (scratch);
+
+ return setup;
+}
+
+static void
+e164_changed_cb (EBookCache *book_cache,
+ EContact *contact,
+ gboolean is_replace,
+ gpointer user_data)
+{
+ TCUFixture *fixture = user_data;
+
+ if (is_replace)
+ fixture->n_locale_changes++;
+ else
+ fixture->n_add_changes++;
+}
+
+void
+tcu_fixture_setup (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ TCUClosure *closure = (TCUClosure *) user_data;
+ ESourceBackendSummarySetup *setup = NULL;
+ gchar *filename, *directory;
+ GError *error = NULL;
+
+ if (!g_file_test (CAMEL_PROVIDERDIR, G_FILE_TEST_IS_DIR | G_FILE_TEST_EXISTS)) {
+ if (g_mkdir_with_parents (CAMEL_PROVIDERDIR, 0700) == -1)
+ g_warning ("%s: Failed to create folder '%s': %s\n", G_STRFUNC, CAMEL_PROVIDERDIR,
g_strerror (errno));
+ }
+
+ /* Cleanup from last test */
+ directory = g_build_filename (g_get_tmp_dir (), "test-book-cache", NULL);
+ delete_work_directory (directory);
+ g_free (directory);
+ filename = g_build_filename (g_get_tmp_dir (), "test-book-cache", "cache.db", NULL);
+
+ if (closure->setup_summary)
+ setup = closure->setup_summary ();
+
+ fixture->book_cache = e_book_cache_new_full (filename, NULL, setup, NULL, &error);
+
+ g_clear_object (&setup);
+
+ if (!fixture->book_cache)
+ g_error ("Failed to create the EBookCache: %s", error->message);
+
+ g_free (filename);
+
+ g_signal_connect (fixture->book_cache, "e164-changed",
+ G_CALLBACK (e164_changed_cb), fixture);
+}
+
+void
+tcu_fixture_teardown (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ g_object_unref (fixture->book_cache);
+}
+
+void
+tcu_cursor_fixture_setup (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ TCUFixture *base_fixture = (TCUFixture *) fixture;
+ TCUCursorClosure *data = (TCUCursorClosure *) user_data;
+ EContactField sort_fields[] = { E_CONTACT_FAMILY_NAME, E_CONTACT_GIVEN_NAME };
+ EBookCursorSortType sort_types[] = { data->sort_type, data->sort_type };
+ GSList *contacts = NULL;
+ GSList *extra_list = NULL;
+ GError *error = NULL;
+ gint ii;
+ gchar *sexp = NULL;
+
+ tcu_fixture_setup (base_fixture, user_data);
+
+ if (data->locale)
+ tcu_cursor_fixture_set_locale (fixture, data->locale);
+ else
+ tcu_cursor_fixture_set_locale (fixture, "en_US.UTF-8");
+
+ for (ii = 0; ii < N_SORTED_CONTACTS; ii++) {
+ gchar *case_name = g_strdup_printf ("sorted-%d", ii + 1);
+ gchar *vcard;
+ EContact *contact;
+
+ vcard = tcu_new_vcard_from_test_case (case_name);
+ contact = e_contact_new_from_vcard (vcard);
+ contacts = g_slist_prepend (contacts, contact);
+ extra_list = g_slist_prepend (extra_list, case_name);
+
+ g_free (vcard);
+
+ fixture->contacts[ii] = g_object_ref (contact);
+ }
+
+ if (!e_book_cache_put_contacts (base_fixture->book_cache, contacts, extra_list, FALSE, NULL, &error))
{
+ /* Dont complain here, we re-use the same addressbook for multiple tests
+ * and we can't add the same contacts twice
+ */
+ if (g_error_matches (error, E_CACHE_ERROR, E_CACHE_ERROR_CONSTRAINT))
+ g_clear_error (&error);
+ else
+ g_error ("Failed to add test contacts: %s", error->message);
+ }
+
+ g_slist_free_full (contacts, g_object_unref);
+ g_slist_free_full (extra_list, g_free);
+
+ /* Allow a surrounding fixture setup to add a query here */
+ if (fixture->query) {
+ sexp = e_book_query_to_string (fixture->query);
+ e_book_query_unref (fixture->query);
+ fixture->query = NULL;
+ }
+
+ fixture->cursor = e_book_cache_cursor_new (
+ base_fixture->book_cache, sexp,
+ sort_fields, sort_types, 2, &error);
+
+ if (!fixture->cursor)
+ g_error ("Failed to create cursor: %s\n", error->message);
+
+ g_free (sexp);
+}
+
+void
+tcu_cursor_fixture_filtered_setup (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ fixture->query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_ENDS_WITH, ".com");
+
+ tcu_cursor_fixture_setup (fixture, user_data);
+}
+
+void
+tcu_cursor_fixture_teardown (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ TCUFixture *base_fixture = (TCUFixture *) fixture;
+ gint ii;
+
+ for (ii = 0; ii < N_SORTED_CONTACTS; ii++) {
+ if (fixture->contacts[ii])
+ g_object_unref (fixture->contacts[ii]);
+ }
+
+ e_book_cache_cursor_free (base_fixture->book_cache, fixture->cursor);
+ tcu_fixture_teardown (base_fixture, user_data);
+}
+
+void
+tcu_cursor_fixture_set_locale (TCUCursorFixture *fixture,
+ const gchar *locale)
+{
+ TCUFixture *base_fixture = (TCUFixture *) fixture;
+ GError *error = NULL;
+
+ if (!e_book_cache_set_locale (base_fixture->book_cache, locale, NULL, &error))
+ g_error ("Failed to set locale: %s", error->message);
+}
+
+static gint
+find_contact_data (EBookCacheSearchData *data,
+ const gchar *uid)
+{
+ return g_strcmp0 (data->uid, uid);
+}
+
+void
+tcu_assert_contacts_order_slist (GSList *results,
+ GSList *uids)
+{
+ gint position = -1;
+ GSList *link, *l;
+
+ /* Assert that all passed UIDs are found in the
+ * results, and that those UIDs are in the
+ * specified order.
+ */
+ for (l = uids; l; l = l->next) {
+ const gchar *uid = l->data;
+ gint new_position;
+
+ link = g_slist_find_custom (results, uid, (GCompareFunc) find_contact_data);
+ if (!link)
+ g_error ("Specified uid '%s' was not found in results", uid);
+
+ new_position = g_slist_position (results, link);
+ g_assert_cmpint (new_position, >, position);
+ position = new_position;
+ }
+}
+
+void
+tcu_assert_contacts_order (GSList *results,
+ const gchar *first_uid,
+ ...)
+{
+ GSList *uids = NULL;
+ gchar *uid;
+ va_list args;
+
+ g_assert (first_uid);
+
+ uids = g_slist_append (uids, (gpointer) first_uid);
+
+ va_start (args, first_uid);
+ uid = va_arg (args, gchar *);
+ while (uid) {
+ uids = g_slist_append (uids, uid);
+ uid = va_arg (args, gchar *);
+ }
+ va_end (args);
+
+ tcu_assert_contacts_order_slist (results, uids);
+ g_slist_free (uids);
+}
+
+void
+tcu_print_results (const GSList *results)
+{
+ const GSList *link;
+
+ if (g_getenv ("TEST_DEBUG") == NULL)
+ return;
+
+ g_print ("\nPRINTING RESULTS:\n");
+
+ for (link = results; link; link = link->next) {
+ EBookCacheSearchData *data = link->data;
+
+ g_print ("\n%s\n", data->vcard);
+ }
+
+ g_print ("\nRESULT LIST_FINISHED\n");
+}
+
+/********************************************
+ * Move By Test Helpers
+ ********************************************/
+#define DEBUG_FIXTURE 0
+
+static TCUStepData *
+step_test_new_internal (const gchar *test_path,
+ const gchar *locale,
+ gboolean empty_book)
+{
+ TCUStepData *data;
+
+ data = g_slice_new0 (TCUStepData);
+
+ data->parent.locale = g_strdup (locale);
+ data->parent.sort_type = E_BOOK_CURSOR_SORT_ASCENDING;
+
+ if (empty_book)
+ data->parent.parent.setup_summary = tcu_setup_empty_book;
+
+ data->path = g_strdup (test_path);
+
+ return data;
+}
+
+static void
+step_test_free (TCUStepData *data)
+{
+ GList *l;
+
+ g_free (data->path);
+ g_free ((gchar *) data->parent.locale);
+
+ for (l = data->assertions; l; l = l->next) {
+ TCUStepAssertion *assertion = l->data;
+
+ g_free (assertion->locale);
+ g_slice_free (TCUStepAssertion, assertion);
+ }
+
+ g_slice_free (TCUStepData, data);
+}
+
+TCUStepData *
+tcu_step_test_new (const gchar *test_prefix,
+ const gchar *test_path,
+ const gchar *locale,
+ gboolean empty_book)
+{
+ TCUStepData *data;
+ gchar *path;
+
+ path = g_strconcat (test_prefix, test_path, NULL);
+ data = step_test_new_internal (path, locale, empty_book);
+ g_free (path);
+
+ return data;
+}
+
+TCUStepData *
+tcu_step_test_new_full (const gchar *test_prefix,
+ const gchar *test_path,
+ const gchar *locale,
+ gboolean empty_book,
+ EBookCursorSortType sort_type)
+{
+ TCUStepData *data;
+ gchar *path;
+
+ path = g_strconcat (test_prefix, test_path, NULL);
+ data = step_test_new_internal (path, locale, empty_book);
+ data->parent.sort_type = sort_type;
+ g_free (path);
+
+ return data;
+}
+
+static void
+test_cursor_move_teardown (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ TCUStepData *data = (TCUStepData *) user_data;
+
+ tcu_cursor_fixture_teardown (fixture, user_data);
+ step_test_free (data);
+}
+
+static void
+assert_step (TCUCursorFixture *fixture,
+ TCUStepData *data,
+ TCUStepAssertion *assertion,
+ GSList *results,
+ gint n_results,
+ gboolean expect_results)
+{
+ GSList *uids = NULL;
+ gint ii, expected = 0;
+
+ /* Count the number of really expected results */
+ for (ii = 0; ii < ABS (assertion->count); ii++) {
+ gint index = assertion->expected[ii];
+
+ if (index < 0)
+ break;
+
+ expected++;
+ }
+
+ g_assert_cmpint (n_results, ==, expected);
+ if (!expect_results) {
+ g_assert_cmpint (g_slist_length (results), ==, 0);
+ return;
+ }
+
+ /* Assert the exact amount of requested results */
+ g_assert_cmpint (g_slist_length (results), ==, expected);
+
+#if DEBUG_FIXTURE
+ g_print (
+ "%s: Constructing expected result list for a fetch of %d: ",
+ data->path, assertion->count);
+#endif
+ for (ii = 0; ii < ABS (assertion->count); ii++) {
+ gint index = assertion->expected[ii];
+ gchar *uid;
+
+ if (index < 0)
+ break;
+
+ uid = (gchar *) e_contact_get_const (fixture->contacts[index], E_CONTACT_UID);
+ uids = g_slist_append (uids, uid);
+
+#if DEBUG_FIXTURE
+ g_print ("%s ", uid);
+#endif
+
+ }
+#if DEBUG_FIXTURE
+ g_print ("\n");
+#endif
+
+ tcu_assert_contacts_order_slist (results, uids);
+ g_slist_free (uids);
+}
+
+static void
+test_step (TCUCursorFixture *fixture,
+ gconstpointer user_data)
+{
+ TCUFixture *base_fixture = (TCUFixture *) fixture;
+ TCUStepData *data = (TCUStepData *) user_data;
+ GSList *results = NULL;
+ GError *error = NULL;
+ gint n_results;
+ EBookCacheCursorOrigin origin;
+ GList *l;
+ gboolean reset = TRUE;
+
+ for (l = data->assertions; l; l = l->next) {
+ TCUStepAssertion *assertion = l->data;
+
+ if (assertion->locale) {
+ gint n_locale_changes = base_fixture->n_locale_changes;
+
+ if (!e_book_cache_set_locale (base_fixture->book_cache, assertion->locale, NULL,
&error))
+ g_error ("Failed to set locale: %s", error->message);
+
+ n_locale_changes = (base_fixture->n_locale_changes - n_locale_changes);
+
+ /* Only check for contact changes is phone numbers are supported,
+ * contact changes only happen because of e164 number interpretations.
+ */
+ if (e_phone_number_is_supported () &&
+ assertion->count != n_locale_changes)
+ g_error ("Expected %d e164 numbers to change, %d actually changed.",
+ assertion->count, n_locale_changes);
+
+ reset = TRUE;
+ continue;
+ }
+
+ /* For the first call to e_book_cache_cursor_step(),
+ * or the first reset after locale change, set the origin accordingly.
+ */
+ if (reset) {
+ if (assertion->count < 0)
+ origin = E_BOOK_CACHE_CURSOR_ORIGIN_END;
+ else
+ origin = E_BOOK_CACHE_CURSOR_ORIGIN_BEGIN;
+
+ reset = FALSE;
+ } else {
+ origin = E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT;
+ }
+
+ /* Try only fetching the contacts but not moving the cursor */
+ n_results = e_book_cache_cursor_step (
+ base_fixture->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_FETCH,
+ origin,
+ assertion->count,
+ &results,
+ NULL, &error);
+ if (n_results < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ tcu_print_results (results);
+ assert_step (fixture, data, assertion, results, n_results, TRUE);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+
+ /* Do it again, this time only moving the cursor */
+ n_results = e_book_cache_cursor_step (
+ base_fixture->book_cache,
+ fixture->cursor,
+ E_BOOK_CACHE_CURSOR_STEP_MOVE,
+ origin,
+ assertion->count,
+ &results,
+ NULL, &error);
+ if (n_results < 0)
+ g_error ("Error fetching cursor results: %s", error->message);
+
+ tcu_print_results (results);
+ assert_step (fixture, data, assertion, results, n_results, FALSE);
+ g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ results = NULL;
+ }
+}
+
+static void
+step_test_add_assertion_va_list (TCUStepData *data,
+ gint count,
+ va_list args)
+{
+ TCUStepAssertion *assertion = g_slice_new0 (TCUStepAssertion);
+ gint expected, ii = 0;
+
+ assertion->count = count;
+
+#if DEBUG_FIXTURE
+ g_print ("Adding assertion to test %d: %s\n", ii + 1, data->path);
+ g_print (" Test will move by %d and expect: ", count);
+#endif
+ for (ii = 0; ii < ABS (count); ii++) {
+ expected = va_arg (args, gint);
+
+#if DEBUG_FIXTURE
+ g_print ("%d ", expected);
+#endif
+ assertion->expected[ii] = expected - 1;
+ }
+#if DEBUG_FIXTURE
+ g_print ("\n");
+#endif
+
+ data->assertions = g_list_append (data->assertions, assertion);
+}
+
+/* A positive of negative 'count' value
+ * followed by ABS (count) UID indexes.
+ *
+ * The indexes start at 1 so that they
+ * are easier to match up with the chart
+ * in data-test-utils.h
+ */
+void
+tcu_step_test_add_assertion (TCUStepData *data,
+ gint count,
+ ...)
+{
+ va_list args;
+
+ va_start (args, count);
+ step_test_add_assertion_va_list (data, count, args);
+ va_end (args);
+}
+
+void
+tcu_step_test_change_locale (TCUStepData *data,
+ const gchar *locale,
+ gint expected_changes)
+{
+ TCUStepAssertion *assertion = g_slice_new0 (TCUStepAssertion);
+
+ assertion->locale = g_strdup (locale);
+ assertion->count = expected_changes;
+ data->assertions = g_list_append (data->assertions, assertion);
+}
+
+void
+tcu_step_test_add (TCUStepData *data,
+ gboolean filtered)
+{
+ data->filtered = filtered;
+
+ g_test_add (
+ data->path, TCUCursorFixture, data,
+ filtered ?
+ tcu_cursor_fixture_filtered_setup :
+ tcu_cursor_fixture_setup,
+ test_step,
+ test_cursor_move_teardown);
+}
diff --git a/tests/libedata-book/test-cache-utils.h b/tests/libedata-book/test-cache-utils.h
new file mode 100644
index 0000000..4b379c0
--- /dev/null
+++ b/tests/libedata-book/test-cache-utils.h
@@ -0,0 +1,174 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2013, Openismus GmbH
+ *
+ * This library 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 library 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 library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Tristan Van Berkom <tristanvb openismus com>
+ */
+
+#ifndef TEST_CACHE_UTILS_H
+#define TEST_CACHE_UTILS_H
+
+#include <libedata-book/libedata-book.h>
+
+/* This legend shows the add order, and various sort order of the sorted
+ * vcards. The UIDs of these contacts are formed as 'sorted-1', 'sorted-2' etc
+ * and the numbering of the contacts is according to the 'N' column in the
+ * following legend.
+ *
+ * The Email column indicates whether the contact has a .com email address
+ * (in order to test filtered cursor results) and corresponds to the natural
+ * order in the 'N' column.
+ *
+ * +-----------------------------------------------------------------------------------------------+
+ * | N | Email | Last Name | en_US_POSIX | en_US / de_DE | fr_CA | de_DE |
+ * | | | | | | | (phonebook) |
+ * +-----------------------------------------------------------------------------------------------+
+ * | 1 | Yes | bad | 11 | 11 | 11 | 11 |
+ * | 2 | Yes | Bad | Bad 2 | bad 1 | bad 1 | bad 1 |
+ * | 3 | Yes | Bat | Bäd 6 | Bad 2 | Bad 2 | Bad 2 |
+ * | 4 | No | bat | Bat 3 | bäd 5 | bäd 5 | bäd 5 |
+ * | 5 | Yes | bäd | Bät 8 | Bäd 6 | Bäd 6 | Bäd 6 |
+ * | 6 | No | Bäd | bad 1 | bat 4 | bat 4 | bät 7 |
+ * | 7 | No | bät | bäd 5 | Bat 3 | Bat 3 | Bät 8 |
+ * | 8 | Yes | Bät | bat 4 | bät 7 | bät 7 | bat 4 |
+ * | 9 | Yes | côté | bät 7 | Bät 8 | Bät 8 | Bat 3 |
+ * | 10 | Yes | C | black-bird 15 | black-bird 15 | black-bird 15 | black-bird 15 |
+ * | 11 | Yes | | black-birds 17 | black-birds 17 | black-birds 17 | black-birds 17 |
+ * | 12 | Yes | coté | blackbird 16 | blackbird 16 | blackbird 16 | blackbird 16 |
+ * | 13 | No | côte | blackbirds 18 | blackbirds 18 | blackbirds 18 | blackbirds 18 |
+ * | 14 | Yes | cote | C 10 | C 10 | C 10 | C 10 |
+ * | 15 | No | black-bird | cote 14 | cote 14 | cote 14 | cote 14 |
+ * | 16 | Yes | blackbird | coté 12 | coté 12 | côte 13 | coté 12 |
+ * | 17 | Yes | black-birds | côte 13 | côte 13 | coté 12 | côte 13 |
+ * | 18 | Yes | blackbirds | côté 9 | côté 9 | côté 9 | côté 9 |
+ * | 19 | No | Muffler | Muffler 19 | Muffler 19 | Muffler 19 | Müller 20 |
+ * | 20 | No | Müller | Müller 20 | Müller 20 | Müller 20 | Muffler 19 |
+ * +-----------------------------------------------------------------------------------------------+
+ *
+ * See this ICU demo to check additional sort ordering by ICU in various locales:
+ * http://demo.icu-project.org/icu-bin/locexp?_=en_US&d_=en&x=col
+ */
+
+/* 13 contacts in the test data have an email address ending with ".com" */
+#define N_FILTERED_CONTACTS 13
+#define N_SORTED_CONTACTS 20
+
+typedef ESourceBackendSummarySetup * (* TCUSetupSummaryFunc) (void);
+
+typedef struct {
+ EBookCache *book_cache;
+
+ gint n_add_changes;
+ gint n_locale_changes;
+} TCUFixture;
+
+typedef struct {
+ TCUSetupSummaryFunc setup_summary;
+} TCUClosure;
+
+typedef struct {
+ TCUFixture parent_fixture;
+
+ EBookCacheCursor *cursor;
+ EContact *contacts[N_SORTED_CONTACTS];
+ EBookQuery *query;
+
+ guint own_id;
+} TCUCursorFixture;
+
+typedef struct {
+ TCUClosure parent;
+
+ const gchar *locale;
+ EBookCursorSortType sort_type;
+} TCUCursorClosure;
+
+typedef struct {
+ /* A locale change */
+ gchar *locale;
+
+ /* count argument for move */
+ gint count;
+
+ /* An array of 'ABS (counts[i])' expected contacts */
+ gint expected[N_SORTED_CONTACTS];
+} TCUStepAssertion;
+
+typedef struct {
+ TCUCursorClosure parent;
+ gchar *path;
+
+ GList *assertions;
+
+ /* Whether this is a filtered test */
+ gboolean filtered;
+} TCUStepData;
+
+/* Base fixture */
+void tcu_fixture_setup (TCUFixture *fixture,
+ gconstpointer user_data);
+void tcu_fixture_teardown (TCUFixture *fixture,
+ gconstpointer user_data);
+ESourceBackendSummarySetup *
+ tcu_setup_empty_book (void);
+
+/* Cursor fixture */
+void tcu_cursor_fixture_setup (TCUCursorFixture *fixture,
+ gconstpointer user_data);
+void tcu_cursor_fixture_teardown (TCUCursorFixture *fixture,
+ gconstpointer user_data);
+void tcu_cursor_fixture_set_locale (TCUCursorFixture *fixture,
+ const gchar *locale);
+
+/* Filters contacts with E_CONTACT_EMAIL ending with '.com' */
+void tcu_cursor_fixture_filtered_setup (TCUCursorFixture *fixture,
+ gconstpointer user_data);
+
+gchar * tcu_new_vcard_from_test_case (const gchar *case_name);
+EContact * tcu_new_contact_from_test_case (const gchar *case_name);
+
+void tcu_add_contact_from_test_case (TCUFixture *fixture,
+ const gchar *case_name,
+ EContact **ret_contact);
+void tcu_assert_contacts_order_slist (GSList *results,
+ GSList *uids);
+void tcu_assert_contacts_order (GSList *results,
+ const gchar *first_uid,
+ ...) G_GNUC_NULL_TERMINATED;
+
+void tcu_print_results (const GSList *results);
+
+/* Step test helpers */
+void tcu_step_test_add_assertion (TCUStepData *data,
+ gint count,
+ ...);
+void tcu_step_test_change_locale (TCUStepData *data,
+ const gchar *locale,
+ gint expected_changes);
+
+TCUStepData * tcu_step_test_new (const gchar *test_prefix,
+ const gchar *test_path,
+ const gchar *locale,
+ gboolean empty_book);
+TCUStepData * tcu_step_test_new_full (const gchar *test_prefix,
+ const gchar *test_path,
+ const gchar *locale,
+ gboolean empty_book,
+ EBookCursorSortType sort_type);
+
+void tcu_step_test_add (TCUStepData *data,
+ gboolean filtered);
+
+#endif /* TEST_CACHE_UTILS_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]