[evolution-data-server/wip/offline-cache] Add some basic tests on the offline part of the EBookCache



commit 9409d44e1cfda91ab1de8adf52a07271a1548fa6
Author: Milan Crha <mcrha redhat com>
Date:   Thu Feb 2 17:17:52 2017 +0100

    Add some basic tests on the offline part of the EBookCache

 src/addressbook/libedata-book/e-book-cache.c       |   79 ++-
 src/addressbook/libedata-book/e-book-cache.h       |    2 +-
 src/libebackend/e-cache.c                          |   67 ++--
 src/libebackend/e-cache.h                          |    3 +-
 tests/libedata-book/CMakeLists.txt                 |    1 +
 tests/libedata-book/test-cache-cursor-calculate.c  |   18 +-
 tests/libedata-book/test-cache-cursor-set-sexp.c   |    6 +-
 tests/libedata-book/test-cache-cursor-set-target.c |    8 +-
 tests/libedata-book/test-cache-get-contact.c       |    2 +-
 tests/libedata-book/test-cache-offline.c           |  555 ++++++++++++++++++++
 tests/libedata-book/test-cache-utils.c             |    6 +-
 11 files changed, 672 insertions(+), 75 deletions(-)
---
diff --git a/src/addressbook/libedata-book/e-book-cache.c b/src/addressbook/libedata-book/e-book-cache.c
index f80f6af..5450a6b 100644
--- a/src/addressbook/libedata-book/e-book-cache.c
+++ b/src/addressbook/libedata-book/e-book-cache.c
@@ -201,8 +201,10 @@ e_book_cache_search_data_copy (const EBookCacheSearchData *data)
  * Since: 3.26
  **/
 void
-e_book_cache_search_data_free (EBookCacheSearchData *data)
+e_book_cache_search_data_free (gpointer ptr)
 {
+       EBookCacheSearchData *data = ptr;
+
        if (data) {
                g_free (data->uid);
                g_free (data->vcard);
@@ -3015,6 +3017,7 @@ ebc_generate_select (EBookCache *book_cache,
        case SEARCH_FULL:
                callback = ebc_search_full_contacts_cb;
                g_string_append (string, "summary." E_CACHE_COLUMN_UID ",");
+               g_string_append (string, "summary." E_CACHE_COLUMN_REVISION ",");
                g_string_append (string, "summary." E_CACHE_COLUMN_OBJECT ",");
                g_string_append (string, "summary." EBC_COLUMN_EXTRA " ");
                break;
@@ -3024,7 +3027,8 @@ ebc_generate_select (EBookCache *book_cache,
                break;
        case SEARCH_UID:
                callback = ebc_search_uids_cb;
-               g_string_append (string, "summary." E_CACHE_COLUMN_UID " ");
+               g_string_append (string, "summary." E_CACHE_COLUMN_UID ",");
+               g_string_append (string, "summary." E_CACHE_COLUMN_REVISION " ");
                break;
        case SEARCH_COUNT:
                if (context->aux_mask != 0)
@@ -3149,7 +3153,7 @@ ebc_generate_autocomplete_query (EBookCache *book_cache,
                context->left_join_mask = 0;
 
                callback = ebc_generate_select (book_cache, string, search_type, context, error);
-               g_string_append (string, " WHERE ");
+               e_cache_sqlite_stmt_append_printf (string, " WHERE summary." E_CACHE_COLUMN_STATE "!=%d AND 
(", E_OFFLINE_STATE_LOCALLY_DELETED);
                context->aux_mask = aux_mask;
                context->left_join_mask = left_join_mask;
                if (!callback)
@@ -3158,7 +3162,7 @@ ebc_generate_autocomplete_query (EBookCache *book_cache,
                generate_test_func = field_test_func_table[test->query];
                generate_test_func (book_cache, string, test);
 
-               g_string_append (string, " UNION ");
+               g_string_append (string, ") UNION ");
        }
 
        /* Finally, generate the SELECT for the primary fields. */
@@ -3168,7 +3172,7 @@ ebc_generate_autocomplete_query (EBookCache *book_cache,
        if (!callback)
                return NULL;
 
-       g_string_append (string, " WHERE ");
+       e_cache_sqlite_stmt_append_printf (string, " WHERE summary." E_CACHE_COLUMN_STATE "!=%d AND (", 
E_OFFLINE_STATE_LOCALLY_DELETED);
 
        for (ii = 0; ii < n_elements; ii++) {
                GenerateFieldTest generate_test_func = NULL;
@@ -3191,6 +3195,8 @@ ebc_generate_autocomplete_query (EBookCache *book_cache,
                generate_test_func (book_cache, string, test);
        }
 
+       g_string_append (string, ")");
+
        return callback;
 }
 
@@ -3292,12 +3298,22 @@ ebc_do_search_query (EBookCache *book_cache,
                /* Generate the leading SELECT statement */
                sd.func = ebc_generate_select (book_cache, stmt, search_type, context, error);
 
-               if (sd.func && EBC_STATUS_GEN_CONSTRAINTS (context->status)) {
-                       /*
-                        * Now generate the search expression on the main contacts table
-                        */
-                       g_string_append (stmt, " WHERE ");
-                       ebc_generate_constraints (book_cache, stmt, context->constraints, sexp);
+               if (sd.func) {
+                       e_cache_sqlite_stmt_append_printf (stmt,
+                               " WHERE summary." E_CACHE_COLUMN_STATE "!=%d",
+                               E_OFFLINE_STATE_LOCALLY_DELETED);
+
+                       if (EBC_STATUS_GEN_CONSTRAINTS (context->status)) {
+                               GString *where_clause = g_string_new ("");
+
+                               /*
+                                * Now generate the search expression on the main contacts table
+                                */
+                               ebc_generate_constraints (book_cache, where_clause, context->constraints, 
sexp);
+                               if (where_clause->len)
+                                       e_cache_sqlite_stmt_append_printf (stmt, " AND (%s)", 
where_clause->str);
+                               g_string_free (where_clause, TRUE);
+                       }
                }
        }
 
@@ -3506,7 +3522,7 @@ ebc_cursor_setup_query (EBookCache *book_cache,
                        GError **error)
 {
        PreflightContext context = PREFLIGHT_CONTEXT_INIT;
-       GString *string;
+       GString *string, *where_clause;
 
        /* Preflighting and error checking */
        if (sexp) {
@@ -3536,18 +3552,25 @@ ebc_cursor_setup_query (EBookCache *book_cache,
        ebc_generate_select (book_cache, string, SEARCH_COUNT, &context, NULL);
        cursor->select_count = g_string_free (string, FALSE);
 
+       where_clause = g_string_new ("");
+
+       e_cache_sqlite_stmt_append_printf (where_clause, "summary." E_CACHE_COLUMN_STATE "!=%d",
+               E_OFFLINE_STATE_LOCALLY_DELETED);
+
        if (!sexp || context.status == PREFLIGHT_LIST_ALL) {
-               cursor->query = NULL;
                cursor->sexp = NULL;
        } else {
-               /* Generate the constraints for our queries
-                */
+               cursor->sexp = e_book_backend_sexp_new (sexp);
+
                string = g_string_new (NULL);
                ebc_generate_constraints (book_cache, string, context.constraints, sexp);
-               cursor->query = g_string_free (string, FALSE);
-               cursor->sexp = e_book_backend_sexp_new (sexp);
+               if (string->len)
+                       e_cache_sqlite_stmt_append_printf (where_clause, " AND (%s)", string->str);
+               g_string_free (string, TRUE);
        }
 
+       cursor->query = g_string_free (where_clause, FALSE);
+
        preflight_context_clear (&context);
 
        return TRUE;
@@ -4179,7 +4202,7 @@ e_book_cache_migrate (ECache *cache,
                        e_cache_sqlite_maybe_vacuum (cache, cancellable, NULL);
                }
 
-               g_slist_free_full (old_contacts, (GDestroyNotify) e_book_cache_search_data_free);
+               g_slist_free_full (old_contacts, e_book_cache_search_data_free);
        }
 
        /* Add any version-related changes here */
@@ -4945,6 +4968,11 @@ e_book_cache_set_contact_extra (EBookCache *book_cache,
        g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
        g_return_val_if_fail (uid != NULL, FALSE);
 
+       if (!e_cache_contains (E_CACHE (book_cache), uid, TRUE)) {
+               g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND, _("Object “%s” not found"), uid);
+               return FALSE;
+       }
+
        if (extra) {
                stmt = e_cache_sqlite_stmt_printf (
                        "UPDATE " E_CACHE_TABLE_OBJECTS " SET " EBC_COLUMN_EXTRA "=%Q"
@@ -4992,6 +5020,11 @@ e_book_cache_get_contact_extra (EBookCache *book_cache,
        g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
        g_return_val_if_fail (uid != NULL, FALSE);
 
+       if (!e_cache_contains (E_CACHE (book_cache), uid, TRUE)) {
+               g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND, _("Object “%s” not found"), uid);
+               return FALSE;
+       }
+
        stmt = e_cache_sqlite_stmt_printf (
                "SELECT " EBC_COLUMN_EXTRA " FROM " E_CACHE_TABLE_OBJECTS
                " WHERE " E_CACHE_COLUMN_UID "=%Q",
@@ -5020,7 +5053,7 @@ e_book_cache_get_contact_extra (EBookCache *book_cache,
  * the search should always be quick, when searching for other #EContactFields
  * a fallback will be used.
  *
- * The returned @out_list list should be freed with g_slist_free_full(list, e_book_cache_search_data_free)
+ * The returned @out_list list should be freed with g_slist_free_full (list, e_book_cache_search_data_free)
  * when no longer needed.
  *
  * If @meta_contact is specified, then shallow vCard representations will be
@@ -5041,6 +5074,8 @@ e_book_cache_search (EBookCache *book_cache,
        g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
        g_return_val_if_fail (out_list != NULL, FALSE);
 
+       *out_list = NULL;
+
        return ebc_search_internal (book_cache, sexp,
                meta_contacts ? SEARCH_UID_AND_REV : SEARCH_FULL,
                out_list, cancellable, error);
@@ -5073,6 +5108,8 @@ e_book_cache_search_uids (EBookCache *book_cache,
        g_return_val_if_fail (E_IS_BOOK_CACHE (book_cache), FALSE);
        g_return_val_if_fail (out_list != NULL, FALSE);
 
+       *out_list = NULL;
+
        return ebc_search_internal (book_cache, sexp, SEARCH_UID, out_list, cancellable, error);
 }
 
@@ -5282,7 +5319,7 @@ ebc_collect_results_for_cursor_cb (ECache *cache,
  * a %NULL #GSList pointer should be provided for the @out_results parameter.
  *
  * The result list will be stored to @out_results and should be freed
- * with g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+ * with g_slist_free_full (results, e_book_cache_search_data_free);
  * when no longer needed.
  *
  * Returns: The number of contacts traversed if successful, otherwise -1 is
@@ -5466,7 +5503,7 @@ e_book_cache_cursor_step (EBookCache *book_cache,
 
        /* Cleanup what was allocated by collect_results_for_cursor_cb() */
        if (data.results)
-               g_slist_free_full (data.results, (GDestroyNotify) e_book_cache_search_data_free);
+               g_slist_free_full (data.results, e_book_cache_search_data_free);
        g_free (data.alloc_vcard);
 
        /* Free the copy state if we were working with a copy */
diff --git a/src/addressbook/libedata-book/e-book-cache.h b/src/addressbook/libedata-book/e-book-cache.h
index 6fcfdb4..71cd432 100644
--- a/src/addressbook/libedata-book/e-book-cache.h
+++ b/src/addressbook/libedata-book/e-book-cache.h
@@ -85,7 +85,7 @@ EBookCacheSearchData *
                                                 const gchar *extra);
 EBookCacheSearchData *
                e_book_cache_search_data_copy   (const EBookCacheSearchData *data);
-void           e_book_cache_search_data_free   (EBookCacheSearchData *data);
+void           e_book_cache_search_data_free   (/* EBookCacheSearchData * */ gpointer data);
 
 /**
  * EBookCache:
diff --git a/src/libebackend/e-cache.c b/src/libebackend/e-cache.c
index e5d47f0..9fdd771 100644
--- a/src/libebackend/e-cache.c
+++ b/src/libebackend/e-cache.c
@@ -827,10 +827,23 @@ e_cache_count_rows_cb (ECache *cache,
        return TRUE;
 }
 
-static gboolean
-e_cache_contains_internal (ECache *cache,
-                          const gchar *uid,
-                          gboolean include_deleted)
+/**
+ * e_cache_contains:
+ * @cache: an #ECache
+ * @uid: a unique identifier of an object
+ * @include_deleted: set to %TRUE, when check also objects marked as locally deleted
+ *
+ * Checkes whether the @cache contains an object with
+ * the given @uid.
+ *
+ * Returns: Whether the cache contains an object with the given @uid.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_cache_contains (ECache *cache,
+                 const gchar *uid,
+                 gboolean include_deleted)
 {
        guint nrows = 0;
 
@@ -840,13 +853,15 @@ e_cache_contains_internal (ECache *cache,
        if (include_deleted) {
                e_cache_sqlite_exec_printf (cache,
                        "SELECT " E_CACHE_COLUMN_UID " FROM " E_CACHE_TABLE_OBJECTS
-                       " WHERE " E_CACHE_COLUMN_UID " = %Q",
+                       " WHERE " E_CACHE_COLUMN_UID " = %Q"
+                       " LIMIT 2",
                        e_cache_count_rows_cb, &nrows, NULL, NULL,
                        uid);
        } else {
                e_cache_sqlite_exec_printf (cache,
                        "SELECT " E_CACHE_COLUMN_UID " FROM " E_CACHE_TABLE_OBJECTS
-                       " WHERE " E_CACHE_COLUMN_UID " = %Q AND " E_CACHE_COLUMN_STATE " != %d",
+                       " WHERE " E_CACHE_COLUMN_UID " = %Q AND " E_CACHE_COLUMN_STATE " != %d"
+                       " LIMIT 2",
                        e_cache_count_rows_cb, &nrows, NULL, NULL,
                        uid, E_OFFLINE_STATE_LOCALLY_DELETED);
        }
@@ -856,30 +871,6 @@ e_cache_contains_internal (ECache *cache,
        return nrows > 0;
 }
 
-/**
- * e_cache_contains:
- * @cache: an #ECache
- * @uid: a unique identifier of an object
- *
- * Checkes whether the @cache contains an object with
- * the given @uid. The objects deleted in offline are
- * not considered. Use e_cache_get_offline_changes()
- * to get those.
- *
- * Returns: Whether the cache contains an object with the given @uid.
- *
- * Since: 3.26
- **/
-gboolean
-e_cache_contains (ECache *cache,
-                 const gchar *uid)
-{
-       g_return_val_if_fail (E_IS_CACHE (cache), FALSE);
-       g_return_val_if_fail (uid != NULL, FALSE);
-
-       return e_cache_contains_internal (cache, uid, FALSE);
-}
-
 struct GetObjectData {
        gchar *object;
        gchar **out_revision;
@@ -1066,7 +1057,7 @@ e_cache_put (ECache *cache,
 
        g_rec_mutex_lock (&cache->priv->lock);
 
-       is_replace = e_cache_contains_internal (cache, uid, FALSE);
+       is_replace = e_cache_contains (cache, uid, FALSE);
 
        success = e_cache_put_locked (cache, uid, revision, object, other_columns,
                E_OFFLINE_STATE_SYNCED, is_replace, cancellable, error);
@@ -1787,7 +1778,7 @@ e_cache_put_offline (ECache *cache,
 
        g_rec_mutex_lock (&cache->priv->lock);
 
-       is_replace = e_cache_contains_internal (cache, uid, TRUE);
+       is_replace = e_cache_contains (cache, uid, TRUE);
        if (is_replace) {
                GError *local_error = NULL;
 
@@ -1882,11 +1873,16 @@ e_cache_get_offline_state (ECache *cache,
                           GError **error)
 {
        EOfflineState offline_state = E_OFFLINE_STATE_UNKNOWN;
-       gint64 value;
+       gint64 value = offline_state;
 
        g_return_val_if_fail (E_IS_CACHE (cache), E_OFFLINE_STATE_UNKNOWN);
        g_return_val_if_fail (uid != NULL, E_OFFLINE_STATE_UNKNOWN);
 
+       if (!e_cache_contains (cache, uid, TRUE)) {
+               g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND, _("Object “%s” not found"), uid);
+               return offline_state;
+       }
+
        if (e_cache_sqlite_exec_printf (cache,
                "SELECT " E_CACHE_COLUMN_STATE " FROM " E_CACHE_TABLE_OBJECTS
                " WHERE " E_CACHE_COLUMN_UID " = %Q",
@@ -1922,6 +1918,11 @@ e_cache_set_offline_state (ECache *cache,
        g_return_val_if_fail (E_IS_CACHE (cache), FALSE);
        g_return_val_if_fail (uid != NULL, FALSE);
 
+       if (!e_cache_contains (cache, uid, TRUE)) {
+               g_set_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND, _("Object “%s” not found"), uid);
+               return FALSE;
+       }
+
        return e_cache_sqlite_exec_printf (cache,
                "UPDATE " E_CACHE_TABLE_OBJECTS " SET " E_CACHE_COLUMN_STATE "=%d"
                " WHERE " E_CACHE_COLUMN_UID " = %Q",
diff --git a/src/libebackend/e-cache.h b/src/libebackend/e-cache.h
index 57f91a6..5cb1128 100644
--- a/src/libebackend/e-cache.h
+++ b/src/libebackend/e-cache.h
@@ -316,7 +316,8 @@ void                e_cache_set_revision            (ECache *cache,
                                                 const gchar *revision);
 void           e_cache_erase                   (ECache *cache);
 gboolean       e_cache_contains                (ECache *cache,
-                                                const gchar *uid);
+                                                const gchar *uid,
+                                                gboolean include_deleted);
 gchar *                e_cache_get                     (ECache *cache,
                                                 const gchar *uid,
                                                 gchar **out_revision,
diff --git a/tests/libedata-book/CMakeLists.txt b/tests/libedata-book/CMakeLists.txt
index d8677d2..b83e065 100644
--- a/tests/libedata-book/CMakeLists.txt
+++ b/tests/libedata-book/CMakeLists.txt
@@ -106,6 +106,7 @@ set(TESTS
        test-cache-cursor-calculate
        test-cache-cursor-set-sexp
        test-cache-cursor-change-locale
+       test-cache-offline
        test-sqlite-get-contact
        test-sqlite-create-cursor
        test-sqlite-cursor-move-by-posix
diff --git a/tests/libedata-book/test-cache-cursor-calculate.c 
b/tests/libedata-book/test-cache-cursor-calculate.c
index cf7172a..e594457 100644
--- a/tests/libedata-book/test-cache-cursor-calculate.c
+++ b/tests/libedata-book/test-cache-cursor-calculate.c
@@ -72,7 +72,7 @@ test_cursor_calculate_move_forward (TCUCursorFixture *fixture,
                "sorted-5",
                "sorted-6",
                NULL);
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 
        /* Check new position */
        if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
@@ -111,7 +111,7 @@ test_cursor_calculate_move_backwards (TCUCursorFixture *fixture,
                "sorted-13",
                "sorted-12",
                NULL);
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 
        /* Check new position */
        if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
@@ -141,7 +141,7 @@ test_cursor_calculate_back_and_forth (TCUCursorFixture *fixture,
                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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
@@ -163,7 +163,7 @@ test_cursor_calculate_back_and_forth (TCUCursorFixture *fixture,
                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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
@@ -185,7 +185,7 @@ test_cursor_calculate_back_and_forth (TCUCursorFixture *fixture,
                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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
@@ -313,7 +313,7 @@ test_cursor_calculate_filtered_move_forward (TCUCursorFixture *fixture,
                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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
@@ -344,7 +344,7 @@ test_cursor_calculate_filtered_move_backwards (TCUCursorFixture *fixture,
                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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
@@ -458,7 +458,7 @@ test_cursor_calculate_descending_move_forward (TCUCursorFixture *fixture,
                "sorted-13",
                "sorted-12",
                NULL);
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
@@ -497,7 +497,7 @@ test_cursor_calculate_descending_move_backwards (TCUCursorFixture *fixture,
                "sorted-5",
                "sorted-6",
                NULL);
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Check new position */
diff --git a/tests/libedata-book/test-cache-cursor-set-sexp.c 
b/tests/libedata-book/test-cache-cursor-set-sexp.c
index 94bc247..2cbf415 100644
--- a/tests/libedata-book/test-cache-cursor-set-sexp.c
+++ b/tests/libedata-book/test-cache-cursor-set-sexp.c
@@ -46,7 +46,7 @@ test_cursor_sexp_calculate_position (TCUCursorFixture *fixture,
        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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 
        /* Check position */
        if (!e_book_cache_cursor_calculate (((TCUFixture *) fixture)->book_cache,
@@ -108,7 +108,7 @@ test_cursor_sexp_and_step (TCUCursorFixture *fixture,
        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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Step 6 results more, gets up to contact 'sorted-12' */
@@ -124,7 +124,7 @@ test_cursor_sexp_and_step (TCUCursorFixture *fixture,
        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);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 }
 
 gint
diff --git a/tests/libedata-book/test-cache-cursor-set-target.c 
b/tests/libedata-book/test-cache-cursor-set-target.c
index ade53c5..ef092e5 100644
--- a/tests/libedata-book/test-cache-cursor-set-target.c
+++ b/tests/libedata-book/test-cache-cursor-set-target.c
@@ -51,7 +51,7 @@ test_cursor_set_target_reset_cursor (TCUCursorFixture *fixture,
                "sorted-6",
                NULL);
 
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
        results = NULL;
 
        /* Second batch reset (same results) */
@@ -75,7 +75,7 @@ test_cursor_set_target_reset_cursor (TCUCursorFixture *fixture,
                "sorted-6",
                NULL);
 
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 }
 
 /*****************************************************
@@ -122,7 +122,7 @@ test_cursor_set_target_c_next_results (TCUCursorFixture *fixture,
                "sorted-9",
                NULL);
 
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 }
 
 /*****************************************************
@@ -169,7 +169,7 @@ test_cursor_set_target_c_prev_results (TCUCursorFixture *fixture,
                "sorted-8",
                NULL);
 
-       g_slist_free_full (results, (GDestroyNotify) e_book_cache_search_data_free);
+       g_slist_free_full (results, e_book_cache_search_data_free);
 }
 
 static TCUCursorClosure closures[] = {
diff --git a/tests/libedata-book/test-cache-get-contact.c b/tests/libedata-book/test-cache-get-contact.c
index d48faed..58fe3b0 100644
--- a/tests/libedata-book/test-cache-get-contact.c
+++ b/tests/libedata-book/test-cache-get-contact.c
@@ -22,7 +22,7 @@
 
 static void
 test_get_contact (TCUFixture *fixture,
-                  gconstpointer user_data)
+                 gconstpointer user_data)
 {
        EContact *contact = NULL;
        EContact *other = NULL;
diff --git a/tests/libedata-book/test-cache-offline.c b/tests/libedata-book/test-cache-offline.c
new file mode 100644
index 0000000..7947816
--- /dev/null
+++ b/tests/libedata-book/test-cache-offline.c
@@ -0,0 +1,555 @@
+/* -*- 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_fill_cache (TCUFixture *fixture,
+                EContact **out_contact)
+{
+       tcu_add_contact_from_test_case (fixture, "custom-1", out_contact);
+       tcu_add_contact_from_test_case (fixture, "custom-3", NULL);
+       tcu_add_contact_from_test_case (fixture, "custom-9", NULL);
+}
+
+static void
+test_check_search_result (const GSList *list,
+                         gboolean expect_custom_1,
+                         gboolean expect_custom_9,
+                         gboolean search_data,
+                         gboolean meta_contacts)
+{
+       gboolean have_custom_1 = FALSE, have_custom_3 = FALSE, have_custom_9 = FALSE;
+       const GSList *link;
+
+       for (link = list; link; link = g_slist_next (link)) {
+               const gchar *uid;
+               if (search_data) {
+                       EBookCacheSearchData *sd = link->data;
+                       EContact *contact;
+
+                       g_assert (sd != NULL);
+                       g_assert (sd->uid != NULL);
+                       g_assert (sd->vcard != NULL);
+
+                       uid = sd->uid;
+
+                       contact = e_contact_new_from_vcard (sd->vcard);
+                       g_assert (E_IS_CONTACT (contact));
+                       g_assert_cmpstr (uid, ==, e_contact_get_const (contact, E_CONTACT_UID));
+
+                       if (meta_contacts) {
+                               g_assert_nonnull (e_contact_get_const (contact, E_CONTACT_REV));
+                               g_assert_null (e_contact_get_const (contact, E_CONTACT_EMAIL_1));
+                       } else {
+                               g_assert_nonnull (e_contact_get_const (contact, E_CONTACT_EMAIL_1));
+                       }
+
+                       g_clear_object (&contact);
+               } else {
+                       uid = link->data;
+               }
+
+               g_assert_nonnull (uid);
+
+               if (g_str_equal (uid, "custom-1")) {
+                       g_assert (expect_custom_1);
+                       g_assert (!have_custom_1);
+                       have_custom_1 = TRUE;
+               } else if (g_str_equal (uid, "custom-3")) {
+                       g_assert (!have_custom_3);
+                       have_custom_3 = TRUE;
+               } else if (g_str_equal (uid, "custom-9")) {
+                       g_assert (expect_custom_9);
+                       g_assert (!have_custom_9);
+                       have_custom_9 = TRUE;
+               } else {
+                       /* It's not supposed to be NULL, but it will print the value of 'uid' */
+                       g_assert_cmpstr (uid, ==, NULL);
+               }
+       }
+
+       g_assert ((expect_custom_1 && have_custom_1) || (!expect_custom_1 && !have_custom_1));
+       g_assert ((expect_custom_9 && have_custom_9) || (!expect_custom_9 && !have_custom_9));
+       g_assert (have_custom_3);
+}
+
+static void
+test_basic_cursor (TCUFixture *fixture,
+                  gboolean expect_custom_1,
+                  gboolean expect_custom_9,
+                  const gchar *sexp)
+{
+       EContactField sort_fields[] = { E_CONTACT_FAMILY_NAME, E_CONTACT_GIVEN_NAME };
+       EBookCursorSortType sort_types[] = { E_BOOK_CURSOR_SORT_ASCENDING, E_BOOK_CURSOR_SORT_ASCENDING };
+       EBookCacheCursor *cursor;
+       gint total = -1, position = -1;
+       GSList *list;
+       GError *error = NULL;
+
+       cursor = e_book_cache_cursor_new (fixture->book_cache, sexp, sort_fields, sort_types, 2, &error);
+       g_assert_no_error (error);
+       g_assert_nonnull (cursor);
+
+       g_assert (e_book_cache_cursor_calculate (fixture->book_cache, cursor, &total, &position, NULL, 
&error));
+       g_assert_no_error (error);
+       g_assert_cmpint (total, ==, 1 + (expect_custom_1 ? 1 : 0) + (expect_custom_9 ? 1 : 0));
+       g_assert_cmpint (position, ==, 0);
+
+       g_assert_cmpint (e_book_cache_cursor_step (fixture->book_cache, cursor, 
E_BOOK_CACHE_CURSOR_STEP_FETCH,
+               E_BOOK_CACHE_CURSOR_ORIGIN_CURRENT, total, &list, NULL, &error), ==, total);
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, total);
+
+       test_check_search_result (list, expect_custom_1, expect_custom_9, TRUE, FALSE);
+
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       e_book_cache_cursor_free (fixture->book_cache, cursor);
+}
+
+static void
+test_basic_search (TCUFixture *fixture,
+                  gboolean expect_custom_1)
+{
+       EBookQuery *query;
+       GSList *list = NULL;
+       gchar *sexp;
+       GError *error = NULL;
+
+       /* All contacts first */
+       g_assert (e_book_cache_search (fixture->book_cache, NULL, FALSE, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, expect_custom_1 ? 3 : 2);
+       test_check_search_result (list, expect_custom_1, TRUE, TRUE, FALSE);
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       list = NULL;
+
+       g_assert (e_book_cache_search (fixture->book_cache, NULL, TRUE, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, expect_custom_1 ? 3 : 2);
+       test_check_search_result (list, expect_custom_1, TRUE, TRUE, TRUE);
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       list = NULL;
+
+       g_assert (e_book_cache_search_uids (fixture->book_cache, NULL, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, expect_custom_1 ? 3 : 2);
+       test_check_search_result (list, expect_custom_1, TRUE, FALSE, FALSE);
+       g_slist_free_full (list, g_free);
+       list = NULL;
+
+       test_basic_cursor (fixture, expect_custom_1, TRUE, NULL);
+
+       /* Only Brown, aka custom-3, as an autocomplete query */
+       query = e_book_query_field_test (E_CONTACT_FULL_NAME, E_BOOK_QUERY_CONTAINS, "Brown");
+       sexp = e_book_query_to_string (query);
+       e_book_query_unref (query);
+
+       g_assert (e_book_cache_search (fixture->book_cache, sexp, FALSE, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, 1);
+       test_check_search_result (list, FALSE, FALSE, TRUE, FALSE);
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       list = NULL;
+
+       g_assert (e_book_cache_search (fixture->book_cache, sexp, TRUE, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, 1);
+       test_check_search_result (list, FALSE, FALSE, TRUE, TRUE);
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       list = NULL;
+
+       g_assert (e_book_cache_search_uids (fixture->book_cache, sexp, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, 1);
+       test_check_search_result (list, FALSE, FALSE, FALSE, FALSE);
+       g_slist_free_full (list, g_free);
+       list = NULL;
+
+       test_basic_cursor (fixture, FALSE, FALSE, sexp);
+
+       g_free (sexp);
+
+       /* Only Brown, aka custom-3, as a regular query */
+       query = e_book_query_field_test (E_CONTACT_EMAIL, E_BOOK_QUERY_CONTAINS, "brown");
+       sexp = e_book_query_to_string (query);
+       e_book_query_unref (query);
+
+       g_assert (e_book_cache_search (fixture->book_cache, sexp, FALSE, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, 1);
+       test_check_search_result (list, FALSE, FALSE, TRUE, FALSE);
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       list = NULL;
+
+       g_assert (e_book_cache_search (fixture->book_cache, sexp, TRUE, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, 1);
+       test_check_search_result (list, FALSE, FALSE, TRUE, TRUE);
+       g_slist_free_full (list, e_book_cache_search_data_free);
+       list = NULL;
+
+       g_assert (e_book_cache_search_uids (fixture->book_cache, sexp, &list, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpint (g_slist_length (list), ==, 1);
+       test_check_search_result (list, FALSE, FALSE, FALSE, FALSE);
+       g_slist_free_full (list, g_free);
+       list = NULL;
+
+       test_basic_cursor (fixture, FALSE, FALSE, sexp);
+
+       g_free (sexp);
+
+       /* Invalid expression */
+       g_assert (!e_book_cache_search (fixture->book_cache, "invalid expression here", TRUE, &list, NULL, 
&error));
+       g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_INVALID_QUERY);
+       g_clear_error (&error);
+
+       g_assert (!e_book_cache_search_uids (fixture->book_cache, "invalid expression here", &list, NULL, 
&error));
+       g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_INVALID_QUERY);
+       g_clear_error (&error);
+}
+
+/* Expects pairs of UID (gchar *) and EOfflineState (gint), terminated by NULL */
+static void
+test_check_offline_states (TCUFixture *fixture,
+                          ...) G_GNUC_NULL_TERMINATED;
+
+static void
+test_check_offline_states (TCUFixture *fixture,
+                          ...)
+{
+       GSList *changes, *link;
+       va_list args;
+       GHashTable *expects;
+       const gchar *uid;
+       GError *error = NULL;
+
+       changes = e_cache_get_offline_changes (E_CACHE (fixture->book_cache), NULL, &error);
+
+       g_assert_no_error (error);
+
+       expects = g_hash_table_new (g_str_hash, g_str_equal);
+
+       va_start (args, fixture);
+       uid = va_arg (args, const gchar *);
+       while (uid) {
+               gint state = va_arg (args, gint);
+
+               g_hash_table_insert (expects, (gpointer) uid, GINT_TO_POINTER (state));
+               uid = va_arg (args, const gchar *);
+       }
+       va_end (args);
+
+       g_assert_cmpint (g_slist_length (changes), ==, g_hash_table_size (expects));
+
+       for (link = changes; link; link = g_slist_next (link)) {
+               ECacheOfflineChange *change = link->data;
+               gint expect_state;
+
+               g_assert_nonnull (change);
+               g_assert (g_hash_table_contains (expects, change->uid));
+
+               expect_state = GPOINTER_TO_INT (g_hash_table_lookup (expects, change->uid));
+               g_assert_cmpint (expect_state, ==, change->state);
+       }
+
+       g_slist_free_full (changes, e_cache_offline_change_free);
+       g_hash_table_destroy (expects);
+}
+
+static void
+test_verify_storage (TCUFixture *fixture,
+                    const gchar *uid,
+                    const gchar *expect_rev,
+                    const gchar *expect_extra,
+                    EOfflineState expect_offline_state)
+{
+       EContact *contact = NULL;
+       EOfflineState offline_state;
+       gchar *vcard, *saved_rev = NULL, *saved_extra = NULL;
+       GError *error = NULL;
+
+       if (expect_offline_state == E_OFFLINE_STATE_LOCALLY_DELETED ||
+           expect_offline_state == E_OFFLINE_STATE_UNKNOWN) {
+               g_assert (!e_book_cache_get_contact (fixture->book_cache, uid, FALSE, &contact, NULL, 
&error));
+               g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND);
+               g_assert_null (contact);
+
+               g_clear_error (&error);
+       } else {
+               g_assert (e_book_cache_get_contact (fixture->book_cache, uid, FALSE, &contact, NULL, &error));
+               g_assert_no_error (error);
+               g_assert_nonnull (contact);
+       }
+
+       offline_state = e_cache_get_offline_state (E_CACHE (fixture->book_cache), uid, NULL, &error);
+       if (offline_state == E_OFFLINE_STATE_UNKNOWN) {
+               g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND);
+               g_clear_error (&error);
+       } else {
+               g_assert_no_error (error);
+       }
+       g_assert_cmpint (offline_state, ==, expect_offline_state);
+
+       if (offline_state == E_OFFLINE_STATE_UNKNOWN) {
+               g_assert (!e_cache_contains (E_CACHE (fixture->book_cache), uid, TRUE));
+               g_assert (!e_cache_contains (E_CACHE (fixture->book_cache), uid, FALSE));
+               test_check_offline_states (fixture, NULL);
+               return;
+       }
+
+       g_assert (e_book_cache_get_contact_extra (fixture->book_cache, uid, &saved_extra, NULL, &error));
+       g_assert_no_error (error);
+
+       g_assert_cmpstr (saved_extra, ==, expect_extra);
+       g_assert_cmpstr (e_contact_get_const (contact, E_CONTACT_REV), ==, expect_rev);
+
+       g_clear_object (&contact);
+
+       vcard = e_cache_get (E_CACHE (fixture->book_cache), uid, &saved_rev, NULL, NULL, &error);
+       g_assert_no_error (error);
+       g_assert_nonnull (vcard);
+       g_assert_nonnull (saved_rev);
+
+       g_assert_cmpstr (saved_rev, ==, expect_rev);
+
+       g_free (vcard);
+       g_free (saved_rev);
+       g_free (saved_extra);
+
+       if (expect_offline_state == E_OFFLINE_STATE_SYNCED)
+               test_check_offline_states (fixture, NULL);
+       else
+               test_check_offline_states (fixture, uid, expect_offline_state, NULL);
+}
+
+static void
+test_offline_basics (TCUFixture *fixture,
+                    gconstpointer user_data)
+{
+       EOfflineState states[] = {
+               E_OFFLINE_STATE_LOCALLY_CREATED,
+               E_OFFLINE_STATE_LOCALLY_MODIFIED,
+               E_OFFLINE_STATE_LOCALLY_DELETED,
+               E_OFFLINE_STATE_SYNCED
+       };
+       EOfflineState offline_state;
+       EContact *contact = NULL;
+       gint ii;
+       const gchar *uid;
+       gchar *saved_extra = NULL, *tmp;
+       GError *error = NULL;
+
+       /* Basic ECache stuff */
+       e_cache_set_version (E_CACHE (fixture->book_cache), 123);
+       g_assert_cmpint (e_cache_get_version (E_CACHE (fixture->book_cache)), ==, 123);
+
+       e_cache_set_revision (E_CACHE (fixture->book_cache), "rev-321");
+       tmp = e_cache_dup_revision (E_CACHE (fixture->book_cache));
+       g_assert_cmpstr ("rev-321", ==, tmp);
+       g_free (tmp);
+
+       g_assert (e_cache_set_key (E_CACHE (fixture->book_cache), "my-key-str", "key-str-value", &error));
+       g_assert_no_error (error);
+
+       tmp = e_cache_dup_key (E_CACHE (fixture->book_cache), "my-key-str", &error);
+       g_assert_no_error (error);
+       g_assert_cmpstr ("key-str-value", ==, tmp);
+       g_free (tmp);
+
+       g_assert (e_cache_set_key_int (E_CACHE (fixture->book_cache), "version", 567, &error));
+       g_assert_no_error (error);
+
+       g_assert_cmpint (e_cache_get_key_int (E_CACHE (fixture->book_cache), "version", &error), ==, 567);
+       g_assert_no_error (error);
+
+       g_assert_cmpint (e_cache_get_version (E_CACHE (fixture->book_cache)), ==, 123);
+
+       /* Add in online */
+       test_fill_cache (fixture, &contact);
+       g_assert_nonnull (contact);
+
+       uid = e_contact_get_const (contact, E_CONTACT_UID);
+       g_assert_nonnull (uid);
+
+       g_assert_cmpint (e_cache_count (E_CACHE (fixture->book_cache), FALSE, NULL, &error), ==, 3);
+       g_assert_no_error (error);
+
+       g_assert (e_book_cache_set_contact_extra (fixture->book_cache, uid, "extra-0", NULL, &error));
+       g_assert_no_error (error);
+
+       g_assert (e_book_cache_get_contact_extra (fixture->book_cache, uid, &saved_extra, NULL, &error));
+       g_assert_no_error (error);
+       g_assert_cmpstr (saved_extra, ==, "extra-0");
+
+       g_free (saved_extra);
+       saved_extra = NULL;
+
+       e_contact_set (contact, E_CONTACT_REV, "rev-0");
+
+       offline_state = e_cache_get_offline_state (E_CACHE (fixture->book_cache), uid, NULL, &error);
+       g_assert_no_error (error);
+       g_assert (offline_state == E_OFFLINE_STATE_SYNCED);
+
+       test_check_offline_states (fixture, NULL);
+
+       /* Try change status */
+       for (ii = 0; ii < G_N_ELEMENTS (states); ii++) {
+               g_assert (e_cache_set_offline_state (E_CACHE (fixture->book_cache), uid, states[ii], NULL, 
&error));
+               g_assert_no_error (error);
+
+               offline_state = e_cache_get_offline_state (E_CACHE (fixture->book_cache), uid, NULL, &error);
+               g_assert_no_error (error);
+               g_assert (offline_state == states[ii]);
+
+               if (states[ii] != E_OFFLINE_STATE_SYNCED)
+                       test_check_offline_states (fixture, uid, states[ii], NULL);
+
+               if (states[ii] == E_OFFLINE_STATE_LOCALLY_DELETED) {
+                       g_assert_cmpint (e_cache_count (E_CACHE (fixture->book_cache), FALSE, NULL, &error), 
==, 2);
+                       g_assert_no_error (error);
+
+                       g_assert (!e_cache_contains (E_CACHE (fixture->book_cache), uid, FALSE));
+
+                       g_assert (e_book_cache_set_contact_extra (fixture->book_cache, uid, "extra-1", NULL, 
&error));
+                       g_assert_no_error (error);
+
+                       g_assert (e_book_cache_get_contact_extra (fixture->book_cache, uid, &saved_extra, 
NULL, &error));
+                       g_assert_no_error (error);
+                       g_assert_cmpstr (saved_extra, ==, "extra-1");
+
+                       g_free (saved_extra);
+                       saved_extra = NULL;
+
+                       /* Search when locally deleted */
+                       test_basic_search (fixture, FALSE);
+               } else {
+                       g_assert_cmpint (e_cache_count (E_CACHE (fixture->book_cache), FALSE, NULL, &error), 
==, 3);
+                       g_assert_no_error (error);
+
+                       g_assert (e_cache_contains (E_CACHE (fixture->book_cache), uid, FALSE));
+
+                       /* Search when locally available */
+                       test_basic_search (fixture, TRUE);
+               }
+
+               g_assert (e_cache_contains (E_CACHE (fixture->book_cache), uid, TRUE));
+
+               g_assert_cmpint (e_cache_count (E_CACHE (fixture->book_cache), TRUE, NULL, &error), ==, 3);
+               g_assert_no_error (error);
+       }
+
+       test_check_offline_states (fixture, NULL);
+
+       /* Edit in online */
+       e_contact_set (contact, E_CONTACT_REV, "rev-1");
+
+       g_assert (e_book_cache_put_contact (fixture->book_cache, contact, NULL, FALSE, NULL, &error));
+       g_assert_no_error (error);
+
+       test_verify_storage (fixture, uid, "rev-1", NULL, E_OFFLINE_STATE_SYNCED);
+       test_check_offline_states (fixture, NULL);
+
+       e_contact_set (contact, E_CONTACT_REV, "rev-2");
+
+       g_assert (e_book_cache_put_contact (fixture->book_cache, contact, "extra-2", FALSE, NULL, &error));
+       g_assert_no_error (error);
+
+       test_verify_storage (fixture, uid, "rev-2", "extra-2", E_OFFLINE_STATE_SYNCED);
+       test_check_offline_states (fixture, NULL);
+
+       g_assert_cmpint (e_cache_count (E_CACHE (fixture->book_cache), FALSE, NULL, &error), ==, 3);
+       g_assert_no_error (error);
+
+       /* Search before delete */
+       test_basic_search (fixture, TRUE);
+
+       /* Delete in online */
+       g_assert (e_book_cache_remove_contact (fixture->book_cache, uid, FALSE, NULL, &error));
+       g_assert_no_error (error);
+
+       g_assert (!e_cache_set_offline_state (E_CACHE (fixture->book_cache), uid, 
E_OFFLINE_STATE_LOCALLY_MODIFIED, NULL, &error));
+       g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND);
+
+       test_verify_storage (fixture, uid, NULL, NULL, E_OFFLINE_STATE_UNKNOWN);
+       test_check_offline_states (fixture, NULL);
+
+       g_clear_object (&contact);
+       g_clear_error (&error);
+
+       g_assert_cmpint (e_cache_count (E_CACHE (fixture->book_cache), FALSE, NULL, &error), ==, 2);
+       g_assert_no_error (error);
+
+       g_assert (!e_book_cache_set_contact_extra (fixture->book_cache, uid, "extra-3", NULL, &error));
+       g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND);
+       g_clear_error (&error);
+
+       g_assert (!e_book_cache_get_contact_extra (fixture->book_cache, uid, &saved_extra, NULL, &error));
+       g_assert_error (error, E_CACHE_ERROR, E_CACHE_ERROR_NOT_FOUND);
+       g_assert_null (saved_extra);
+       g_clear_error (&error);
+
+       /* Search after delete */
+       test_basic_search (fixture, FALSE);
+}
+
+gint
+main (gint argc,
+      gchar **argv)
+{
+       TCUClosure closure = { NULL };
+
+#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 ("/EBookCache/Offline/Basics", TCUFixture, &closure,
+               tcu_fixture_setup, test_offline_basics, tcu_fixture_teardown);
+       /*g_test_add ("/EBookCache/Offline/Add", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_add, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/AddEdit", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_add_edit, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/AddDelete", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_add_delete, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/AddDeleteAdd", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_add_delete_add, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/AddResync", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_add_resync, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/Edit", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_edit, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/EditDelete", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_edit_delete, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/EditResync", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_edit_resync, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/Delete", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_delete, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/DeleteAdd", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_delete_add, tcu_fixture_teardown);
+       g_test_add ("/EBookCache/Offline/DeleteResync", TCUFixture, closure,
+               tcu_fixture_setup, test_offline_delete_resync, 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
index 70a74d4..caedd46 100644
--- a/tests/libedata-book/test-cache-utils.c
+++ b/tests/libedata-book/test-cache-utils.c
@@ -96,6 +96,8 @@ tcu_add_contact_from_test_case (TCUFixture *fixture,
 
        if (ret_contact)
                *ret_contact = g_object_ref (contact);
+
+       g_clear_object (&contact);
 }
 
 static void
@@ -593,7 +595,7 @@ test_step (TCUCursorFixture *fixture,
 
                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);
+               g_slist_free_full (results, e_book_cache_search_data_free);
                results = NULL;
 
                /* Do it again, this time only moving the cursor */
@@ -610,7 +612,7 @@ test_step (TCUCursorFixture *fixture,
 
                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);
+               g_slist_free_full (results, e_book_cache_search_data_free);
                results = NULL;
        }
 }



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