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