kill maintainer mode
[dconf.git] / tests / gsettings.c
blob5695fa7d542c190c7f3e5243f028a7f715bcafd4
1 /**
2 * Copyright © 2010 Canonical Limited
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the licence, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
18 **/
20 #define G_SETTINGS_ENABLE_BACKEND
21 #include <gio/gsettingsbackend.h>
22 #include <gio/gio.h>
24 #include <stdbool.h>
25 #include <string.h>
27 static GSettingsBackend *backend;
29 static void
30 free_variant (gpointer data)
32 if (data != NULL)
33 g_variant_unref (data);
36 static GVariant *
37 do_read (const gchar *key)
39 return G_SETTINGS_BACKEND_GET_CLASS (backend)
40 ->read (backend, key, NULL, FALSE);
43 static gboolean
44 do_write (const gchar *key,
45 GVariant *value)
47 return G_SETTINGS_BACKEND_GET_CLASS (backend)
48 ->write (backend, key, value, do_write);
51 static gboolean
52 do_write_tree (GTree *tree)
54 return G_SETTINGS_BACKEND_GET_CLASS (backend)
55 ->write_tree (backend, tree, do_write);
58 static void
59 do_sync (void)
61 return G_SETTINGS_BACKEND_GET_CLASS (backend)
62 ->sync (backend);
65 #define RANDOM_ELEMENT(array) \
66 array[g_test_rand_int_range(0, G_N_ELEMENTS(array))]
68 static gchar *
69 random_key (void)
71 const gchar * const words[] = {
72 "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf",
73 "hotel", "india", "juliet", "kilo", "lima", "mike", "november",
74 "oscar", "papa", "quebec", "romeo", "sierra", "tango", "uniform",
75 "victor", "whiskey", "xray", "yankee", "zulu"
77 const gchar *parts[8];
78 gint n, i;
80 n = g_test_rand_int_range (2, 8);
81 parts[0] = "";
82 for (i = 1; i < n; i++)
83 parts[i] = RANDOM_ELEMENT (words);
84 parts[n] = NULL;
86 return g_strjoinv ("/", (gchar **) parts);
89 static GVariant *
90 random_value (void)
92 switch (g_test_rand_int_range (0, 3))
94 case 0:
95 return g_variant_new_int32 (g_test_rand_int ());
97 case 1:
98 return g_variant_new_boolean (g_test_rand_bit ());
100 case 2:
102 gint length = g_test_rand_int_range (0, 24);
103 gchar buffer[24];
104 gint i;
106 for (i = 0; i < length; i++)
107 buffer[i] = 'a' + g_test_rand_int_range (0, 26);
108 buffer[i] = '\0';
110 return g_variant_new_string (buffer);
113 default:
114 g_assert_not_reached ();
118 static GTree *
119 random_tree (void)
121 GTree *tree;
122 gint n;
124 tree = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
125 g_free, free_variant);
126 n = g_test_rand_int_range (1, 20);
128 while (n--)
129 g_tree_insert (tree, random_key (), g_variant_ref_sink (random_value ()));
131 return tree;
134 static void
135 apply_change (GHashTable *table,
136 const gchar *key,
137 GVariant *value)
139 if (value)
140 g_hash_table_insert (table, g_strdup (key), g_variant_ref_sink (value));
141 else
142 g_hash_table_insert (table, g_strdup (key), NULL);
145 static gboolean
146 apply_one_change (gpointer key,
147 gpointer value,
148 gpointer user_data)
150 apply_change (user_data, key, value);
151 return FALSE;
154 static void
155 apply_change_tree (GHashTable *table,
156 GTree *tree)
158 g_tree_foreach (tree, apply_one_change, table);
161 static GHashTable *implicit;
162 static GHashTable *explicit;
164 /* interpose */
165 void
166 g_settings_backend_changed (GSettingsBackend *backend_,
167 const gchar *key,
168 gpointer origin_tag)
170 GVariant *value;
172 /* ensure that we see no dupes from the bus */
173 g_assert (origin_tag == do_write);
174 g_assert (backend == backend_);
176 value = do_read (key);
177 apply_change (implicit, key, value);
178 g_variant_unref (value);
181 /* interpose */
182 void
183 g_settings_backend_keys_changed (GSettingsBackend *backend_,
184 const gchar *path,
185 const gchar * const *items,
186 gpointer origin_tag)
188 gint i;
190 /* ensure that we see no dupes from the bus */
191 g_assert (origin_tag == do_write);
192 g_assert (backend == backend_);
194 for (i = 0; items[i]; i++)
196 GVariant *value;
197 gchar *key;
199 key = g_strconcat (path, items[i], NULL);
200 value = do_read (key);
202 apply_change (implicit, key, value);
204 g_variant_unref (value);
205 g_free (key);
209 /* interpose */
210 void
211 g_settings_backend_changed_tree (GSettingsBackend *backend_,
212 GTree *tree,
213 gpointer origin_tag)
215 const gchar **keys;
216 gchar *path;
218 g_settings_backend_flatten_tree (tree, &path, &keys, NULL);
219 g_settings_backend_keys_changed (backend_, path, keys, origin_tag);
222 static void
223 setup (void)
225 extern void _g_io_modules_ensure_loaded (void);
226 GIOExtensionPoint *point;
227 GIOExtension *extension;
228 GType extension_type;
229 gchar *file;
231 file = g_build_filename (g_get_user_config_dir (),
232 "dconf/test", NULL);
233 unlink (file);
234 g_free (file);
236 g_setenv ("DCONF_PROFILE", "test", false);
238 g_type_init ();
240 /* Cause GIO modules to be loaded... */
241 g_object_unref (g_file_new_for_path ("."));
243 point = g_io_extension_point_lookup ("gsettings-backend");
244 extension = g_io_extension_point_get_extension_by_name (point, "dconf");
245 extension_type = g_io_extension_get_type (extension);
246 backend = g_object_new (extension_type, NULL);
248 G_SETTINGS_BACKEND_GET_CLASS (backend)
249 ->subscribe (backend, "/");
251 implicit = g_hash_table_new_full (g_str_hash, g_str_equal,
252 g_free, free_variant);
253 explicit = g_hash_table_new_full (g_str_hash, g_str_equal,
254 g_free, free_variant);
256 sleep(1);
259 static void
260 make_random_change (void)
262 if (g_test_rand_bit ())
264 GVariant *value;
265 gchar *key;
267 key = random_key ();
268 value = random_value ();
269 apply_change (explicit, key, value);
270 do_write (key, value);
272 g_free (key);
274 else
276 GTree *tree;
278 tree = random_tree ();
279 apply_change_tree (explicit, tree);
280 do_write_tree (tree);
282 g_tree_unref (tree);
286 guint64 dconf_time;
287 guint64 ghash_time;
288 guint64 lookups;
289 gboolean dots;
291 static void
292 verify_consistency (void)
294 GHashTableIter iter;
295 gpointer key, value;
297 if (dots)
298 g_print (".");
299 else
300 g_print ("(%d)", g_hash_table_size (implicit));
302 g_assert (g_hash_table_size (explicit) == g_hash_table_size (implicit));
303 g_hash_table_iter_init (&iter, explicit);
304 while (g_hash_table_iter_next (&iter, &key, &value))
306 if (value)
308 GVariant *other;
310 ghash_time -= g_get_monotonic_time ();
311 other = g_hash_table_lookup (implicit, key);
312 ghash_time += g_get_monotonic_time ();
313 g_assert (g_variant_equal (value, other));
315 dconf_time -= g_get_monotonic_time ();
316 other = do_read (key);
317 dconf_time += g_get_monotonic_time ();
318 g_assert (g_variant_equal (value, other));
319 g_variant_unref (other);
321 else
323 g_assert (g_hash_table_lookup (implicit, key) == NULL);
324 g_assert (do_read (key) == NULL);
327 lookups++;
331 #if 0
332 static void
333 dump_table (void)
335 GHashTableIter iter;
336 gpointer key, value;
338 g_print ("{");
339 g_hash_table_iter_init (&iter, explicit);
340 while (g_hash_table_iter_next (&iter, &key, &value))
341 if (value)
343 gchar *printed;
345 if (value)
346 printed = g_variant_print (value, FALSE);
347 else
348 printed = g_strdup ("None");
350 g_print ("'%s': %s, ", (gchar *) key, printed);
351 g_free (printed);
353 g_print ("}");
355 #endif
357 static void
358 test (void)
360 int i;
362 g_print ("Testing dconf...");
363 for (i = 0; i < 1000; i++)
365 g_print (" %d", i);
366 make_random_change ();
367 verify_consistency ();
370 g_print ("\n");
371 g_print ("GSettings lookup time: %f µs/lookup\n",
372 ((double) dconf_time / lookups));
373 g_print ("GHashTable lookup time: %f µs/lookup\n",
374 ((double) ghash_time / lookups));
376 dconf_time = 0;
377 ghash_time = 0;
378 lookups = 0;
380 g_print ("\nWaiting for dconf-service to catch up...");
381 do_sync ();
382 g_print (" done.\n");
384 g_print ("Measuring dconf read performance...");
385 dots = TRUE;
386 for (i = 0; i < 1000; i++)
387 verify_consistency ();
388 g_print ("\n");
390 g_print ("dconf lookup time: %f µs/lookup\n",
391 ((double) dconf_time / lookups));
392 g_print ("GHashTable lookup time: %f µs/lookup\n",
393 ((double) ghash_time / lookups));
395 g_hash_table_unref (explicit);
396 g_hash_table_unref (implicit);
400 main (int argc, char **argv)
402 g_test_init (&argc, &argv, NULL);
404 setup ();
406 test ();
408 return g_test_run ();