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