Improve GSettings test coverage
[platform/upstream/glib.git] / gio / tests / gsettings.c
1 #include <stdlib.h>
2 #include <locale.h>
3 #include <libintl.h>
4 #include <gio/gio.h>
5 #include <gstdio.h>
6 #define G_SETTINGS_ENABLE_BACKEND
7 #include <gio/gsettingsbackend.h>
8
9 #include "testenum.h"
10
11 static gboolean backend_set;
12
13 /* These tests rely on the schemas in org.gtk.test.gschema.xml
14  * to be compiled and installed in the same directory.
15  */
16
17 static void
18 check_and_free (GVariant    *value,
19                 const gchar *expected)
20 {
21   gchar *printed;
22
23   printed = g_variant_print (value, TRUE);
24   g_assert_cmpstr (printed, ==, expected);
25   g_free (printed);
26
27   g_variant_unref (value);
28 }
29
30
31 /* Just to get warmed up: Read and set a string, and
32  * verify that can read the changed string back
33  */
34 static void
35 test_basic (void)
36 {
37   gchar *str = NULL;
38   GSettings *settings;
39
40   settings = g_settings_new ("org.gtk.test");
41
42   g_object_get (settings, "schema", &str, NULL);
43   g_assert_cmpstr (str, ==, "org.gtk.test");
44   g_free (str);
45
46   g_settings_get (settings, "greeting", "s", &str);
47   g_assert_cmpstr (str, ==, "Hello, earthlings");
48   g_free (str);
49
50   g_settings_set (settings, "greeting", "s", "goodbye world");
51   g_settings_get (settings, "greeting", "s", &str);
52   g_assert_cmpstr (str, ==, "goodbye world");
53   g_free (str);
54   str = NULL;
55
56   if (!backend_set && g_test_undefined ())
57     {
58       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
59         {
60           settings = g_settings_new ("org.gtk.test");
61           g_settings_set (settings, "greeting", "i", 555);
62           abort ();
63         }
64       g_test_trap_assert_failed ();
65       g_test_trap_assert_stderr ("*g_settings_set_value*expects type*");
66     }
67
68   g_settings_get (settings, "greeting", "s", &str);
69   g_assert_cmpstr (str, ==, "goodbye world");
70   g_free (str);
71   str = NULL;
72
73   g_settings_reset (settings, "greeting");
74   str = g_settings_get_string (settings, "greeting");
75   g_assert_cmpstr (str, ==, "Hello, earthlings");
76   g_free (str);
77
78   g_settings_set (settings, "greeting", "s", "this is the end");
79   g_object_unref (settings);
80 }
81
82 /* Check that we get an error when getting a key
83  * that is not in the schema
84  */
85 static void
86 test_unknown_key (void)
87 {
88   if (!g_test_undefined ())
89     return;
90
91   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
92     {
93       GSettings *settings;
94       GVariant *value;
95
96       settings = g_settings_new ("org.gtk.test");
97       value = g_settings_get_value (settings, "no_such_key");
98
99       g_assert (value == NULL);
100
101       g_object_unref (settings);
102     }
103   g_test_trap_assert_failed ();
104   g_test_trap_assert_stderr ("*does not contain*");
105 }
106
107 /* Check that we get an error when the schema
108  * has not been installed
109  */
110 static void
111 test_no_schema (void)
112 {
113   if (!g_test_undefined ())
114     return;
115
116   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
117     {
118       GSettings *settings;
119
120       settings = g_settings_new ("no.such.schema");
121
122       g_assert (settings == NULL);
123     }
124
125   g_test_trap_assert_failed ();
126   g_test_trap_assert_stderr ("*Settings schema 'no.such.schema' is not installed*");
127 }
128
129 /* Check that we get an error when passing a type string
130  * that does not match the schema
131  */
132 static void
133 test_wrong_type (void)
134 {
135   if (!g_test_undefined ())
136     return;
137
138   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
139     {
140       GSettings *settings;
141       gchar *str = NULL;
142
143       settings = g_settings_new ("org.gtk.test");
144
145       g_settings_get (settings, "greeting", "o", &str);
146
147       g_assert (str == NULL);
148     }
149   g_test_trap_assert_failed ();
150   g_test_trap_assert_stderr ("*CRITICAL*");
151
152   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
153     {
154       GSettings *settings;
155
156       settings = g_settings_new ("org.gtk.test");
157
158       g_settings_set (settings, "greeting", "o", "/a/path");
159     }
160   g_test_trap_assert_failed ();
161   g_test_trap_assert_stderr ("*CRITICAL*");
162 }
163
164 /* Check errors with explicit paths */
165 static void
166 test_wrong_path (void)
167 {
168   if (!g_test_undefined ())
169     return;
170
171   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
172     {
173       GSettings *settings G_GNUC_UNUSED;
174
175       settings = g_settings_new_with_path ("org.gtk.test", "/wrong-path/");
176     }
177
178   g_test_trap_assert_failed ();
179   g_test_trap_assert_stderr ("*but path * specified by schema*");
180 }
181
182 static void
183 test_no_path (void)
184 {
185   if (!g_test_undefined ())
186     return;
187
188   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
189     {
190       GSettings *settings G_GNUC_UNUSED;
191
192       settings = g_settings_new ("org.gtk.test.no-path");
193     }
194
195   g_test_trap_assert_failed ();
196   g_test_trap_assert_stderr ("*attempting to create schema * without a path**");
197 }
198
199
200 /* Check that we can successfully read and set the full
201  * range of all basic types
202  */
203 static void
204 test_basic_types (void)
205 {
206   GSettings *settings;
207   gboolean b;
208   guint8 byte;
209   gint16 i16;
210   guint16 u16;
211   gint32 i32;
212   guint32 u32;
213   gint64 i64;
214   guint64 u64;
215   gdouble d;
216   gchar *str;
217
218   settings = g_settings_new ("org.gtk.test.basic-types");
219
220   g_settings_get (settings, "test-boolean", "b", &b);
221   g_assert_cmpint (b, ==, 1);
222
223   g_settings_set (settings, "test-boolean", "b", 0);
224   g_settings_get (settings, "test-boolean", "b", &b);
225   g_assert_cmpint (b, ==, 0);
226
227   g_settings_get (settings, "test-byte", "y", &byte);
228   g_assert_cmpint (byte, ==, 25);
229
230   g_settings_set (settings, "test-byte", "y", G_MAXUINT8);
231   g_settings_get (settings, "test-byte", "y", &byte);
232   g_assert_cmpint (byte, ==, G_MAXUINT8);
233
234   g_settings_get (settings, "test-int16", "n", &i16);
235   g_assert_cmpint (i16, ==, -1234);
236
237   g_settings_set (settings, "test-int16", "n", G_MININT16);
238   g_settings_get (settings, "test-int16", "n", &i16);
239   g_assert_cmpint (i16, ==, G_MININT16);
240
241   g_settings_set (settings, "test-int16", "n", G_MAXINT16);
242   g_settings_get (settings, "test-int16", "n", &i16);
243   g_assert_cmpint (i16, ==, G_MAXINT16);
244
245   g_settings_get (settings, "test-uint16", "q", &u16);
246   g_assert_cmpuint (u16, ==, 1234);
247
248   g_settings_set (settings, "test-uint16", "q", G_MAXUINT16);
249   g_settings_get (settings, "test-uint16", "q", &u16);
250   g_assert_cmpuint (u16, ==, G_MAXUINT16);
251
252   g_settings_get (settings, "test-int32", "i", &i32);
253   g_assert_cmpint (i32, ==, -123456);
254
255   g_settings_set (settings, "test-int32", "i", G_MININT32);
256   g_settings_get (settings, "test-int32", "i", &i32);
257   g_assert_cmpint (i32, ==, G_MININT32);
258
259   g_settings_set (settings, "test-int32", "i", G_MAXINT32);
260   g_settings_get (settings, "test-int32", "i", &i32);
261   g_assert_cmpint (i32, ==, G_MAXINT32);
262
263   g_settings_get (settings, "test-uint32", "u", &u32);
264   g_assert_cmpuint (u32, ==, 123456);
265
266   g_settings_set (settings, "test-uint32", "u", G_MAXUINT32);
267   g_settings_get (settings, "test-uint32", "u", &u32);
268   g_assert_cmpuint (u32, ==, G_MAXUINT32);
269
270   g_settings_get (settings, "test-int64", "x", &i64);
271   g_assert_cmpuint (i64, ==, -123456789);
272
273   g_settings_set (settings, "test-int64", "x", G_MININT64);
274   g_settings_get (settings, "test-int64", "x", &i64);
275   g_assert_cmpuint (i64, ==, G_MININT64);
276
277   g_settings_set (settings, "test-int64", "x", G_MAXINT64);
278   g_settings_get (settings, "test-int64", "x", &i64);
279   g_assert_cmpuint (i64, ==, G_MAXINT64);
280
281   g_settings_get (settings, "test-uint64", "t", &u64);
282   g_assert_cmpuint (u64, ==, 123456789);
283
284   g_settings_set (settings, "test-uint64", "t", G_MAXUINT64);
285   g_settings_get (settings, "test-uint64", "t", &u64);
286   g_assert_cmpuint (u64, ==, G_MAXUINT64);
287
288   g_settings_get (settings, "test-double", "d", &d);
289   g_assert_cmpfloat (d, ==, 123.456);
290
291   g_settings_set (settings, "test-double", "d", G_MINDOUBLE);
292   g_settings_get (settings, "test-double", "d", &d);
293   g_assert_cmpfloat (d, ==, G_MINDOUBLE);
294
295   g_settings_set (settings, "test-double", "d", G_MAXDOUBLE);
296   g_settings_get (settings, "test-double", "d", &d);
297   g_assert_cmpfloat (d, ==, G_MAXDOUBLE);
298
299   g_settings_get (settings, "test-string", "s", &str);
300   g_assert_cmpstr (str, ==, "a string, it seems");
301   g_free (str);
302   str = NULL;
303
304   g_settings_get (settings, "test-objectpath", "o", &str);
305   g_assert_cmpstr (str, ==, "/a/object/path");
306   g_object_unref (settings);
307   g_free (str);
308   str = NULL;
309 }
310
311 /* Check that we can read an set complex types like
312  * tuples, arrays and dictionaries
313  */
314 static void
315 test_complex_types (void)
316 {
317   GSettings *settings;
318   gchar *s;
319   gint i1, i2;
320   GVariantIter *iter = NULL;
321
322   settings = g_settings_new ("org.gtk.test.complex-types");
323
324   g_settings_get (settings, "test-tuple", "(s(ii))", &s, &i1, &i2);
325   g_assert_cmpstr (s, ==, "one");
326   g_assert_cmpint (i1,==, 2);
327   g_assert_cmpint (i2,==, 3);
328   g_free (s) ;
329   s = NULL;
330
331   g_settings_set (settings, "test-tuple", "(s(ii))", "none", 0, 0);
332   g_settings_get (settings, "test-tuple", "(s(ii))", &s, &i1, &i2);
333   g_assert_cmpstr (s, ==, "none");
334   g_assert_cmpint (i1,==, 0);
335   g_assert_cmpint (i2,==, 0);
336   g_free (s);
337   s = NULL;
338
339   g_settings_get (settings, "test-array", "ai", &iter);
340   g_assert_cmpint (g_variant_iter_n_children (iter), ==, 6);
341   g_assert (g_variant_iter_next (iter, "i", &i1));
342   g_assert_cmpint (i1, ==, 0);
343   g_assert (g_variant_iter_next (iter, "i", &i1));
344   g_assert_cmpint (i1, ==, 1);
345   g_assert (g_variant_iter_next (iter, "i", &i1));
346   g_assert_cmpint (i1, ==, 2);
347   g_assert (g_variant_iter_next (iter, "i", &i1));
348   g_assert_cmpint (i1, ==, 3);
349   g_assert (g_variant_iter_next (iter, "i", &i1));
350   g_assert_cmpint (i1, ==, 4);
351   g_assert (g_variant_iter_next (iter, "i", &i1));
352   g_assert_cmpint (i1, ==, 5);
353   g_assert (!g_variant_iter_next (iter, "i", &i1));
354   g_variant_iter_free (iter);
355
356   g_object_unref (settings);
357 }
358
359 static gboolean changed_cb_called;
360
361 static void
362 changed_cb (GSettings   *settings,
363             const gchar *key,
364             gpointer     data)
365 {
366   changed_cb_called = TRUE;
367
368   g_assert_cmpstr (key, ==, data);
369 }
370
371 /* Test that basic change notification with the changed signal works.
372  */
373 static void
374 test_changes (void)
375 {
376   GSettings *settings;
377   GSettings *settings2;
378
379   settings = g_settings_new ("org.gtk.test");
380
381   g_signal_connect (settings, "changed",
382                     G_CALLBACK (changed_cb), "greeting");
383
384   changed_cb_called = FALSE;
385
386   g_settings_set (settings, "greeting", "s", "new greeting");
387   g_assert (changed_cb_called);
388
389   settings2 = g_settings_new ("org.gtk.test");
390
391   changed_cb_called = FALSE;
392
393   g_settings_set (settings2, "greeting", "s", "hi");
394   g_assert (changed_cb_called);
395
396   g_object_unref (settings2);
397   g_object_unref (settings);
398 }
399
400 static gboolean changed_cb_called2;
401
402 static void
403 changed_cb2 (GSettings   *settings,
404              const gchar *key,
405              gpointer     data)
406 {
407   gboolean *p = data;
408
409   *p = TRUE;
410 }
411
412 /* Test that changes done to a delay-mode instance
413  * don't appear to the outside world until apply. Also
414  * check that we get change notification when they are
415  * applied.
416  * Also test that the has-unapplied property is properly
417  * maintained.
418  */
419 static void
420 test_delay_apply (void)
421 {
422   GSettings *settings;
423   GSettings *settings2;
424   gchar *str;
425
426   settings = g_settings_new ("org.gtk.test");
427   settings2 = g_settings_new ("org.gtk.test");
428
429   g_settings_set (settings2, "greeting", "s", "top o' the morning");
430
431   changed_cb_called = FALSE;
432   changed_cb_called2 = FALSE;
433
434   g_signal_connect (settings, "changed",
435                     G_CALLBACK (changed_cb2), &changed_cb_called);
436   g_signal_connect (settings2, "changed",
437                     G_CALLBACK (changed_cb2), &changed_cb_called2);
438
439   g_settings_delay (settings);
440
441   g_settings_set (settings, "greeting", "s", "greetings from test_delay_apply");
442
443   g_assert (changed_cb_called);
444   g_assert (!changed_cb_called2);
445
446   g_settings_get (settings, "greeting", "s", &str);
447   g_assert_cmpstr (str, ==, "greetings from test_delay_apply");
448   g_free (str);
449   str = NULL;
450
451   g_settings_get (settings2, "greeting", "s", &str);
452   g_assert_cmpstr (str, ==, "top o' the morning");
453   g_free (str);
454   str = NULL;
455
456   g_assert (g_settings_get_has_unapplied (settings));
457   g_assert (!g_settings_get_has_unapplied (settings2));
458
459   changed_cb_called = FALSE;
460   changed_cb_called2 = FALSE;
461
462   g_settings_apply (settings);
463
464   g_assert (!changed_cb_called);
465   g_assert (changed_cb_called2);
466
467   g_settings_get (settings, "greeting", "s", &str);
468   g_assert_cmpstr (str, ==, "greetings from test_delay_apply");
469   g_free (str);
470   str = NULL;
471
472   g_settings_get (settings2, "greeting", "s", &str);
473   g_assert_cmpstr (str, ==, "greetings from test_delay_apply");
474   g_free (str);
475   str = NULL;
476
477   g_assert (!g_settings_get_has_unapplied (settings));
478   g_assert (!g_settings_get_has_unapplied (settings2));
479
480   g_object_unref (settings2);
481   g_object_unref (settings);
482 }
483
484 /* Test that reverting unapplied changes in a delay-apply
485  * settings instance works.
486  */
487 static void
488 test_delay_revert (void)
489 {
490   GSettings *settings;
491   GSettings *settings2;
492   gchar *str;
493
494   settings = g_settings_new ("org.gtk.test");
495   settings2 = g_settings_new ("org.gtk.test");
496
497   g_settings_set (settings2, "greeting", "s", "top o' the morning");
498
499   g_settings_delay (settings);
500
501   g_settings_set (settings, "greeting", "s", "greetings from test_delay_revert");
502
503   g_settings_get (settings, "greeting", "s", &str);
504   g_assert_cmpstr (str, ==, "greetings from test_delay_revert");
505   g_free (str);
506   str = NULL;
507
508   g_settings_get (settings2, "greeting", "s", &str);
509   g_assert_cmpstr (str, ==, "top o' the morning");
510   g_free (str);
511   str = NULL;
512
513   g_assert (g_settings_get_has_unapplied (settings));
514
515   g_settings_revert (settings);
516
517   g_assert (!g_settings_get_has_unapplied (settings));
518
519   g_settings_get (settings, "greeting", "s", &str);
520   g_assert_cmpstr (str, ==, "top o' the morning");
521   g_free (str);
522   str = NULL;
523
524   g_settings_get (settings2, "greeting", "s", &str);
525   g_assert_cmpstr (str, ==, "top o' the morning");
526   g_free (str);
527   str = NULL;
528
529   g_object_unref (settings2);
530   g_object_unref (settings);
531 }
532
533 static void
534 keys_changed_cb (GSettings    *settings,
535                  const GQuark *keys,
536                  gint          n_keys)
537 {
538   gchar *str;
539
540   g_assert_cmpint (n_keys, ==, 2);
541
542   g_assert ((keys[0] == g_quark_from_static_string ("greeting") &&
543              keys[1] == g_quark_from_static_string ("farewell")) ||
544             (keys[1] == g_quark_from_static_string ("greeting") &&
545              keys[0] == g_quark_from_static_string ("farewell")));
546
547   g_settings_get (settings, "greeting", "s", &str);
548   g_assert_cmpstr (str, ==, "greetings from test_atomic");
549   g_free (str);
550   str = NULL;
551
552   g_settings_get (settings, "farewell", "s", &str);
553   g_assert_cmpstr (str, ==, "atomic bye-bye");
554   g_free (str);
555   str = NULL;
556 }
557
558 /* Check that delay-applied changes appear atomically.
559  * More specifically, verify that all changed keys appear
560  * with their new value while handling the change-event signal.
561  */
562 static void
563 test_atomic (void)
564 {
565   GSettings *settings;
566   GSettings *settings2;
567   gchar *str;
568
569   settings = g_settings_new ("org.gtk.test");
570   settings2 = g_settings_new ("org.gtk.test");
571
572   g_settings_set (settings2, "greeting", "s", "top o' the morning");
573
574   changed_cb_called = FALSE;
575   changed_cb_called2 = FALSE;
576
577   g_signal_connect (settings2, "change-event",
578                     G_CALLBACK (keys_changed_cb), NULL);
579
580   g_settings_delay (settings);
581
582   g_settings_set (settings, "greeting", "s", "greetings from test_atomic");
583   g_settings_set (settings, "farewell", "s", "atomic bye-bye");
584
585   g_settings_apply (settings);
586
587   g_settings_get (settings, "greeting", "s", &str);
588   g_assert_cmpstr (str, ==, "greetings from test_atomic");
589   g_free (str);
590   str = NULL;
591
592   g_settings_get (settings, "farewell", "s", &str);
593   g_assert_cmpstr (str, ==, "atomic bye-bye");
594   g_free (str);
595   str = NULL;
596
597   g_settings_get (settings2, "greeting", "s", &str);
598   g_assert_cmpstr (str, ==, "greetings from test_atomic");
599   g_free (str);
600   str = NULL;
601
602   g_settings_get (settings2, "farewell", "s", &str);
603   g_assert_cmpstr (str, ==, "atomic bye-bye");
604   g_free (str);
605   str = NULL;
606
607   g_object_unref (settings2);
608   g_object_unref (settings);
609 }
610
611 /* On Windows the interaction between the C library locale and libintl
612  * (from GNU gettext) is not like on POSIX, so just skip these tests
613  * for now.
614  *
615  * There are several issues:
616  *
617  * 1) The C library doesn't use LC_MESSAGES, that is implemented only
618  * in libintl (defined in its <libintl.h>).
619  *
620  * 2) The locale names that setlocale() accepts and returns aren't in
621  * the "de_DE" style, but like "German_Germany".
622  *
623  * 3) libintl looks at the Win32 thread locale and not the C library
624  * locale. (And even if libintl would use the C library's locale, as
625  * there are several alternative C library DLLs, libintl might be
626  * linked to a different one than the application code, so they
627  * wouldn't have the same C library locale anyway.)
628  */
629
630 /* Test that translations work for schema defaults.
631  *
632  * This test relies on the de.po file in the same directory
633  * to be compiled into ./de/LC_MESSAGES/test.mo
634  */
635 static void
636 test_l10n (void)
637 {
638   GSettings *settings;
639   gchar *str;
640   gchar *locale;
641
642   bindtextdomain ("test", ".");
643   bind_textdomain_codeset ("test", "UTF-8");
644
645   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
646
647   settings = g_settings_new ("org.gtk.test.localized");
648
649   setlocale (LC_MESSAGES, "C");
650   str = g_settings_get_string (settings, "error-message");
651   setlocale (LC_MESSAGES, locale);
652
653   g_assert_cmpstr (str, ==, "Unnamed");
654   g_free (str);
655   str = NULL;
656
657   setlocale (LC_MESSAGES, "de_DE");
658   str = g_settings_get_string (settings, "error-message");
659   setlocale (LC_MESSAGES, locale);
660
661   g_assert_cmpstr (str, ==, "Unbenannt");
662   g_object_unref (settings);
663   g_free (str);
664   str = NULL;
665
666   g_free (locale);
667 }
668
669 /* Test that message context works as expected with translated
670  * schema defaults. Also, verify that non-ASCII UTF-8 content
671  * works.
672  *
673  * This test relies on the de.po file in the same directory
674  * to be compiled into ./de/LC_MESSAGES/test.mo
675  */
676 static void
677 test_l10n_context (void)
678 {
679   GSettings *settings;
680   gchar *str;
681   gchar *locale;
682
683   bindtextdomain ("test", ".");
684   bind_textdomain_codeset ("test", "UTF-8");
685
686   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
687
688   settings = g_settings_new ("org.gtk.test.localized");
689
690   setlocale (LC_MESSAGES, "C");
691   g_settings_get (settings, "backspace", "s", &str);
692   setlocale (LC_MESSAGES, locale);
693
694   g_assert_cmpstr (str, ==, "BackSpace");
695   g_free (str);
696   str = NULL;
697
698   setlocale (LC_MESSAGES, "de_DE");
699   g_settings_get (settings, "backspace", "s", &str);
700   setlocale (LC_MESSAGES, locale);
701
702   g_assert_cmpstr (str, ==, "Löschen");
703   g_object_unref (settings);
704   g_free (str);
705   str = NULL;
706
707   g_free (locale);
708 }
709
710 enum
711 {
712   PROP_0,
713   PROP_BOOL,
714   PROP_ANTI_BOOL,
715   PROP_BYTE,
716   PROP_INT16,
717   PROP_UINT16,
718   PROP_INT,
719   PROP_UINT,
720   PROP_INT64,
721   PROP_UINT64,
722   PROP_DOUBLE,
723   PROP_STRING,
724   PROP_NO_READ,
725   PROP_NO_WRITE,
726   PROP_STRV,
727   PROP_ENUM,
728   PROP_FLAGS
729 };
730
731 typedef struct
732 {
733   GObject parent_instance;
734
735   gboolean bool_prop;
736   gboolean anti_bool_prop;
737   gint8 byte_prop;
738   gint int16_prop;
739   guint16 uint16_prop;
740   gint int_prop;
741   guint uint_prop;
742   gint64 int64_prop;
743   guint64 uint64_prop;
744   gdouble double_prop;
745   gchar *string_prop;
746   gchar *no_read_prop;
747   gchar *no_write_prop;
748   gchar **strv_prop;
749   guint enum_prop;
750   guint flags_prop;
751 } TestObject;
752
753 typedef struct
754 {
755   GObjectClass parent_class;
756 } TestObjectClass;
757
758 static GType test_object_get_type (void);
759 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
760
761 static void
762 test_object_init (TestObject *object)
763 {
764 }
765
766 static void
767 test_object_finalize (GObject *object)
768 {
769   TestObject *testo = (TestObject*)object;
770   g_strfreev (testo->strv_prop);
771   g_free (testo->string_prop);
772   G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
773 }
774
775 static void
776 test_object_get_property (GObject    *object,
777                           guint       prop_id,
778                           GValue     *value,
779                           GParamSpec *pspec)
780 {
781   TestObject *test_object = (TestObject *)object;
782
783   switch (prop_id)
784     {
785     case PROP_BOOL:
786       g_value_set_boolean (value, test_object->bool_prop);
787       break;
788     case PROP_ANTI_BOOL:
789       g_value_set_boolean (value, test_object->anti_bool_prop);
790       break;
791     case PROP_BYTE:
792       g_value_set_schar (value, test_object->byte_prop);
793       break;
794     case PROP_UINT16:
795       g_value_set_uint (value, test_object->uint16_prop);
796       break;
797     case PROP_INT16:
798       g_value_set_int (value, test_object->int16_prop);
799       break;
800     case PROP_INT:
801       g_value_set_int (value, test_object->int_prop);
802       break;
803     case PROP_UINT:
804       g_value_set_uint (value, test_object->uint_prop);
805       break;
806     case PROP_INT64:
807       g_value_set_int64 (value, test_object->int64_prop);
808       break;
809     case PROP_UINT64:
810       g_value_set_uint64 (value, test_object->uint64_prop);
811       break;
812     case PROP_DOUBLE:
813       g_value_set_double (value, test_object->double_prop);
814       break;
815     case PROP_STRING:
816       g_value_set_string (value, test_object->string_prop);
817       break;
818     case PROP_NO_WRITE:
819       g_value_set_string (value, test_object->no_write_prop);
820       break;
821     case PROP_STRV:
822       g_value_set_boxed (value, test_object->strv_prop);
823       break;
824     case PROP_ENUM:
825       g_value_set_enum (value, test_object->enum_prop);
826       break;
827     case PROP_FLAGS:
828       g_value_set_flags (value, test_object->flags_prop);
829       break;
830     default:
831       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
832       break;
833     }
834 }
835
836 static void
837 test_object_set_property (GObject      *object,
838                           guint         prop_id,
839                           const GValue *value,
840                           GParamSpec   *pspec)
841 {
842   TestObject *test_object = (TestObject *)object;
843
844   switch (prop_id)
845     {
846     case PROP_BOOL:
847       test_object->bool_prop = g_value_get_boolean (value);
848       break;
849     case PROP_ANTI_BOOL:
850       test_object->anti_bool_prop = g_value_get_boolean (value);
851       break;
852     case PROP_BYTE:
853       test_object->byte_prop = g_value_get_schar (value);
854       break;
855     case PROP_INT16:
856       test_object->int16_prop = g_value_get_int (value);
857       break;
858     case PROP_UINT16:
859       test_object->uint16_prop = g_value_get_uint (value);
860       break;
861     case PROP_INT:
862       test_object->int_prop = g_value_get_int (value);
863       break;
864     case PROP_UINT:
865       test_object->uint_prop = g_value_get_uint (value);
866       break;
867     case PROP_INT64:
868       test_object->int64_prop = g_value_get_int64 (value);
869       break;
870     case PROP_UINT64:
871       test_object->uint64_prop = g_value_get_uint64 (value);
872       break;
873     case PROP_DOUBLE:
874       test_object->double_prop = g_value_get_double (value);
875       break;
876     case PROP_STRING:
877       g_free (test_object->string_prop);
878       test_object->string_prop = g_value_dup_string (value);
879       break;
880     case PROP_NO_READ:
881       g_free (test_object->no_read_prop);
882       test_object->no_read_prop = g_value_dup_string (value);
883       break;
884     case PROP_STRV:
885       g_strfreev (test_object->strv_prop);
886       test_object->strv_prop = g_value_dup_boxed (value);
887       break;
888     case PROP_ENUM:
889       test_object->enum_prop = g_value_get_enum (value);
890       break;
891     case PROP_FLAGS:
892       test_object->flags_prop = g_value_get_flags (value);
893       break;
894     default:
895       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
896       break;
897     }
898 }
899
900 static GType
901 test_enum_get_type (void)
902 {
903   static volatile gsize define_type_id = 0;
904
905   if (g_once_init_enter (&define_type_id))
906     {
907       static const GEnumValue values[] = {
908         { TEST_ENUM_FOO, "TEST_ENUM_FOO", "foo" },
909         { TEST_ENUM_BAR, "TEST_ENUM_BAR", "bar" },
910         { TEST_ENUM_BAZ, "TEST_ENUM_BAZ", "baz" },
911         { TEST_ENUM_QUUX, "TEST_ENUM_QUUX", "quux" },
912         { 0, NULL, NULL }
913       };
914
915       GType type_id = g_enum_register_static ("TestEnum", values);
916       g_once_init_leave (&define_type_id, type_id);
917     }
918
919   return define_type_id;
920 }
921
922 static GType
923 test_flags_get_type (void)
924 {
925   static volatile gsize define_type_id = 0;
926
927   if (g_once_init_enter (&define_type_id))
928     {
929       static const GFlagsValue values[] = {
930         { TEST_FLAGS_NONE, "TEST_FLAGS_NONE", "none" },
931         { TEST_FLAGS_MOURNING, "TEST_FLAGS_MOURNING", "mourning" },
932         { TEST_FLAGS_LAUGHING, "TEST_FLAGS_LAUGHING", "laughing" },
933         { TEST_FLAGS_WALKING, "TEST_FLAGS_WALKING", "walking" },
934         { 0, NULL, NULL }
935       };
936
937       GType type_id = g_flags_register_static ("TestFlags", values);
938       g_once_init_leave (&define_type_id, type_id);
939     }
940
941   return define_type_id;
942 }
943
944 static void
945 test_object_class_init (TestObjectClass *class)
946 {
947   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
948
949   gobject_class->get_property = test_object_get_property;
950   gobject_class->set_property = test_object_set_property;
951   gobject_class->finalize = test_object_finalize;
952
953   g_object_class_install_property (gobject_class, PROP_BOOL,
954     g_param_spec_boolean ("bool", "", "", FALSE, G_PARAM_READWRITE));
955   g_object_class_install_property (gobject_class, PROP_ANTI_BOOL,
956     g_param_spec_boolean ("anti-bool", "", "", FALSE, G_PARAM_READWRITE));
957   g_object_class_install_property (gobject_class, PROP_BYTE,
958     g_param_spec_char ("byte", "", "", G_MININT8, G_MAXINT8, 0, G_PARAM_READWRITE));
959   g_object_class_install_property (gobject_class, PROP_INT16,
960     g_param_spec_int ("int16", "", "", -G_MAXINT16, G_MAXINT16, 0, G_PARAM_READWRITE));
961   g_object_class_install_property (gobject_class, PROP_UINT16,
962     g_param_spec_uint ("uint16", "", "", 0, G_MAXUINT16, 0, G_PARAM_READWRITE));
963   g_object_class_install_property (gobject_class, PROP_INT,
964     g_param_spec_int ("int", "", "", G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
965   g_object_class_install_property (gobject_class, PROP_UINT,
966     g_param_spec_uint ("uint", "", "", 0, G_MAXUINT, 0, G_PARAM_READWRITE));
967   g_object_class_install_property (gobject_class, PROP_INT64,
968     g_param_spec_int64 ("int64", "", "", G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE));
969   g_object_class_install_property (gobject_class, PROP_UINT64,
970     g_param_spec_uint64 ("uint64", "", "", 0, G_MAXUINT64, 0, G_PARAM_READWRITE));
971   g_object_class_install_property (gobject_class, PROP_DOUBLE,
972     g_param_spec_double ("double", "", "", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE));
973   g_object_class_install_property (gobject_class, PROP_STRING,
974     g_param_spec_string ("string", "", "", NULL, G_PARAM_READWRITE));
975   g_object_class_install_property (gobject_class, PROP_NO_WRITE,
976     g_param_spec_string ("no-write", "", "", NULL, G_PARAM_READABLE));
977   g_object_class_install_property (gobject_class, PROP_NO_READ,
978     g_param_spec_string ("no-read", "", "", NULL, G_PARAM_WRITABLE));
979   g_object_class_install_property (gobject_class, PROP_STRV,
980     g_param_spec_boxed ("strv", "", "", G_TYPE_STRV, G_PARAM_READWRITE));
981   g_object_class_install_property (gobject_class, PROP_ENUM,
982     g_param_spec_enum ("enum", "", "", test_enum_get_type (), TEST_ENUM_FOO, G_PARAM_READWRITE));
983   g_object_class_install_property (gobject_class, PROP_FLAGS,
984     g_param_spec_flags ("flags", "", "", test_flags_get_type (), TEST_FLAGS_NONE, G_PARAM_READWRITE));
985 }
986
987 static TestObject *
988 test_object_new (void)
989 {
990   return (TestObject*)g_object_new (test_object_get_type (), NULL);
991 }
992
993 /* Test basic binding functionality for simple types.
994  * Verify that with bidirectional bindings, changes on either side
995  * are notified on the other end.
996  */
997 static void
998 test_simple_binding (void)
999 {
1000   TestObject *obj;
1001   GSettings *settings;
1002   gboolean b;
1003   gchar y;
1004   gint i;
1005   guint u;
1006   gint16 n;
1007   guint16 q;
1008   gint n2;
1009   guint q2;
1010   gint64 i64;
1011   guint64 u64;
1012   gdouble d;
1013   gchar *s;
1014   GVariant *value;
1015   gchar **strv;
1016
1017   settings = g_settings_new ("org.gtk.test.binding");
1018   obj = test_object_new ();
1019
1020   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_DEFAULT);
1021   g_object_set (obj, "bool", TRUE, NULL);
1022   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
1023
1024   g_settings_set_boolean (settings, "bool", FALSE);
1025   b = TRUE;
1026   g_object_get (obj, "bool", &b, NULL);
1027   g_assert_cmpint (b, ==, FALSE);
1028
1029   g_settings_bind (settings, "anti-bool", obj, "anti-bool",
1030                    G_SETTINGS_BIND_INVERT_BOOLEAN);
1031   g_object_set (obj, "anti-bool", FALSE, NULL);
1032   g_assert_cmpint (g_settings_get_boolean (settings, "anti-bool"), ==, TRUE);
1033
1034   g_settings_set_boolean (settings, "anti-bool", FALSE);
1035   b = FALSE;
1036   g_object_get (obj, "anti-bool", &b, NULL);
1037   g_assert_cmpint (b, ==, TRUE);
1038
1039   g_settings_bind (settings, "byte", obj, "byte", G_SETTINGS_BIND_DEFAULT);
1040
1041   g_object_set (obj, "byte", 123, NULL);
1042   y = 'c';
1043   g_settings_get (settings, "byte", "y", &y);
1044   g_assert_cmpint (y, ==, 123);
1045
1046   g_settings_set (settings, "byte", "y", 54);
1047   y = 'c';
1048   g_object_get (obj, "byte", &y, NULL);
1049   g_assert_cmpint (y, ==, 54);
1050
1051   g_settings_bind (settings, "int16", obj, "int16", G_SETTINGS_BIND_DEFAULT);
1052
1053   g_object_set (obj, "int16", 1234, NULL);
1054   n = 4321;
1055   g_settings_get (settings, "int16", "n", &n);
1056   g_assert_cmpint (n, ==, 1234);
1057
1058   g_settings_set (settings, "int16", "n", 4321);
1059   n2 = 1111;
1060   g_object_get (obj, "int16", &n2, NULL);
1061   g_assert_cmpint (n2, ==, 4321);
1062
1063   g_settings_bind (settings, "uint16", obj, "uint16", G_SETTINGS_BIND_DEFAULT);
1064
1065   g_object_set (obj, "uint16", (guint16) G_MAXUINT16, NULL);
1066   q = 1111;
1067   g_settings_get (settings, "uint16", "q", &q);
1068   g_assert_cmpuint (q, ==, G_MAXUINT16);
1069
1070   g_settings_set (settings, "uint16", "q", (guint16) G_MAXINT16);
1071   q2 = 1111;
1072   g_object_get (obj, "uint16", &q2, NULL);
1073   g_assert_cmpuint (q2, ==, (guint16) G_MAXINT16);
1074
1075   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
1076
1077   g_object_set (obj, "int", 12345, NULL);
1078   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
1079
1080   g_settings_set_int (settings, "int", 54321);
1081   i = 1111;
1082   g_object_get (obj, "int", &i, NULL);
1083   g_assert_cmpint (i, ==, 54321);
1084
1085   g_settings_bind (settings, "uint", obj, "uint", G_SETTINGS_BIND_DEFAULT);
1086
1087   g_object_set (obj, "uint", 12345, NULL);
1088   g_assert_cmpuint (g_settings_get_uint (settings, "uint"), ==, 12345);
1089
1090   g_settings_set_uint (settings, "uint", 54321);
1091   u = 1111;
1092   g_object_get (obj, "uint", &u, NULL);
1093   g_assert_cmpuint (u, ==, 54321);
1094
1095   g_settings_bind (settings, "int64", obj, "int64", G_SETTINGS_BIND_DEFAULT);
1096
1097   g_object_set (obj, "int64", (gint64) G_MAXINT64, NULL);
1098   i64 = 1111;
1099   g_settings_get (settings, "int64", "x", &i64);
1100   g_assert_cmpint (i64, ==, G_MAXINT64);
1101
1102   g_settings_set (settings, "int64", "x", (gint64) G_MININT64);
1103   i64 = 1111;
1104   g_object_get (obj, "int64", &i64, NULL);
1105   g_assert_cmpint (i64, ==, G_MININT64);
1106
1107   g_settings_bind (settings, "uint64", obj, "uint64", G_SETTINGS_BIND_DEFAULT);
1108
1109   g_object_set (obj, "uint64", (guint64) G_MAXUINT64, NULL);
1110   u64 = 1111;
1111   g_settings_get (settings, "uint64", "t", &u64);
1112   g_assert_cmpuint (u64, ==, G_MAXUINT64);
1113
1114   g_settings_set (settings, "uint64", "t", (guint64) G_MAXINT64);
1115   u64 = 1111;
1116   g_object_get (obj, "uint64", &u64, NULL);
1117   g_assert_cmpuint (u64, ==, (guint64) G_MAXINT64);
1118
1119   g_settings_bind (settings, "string", obj, "string", G_SETTINGS_BIND_DEFAULT);
1120
1121   g_object_set (obj, "string", "bu ba", NULL);
1122   s = g_settings_get_string (settings, "string");
1123   g_assert_cmpstr (s, ==, "bu ba");
1124   g_free (s);
1125
1126   g_settings_set_string (settings, "string", "bla bla");
1127   g_object_get (obj, "string", &s, NULL);
1128   g_assert_cmpstr (s, ==, "bla bla");
1129   g_free (s);
1130
1131   g_settings_bind (settings, "chararray", obj, "string", G_SETTINGS_BIND_DEFAULT);
1132
1133   g_object_set (obj, "string", "non-unicode:\315", NULL);
1134   value = g_settings_get_value (settings, "chararray");
1135   g_assert_cmpstr (g_variant_get_bytestring (value), ==, "non-unicode:\315");
1136   g_variant_unref (value);
1137
1138   g_settings_bind (settings, "double", obj, "double", G_SETTINGS_BIND_DEFAULT);
1139
1140   g_object_set (obj, "double", G_MAXFLOAT, NULL);
1141   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXFLOAT);
1142
1143   g_settings_set_double (settings, "double", G_MINFLOAT);
1144   d = 1.0;
1145   g_object_get (obj, "double", &d, NULL);
1146   g_assert_cmpfloat (d, ==, G_MINFLOAT);
1147
1148   g_object_set (obj, "double", G_MAXDOUBLE, NULL);
1149   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXDOUBLE);
1150
1151   g_settings_set_double (settings, "double", -G_MINDOUBLE);
1152   d = 1.0;
1153   g_object_get (obj, "double", &d, NULL);
1154   g_assert_cmpfloat (d, ==, -G_MINDOUBLE);
1155
1156   strv = g_strsplit ("plastic bag,middle class,polyethylene", ",", 0);
1157   g_settings_bind (settings, "strv", obj, "strv", G_SETTINGS_BIND_DEFAULT);
1158   g_object_set (obj, "strv", strv, NULL);
1159   g_strfreev (strv);
1160   strv = g_settings_get_strv (settings, "strv");
1161   s = g_strjoinv (",", strv);
1162   g_assert_cmpstr (s, ==, "plastic bag,middle class,polyethylene");
1163   g_strfreev (strv);
1164   g_free (s);
1165   strv = g_strsplit ("decaffeinate,unleaded,keep all surfaces clean", ",", 0);
1166   g_settings_set_strv (settings, "strv", (const gchar **) strv);
1167   g_strfreev (strv);
1168   g_object_get (obj, "strv", &strv, NULL);
1169   s = g_strjoinv (",", strv);
1170   g_assert_cmpstr (s, ==, "decaffeinate,unleaded,keep all surfaces clean");
1171   g_strfreev (strv);
1172   g_free (s);
1173
1174   g_settings_bind (settings, "enum", obj, "enum", G_SETTINGS_BIND_DEFAULT);
1175   g_object_set (obj, "enum", TEST_ENUM_BAZ, NULL);
1176   s = g_settings_get_string (settings, "enum");
1177   g_assert_cmpstr (s, ==, "baz");
1178   g_free (s);
1179   g_assert_cmpint (g_settings_get_enum (settings, "enum"), ==, TEST_ENUM_BAZ);
1180
1181   g_settings_set_enum (settings, "enum", TEST_ENUM_QUUX);
1182   i = 230;
1183   g_object_get (obj, "enum", &i, NULL);
1184   g_assert_cmpint (i, ==, TEST_ENUM_QUUX);
1185
1186   g_settings_set_string (settings, "enum", "baz");
1187   i = 230;
1188   g_object_get (obj, "enum", &i, NULL);
1189   g_assert_cmpint (i, ==, TEST_ENUM_BAZ);
1190
1191   g_settings_bind (settings, "flags", obj, "flags", G_SETTINGS_BIND_DEFAULT);
1192   g_object_set (obj, "flags", TEST_FLAGS_MOURNING, NULL);
1193   strv = g_settings_get_strv (settings, "flags");
1194   g_assert_cmpint (g_strv_length (strv), ==, 1);
1195   g_assert_cmpstr (strv[0], ==, "mourning");
1196   g_strfreev (strv);
1197
1198   g_assert_cmpint (g_settings_get_flags (settings, "flags"), ==, TEST_FLAGS_MOURNING);
1199
1200   g_settings_set_flags (settings, "flags", TEST_FLAGS_MOURNING | TEST_FLAGS_WALKING);
1201   i = 230;
1202   g_object_get (obj, "flags", &i, NULL);
1203   g_assert_cmpint (i, ==, TEST_FLAGS_MOURNING | TEST_FLAGS_WALKING);
1204
1205   g_object_unref (obj);
1206   g_object_unref (settings);
1207 }
1208
1209 static void
1210 test_unbind (void)
1211 {
1212   TestObject *obj;
1213   GSettings *settings;
1214
1215   settings = g_settings_new ("org.gtk.test.binding");
1216   obj = test_object_new ();
1217
1218   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
1219
1220   g_object_set (obj, "int", 12345, NULL);
1221   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
1222
1223   g_settings_unbind (obj, "int");
1224
1225   g_object_set (obj, "int", 54321, NULL);
1226   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
1227
1228   g_object_unref (obj);
1229   g_object_unref (settings);
1230 }
1231
1232 static void
1233 test_bind_writable (void)
1234 {
1235   TestObject *obj;
1236   GSettings *settings;
1237   gboolean b;
1238
1239   settings = g_settings_new ("org.gtk.test.binding");
1240   obj = test_object_new ();
1241
1242   g_object_set (obj, "bool", FALSE, NULL);
1243
1244   g_settings_bind_writable (settings, "int", obj, "bool", FALSE);
1245
1246   g_object_get (obj, "bool", &b, NULL);
1247   g_assert (b);
1248
1249   g_settings_unbind (obj, "bool");
1250
1251   g_settings_bind_writable (settings, "int", obj, "bool", TRUE);
1252
1253   g_object_get (obj, "bool", &b, NULL);
1254   g_assert (!b);
1255
1256   g_object_unref (obj);
1257   g_object_unref (settings);
1258 }
1259
1260 /* Test one-way bindings.
1261  * Verify that changes on one side show up on the other,
1262  * but not vice versa
1263  */
1264 static void
1265 test_directional_binding (void)
1266 {
1267   TestObject *obj;
1268   GSettings *settings;
1269   gboolean b;
1270   gint i;
1271
1272   settings = g_settings_new ("org.gtk.test.binding");
1273   obj = test_object_new ();
1274
1275   g_object_set (obj, "bool", FALSE, NULL);
1276   g_settings_set_boolean (settings, "bool", FALSE);
1277
1278   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET);
1279
1280   g_settings_set_boolean (settings, "bool", TRUE);
1281   g_object_get (obj, "bool", &b, NULL);
1282   g_assert_cmpint (b, ==, TRUE);
1283
1284   g_object_set (obj, "bool", FALSE, NULL);
1285   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
1286
1287   g_object_set (obj, "int", 20, NULL);
1288   g_settings_set_int (settings, "int", 20);
1289
1290   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_SET);
1291
1292   g_object_set (obj, "int", 32, NULL);
1293   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 32);
1294
1295   g_settings_set_int (settings, "int", 20);
1296   g_object_get (obj, "int", &i, NULL);
1297   g_assert_cmpint (i, ==, 32);
1298
1299   g_object_unref (obj);
1300   g_object_unref (settings);
1301 }
1302
1303 /* Test that type mismatch is caught when creating a binding
1304  */
1305 static void
1306 test_typesafe_binding (void)
1307 {
1308   if (!g_test_undefined ())
1309     return;
1310
1311   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1312     {
1313       TestObject *obj;
1314       GSettings *settings;
1315
1316       settings = g_settings_new ("org.gtk.test.binding");
1317       obj = test_object_new ();
1318
1319       g_settings_bind (settings, "string", obj, "int", G_SETTINGS_BIND_DEFAULT);
1320
1321       g_object_unref (obj);
1322       g_object_unref (settings);
1323     }
1324   g_test_trap_assert_failed ();
1325   g_test_trap_assert_stderr ("*not compatible*");
1326 }
1327
1328 static gboolean
1329 string_to_bool (GValue   *value,
1330                 GVariant *variant,
1331                 gpointer  user_data)
1332 {
1333   const gchar *s;
1334
1335   s = g_variant_get_string (variant, NULL);
1336   g_value_set_boolean (value, g_strcmp0 (s, "true") == 0);
1337
1338   return TRUE;
1339 }
1340
1341 static GVariant *
1342 bool_to_string (const GValue       *value,
1343                 const GVariantType *expected_type,
1344                 gpointer            user_data)
1345 {
1346   if (g_value_get_boolean (value))
1347     return g_variant_new_string ("true");
1348   else
1349     return g_variant_new_string ("false");
1350 }
1351
1352 /* Test custom bindings.
1353  * Translate strings to booleans and back
1354  */
1355 static void
1356 test_custom_binding (void)
1357 {
1358   TestObject *obj;
1359   GSettings *settings;
1360   gchar *s;
1361   gboolean b;
1362
1363   settings = g_settings_new ("org.gtk.test.binding");
1364   obj = test_object_new ();
1365
1366   g_settings_set_string (settings, "string", "true");
1367
1368   g_settings_bind_with_mapping (settings, "string",
1369                                 obj, "bool",
1370                                 G_SETTINGS_BIND_DEFAULT,
1371                                 string_to_bool,
1372                                 bool_to_string,
1373                                 NULL, NULL);
1374
1375   g_settings_set_string (settings, "string", "false");
1376   g_object_get (obj, "bool", &b, NULL);
1377   g_assert_cmpint (b, ==, FALSE);
1378
1379   g_settings_set_string (settings, "string", "not true");
1380   g_object_get (obj, "bool", &b, NULL);
1381   g_assert_cmpint (b, ==, FALSE);
1382
1383   g_object_set (obj, "bool", TRUE, NULL);
1384   s = g_settings_get_string (settings, "string");
1385   g_assert_cmpstr (s, ==, "true");
1386   g_free (s);
1387
1388   g_object_unref (obj);
1389   g_object_unref (settings);
1390 }
1391
1392 /* Test that with G_SETTINGS_BIND_NO_CHANGES, the
1393  * initial settings value is transported to the object
1394  * side, but later settings changes do not affect the
1395  * object
1396  */
1397 static void
1398 test_no_change_binding (void)
1399 {
1400   TestObject *obj;
1401   GSettings *settings;
1402   gboolean b;
1403
1404   settings = g_settings_new ("org.gtk.test.binding");
1405   obj = test_object_new ();
1406
1407   g_object_set (obj, "bool", TRUE, NULL);
1408   g_settings_set_boolean (settings, "bool", FALSE);
1409
1410   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET_NO_CHANGES);
1411
1412   g_object_get (obj, "bool", &b, NULL);
1413   g_assert_cmpint (b, ==, FALSE);
1414
1415   g_settings_set_boolean (settings, "bool", TRUE);
1416   g_object_get (obj, "bool", &b, NULL);
1417   g_assert_cmpint (b, ==, FALSE);
1418
1419   g_settings_set_boolean (settings, "bool", FALSE);
1420   g_object_set (obj, "bool", TRUE, NULL);
1421   b = g_settings_get_boolean (settings, "bool");
1422   g_assert_cmpint (b, ==, TRUE);
1423
1424   g_object_unref (obj);
1425   g_object_unref (settings);
1426 }
1427
1428 /* Test that binding a non-readable property only
1429  * works in 'GET' mode.
1430  */
1431 static void
1432 test_no_read_binding (void)
1433 {
1434   if (g_test_undefined ())
1435     {
1436       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1437         {
1438           TestObject *obj;
1439           GSettings *settings;
1440
1441           settings = g_settings_new ("org.gtk.test.binding");
1442           obj = test_object_new ();
1443
1444           g_settings_bind (settings, "string", obj, "no-read", 0);
1445         }
1446       g_test_trap_assert_failed ();
1447       g_test_trap_assert_stderr ("*property*is not readable*");
1448     }
1449
1450   if (g_test_trap_fork (0, 0))
1451     {
1452       TestObject *obj;
1453       GSettings *settings;
1454
1455       settings = g_settings_new ("org.gtk.test.binding");
1456       obj = test_object_new ();
1457
1458       g_settings_bind (settings, "string", obj, "no-read", G_SETTINGS_BIND_GET);
1459
1460       exit (0);
1461     }
1462   g_test_trap_assert_passed ();
1463 }
1464
1465 /* Test that binding a non-writable property only
1466  * works in 'SET' mode.
1467  */
1468 static void
1469 test_no_write_binding (void)
1470 {
1471   if (g_test_undefined ())
1472     {
1473       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1474         {
1475           TestObject *obj;
1476           GSettings *settings;
1477
1478           settings = g_settings_new ("org.gtk.test.binding");
1479           obj = test_object_new ();
1480
1481           g_settings_bind (settings, "string", obj, "no-write", 0);
1482         }
1483       g_test_trap_assert_failed ();
1484       g_test_trap_assert_stderr ("*property*is not writable*");
1485     }
1486
1487   if (g_test_trap_fork (0, 0))
1488     {
1489       TestObject *obj;
1490       GSettings *settings;
1491
1492       settings = g_settings_new ("org.gtk.test.binding");
1493       obj = test_object_new ();
1494
1495       g_settings_bind (settings, "string", obj, "no-write", G_SETTINGS_BIND_SET);
1496
1497       exit (0);
1498     }
1499   g_test_trap_assert_passed ();
1500 }
1501
1502 /*
1503  * Test that using a keyfile works
1504  */
1505 static void
1506 test_keyfile (void)
1507 {
1508   GSettingsBackend *kf_backend;
1509   GSettings *settings;
1510   GKeyFile *keyfile;
1511   gchar *str;
1512
1513   g_remove ("gsettings.store");
1514
1515   kf_backend = g_keyfile_settings_backend_new ("gsettings.store", "/", "root");
1516   settings = g_settings_new_with_backend ("org.gtk.test", kf_backend);
1517   g_object_unref (kf_backend);
1518
1519   g_settings_set (settings, "greeting", "s", "see if this works");
1520
1521   keyfile = g_key_file_new ();
1522   g_assert (g_key_file_load_from_file (keyfile, "gsettings.store", 0, NULL));
1523
1524   str = g_key_file_get_string (keyfile, "tests", "greeting", NULL);
1525   g_assert_cmpstr (str, ==, "'see if this works'");
1526
1527   g_free (str);
1528   g_key_file_free (keyfile);
1529   g_object_unref (settings);
1530 }
1531
1532 /* Test that getting child schemas works
1533  */
1534 static void
1535 test_child_schema (void)
1536 {
1537   GSettings *settings;
1538   GSettings *child;
1539   guint8 byte;
1540
1541   /* first establish some known conditions */
1542   settings = g_settings_new ("org.gtk.test.basic-types");
1543   g_settings_set (settings, "test-byte", "y", 36);
1544
1545   g_settings_get (settings, "test-byte", "y", &byte);
1546   g_assert_cmpint (byte, ==, 36);
1547
1548   g_object_unref (settings);
1549
1550   settings = g_settings_new ("org.gtk.test");
1551   child = g_settings_get_child (settings, "basic-types");
1552   g_assert (child != NULL);
1553
1554   g_settings_get (child, "test-byte", "y", &byte);
1555   g_assert_cmpint (byte, ==, 36);
1556
1557   g_object_unref (child);
1558   g_object_unref (settings);
1559 }
1560
1561 static gboolean
1562 glib_translations_work (void)
1563 {
1564   gboolean works;
1565   gchar *locale;
1566   gchar *orig = "Unnamed";
1567
1568   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
1569   if (!setlocale (LC_MESSAGES, "de"))
1570     works = FALSE;
1571   else
1572     works = dgettext ("glib20", orig) != orig;
1573   setlocale (LC_MESSAGES, locale);
1574   g_free (locale);
1575
1576   return works;
1577 }
1578
1579 #include "../strinfo.c"
1580
1581 static void
1582 test_strinfo (void)
1583 {
1584   /*  "foo" has a value of 1
1585    *  "bar" has a value of 2
1586    *  "baz" is an alias for "bar"
1587    */
1588   gchar array[] =
1589     "\1\0\0\0"      "\xff""foo"     "\0\0\0\xff"    "\2\0\0\0"
1590     "\xff" "bar"    "\0\0\0\xff"    "\3\0\0\0"      "\xfe""baz"
1591     "\0\0\0\xff";
1592   const guint32 *strinfo = (guint32 *) array;
1593   guint length = sizeof array / 4;
1594   guint result;
1595
1596   {
1597     /* build it and compare */
1598     GString *builder;
1599
1600     builder = g_string_new (NULL);
1601     strinfo_builder_append_item (builder, "foo", 1);
1602     strinfo_builder_append_item (builder, "bar", 2);
1603     g_assert (strinfo_builder_append_alias (builder, "baz", "bar"));
1604     g_assert_cmpint (builder->len % 4, ==, 0);
1605     g_assert_cmpint (builder->len / 4, ==, length);
1606     g_assert (memcmp (builder->str, strinfo, length * 4) == 0);
1607     g_string_free (builder, TRUE);
1608   }
1609
1610   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "foo"),
1611                    ==, NULL);
1612   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "bar"),
1613                    ==, NULL);
1614   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "baz"),
1615                    ==, "bar");
1616   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "quux"),
1617                    ==, NULL);
1618
1619   g_assert (strinfo_enum_from_string (strinfo, length, "foo", &result));
1620   g_assert_cmpint (result, ==, 1);
1621   g_assert (strinfo_enum_from_string (strinfo, length, "bar", &result));
1622   g_assert_cmpint (result, ==, 2);
1623   g_assert (!strinfo_enum_from_string (strinfo, length, "baz", &result));
1624   g_assert (!strinfo_enum_from_string (strinfo, length, "quux", &result));
1625
1626   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 0), ==, NULL);
1627   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 1), ==, "foo");
1628   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 2), ==, "bar");
1629   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 3), ==, NULL);
1630
1631   g_assert (strinfo_is_string_valid (strinfo, length, "foo"));
1632   g_assert (strinfo_is_string_valid (strinfo, length, "bar"));
1633   g_assert (!strinfo_is_string_valid (strinfo, length, "baz"));
1634   g_assert (!strinfo_is_string_valid (strinfo, length, "quux"));
1635 }
1636
1637 static void
1638 test_enums (void)
1639 {
1640   GSettings *settings, *direct;
1641   gchar *str;
1642
1643   settings = g_settings_new ("org.gtk.test.enums");
1644   direct = g_settings_new ("org.gtk.test.enums.direct");
1645
1646   if (g_test_undefined () && !backend_set)
1647     {
1648       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1649         g_settings_get_enum (direct, "test");
1650       g_test_trap_assert_failed ();
1651       g_test_trap_assert_stderr ("*not associated with an enum*");
1652
1653       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1654         g_settings_set_enum (settings, "test", 42);
1655       g_test_trap_assert_failed ();
1656       g_test_trap_assert_stderr ("*invalid enum value 42*");
1657
1658       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1659         g_settings_set_string (settings, "test", "qux");
1660       g_test_trap_assert_failed ();
1661       g_test_trap_assert_stderr ("*g_settings_set_value*valid range*");
1662
1663       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1664         g_settings_get_flags (settings, "test");
1665       g_test_trap_assert_failed ();
1666       g_test_trap_assert_stderr ("*not associated with a flags*");
1667     }
1668
1669   str = g_settings_get_string (settings, "test");
1670   g_assert_cmpstr (str, ==, "bar");
1671   g_free (str);
1672
1673   g_settings_set_enum (settings, "test", TEST_ENUM_FOO);
1674
1675   str = g_settings_get_string (settings, "test");
1676   g_assert_cmpstr (str, ==, "foo");
1677   g_free (str);
1678
1679   g_assert_cmpint (g_settings_get_enum (settings, "test"), ==, TEST_ENUM_FOO);
1680
1681   g_settings_set_string (direct, "test", "qux");
1682
1683   str = g_settings_get_string (direct, "test");
1684   g_assert_cmpstr (str, ==, "qux");
1685   g_free (str);
1686
1687   str = g_settings_get_string (settings, "test");
1688   g_assert_cmpstr (str, ==, "quux");
1689   g_free (str);
1690
1691   g_assert_cmpint (g_settings_get_enum (settings, "test"), ==, TEST_ENUM_QUUX);
1692 }
1693
1694 static void
1695 test_flags (void)
1696 {
1697   GSettings *settings, *direct;
1698   gchar **strv;
1699   gchar *str;
1700
1701   settings = g_settings_new ("org.gtk.test.enums");
1702   direct = g_settings_new ("org.gtk.test.enums.direct");
1703
1704   if (g_test_undefined () && !backend_set)
1705     {
1706       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1707         g_settings_get_flags (direct, "test");
1708       g_test_trap_assert_failed ();
1709       g_test_trap_assert_stderr ("*not associated with a flags*");
1710
1711       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1712         g_settings_set_flags (settings, "f-test", 0x42);
1713       g_test_trap_assert_failed ();
1714       g_test_trap_assert_stderr ("*invalid flags value 0x00000042*");
1715
1716       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1717         g_settings_set_strv (settings, "f-test",
1718                              (const gchar **) g_strsplit ("rock", ",", 0));
1719       g_test_trap_assert_failed ();
1720       g_test_trap_assert_stderr ("*g_settings_set_value*valid range*");
1721
1722       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1723         g_settings_get_enum (settings, "f-test");
1724       g_test_trap_assert_failed ();
1725       g_test_trap_assert_stderr ("*not associated with an enum*");
1726     }
1727
1728   strv = g_settings_get_strv (settings, "f-test");
1729   str = g_strjoinv (",", strv);
1730   g_assert_cmpstr (str, ==, "");
1731   g_strfreev (strv);
1732   g_free (str);
1733
1734   g_settings_set_flags (settings, "f-test",
1735                         TEST_FLAGS_WALKING | TEST_FLAGS_TALKING);
1736
1737   strv = g_settings_get_strv (settings, "f-test");
1738   str = g_strjoinv (",", strv);
1739   g_assert_cmpstr (str, ==, "talking,walking");
1740   g_strfreev (strv);
1741   g_free (str);
1742
1743   g_assert_cmpint (g_settings_get_flags (settings, "f-test"), ==,
1744                    TEST_FLAGS_WALKING | TEST_FLAGS_TALKING);
1745
1746   strv = g_strsplit ("speaking,laughing", ",", 0);
1747   g_settings_set_strv (direct, "f-test", (const gchar **) strv);
1748   g_strfreev (strv);
1749
1750   strv = g_settings_get_strv (direct, "f-test");
1751   str = g_strjoinv (",", strv);
1752   g_assert_cmpstr (str, ==, "speaking,laughing");
1753   g_strfreev (strv);
1754   g_free (str);
1755
1756   strv = g_settings_get_strv (settings, "f-test");
1757   str = g_strjoinv (",", strv);
1758   g_assert_cmpstr (str, ==, "talking,laughing");
1759   g_strfreev (strv);
1760   g_free (str);
1761
1762   g_assert_cmpint (g_settings_get_flags (settings, "f-test"), ==,
1763                    TEST_FLAGS_TALKING | TEST_FLAGS_LAUGHING);
1764 }
1765
1766 static void
1767 test_range (void)
1768 {
1769   GSettings *settings, *direct;
1770   GVariant *value;
1771
1772   settings = g_settings_new ("org.gtk.test.range");
1773   direct = g_settings_new ("org.gtk.test.range.direct");
1774
1775   if (g_test_undefined () && !backend_set)
1776     {
1777       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1778         g_settings_set_int (settings, "val", 45);
1779       g_test_trap_assert_failed ();
1780       g_test_trap_assert_stderr ("*g_settings_set_value*valid range*");
1781
1782       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1783         g_settings_set_int (settings, "val", 1);
1784       g_test_trap_assert_failed ();
1785       g_test_trap_assert_stderr ("*g_settings_set_value*valid range*");
1786     }
1787
1788   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 33);
1789   g_settings_set_int (direct, "val", 22);
1790   g_assert_cmpint (g_settings_get_int (direct, "val"), ==, 22);
1791   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 22);
1792   g_settings_set_int (direct, "val", 45);
1793   g_assert_cmpint (g_settings_get_int (direct, "val"), ==, 45);
1794   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 33);
1795   g_settings_set_int (direct, "val", 1);
1796   g_assert_cmpint (g_settings_get_int (direct, "val"), ==, 1);
1797   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 33);
1798
1799   value = g_variant_new_int32 (1);
1800   g_assert (!g_settings_range_check (settings, "val", value));
1801   g_variant_unref (value);
1802   value = g_variant_new_int32 (33);
1803   g_assert (g_settings_range_check (settings, "val", value));
1804   g_variant_unref (value);
1805   value = g_variant_new_int32 (45);
1806   g_assert (!g_settings_range_check (settings, "val", value));
1807   g_variant_unref (value);
1808 }
1809
1810 static gboolean
1811 strv_has_string (gchar       **haystack,
1812                  const gchar  *needle)
1813 {
1814   guint n;
1815
1816   for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
1817     {
1818       if (g_strcmp0 (haystack[n], needle) == 0)
1819         return TRUE;
1820     }
1821   return FALSE;
1822 }
1823
1824 static gboolean
1825 strv_set_equal (gchar **strv, ...)
1826 {
1827   gint count;
1828   va_list list;
1829   const gchar *str;
1830   gboolean res;
1831
1832   res = TRUE;
1833   count = 0;
1834   va_start (list, strv);
1835   while (1)
1836     {
1837       str = va_arg (list, const gchar *);
1838       if (str == NULL)
1839         break;
1840       if (!strv_has_string (strv, str))
1841         {
1842           res = FALSE;
1843           break;
1844         }
1845       count++;
1846     }
1847   va_end (list);
1848
1849   if (res)
1850     res = g_strv_length ((gchar**)strv) == count;
1851
1852   return res;
1853 }
1854
1855 static void
1856 test_list_items (void)
1857 {
1858   GSettings *settings;
1859   gchar **children;
1860   gchar **keys;
1861
1862   settings = g_settings_new ("org.gtk.test");
1863   children = g_settings_list_children (settings);
1864   keys = g_settings_list_keys (settings);
1865
1866   g_assert (strv_set_equal (children, "basic-types", "complex-types", "localized", NULL));
1867   g_assert (strv_set_equal (keys, "greeting", "farewell", NULL));
1868
1869   g_strfreev (children);
1870   g_strfreev (keys);
1871
1872   g_object_unref (settings);
1873 }
1874
1875 static void
1876 test_list_schemas (void)
1877 {
1878   const gchar * const *schemas;
1879   const gchar * const *relocs;
1880
1881   relocs = g_settings_list_relocatable_schemas ();
1882   schemas = g_settings_list_schemas ();
1883
1884   g_assert (strv_set_equal ((gchar **)relocs,
1885                             "org.gtk.test.no-path",
1886                             NULL));
1887
1888   g_assert (strv_set_equal ((gchar **)schemas,
1889                             "org.gtk.test",
1890                             "org.gtk.test.basic-types",
1891                             "org.gtk.test.complex-types",
1892                             "org.gtk.test.localized",
1893                             "org.gtk.test.binding",
1894                             "org.gtk.test.enums",
1895                             "org.gtk.test.enums.direct",
1896                             "org.gtk.test.range",
1897                             "org.gtk.test.range.direct",
1898                             "org.gtk.test.mapped",
1899                             NULL));
1900 }
1901
1902 static gboolean
1903 map_func (GVariant *value,
1904           gpointer *result,
1905           gpointer  user_data)
1906 {
1907   gint *state = user_data;
1908   gint v;
1909
1910   if (value)
1911     v = g_variant_get_int32 (value);
1912   else
1913     v = -1;
1914
1915   if (*state == 0)
1916     {
1917       g_assert_cmpint (v, ==, 1);
1918       (*state)++;
1919       return FALSE;
1920     }
1921   else if (*state == 1)
1922     {
1923       g_assert_cmpint (v, ==, 0);
1924       (*state)++;
1925       return FALSE;
1926     }
1927   else
1928     {
1929       g_assert (value == NULL);
1930       *result = g_variant_new_int32 (5);
1931       return TRUE;
1932     }
1933 }
1934
1935 static void
1936 test_get_mapped (void)
1937 {
1938   GSettings *settings;
1939   gint state;
1940   gpointer p;
1941   gint val;
1942
1943   settings = g_settings_new ("org.gtk.test.mapped");
1944   g_settings_set_int (settings, "val", 1);
1945
1946   state = 0;
1947   p = g_settings_get_mapped (settings, "val", map_func, &state);
1948   val = g_variant_get_int32 ((GVariant*)p);
1949   g_assert_cmpint (val, ==, 5);
1950
1951   g_variant_unref (p);
1952   g_object_unref (settings);
1953 }
1954
1955 static void
1956 test_get_range (void)
1957 {
1958   GSettings *settings;
1959   GVariant *range;
1960
1961   settings = g_settings_new ("org.gtk.test.range");
1962   range = g_settings_get_range (settings, "val");
1963   check_and_free (range, "('range', <(2, 44)>)");
1964   g_object_unref (settings);
1965
1966   settings = g_settings_new ("org.gtk.test.enums");
1967   range = g_settings_get_range (settings, "test");
1968   check_and_free (range, "('enum', <['foo', 'bar', 'baz', 'quux']>)");
1969   g_object_unref (settings);
1970
1971   settings = g_settings_new ("org.gtk.test.enums");
1972   range = g_settings_get_range (settings, "f-test");
1973   check_and_free (range, "('flags', "
1974                   "<['mourning', 'laughing', 'talking', 'walking']>)");
1975   g_object_unref (settings);
1976
1977   settings = g_settings_new ("org.gtk.test");
1978   range = g_settings_get_range (settings, "greeting");
1979   check_and_free (range, "('type', <@as []>)");
1980   g_object_unref (settings);
1981 }
1982
1983 static void
1984 test_schema_source (void)
1985 {
1986   GSettingsSchemaSource *parent;
1987   GSettingsSchemaSource *source;
1988   GSettingsBackend *backend;
1989   GSettingsSchema *schema;
1990   GError *error = NULL;
1991   GSettings *settings;
1992   gboolean enabled;
1993
1994   backend = g_settings_backend_get_default ();
1995
1996   /* make sure it fails properly */
1997   parent = g_settings_schema_source_get_default ();
1998   source = g_settings_schema_source_new_from_directory ("/path/that/does/not/exist", parent,  TRUE, &error);
1999   g_assert (source == NULL);
2000   g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
2001   g_clear_error (&error);
2002
2003   /* create a source with the parent */
2004   source = g_settings_schema_source_new_from_directory ("schema-source", parent, TRUE, &error);
2005   g_assert_no_error (error);
2006   g_assert (source != NULL);
2007
2008   /* check recursive lookups are working */
2009   schema = g_settings_schema_source_lookup (source, "org.gtk.test", TRUE);
2010   g_assert (schema != NULL);
2011   g_settings_schema_unref (schema);
2012
2013   /* check recursive lookups for non-existent schemas */
2014   schema = g_settings_schema_source_lookup (source, "org.gtk.doesnotexist", TRUE);
2015   g_assert (schema == NULL);
2016
2017   /* check non-recursive for schema that only exists in lower layers */
2018   schema = g_settings_schema_source_lookup (source, "org.gtk.test", FALSE);
2019   g_assert (schema == NULL);
2020
2021   /* check non-recursive lookup for non-existent */
2022   schema = g_settings_schema_source_lookup (source, "org.gtk.doesnotexist", FALSE);
2023   g_assert (schema == NULL);
2024
2025   /* check non-recursive for schema that exists in toplevel */
2026   schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", FALSE);
2027   g_assert (schema != NULL);
2028   g_settings_schema_unref (schema);
2029
2030   /* check recursive for schema that exists in toplevel */
2031   schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", TRUE);
2032   g_assert (schema != NULL);
2033
2034   /* try to use it for something */
2035   settings = g_settings_new_full (schema, backend, g_settings_schema_get_path (schema));
2036   g_settings_schema_unref (schema);
2037   enabled = FALSE;
2038   g_settings_get (settings, "enabled", "b", &enabled);
2039   g_assert (enabled);
2040   g_object_unref (settings);
2041
2042   g_settings_schema_source_unref (source);
2043
2044   /* try again, but with no parent */
2045   source = g_settings_schema_source_new_from_directory ("schema-source", NULL, FALSE, NULL);
2046   g_assert (source != NULL);
2047
2048   /* should not find it this time, even if recursive... */
2049   schema = g_settings_schema_source_lookup (source, "org.gtk.test", FALSE);
2050   g_assert (schema == NULL);
2051   schema = g_settings_schema_source_lookup (source, "org.gtk.test", TRUE);
2052   g_assert (schema == NULL);
2053
2054   /* should still find our own... */
2055   schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", TRUE);
2056   g_assert (schema != NULL);
2057   g_settings_schema_unref (schema);
2058   schema = g_settings_schema_source_lookup (source, "org.gtk.schemasourcecheck", FALSE);
2059   g_assert (schema != NULL);
2060   g_settings_schema_unref (schema);
2061
2062   g_settings_schema_source_unref (source);
2063 }
2064
2065 static void
2066 test_actions (void)
2067 {
2068   GAction *string, *toggle;
2069   gboolean c1, c2, c3;
2070   GSettings *settings;
2071   gchar *name;
2072   GVariantType *param_type;
2073   gboolean enabled;
2074   GVariantType *state_type;
2075   GVariant *state;
2076
2077   settings = g_settings_new ("org.gtk.test.basic-types");
2078   string = g_settings_create_action (settings, "test-string");
2079   toggle = g_settings_create_action (settings, "test-boolean");
2080   g_object_unref (settings); /* should be held by the actions */
2081
2082   g_signal_connect (settings, "changed", G_CALLBACK (changed_cb2), &c1);
2083   g_signal_connect (string, "notify::state", G_CALLBACK (changed_cb2), &c2);
2084   g_signal_connect (toggle, "notify::state", G_CALLBACK (changed_cb2), &c3);
2085
2086   c1 = c2 = c3 = FALSE;
2087   g_settings_set_string (settings, "test-string", "hello world");
2088   check_and_free (g_action_get_state (string), "'hello world'");
2089   g_assert (c1 && c2 && !c3);
2090   c1 = c2 = c3 = FALSE;
2091
2092   g_action_activate (string, g_variant_new_string ("hihi"));
2093   check_and_free (g_settings_get_value (settings, "test-string"), "'hihi'");
2094   g_assert (c1 && c2 && !c3);
2095   c1 = c2 = c3 = FALSE;
2096
2097   g_action_change_state (string, g_variant_new_string ("kthxbye"));
2098   check_and_free (g_settings_get_value (settings, "test-string"), "'kthxbye'");
2099   g_assert (c1 && c2 && !c3);
2100   c1 = c2 = c3 = FALSE;
2101
2102   g_action_change_state (toggle, g_variant_new_boolean (TRUE));
2103   g_assert (g_settings_get_boolean (settings, "test-boolean"));
2104   g_assert (c1 && !c2 && c3);
2105   c1 = c2 = c3 = FALSE;
2106
2107   g_action_activate (toggle, NULL);
2108   g_assert (!g_settings_get_boolean (settings, "test-boolean"));
2109   g_assert (c1 && !c2 && c3);
2110
2111   g_object_get (string,
2112                 "name", &name,
2113                 "parameter-type", &param_type,
2114                 "enabled", &enabled,
2115                 "state-type", &state_type,
2116                 "state", &state,
2117                 NULL);
2118
2119   g_assert_cmpstr (name, ==, "test-string");
2120   g_assert (g_variant_type_equal (param_type, G_VARIANT_TYPE_STRING));
2121   g_assert (enabled);
2122   g_assert (g_variant_type_equal (state_type, G_VARIANT_TYPE_STRING));
2123   g_assert_cmpstr (g_variant_get_string (state, NULL), ==, "kthxbye");
2124
2125   g_free (name);
2126   g_variant_unref (state);
2127
2128   g_object_unref (string);
2129   g_object_unref (toggle);
2130 }
2131
2132 int
2133 main (int argc, char *argv[])
2134 {
2135   gchar *enums;
2136   gint result;
2137
2138   setlocale (LC_ALL, "");
2139
2140   backend_set = g_getenv ("GSETTINGS_BACKEND") != NULL;
2141
2142   g_setenv ("XDG_DATA_DIRS", ".", TRUE);
2143   g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
2144
2145   if (!backend_set)
2146     g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
2147
2148   g_type_init ();
2149   g_test_init (&argc, &argv, NULL);
2150
2151   g_remove ("org.gtk.test.enums.xml");
2152   g_assert (g_spawn_command_line_sync ("../../gobject/glib-mkenums "
2153                                        "--template " SRCDIR "/enums.xml.template "
2154                                        SRCDIR "/testenum.h",
2155                                        &enums, NULL, &result, NULL));
2156   g_assert (result == 0);
2157   g_assert (g_file_set_contents ("org.gtk.test.enums.xml", enums, -1, NULL));
2158   g_free (enums);
2159
2160   g_remove ("gschemas.compiled");
2161   g_assert (g_spawn_command_line_sync ("../glib-compile-schemas --targetdir=. "
2162                                        "--schema-file=org.gtk.test.enums.xml "
2163                                        "--schema-file=" SRCDIR "/org.gtk.test.gschema.xml",
2164                                        NULL, NULL, &result, NULL));
2165   g_assert (result == 0);
2166
2167   g_remove ("schema-source/gschemas.compiled");
2168   g_mkdir ("schema-source", 0777);
2169   g_assert (g_spawn_command_line_sync ("../glib-compile-schemas --targetdir=schema-source "
2170                                        "--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml",
2171                                        NULL, NULL, &result, NULL));
2172   g_assert (result == 0);
2173
2174   g_test_add_func ("/gsettings/basic", test_basic);
2175
2176   if (!backend_set)
2177     {
2178       g_test_add_func ("/gsettings/no-schema", test_no_schema);
2179       g_test_add_func ("/gsettings/unknown-key", test_unknown_key);
2180       g_test_add_func ("/gsettings/wrong-type", test_wrong_type);
2181       g_test_add_func ("/gsettings/wrong-path", test_wrong_path);
2182       g_test_add_func ("/gsettings/no-path", test_no_path);
2183     }
2184
2185   g_test_add_func ("/gsettings/basic-types", test_basic_types);
2186   g_test_add_func ("/gsettings/complex-types", test_complex_types);
2187   g_test_add_func ("/gsettings/changes", test_changes);
2188
2189   if (glib_translations_work ())
2190     {
2191       g_test_add_func ("/gsettings/l10n", test_l10n);
2192       g_test_add_func ("/gsettings/l10n-context", test_l10n_context);
2193     }
2194
2195   g_test_add_func ("/gsettings/delay-apply", test_delay_apply);
2196   g_test_add_func ("/gsettings/delay-revert", test_delay_revert);
2197   g_test_add_func ("/gsettings/atomic", test_atomic);
2198
2199   g_test_add_func ("/gsettings/simple-binding", test_simple_binding);
2200   g_test_add_func ("/gsettings/directional-binding", test_directional_binding);
2201   g_test_add_func ("/gsettings/custom-binding", test_custom_binding);
2202   g_test_add_func ("/gsettings/no-change-binding", test_no_change_binding);
2203   g_test_add_func ("/gsettings/unbinding", test_unbind);
2204   g_test_add_func ("/gsettings/writable-binding", test_bind_writable);
2205
2206   if (!backend_set)
2207     {
2208       g_test_add_func ("/gsettings/typesafe-binding", test_typesafe_binding);
2209       g_test_add_func ("/gsettings/no-read-binding", test_no_read_binding);
2210       g_test_add_func ("/gsettings/no-write-binding", test_no_write_binding);
2211     }
2212
2213   g_test_add_func ("/gsettings/keyfile", test_keyfile);
2214   g_test_add_func ("/gsettings/child-schema", test_child_schema);
2215   g_test_add_func ("/gsettings/strinfo", test_strinfo);
2216   g_test_add_func ("/gsettings/enums", test_enums);
2217   g_test_add_func ("/gsettings/flags", test_flags);
2218   g_test_add_func ("/gsettings/range", test_range);
2219   g_test_add_func ("/gsettings/list-items", test_list_items);
2220   g_test_add_func ("/gsettings/list-schemas", test_list_schemas);
2221   g_test_add_func ("/gsettings/mapped", test_get_mapped);
2222   g_test_add_func ("/gsettings/get-range", test_get_range);
2223   g_test_add_func ("/gsettings/schema-source", test_schema_source);
2224   g_test_add_func ("/gsettings/actions", test_actions);
2225
2226   result = g_test_run ();
2227
2228   g_settings_sync ();
2229
2230   return result;
2231 }