diff options
-rw-r--r-- | tests/dconf-mock-gvdb.c | 123 | ||||
-rw-r--r-- | tests/dconf-mock-shm.c | 46 | ||||
-rw-r--r-- | tests/dconf-mock.h | 12 | ||||
-rw-r--r-- | tests/engine.c | 97 |
4 files changed, 270 insertions, 8 deletions
diff --git a/tests/dconf-mock-gvdb.c b/tests/dconf-mock-gvdb.c index 96695ad..50ffbac 100644 --- a/tests/dconf-mock-gvdb.c +++ b/tests/dconf-mock-gvdb.c @@ -1,36 +1,136 @@ #include "../gvdb/gvdb-reader.h" +#include "dconf-mock.h" + +/* The global dconf_mock_gvdb_tables hashtable is modified all the time + * so we need to hold the lock while we access it. + * + * The hashtables contained within it are never modified, however. They + * can be safely accessed without a lock. + */ + +static GHashTable *dconf_mock_gvdb_tables; +static GMutex dconf_mock_gvdb_lock; + +typedef struct +{ + GVariant *value; + GHashTable *table; +} DConfMockGvdbItem; + +static void +dconf_mock_gvdb_item_free (gpointer data) +{ + DConfMockGvdbItem *item = data; + + if (item->value) + g_variant_unref (item->value); + + if (item->table) + g_hash_table_unref (item->table); + + g_slice_free (DConfMockGvdbItem, item); +} + +static void +dconf_mock_gvdb_init (void) +{ + if (dconf_mock_gvdb_tables == NULL) + dconf_mock_gvdb_tables = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + (GDestroyNotify) g_hash_table_unref); +} + +DConfMockGvdbTable * +dconf_mock_gvdb_table_new (void) +{ + GHashTable *hash_table; + + hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, dconf_mock_gvdb_item_free); + + return (DConfMockGvdbTable *) hash_table; +} + +void +dconf_mock_gvdb_table_insert (DConfMockGvdbTable *table, + const gchar *name, + GVariant *value, + DConfMockGvdbTable *subtable) +{ + GHashTable *hash_table = (GHashTable *) table; + DConfMockGvdbItem *item; + + g_assert (value == NULL || subtable == NULL); + + item = g_slice_new (DConfMockGvdbItem); + item->value = value ? g_variant_ref_sink (value) : NULL; + item->table = (GHashTable *) subtable; + + g_hash_table_insert (hash_table, g_strdup (name), item); +} + +void +dconf_mock_gvdb_install (const gchar *filename, + DConfMockGvdbTable *table) +{ + g_mutex_lock (&dconf_mock_gvdb_lock); + dconf_mock_gvdb_init (); + + if (table) + g_hash_table_insert (dconf_mock_gvdb_tables, g_strdup (filename), table); + else + g_hash_table_remove (dconf_mock_gvdb_tables, filename); + + g_mutex_unlock (&dconf_mock_gvdb_lock); +} void gvdb_table_unref (GvdbTable *table) { + GHashTable *hash_table = (GHashTable *) table; + + g_hash_table_unref (hash_table); } GvdbTable * gvdb_table_get_table (GvdbTable *table, const gchar *key) { - return NULL; + GHashTable *hash_table = (GHashTable *) table; + DConfMockGvdbItem *item; + + item = g_hash_table_lookup (hash_table, key); + + return (GvdbTable *) (item ? g_hash_table_ref (item->table) : NULL); } gboolean gvdb_table_has_value (GvdbTable *table, const gchar *key) { - return FALSE; + GHashTable *hash_table = (GHashTable *) table; + DConfMockGvdbItem *item; + + item = g_hash_table_lookup (hash_table, key); + + return item && item->value; } GVariant * gvdb_table_get_value (GvdbTable *table, const gchar *key) { - return NULL; + GHashTable *hash_table = (GHashTable *) table; + DConfMockGvdbItem *item; + + item = g_hash_table_lookup (hash_table, key); + + return item ? g_variant_ref (item->value) : NULL; } gchar ** gvdb_table_list (GvdbTable *table, const gchar *key) { - return NULL; + g_assert_not_reached (); } GvdbTable * @@ -38,8 +138,19 @@ gvdb_table_new (const gchar *filename, gboolean trusted, GError **error) { - g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "not implemented"); - return NULL; + GHashTable *hash_table; + + g_mutex_lock (&dconf_mock_gvdb_lock); + dconf_mock_gvdb_init (); + hash_table = g_hash_table_lookup (dconf_mock_gvdb_tables, filename); + if (hash_table) + g_hash_table_ref (hash_table); + g_mutex_unlock (&dconf_mock_gvdb_lock); + + if (hash_table == NULL) + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "this gvdb does not exist"); + + return (GvdbTable *) hash_table; } gboolean diff --git a/tests/dconf-mock-shm.c b/tests/dconf-mock-shm.c index 3e9c38d..588667e 100644 --- a/tests/dconf-mock-shm.c +++ b/tests/dconf-mock-shm.c @@ -10,6 +10,7 @@ typedef struct static GHashTable *dconf_mock_shm_table; static GMutex dconf_mock_shm_lock; +static GString *dconf_mock_shm_log; static void dconf_mock_shm_unref (gpointer data) @@ -36,7 +37,10 @@ dconf_shm_open (const gchar *name) g_mutex_lock (&dconf_mock_shm_lock); if G_UNLIKELY (dconf_mock_shm_table == NULL) - dconf_mock_shm_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, dconf_mock_shm_unref); + { + dconf_mock_shm_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, dconf_mock_shm_unref); + dconf_mock_shm_log = g_string_new (NULL); + } shm = g_hash_table_lookup (dconf_mock_shm_table, name); if (shm == NULL) @@ -48,6 +52,8 @@ dconf_shm_open (const gchar *name) /* before unlocking... */ dconf_mock_shm_ref (shm); + g_string_append_printf (dconf_mock_shm_log, "open %s;", name); + g_mutex_unlock (&dconf_mock_shm_lock); return &shm->flagged; @@ -57,7 +63,32 @@ void dconf_shm_close (guint8 *shm) { if (shm) - dconf_mock_shm_unref (shm); + { + g_mutex_lock (&dconf_mock_shm_lock); + g_string_append (dconf_mock_shm_log, "close;"); + g_mutex_unlock (&dconf_mock_shm_lock); + + dconf_mock_shm_unref (shm); + } +} + +gint +dconf_mock_shm_flag (const gchar *name) +{ + DConfMockShm *shm; + gint count = 0; + + g_mutex_lock (&dconf_mock_shm_lock); + shm = g_hash_table_lookup (dconf_mock_shm_table, name); + if (shm) + { + shm->flagged = 1; + count = shm->ref_count; + g_hash_table_remove (dconf_mock_shm_table, name); + } + g_mutex_unlock (&dconf_mock_shm_lock); + + return count; } void @@ -77,6 +108,17 @@ dconf_mock_shm_reset (void) g_assert_cmpint (shm->ref_count, ==, 1); g_hash_table_iter_remove (&iter); } + + g_string_truncate (dconf_mock_shm_log, 0); } g_mutex_unlock (&dconf_mock_shm_lock); } + +void +dconf_mock_shm_assert_log (const gchar *expected_log) +{ + g_mutex_lock (&dconf_mock_shm_lock); + g_assert_cmpstr (dconf_mock_shm_log->str, ==, expected_log); + g_string_truncate (dconf_mock_shm_log, 0); + g_mutex_unlock (&dconf_mock_shm_lock); +} diff --git a/tests/dconf-mock.h b/tests/dconf-mock.h index 8ce7f1f..81c41c4 100644 --- a/tests/dconf-mock.h +++ b/tests/dconf-mock.h @@ -2,5 +2,17 @@ #define __dconf_mock_h__ void dconf_mock_shm_reset (void); +gint dconf_mock_shm_flag (const gchar *name); +void dconf_mock_shm_assert_log (const gchar *expected_log); + +typedef struct _DConfMockGvdbTable DConfMockGvdbTable; + +DConfMockGvdbTable * dconf_mock_gvdb_table_new (void); +void dconf_mock_gvdb_table_insert (DConfMockGvdbTable *table, + const gchar *name, + GVariant *value, + DConfMockGvdbTable *subtable); +void dconf_mock_gvdb_install (const gchar *filename, + DConfMockGvdbTable *table); #endif diff --git a/tests/engine.c b/tests/engine.c index ea29e37..4ac0a2e 100644 --- a/tests/engine.c +++ b/tests/engine.c @@ -224,9 +224,105 @@ test_signal_threadsafety (void) dconf_mock_shm_reset (); } +static void +test_user_source (void) +{ + DConfEngineSource *source; + DConfMockGvdbTable *table; + DConfMockGvdbTable *locks; + gboolean reopened; + + source = dconf_engine_source_new ("user-db:user"); + g_assert (source != NULL); + + /* Create the source from a clean slate */ + dconf_engine_source_init (source); + g_assert (source->values == NULL); + g_assert (source->locks == NULL); + dconf_mock_shm_assert_log ("open user;"); + + /* Try to refresh it. There must be no IO at this point. */ + reopened = dconf_engine_source_refresh (source); + g_assert (!reopened); + dconf_mock_shm_assert_log (""); + + /* Add a real database. */ + table = dconf_mock_gvdb_table_new (); + dconf_mock_gvdb_table_insert (table, "/values/int32", g_variant_new_int32 (123456), NULL); + dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table); + + /* Try to refresh it again. + * Because we didn't flag the change there must still be no IO. + */ + reopened = dconf_engine_source_refresh (source); + g_assert (!reopened); + g_assert (source->values == NULL); + g_assert (source->locks == NULL); + dconf_mock_shm_assert_log (""); + + /* Now flag it and reopen. */ + dconf_mock_shm_flag ("user"); + reopened = dconf_engine_source_refresh (source); + g_assert (reopened); + g_assert (source->values != NULL); + g_assert (source->locks == NULL); + g_assert (gvdb_table_has_value (source->values, "/values/int32")); + dconf_mock_shm_assert_log ("close;open user;"); + + /* Do it again -- should get the same result, after some IO */ + dconf_mock_shm_flag ("user"); + reopened = dconf_engine_source_refresh (source); + g_assert (reopened); + g_assert (source->values != NULL); + g_assert (source->locks == NULL); + dconf_mock_shm_assert_log ("close;open user;"); + + /* "Delete" the gvdb and make sure dconf notices after a flag */ + dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL); + dconf_mock_shm_flag ("user"); + reopened = dconf_engine_source_refresh (source); + g_assert (reopened); + g_assert (source->values == NULL); + g_assert (source->locks == NULL); + dconf_mock_shm_assert_log ("close;open user;"); + + /* Add a gvdb with a lock */ + table = dconf_mock_gvdb_table_new (); + locks = dconf_mock_gvdb_table_new (); + dconf_mock_gvdb_table_insert (table, "/values/int32", g_variant_new_int32 (123456), NULL); + dconf_mock_gvdb_table_insert (locks, "/values/int32", g_variant_new_boolean (TRUE), NULL); + dconf_mock_gvdb_table_insert (table, ".locks", NULL, locks); + dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table); + + /* Reopen and check if we have the lock */ + dconf_mock_shm_flag ("user"); + reopened = dconf_engine_source_refresh (source); + g_assert (reopened); + g_assert (source->values != NULL); + g_assert (source->locks != NULL); + g_assert (gvdb_table_has_value (source->values, "/values/int32")); + g_assert (gvdb_table_has_value (source->locks, "/values/int32")); + dconf_mock_shm_assert_log ("close;open user;"); + + /* Reopen one last time */ + dconf_mock_shm_flag ("user"); + reopened = dconf_engine_source_refresh (source); + g_assert (reopened); + g_assert (source->values != NULL); + g_assert (source->locks != NULL); + dconf_mock_shm_assert_log ("close;open user;"); + + dconf_engine_source_free (source); + dconf_mock_shm_assert_log ("close;"); + + dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL); + dconf_mock_shm_reset (); +} + int main (int argc, char **argv) { + g_setenv ("XDG_CONFIG_HOME", "/HOME/.config", TRUE); g_unsetenv ("DCONF_PROFILE"); main_thread = g_thread_self (); @@ -235,6 +331,7 @@ main (int argc, char **argv) g_test_add_func ("/engine/profile-parser", test_profile_parser); g_test_add_func ("/engine/signal-threadsafety", test_signal_threadsafety); + g_test_add_func ("/engine/sources/user", test_user_source); return g_test_run (); } |