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