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