Plug a mem leak in gsettings test
[platform/upstream/glib.git] / gio / tests / gsettings.c
1 #include <stdlib.h>
2 #include <locale.h>
3 #include <libintl.h>
4 #include <gio/gio.h>
5 #include <gstdio.h>
6 #define G_SETTINGS_ENABLE_BACKEND
7 #include <gio/gsettingsbackend.h>
8
9 #include "testenum.h"
10
11 static gboolean backend_set;
12
13 /* These tests rely on the schemas in org.gtk.test.gschema.xml
14  * to be compiled and installed in the same directory.
15  */
16
17 /* Just to get warmed up: Read and set a string, and
18  * verify that can read the changed string back
19  */
20 static void
21 test_basic (void)
22 {
23   gchar *str = NULL;
24   GSettings *settings;
25
26   settings = g_settings_new ("org.gtk.test");
27
28   g_object_get (settings, "schema", &str, NULL);
29   g_assert_cmpstr (str, ==, "org.gtk.test");
30   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   gint64 i64;
946   guint64 u64;
947   gdouble d;
948   gchar *s;
949   GVariant *value;
950   gchar **strv;
951
952   settings = g_settings_new ("org.gtk.test.binding");
953   obj = test_object_new ();
954
955   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_DEFAULT);
956   g_object_set (obj, "bool", TRUE, NULL);
957   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
958
959   g_settings_set_boolean (settings, "bool", FALSE);
960   b = TRUE;
961   g_object_get (obj, "bool", &b, NULL);
962   g_assert_cmpint (b, ==, FALSE);
963
964   g_settings_bind (settings, "anti-bool", obj, "anti-bool",
965                    G_SETTINGS_BIND_INVERT_BOOLEAN);
966   g_object_set (obj, "anti-bool", FALSE, NULL);
967   g_assert_cmpint (g_settings_get_boolean (settings, "anti-bool"), ==, TRUE);
968
969   g_settings_set_boolean (settings, "anti-bool", FALSE);
970   b = FALSE;
971   g_object_get (obj, "anti-bool", &b, NULL);
972   g_assert_cmpint (b, ==, TRUE);
973
974   g_settings_bind (settings, "byte", obj, "byte", G_SETTINGS_BIND_DEFAULT);
975
976   g_object_set (obj, "byte", 123, NULL);
977   y = 'c';
978   g_settings_get (settings, "byte", "y", &y);
979   g_assert_cmpint (y, ==, 123);
980
981   g_settings_set (settings, "byte", "y", 54);
982   y = 'c';
983   g_object_get (obj, "byte", &y, NULL);
984   g_assert_cmpint (y, ==, 54);
985
986   g_settings_bind (settings, "int16", obj, "int16", G_SETTINGS_BIND_DEFAULT);
987
988   g_object_set (obj, "int16", 1234, NULL);
989   n = 4321;
990   g_settings_get (settings, "int16", "n", &n);
991   g_assert_cmpint (n, ==, 1234);
992
993   g_settings_set (settings, "int16", "n", 4321);
994   n = 1111;
995   g_object_get (obj, "int16", &n, NULL);
996   g_assert_cmpint (n, ==, 4321);
997
998   g_settings_bind (settings, "uint16", obj, "uint16", G_SETTINGS_BIND_DEFAULT);
999
1000   g_object_set (obj, "uint16", (guint16) G_MAXUINT16, NULL);
1001   q = 1111;
1002   g_settings_get (settings, "uint16", "q", &q);
1003   g_assert_cmpuint (q, ==, G_MAXUINT16);
1004
1005   g_settings_set (settings, "uint16", "q", (guint16) G_MAXINT16);
1006   q = 1111;
1007   g_object_get (obj, "uint16", &q, NULL);
1008   g_assert_cmpuint (q, ==, (guint16) G_MAXINT16);
1009
1010   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
1011
1012   g_object_set (obj, "int", 12345, NULL);
1013   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
1014
1015   g_settings_set_int (settings, "int", 54321);
1016   i = 1111;
1017   g_object_get (obj, "int", &i, NULL);
1018   g_assert_cmpint (i, ==, 54321);
1019
1020   g_settings_bind (settings, "int64", obj, "int64", G_SETTINGS_BIND_DEFAULT);
1021
1022   g_object_set (obj, "int64", (gint64) G_MAXINT64, NULL);
1023   i64 = 1111;
1024   g_settings_get (settings, "int64", "x", &i64);
1025   g_assert_cmpint (i64, ==, G_MAXINT64);
1026
1027   g_settings_set (settings, "int64", "x", (gint64) G_MININT64);
1028   i64 = 1111;
1029   g_object_get (obj, "int64", &i64, NULL);
1030   g_assert_cmpint (i64, ==, G_MININT64);
1031
1032   g_settings_bind (settings, "uint64", obj, "uint64", G_SETTINGS_BIND_DEFAULT);
1033
1034   g_object_set (obj, "uint64", (guint64) G_MAXUINT64, NULL);
1035   u64 = 1111;
1036   g_settings_get (settings, "uint64", "t", &u64);
1037   g_assert_cmpuint (u64, ==, G_MAXUINT64);
1038
1039   g_settings_set (settings, "uint64", "t", (guint64) G_MAXINT64);
1040   u64 = 1111;
1041   g_object_get (obj, "uint64", &u64, NULL);
1042   g_assert_cmpuint (u64, ==, (guint64) G_MAXINT64);
1043
1044   g_settings_bind (settings, "string", obj, "string", G_SETTINGS_BIND_DEFAULT);
1045
1046   g_object_set (obj, "string", "bu ba", NULL);
1047   s = g_settings_get_string (settings, "string");
1048   g_assert_cmpstr (s, ==, "bu ba");
1049   g_free (s);
1050
1051   g_settings_set_string (settings, "string", "bla bla");
1052   g_object_get (obj, "string", &s, NULL);
1053   g_assert_cmpstr (s, ==, "bla bla");
1054   g_free (s);
1055
1056   g_settings_bind (settings, "chararray", obj, "string", G_SETTINGS_BIND_DEFAULT);
1057
1058   g_object_set (obj, "string", "non-unicode:\315", NULL);
1059   value = g_settings_get_value (settings, "chararray");
1060   g_assert_cmpstr (g_variant_get_bytestring (value), ==, "non-unicode:\315");
1061   g_variant_unref (value);
1062
1063   g_settings_bind (settings, "double", obj, "double", G_SETTINGS_BIND_DEFAULT);
1064
1065   g_object_set (obj, "double", G_MAXFLOAT, NULL);
1066   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXFLOAT);
1067
1068   g_settings_set_double (settings, "double", G_MINFLOAT);
1069   d = 1.0;
1070   g_object_get (obj, "double", &d, NULL);
1071   g_assert_cmpfloat (d, ==, G_MINFLOAT);
1072
1073   g_object_set (obj, "double", G_MAXDOUBLE, NULL);
1074   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXDOUBLE);
1075
1076   g_settings_set_double (settings, "double", -G_MINDOUBLE);
1077   d = 1.0;
1078   g_object_get (obj, "double", &d, NULL);
1079   g_assert_cmpfloat (d, ==, -G_MINDOUBLE);
1080
1081   strv = g_strsplit ("plastic bag,middle class,polyethylene", ",", 0);
1082   g_settings_bind (settings, "strv", obj, "strv", G_SETTINGS_BIND_DEFAULT);
1083   g_object_set (obj, "strv", strv, NULL);
1084   g_strfreev (strv);
1085   strv = g_settings_get_strv (settings, "strv");
1086   s = g_strjoinv (",", strv);
1087   g_assert_cmpstr (s, ==, "plastic bag,middle class,polyethylene");
1088   g_strfreev (strv);
1089   g_free (s);
1090   strv = g_strsplit ("decaffeinate,unleaded,keep all surfaces clean", ",", 0);
1091   g_settings_set_strv (settings, "strv", (const gchar **) strv);
1092   g_strfreev (strv);
1093   g_object_get (obj, "strv", &strv, NULL);
1094   s = g_strjoinv (",", strv);
1095   g_assert_cmpstr (s, ==, "decaffeinate,unleaded,keep all surfaces clean");
1096   g_strfreev (strv);
1097   g_free (s);
1098
1099   g_settings_bind (settings, "enum", obj, "enum", G_SETTINGS_BIND_DEFAULT);
1100   g_object_set (obj, "enum", TEST_ENUM_BAZ, NULL);
1101   s = g_settings_get_string (settings, "enum");
1102   g_assert_cmpstr (s, ==, "baz");
1103   g_free (s);
1104   g_assert_cmpint (g_settings_get_enum (settings, "enum"), ==, TEST_ENUM_BAZ);
1105
1106   g_settings_set_enum (settings, "enum", TEST_ENUM_QUUX);
1107   i = 230;
1108   g_object_get (obj, "enum", &i, NULL);
1109   g_assert_cmpint (i, ==, TEST_ENUM_QUUX);
1110
1111   g_settings_set_string (settings, "enum", "baz");
1112   i = 230;
1113   g_object_get (obj, "enum", &i, NULL);
1114   g_assert_cmpint (i, ==, TEST_ENUM_BAZ);
1115
1116   g_object_unref (obj);
1117   g_object_unref (settings);
1118 }
1119
1120 static void
1121 test_unbind (void)
1122 {
1123   TestObject *obj;
1124   GSettings *settings;
1125
1126   settings = g_settings_new ("org.gtk.test.binding");
1127   obj = test_object_new ();
1128
1129   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
1130
1131   g_object_set (obj, "int", 12345, NULL);
1132   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
1133
1134   g_settings_unbind (obj, "int");
1135
1136   g_object_set (obj, "int", 54321, NULL);
1137   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
1138
1139   g_object_unref (obj);
1140   g_object_unref (settings);
1141 }
1142
1143 static void
1144 test_bind_writable (void)
1145 {
1146   TestObject *obj;
1147   GSettings *settings;
1148   gboolean b;
1149
1150   settings = g_settings_new ("org.gtk.test.binding");
1151   obj = test_object_new ();
1152
1153   g_object_set (obj, "bool", FALSE, NULL);
1154
1155   g_settings_bind_writable (settings, "int", obj, "bool", FALSE);
1156
1157   g_object_get (obj, "bool", &b, NULL);
1158   g_assert (b);
1159
1160   g_settings_unbind (obj, "bool");
1161
1162   g_settings_bind_writable (settings, "int", obj, "bool", TRUE);
1163
1164   g_object_get (obj, "bool", &b, NULL);
1165   g_assert (!b);
1166
1167   g_object_unref (obj);
1168   g_object_unref (settings);
1169 }
1170
1171 /* Test one-way bindings.
1172  * Verify that changes on one side show up on the other,
1173  * but not vice versa
1174  */
1175 static void
1176 test_directional_binding (void)
1177 {
1178   TestObject *obj;
1179   GSettings *settings;
1180   gboolean b;
1181   gint i;
1182
1183   settings = g_settings_new ("org.gtk.test.binding");
1184   obj = test_object_new ();
1185
1186   g_object_set (obj, "bool", FALSE, NULL);
1187   g_settings_set_boolean (settings, "bool", FALSE);
1188
1189   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET);
1190
1191   g_settings_set_boolean (settings, "bool", TRUE);
1192   g_object_get (obj, "bool", &b, NULL);
1193   g_assert_cmpint (b, ==, TRUE);
1194
1195   g_object_set (obj, "bool", FALSE, NULL);
1196   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
1197
1198   g_object_set (obj, "int", 20, NULL);
1199   g_settings_set_int (settings, "int", 20);
1200
1201   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_SET);
1202
1203   g_object_set (obj, "int", 32, NULL);
1204   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 32);
1205
1206   g_settings_set_int (settings, "int", 20);
1207   g_object_get (obj, "int", &i, NULL);
1208   g_assert_cmpint (i, ==, 32);
1209
1210   g_object_unref (obj);
1211   g_object_unref (settings);
1212 }
1213
1214 /* Test that type mismatch is caught when creating a binding
1215  */
1216 static void
1217 test_typesafe_binding (void)
1218 {
1219   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1220     {
1221       TestObject *obj;
1222       GSettings *settings;
1223
1224       settings = g_settings_new ("org.gtk.test.binding");
1225       obj = test_object_new ();
1226
1227       g_settings_bind (settings, "string", obj, "int", G_SETTINGS_BIND_DEFAULT);
1228
1229       g_object_unref (obj);
1230       g_object_unref (settings);
1231     }
1232   g_test_trap_assert_failed ();
1233   g_test_trap_assert_stderr ("*not compatible*");
1234 }
1235
1236 static gboolean
1237 string_to_bool (GValue   *value,
1238                 GVariant *variant,
1239                 gpointer  user_data)
1240 {
1241   const gchar *s;
1242
1243   s = g_variant_get_string (variant, NULL);
1244   g_value_set_boolean (value, g_strcmp0 (s, "true") == 0);
1245
1246   return TRUE;
1247 }
1248
1249 static GVariant *
1250 bool_to_string (const GValue       *value,
1251                 const GVariantType *expected_type,
1252                 gpointer            user_data)
1253 {
1254   if (g_value_get_boolean (value))
1255     return g_variant_new_string ("true");
1256   else
1257     return g_variant_new_string ("false");
1258 }
1259
1260 /* Test custom bindings.
1261  * Translate strings to booleans and back
1262  */
1263 static void
1264 test_custom_binding (void)
1265 {
1266   TestObject *obj;
1267   GSettings *settings;
1268   gchar *s;
1269   gboolean b;
1270
1271   settings = g_settings_new ("org.gtk.test.binding");
1272   obj = test_object_new ();
1273
1274   g_settings_set_string (settings, "string", "true");
1275
1276   g_settings_bind_with_mapping (settings, "string",
1277                                 obj, "bool",
1278                                 G_SETTINGS_BIND_DEFAULT,
1279                                 string_to_bool,
1280                                 bool_to_string,
1281                                 NULL, NULL);
1282
1283   g_settings_set_string (settings, "string", "false");
1284   g_object_get (obj, "bool", &b, NULL);
1285   g_assert_cmpint (b, ==, FALSE);
1286
1287   g_settings_set_string (settings, "string", "not true");
1288   g_object_get (obj, "bool", &b, NULL);
1289   g_assert_cmpint (b, ==, FALSE);
1290
1291   g_object_set (obj, "bool", TRUE, NULL);
1292   s = g_settings_get_string (settings, "string");
1293   g_assert_cmpstr (s, ==, "true");
1294   g_free (s);
1295
1296   g_object_unref (obj);
1297   g_object_unref (settings);
1298 }
1299
1300 /* Test that with G_SETTINGS_BIND_NO_CHANGES, the
1301  * initial settings value is transported to the object
1302  * side, but later settings changes do not affect the
1303  * object
1304  */
1305 static void
1306 test_no_change_binding (void)
1307 {
1308   TestObject *obj;
1309   GSettings *settings;
1310   gboolean b;
1311
1312   settings = g_settings_new ("org.gtk.test.binding");
1313   obj = test_object_new ();
1314
1315   g_object_set (obj, "bool", TRUE, NULL);
1316   g_settings_set_boolean (settings, "bool", FALSE);
1317
1318   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET_NO_CHANGES);
1319
1320   g_object_get (obj, "bool", &b, NULL);
1321   g_assert_cmpint (b, ==, FALSE);
1322
1323   g_settings_set_boolean (settings, "bool", TRUE);
1324   g_object_get (obj, "bool", &b, NULL);
1325   g_assert_cmpint (b, ==, FALSE);
1326
1327   g_settings_set_boolean (settings, "bool", FALSE);
1328   g_object_set (obj, "bool", TRUE, NULL);
1329   b = g_settings_get_boolean (settings, "bool");
1330   g_assert_cmpint (b, ==, TRUE);
1331
1332   g_object_unref (obj);
1333   g_object_unref (settings);
1334 }
1335
1336 /* Test that binding a non-readable property only
1337  * works in 'GET' mode.
1338  */
1339 static void
1340 test_no_read_binding (void)
1341 {
1342   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1343     {
1344       TestObject *obj;
1345       GSettings *settings;
1346
1347       settings = g_settings_new ("org.gtk.test.binding");
1348       obj = test_object_new ();
1349
1350       g_settings_bind (settings, "string", obj, "no-read", 0);
1351     }
1352   g_test_trap_assert_failed ();
1353   g_test_trap_assert_stderr ("*property*is not readable*");
1354
1355   if (g_test_trap_fork (0, 0))
1356     {
1357       TestObject *obj;
1358       GSettings *settings;
1359
1360       settings = g_settings_new ("org.gtk.test.binding");
1361       obj = test_object_new ();
1362
1363       g_settings_bind (settings, "string", obj, "no-read", G_SETTINGS_BIND_GET);
1364
1365       exit (0);
1366     }
1367   g_test_trap_assert_passed ();
1368 }
1369
1370 /* Test that binding a non-writable property only
1371  * works in 'SET' mode.
1372  */
1373 static void
1374 test_no_write_binding (void)
1375 {
1376   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1377     {
1378       TestObject *obj;
1379       GSettings *settings;
1380
1381       settings = g_settings_new ("org.gtk.test.binding");
1382       obj = test_object_new ();
1383
1384       g_settings_bind (settings, "string", obj, "no-write", 0);
1385     }
1386   g_test_trap_assert_failed ();
1387   g_test_trap_assert_stderr ("*property*is not writable*");
1388
1389   if (g_test_trap_fork (0, 0))
1390     {
1391       TestObject *obj;
1392       GSettings *settings;
1393
1394       settings = g_settings_new ("org.gtk.test.binding");
1395       obj = test_object_new ();
1396
1397       g_settings_bind (settings, "string", obj, "no-write", G_SETTINGS_BIND_SET);
1398
1399       exit (0);
1400     }
1401   g_test_trap_assert_passed ();
1402 }
1403
1404 /*
1405  * Test that using a keyfile works
1406  */
1407 static void
1408 test_keyfile (void)
1409 {
1410   GSettingsBackend *kf_backend;
1411   GSettings *settings;
1412   GKeyFile *keyfile;
1413   gchar *str;
1414
1415   g_remove ("gsettings.store");
1416
1417   kf_backend = g_keyfile_settings_backend_new ("gsettings.store", "/", "root");
1418   settings = g_settings_new_with_backend ("org.gtk.test", kf_backend);
1419   g_object_unref (kf_backend);
1420
1421   g_settings_set (settings, "greeting", "s", "see if this works");
1422
1423   keyfile = g_key_file_new ();
1424   g_assert (g_key_file_load_from_file (keyfile, "gsettings.store", 0, NULL));
1425
1426   str = g_key_file_get_string (keyfile, "tests", "greeting", NULL);
1427   g_assert_cmpstr (str, ==, "'see if this works'");
1428
1429   g_free (str);
1430   g_key_file_free (keyfile);
1431   g_object_unref (settings);
1432 }
1433
1434 /* Test that getting child schemas works
1435  */
1436 static void
1437 test_child_schema (void)
1438 {
1439   GSettings *settings;
1440   GSettings *child;
1441   guint8 byte;
1442
1443   /* first establish some known conditions */
1444   settings = g_settings_new ("org.gtk.test.basic-types");
1445   g_settings_set (settings, "test-byte", "y", 36);
1446
1447   g_settings_get (settings, "test-byte", "y", &byte);
1448   g_assert_cmpint (byte, ==, 36);
1449
1450   g_object_unref (settings);
1451
1452   settings = g_settings_new ("org.gtk.test");
1453   child = g_settings_get_child (settings, "basic-types");
1454   g_assert (child != NULL);
1455
1456   g_settings_get (child, "test-byte", "y", &byte);
1457   g_assert_cmpint (byte, ==, 36);
1458
1459   g_object_unref (child);
1460   g_object_unref (settings);
1461 }
1462
1463 static gboolean
1464 glib_translations_work (void)
1465 {
1466   gchar *locale;
1467   gchar *orig = "Unnamed";
1468   gchar *str;
1469
1470   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
1471   setlocale (LC_MESSAGES, "de");
1472   str = dgettext ("glib20", orig);
1473   setlocale (LC_MESSAGES, locale);
1474   g_free (locale);
1475
1476   return str != orig;
1477 }
1478
1479 #include "../strinfo.c"
1480
1481 static void
1482 test_strinfo (void)
1483 {
1484   /*  "foo" has a value of 1
1485    *  "bar" has a value of 2
1486    *  "baz" is an alias for "bar"
1487    */
1488   gchar array[] =
1489     "\1\0\0\0"      "\xff""foo"     "\0\0\0\xff"    "\2\0\0\0"
1490     "\xff" "bar"    "\0\0\0\xff"    "\3\0\0\0"      "\xfe""baz"
1491     "\0\0\0\xff";
1492   const guint32 *strinfo = (guint32 *) array;
1493   guint length = sizeof array / 4;
1494   guint result;
1495
1496   {
1497     /* build it and compare */
1498     GString *builder;
1499
1500     builder = g_string_new (NULL);
1501     strinfo_builder_append_item (builder, "foo", 1);
1502     strinfo_builder_append_item (builder, "bar", 2);
1503     g_assert (strinfo_builder_append_alias (builder, "baz", "bar"));
1504     g_assert_cmpint (builder->len % 4, ==, 0);
1505     g_assert_cmpint (builder->len / 4, ==, length);
1506     g_assert (memcmp (builder->str, strinfo, length * 4) == 0);
1507     g_string_free (builder, TRUE);
1508   }
1509
1510   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "foo"),
1511                    ==, NULL);
1512   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "bar"),
1513                    ==, NULL);
1514   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "baz"),
1515                    ==, "bar");
1516   g_assert_cmpstr (strinfo_string_from_alias (strinfo, length, "quux"),
1517                    ==, NULL);
1518
1519   g_assert (strinfo_enum_from_string (strinfo, length, "foo", &result));
1520   g_assert_cmpint (result, ==, 1);
1521   g_assert (strinfo_enum_from_string (strinfo, length, "bar", &result));
1522   g_assert_cmpint (result, ==, 2);
1523   g_assert (!strinfo_enum_from_string (strinfo, length, "baz", &result));
1524   g_assert (!strinfo_enum_from_string (strinfo, length, "quux", &result));
1525
1526   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 0), ==, NULL);
1527   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 1), ==, "foo");
1528   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 2), ==, "bar");
1529   g_assert_cmpstr (strinfo_string_from_enum (strinfo, length, 3), ==, NULL);
1530
1531   g_assert (strinfo_is_string_valid (strinfo, length, "foo"));
1532   g_assert (strinfo_is_string_valid (strinfo, length, "bar"));
1533   g_assert (!strinfo_is_string_valid (strinfo, length, "baz"));
1534   g_assert (!strinfo_is_string_valid (strinfo, length, "quux"));
1535 }
1536
1537 static void
1538 test_enums (void)
1539 {
1540   GSettings *settings, *direct;
1541   gchar *str;
1542
1543   settings = g_settings_new ("org.gtk.test.enums");
1544   direct = g_settings_new ("org.gtk.test.enums.direct");
1545
1546   if (!backend_set)
1547     {
1548       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1549         g_settings_get_enum (direct, "test");
1550       g_test_trap_assert_failed ();
1551       g_test_trap_assert_stderr ("*not associated with an enum*");
1552
1553       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1554         g_settings_set_enum (settings, "test", 42);
1555       g_test_trap_assert_failed ();
1556       g_test_trap_assert_stderr ("*invalid enum value 42*");
1557
1558       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1559         g_settings_set_string (settings, "test", "qux");
1560       g_test_trap_assert_failed ();
1561       g_test_trap_assert_stderr ("*g_settings_range_check*");
1562
1563       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1564         g_settings_get_flags (settings, "test");
1565       g_test_trap_assert_failed ();
1566       g_test_trap_assert_stderr ("*not associated with a flags*");
1567     }
1568
1569   str = g_settings_get_string (settings, "test");
1570   g_assert_cmpstr (str, ==, "bar");
1571   g_free (str);
1572
1573   g_settings_set_enum (settings, "test", TEST_ENUM_FOO);
1574
1575   str = g_settings_get_string (settings, "test");
1576   g_assert_cmpstr (str, ==, "foo");
1577   g_free (str);
1578
1579   g_assert_cmpint (g_settings_get_enum (settings, "test"), ==, TEST_ENUM_FOO);
1580
1581   g_settings_set_string (direct, "test", "qux");
1582
1583   str = g_settings_get_string (direct, "test");
1584   g_assert_cmpstr (str, ==, "qux");
1585   g_free (str);
1586
1587   str = g_settings_get_string (settings, "test");
1588   g_assert_cmpstr (str, ==, "quux");
1589   g_free (str);
1590
1591   g_assert_cmpint (g_settings_get_enum (settings, "test"), ==, TEST_ENUM_QUUX);
1592 }
1593
1594 static void
1595 test_flags (void)
1596 {
1597   GSettings *settings, *direct;
1598   gchar **strv;
1599   gchar *str;
1600
1601   settings = g_settings_new ("org.gtk.test.enums");
1602   direct = g_settings_new ("org.gtk.test.enums.direct");
1603
1604   if (!backend_set)
1605     {
1606       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1607         g_settings_get_flags (direct, "test");
1608       g_test_trap_assert_failed ();
1609       g_test_trap_assert_stderr ("*not associated with a flags*");
1610
1611       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1612         g_settings_set_flags (settings, "f-test", 0x42);
1613       g_test_trap_assert_failed ();
1614       g_test_trap_assert_stderr ("*invalid flags value 0x00000042*");
1615
1616       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1617         g_settings_set_strv (settings, "f-test",
1618                              (const gchar **) g_strsplit ("rock", ",", 0));
1619       g_test_trap_assert_failed ();
1620       g_test_trap_assert_stderr ("*g_settings_range_check*");
1621
1622       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1623         g_settings_get_enum (settings, "f-test");
1624       g_test_trap_assert_failed ();
1625       g_test_trap_assert_stderr ("*not associated with an enum*");
1626     }
1627
1628   strv = g_settings_get_strv (settings, "f-test");
1629   str = g_strjoinv (",", strv);
1630   g_assert_cmpstr (str, ==, "");
1631   g_strfreev (strv);
1632   g_free (str);
1633
1634   g_settings_set_flags (settings, "f-test",
1635                         TEST_FLAGS_WALKING | TEST_FLAGS_TALKING);
1636
1637   strv = g_settings_get_strv (settings, "f-test");
1638   str = g_strjoinv (",", strv);
1639   g_assert_cmpstr (str, ==, "talking,walking");
1640   g_strfreev (strv);
1641   g_free (str);
1642
1643   g_assert_cmpint (g_settings_get_flags (settings, "f-test"), ==,
1644                    TEST_FLAGS_WALKING | TEST_FLAGS_TALKING);
1645
1646   strv = g_strsplit ("speaking,laughing", ",", 0);
1647   g_settings_set_strv (direct, "f-test", (const gchar **) strv);
1648   g_strfreev (strv);
1649
1650   strv = g_settings_get_strv (direct, "f-test");
1651   str = g_strjoinv (",", strv);
1652   g_assert_cmpstr (str, ==, "speaking,laughing");
1653   g_strfreev (strv);
1654   g_free (str);
1655
1656   strv = g_settings_get_strv (settings, "f-test");
1657   str = g_strjoinv (",", strv);
1658   g_assert_cmpstr (str, ==, "talking,laughing");
1659   g_strfreev (strv);
1660   g_free (str);
1661
1662   g_assert_cmpint (g_settings_get_flags (settings, "f-test"), ==,
1663                    TEST_FLAGS_TALKING | TEST_FLAGS_LAUGHING);
1664 }
1665
1666 static void
1667 test_range (void)
1668 {
1669   GSettings *settings, *direct;
1670
1671   settings = g_settings_new ("org.gtk.test.range");
1672   direct = g_settings_new ("org.gtk.test.range.direct");
1673
1674   if (!backend_set)
1675     {
1676       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1677         g_settings_set_int (settings, "val", 45);
1678       g_test_trap_assert_failed ();
1679       g_test_trap_assert_stderr ("*g_settings_range_check*");
1680
1681       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1682         g_settings_set_int (settings, "val", 1);
1683       g_test_trap_assert_failed ();
1684       g_test_trap_assert_stderr ("*g_settings_range_check*");
1685     }
1686
1687   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 33);
1688   g_settings_set_int (direct, "val", 22);
1689   g_assert_cmpint (g_settings_get_int (direct, "val"), ==, 22);
1690   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 22);
1691   g_settings_set_int (direct, "val", 45);
1692   g_assert_cmpint (g_settings_get_int (direct, "val"), ==, 45);
1693   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 33);
1694   g_settings_set_int (direct, "val", 1);
1695   g_assert_cmpint (g_settings_get_int (direct, "val"), ==, 1);
1696   g_assert_cmpint (g_settings_get_int (settings, "val"), ==, 33);
1697 }
1698
1699 static gboolean
1700 strv_has_string (const gchar **haystack,
1701                  const gchar  *needle)
1702 {
1703   guint n;
1704
1705   for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
1706     {
1707       if (g_strcmp0 (haystack[n], needle) == 0)
1708         return TRUE;
1709     }
1710   return FALSE;
1711 }
1712
1713 static gboolean
1714 strv_set_equal (const gchar **strv, ...)
1715 {
1716   gint count;
1717   va_list list;
1718   const gchar *str;
1719   gboolean res;
1720
1721   res = TRUE;
1722   count = 0;
1723   va_start (list, strv);
1724   while (1)
1725     {
1726       str = va_arg (list, const gchar *);
1727       if (str == NULL)
1728         break;
1729       if (!strv_has_string (strv, str))
1730         {
1731           res = FALSE;
1732           break;
1733         }
1734       count++;
1735     }
1736   va_end (list);
1737
1738   if (res)
1739     res = g_strv_length ((gchar**)strv) == count;
1740
1741   return res;
1742 }
1743
1744 static void
1745 test_list_items (void)
1746 {
1747   GSettings *settings;
1748   const gchar **items;
1749
1750   settings = g_settings_new ("org.gtk.test");
1751   items = g_settings_list_items (settings);
1752
1753   g_assert (strv_set_equal (items, "greeting", "farewell", "basic-types/", "complex-types/", "localized/", NULL));
1754
1755   g_free (items);
1756
1757   g_object_unref (settings);
1758 }
1759
1760 static void
1761 test_list_schemas (void)
1762 {
1763   const gchar * const *schemas;
1764
1765   schemas = g_settings_list_schemas ();
1766
1767   g_assert (strv_set_equal ((const gchar **)schemas,
1768                             "org.gtk.test",
1769                             "org.gtk.test.no-path",
1770                             "org.gtk.test.basic-types",
1771                             "org.gtk.test.complex-types",
1772                             "org.gtk.test.localized",
1773                             "org.gtk.test.binding",
1774                             "org.gtk.test.enums",
1775                             "org.gtk.test.enums.direct",
1776                             "org.gtk.test.range",
1777                             "org.gtk.test.range.direct",
1778                             "org.gtk.test.mapped",
1779                             NULL));
1780 }
1781
1782 static gboolean
1783 map_func (GVariant *value,
1784           gpointer *result,
1785           gpointer  user_data)
1786 {
1787   gint *state = user_data;
1788   gint v;
1789
1790   if (value)
1791     v = g_variant_get_int32 (value);
1792   else
1793     v = -1;
1794
1795   if (*state == 0)
1796     {
1797       g_assert_cmpint (v, ==, 1);
1798       (*state)++;
1799       return FALSE;
1800     }
1801   else if (*state == 1)
1802     {
1803       g_assert_cmpint (v, ==, 0);
1804       (*state)++;
1805       return FALSE;
1806     }
1807   else
1808     {
1809       g_assert (value == NULL);
1810       *result = g_variant_new_int32 (5);
1811       return TRUE;
1812     }
1813 }
1814
1815 static void
1816 test_get_mapped (void)
1817 {
1818   GSettings *settings;
1819   gint state;
1820   gpointer p;
1821   gint val;
1822
1823   settings = g_settings_new ("org.gtk.test.mapped");
1824   g_settings_set_int (settings, "val", 1);
1825
1826   state = 0;
1827   p = g_settings_get_mapped (settings, "val", map_func, &state);
1828   val = g_variant_get_int32 ((GVariant*)p);
1829   g_assert_cmpint (val, ==, 5);
1830
1831   g_variant_unref (p);
1832   g_object_unref (settings);
1833 }
1834
1835 int
1836 main (int argc, char *argv[])
1837 {
1838   gchar *enums;
1839   gint result;
1840
1841   setlocale (LC_ALL, "");
1842
1843   backend_set = g_getenv ("GSETTINGS_BACKEND") != NULL;
1844
1845   g_setenv ("XDG_DATA_DIRS", ".", TRUE);
1846   g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
1847
1848   if (!backend_set)
1849     g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
1850
1851   g_type_init ();
1852   g_test_init (&argc, &argv, NULL);
1853
1854   g_remove ("org.gtk.test.enums.xml");
1855   g_assert (g_spawn_command_line_sync ("../../gobject/glib-mkenums "
1856                                        "--template " SRCDIR "/enums.xml.template "
1857                                        SRCDIR "/testenum.h",
1858                                        &enums, NULL, &result, NULL));
1859   g_assert (result == 0);
1860   g_assert (g_file_set_contents ("org.gtk.test.enums.xml", enums, -1, NULL));
1861   g_free (enums);
1862
1863   g_remove ("gschemas.compiled");
1864   g_assert (g_spawn_command_line_sync ("../glib-compile-schemas --targetdir=. "
1865                                        "--schema-file=org.gtk.test.enums.xml "
1866                                        "--schema-file=" SRCDIR "/org.gtk.test.gschema.xml",
1867                                        NULL, NULL, &result, NULL));
1868   g_assert (result == 0);
1869
1870   g_test_add_func ("/gsettings/basic", test_basic);
1871
1872   if (!backend_set)
1873     {
1874       g_test_add_func ("/gsettings/no-schema", test_no_schema);
1875       g_test_add_func ("/gsettings/unknown-key", test_unknown_key);
1876       g_test_add_func ("/gsettings/wrong-type", test_wrong_type);
1877       g_test_add_func ("/gsettings/wrong-path", test_wrong_path);
1878       g_test_add_func ("/gsettings/no-path", test_no_path);
1879     }
1880
1881   g_test_add_func ("/gsettings/basic-types", test_basic_types);
1882   g_test_add_func ("/gsettings/complex-types", test_complex_types);
1883   g_test_add_func ("/gsettings/changes", test_changes);
1884
1885   if (glib_translations_work ())
1886     {
1887       g_test_add_func ("/gsettings/l10n", test_l10n);
1888       g_test_add_func ("/gsettings/l10n-context", test_l10n_context);
1889     }
1890
1891   g_test_add_func ("/gsettings/delay-apply", test_delay_apply);
1892   g_test_add_func ("/gsettings/delay-revert", test_delay_revert);
1893   g_test_add_func ("/gsettings/atomic", test_atomic);
1894
1895   g_test_add_func ("/gsettings/simple-binding", test_simple_binding);
1896   g_test_add_func ("/gsettings/directional-binding", test_directional_binding);
1897   g_test_add_func ("/gsettings/custom-binding", test_custom_binding);
1898   g_test_add_func ("/gsettings/no-change-binding", test_no_change_binding);
1899   g_test_add_func ("/gsettings/unbinding", test_unbind);
1900   g_test_add_func ("/gsettings/writable-binding", test_bind_writable);
1901
1902   if (!backend_set)
1903     {
1904       g_test_add_func ("/gsettings/typesafe-binding", test_typesafe_binding);
1905       g_test_add_func ("/gsettings/no-read-binding", test_no_read_binding);
1906       g_test_add_func ("/gsettings/no-write-binding", test_no_write_binding);
1907     }
1908
1909   g_test_add_func ("/gsettings/keyfile", test_keyfile);
1910   g_test_add_func ("/gsettings/child-schema", test_child_schema);
1911   g_test_add_func ("/gsettings/strinfo", test_strinfo);
1912   g_test_add_func ("/gsettings/enums", test_enums);
1913   g_test_add_func ("/gsettings/flags", test_flags);
1914   g_test_add_func ("/gsettings/range", test_range);
1915   g_test_add_func ("/gsettings/list-items", test_list_items);
1916   g_test_add_func ("/gsettings/list-schemas", test_list_schemas);
1917   g_test_add_func ("/gsettings/mapped", test_get_mapped);
1918
1919   result = g_test_run ();
1920
1921   g_settings_sync ();
1922
1923   return result;
1924 }