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