Bypass l10n tests for now on Windows
[platform/upstream/glib.git] / gio / tests / gsettings.c
1 #include <stdlib.h>
2 #include <locale.h>
3 #include <libintl.h>
4 #include <gio.h>
5 #include <gstdio.h>
6 #define G_SETTINGS_ENABLE_BACKEND
7 #include <gio/gsettingsbackend.h>
8
9 /* These tests rely on the schemas in org.gtk.test.gschema.xml
10  * to be compiled and installed in the same directory.
11  */
12
13 /* Just to get warmed up: Read and set a string, and
14  * verify that can read the changed string back
15  */
16 static void
17 test_basic (void)
18 {
19   gchar *str = NULL;
20   GSettings *settings;
21
22   settings = g_settings_new ("org.gtk.test");
23
24   g_settings_get (settings, "greeting", "s", &str);
25   g_assert_cmpstr (str, ==, "Hello, earthlings");
26
27   g_settings_set (settings, "greeting", "s", "goodbye world");
28   g_settings_get (settings, "greeting", "s", &str);
29   g_assert_cmpstr (str, ==, "goodbye world");
30   g_free (str);
31   str = NULL;
32
33   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
34     {
35       settings = g_settings_new ("org.gtk.test");
36       g_settings_set (settings, "greeting", "i", 555);
37       abort ();
38     }
39   g_test_trap_assert_failed ();
40   g_test_trap_assert_stderr ("*correct_type*");
41
42   g_settings_get (settings, "greeting", "s", &str);
43   g_assert_cmpstr (str, ==, "goodbye world");
44   g_free (str);
45   str = NULL;
46
47   g_settings_set (settings, "greeting", "s", "this is the end");
48   g_object_unref (settings);
49 }
50
51 /* Check that we get an error when getting a key
52  * that is not in the schema
53  */
54 static void
55 test_unknown_key (void)
56 {
57   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
58     {
59       GSettings *settings;
60       GVariant *value;
61
62       settings = g_settings_new ("org.gtk.test");
63       value = g_settings_get_value (settings, "no_such_key");
64
65       g_assert (value == NULL);
66
67       g_object_unref (settings);
68     }
69   g_test_trap_assert_failed ();
70   g_test_trap_assert_stderr ("*does not contain*");
71 }
72
73 /* Check that we get an error when the schema
74  * has not been installed
75  */
76 void
77 test_no_schema (void)
78 {
79   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
80     {
81       GSettings *settings;
82
83       settings = g_settings_new ("no.such.schema");
84
85       g_assert (settings == NULL);
86     }
87
88   g_test_trap_assert_failed ();
89   g_test_trap_assert_stderr ("*Settings schema 'no.such.schema' is not installed*");
90 }
91
92 /* Check that we get an error when passing a type string
93  * that does not match the schema
94  */
95 static void
96 test_wrong_type (void)
97 {
98   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
99     {
100       GSettings *settings;
101       gchar *str = NULL;
102
103       settings = g_settings_new ("org.gtk.test");
104
105       g_settings_get (settings, "greeting", "o", &str);
106
107       g_assert (str == NULL);
108     }
109   g_test_trap_assert_failed ();
110   g_test_trap_assert_stderr ("*CRITICAL*");
111
112   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
113     {
114       GSettings *settings;
115
116       settings = g_settings_new ("org.gtk.test");
117
118       g_settings_set (settings, "greetings", "o", "/a/path");
119     }
120   g_test_trap_assert_failed ();
121   g_test_trap_assert_stderr ("*CRITICAL*");
122 }
123
124 /* Check that we can successfully read and set the full
125  * range of all basic types
126  */
127 static void
128 test_basic_types (void)
129 {
130   GSettings *settings;
131   gboolean b;
132   guint8 byte;
133   gint16 i16;
134   guint16 u16;
135   gint32 i32;
136   guint32 u32;
137   gint64 i64;
138   guint64 u64;
139   gdouble d;
140   gchar *str;
141
142   settings = g_settings_new ("org.gtk.test.basic-types");
143
144   g_settings_get (settings, "test-boolean", "b", &b);
145   g_assert_cmpint (b, ==, 1);
146
147   g_settings_set (settings, "test-boolean", "b", 0);
148   g_settings_get (settings, "test-boolean", "b", &b);
149   g_assert_cmpint (b, ==, 0);
150
151   g_settings_get (settings, "test-byte", "y", &byte);
152   g_assert_cmpint (byte, ==, 25);
153
154   g_settings_set (settings, "test-byte", "y", G_MAXUINT8);
155   g_settings_get (settings, "test-byte", "y", &byte);
156   g_assert_cmpint (byte, ==, G_MAXUINT8);
157
158   g_settings_get (settings, "test-int16", "n", &i16);
159   g_assert_cmpint (i16, ==, -1234);
160
161   g_settings_set (settings, "test-int16", "n", G_MININT16);
162   g_settings_get (settings, "test-int16", "n", &i16);
163   g_assert_cmpint (i16, ==, G_MININT16);
164
165   g_settings_set (settings, "test-int16", "n", G_MAXINT16);
166   g_settings_get (settings, "test-int16", "n", &i16);
167   g_assert_cmpint (i16, ==, G_MAXINT16);
168
169   g_settings_get (settings, "test-uint16", "q", &u16);
170   g_assert_cmpuint (u16, ==, 1234);
171
172   g_settings_set (settings, "test-uint16", "q", G_MAXUINT16);
173   g_settings_get (settings, "test-uint16", "q", &u16);
174   g_assert_cmpuint (u16, ==, G_MAXUINT16);
175
176   g_settings_get (settings, "test-int32", "i", &i32);
177   g_assert_cmpint (i32, ==, -123456);
178
179   g_settings_set (settings, "test-int32", "i", G_MININT32);
180   g_settings_get (settings, "test-int32", "i", &i32);
181   g_assert_cmpint (i32, ==, G_MININT32);
182
183   g_settings_set (settings, "test-int32", "i", G_MAXINT32);
184   g_settings_get (settings, "test-int32", "i", &i32);
185   g_assert_cmpint (i32, ==, G_MAXINT32);
186
187   g_settings_get (settings, "test-uint32", "u", &u32);
188   g_assert_cmpuint (u32, ==, 123456);
189
190   g_settings_set (settings, "test-uint32", "u", G_MAXUINT32);
191   g_settings_get (settings, "test-uint32", "u", &u32);
192   g_assert_cmpuint (u32, ==, G_MAXUINT32);
193
194   g_settings_get (settings, "test-int64", "x", &i64);
195   g_assert_cmpuint (i64, ==, -123456789);
196
197   g_settings_set (settings, "test-int64", "x", G_MININT64);
198   g_settings_get (settings, "test-int64", "x", &i64);
199   g_assert_cmpuint (i64, ==, G_MININT64);
200
201   g_settings_set (settings, "test-int64", "x", G_MAXINT64);
202   g_settings_get (settings, "test-int64", "x", &i64);
203   g_assert_cmpuint (i64, ==, G_MAXINT64);
204
205   g_settings_get (settings, "test-uint64", "t", &u64);
206   g_assert_cmpuint (u64, ==, 123456789);
207
208   g_settings_set (settings, "test-uint64", "t", G_MAXUINT64);
209   g_settings_get (settings, "test-uint64", "t", &u64);
210   g_assert_cmpuint (u64, ==, G_MAXUINT64);
211
212   g_settings_get (settings, "test-double", "d", &d);
213   g_assert_cmpfloat (d, ==, 123.456);
214
215   g_settings_set (settings, "test-double", "d", G_MINDOUBLE);
216   g_settings_get (settings, "test-double", "d", &d);
217   g_assert_cmpfloat (d, ==, G_MINDOUBLE);
218
219   g_settings_set (settings, "test-double", "d", G_MAXDOUBLE);
220   g_settings_get (settings, "test-double", "d", &d);
221   g_assert_cmpfloat (d, ==, G_MAXDOUBLE);
222
223   g_settings_get (settings, "test-string", "s", &str);
224   g_assert_cmpstr (str, ==, "a string, it seems");
225   g_free (str);
226   str = NULL;
227
228   g_settings_get (settings, "test-objectpath", "o", &str);
229   g_assert_cmpstr (str, ==, "/a/object/path");
230   g_object_unref (settings);
231   g_free (str);
232   str = NULL;
233 }
234
235 /* Check that we can read an set complex types like
236  * tuples, arrays and dictionaries
237  */
238 static void
239 test_complex_types (void)
240 {
241   GSettings *settings;
242   gchar *s;
243   gint i1, i2;
244   GVariantIter *iter = NULL;
245
246   settings = g_settings_new ("org.gtk.test.complex-types");
247
248   g_settings_get (settings, "test-tuple", "(s(ii))", &s, &i1, &i2);
249   g_assert_cmpstr (s, ==, "one");
250   g_assert_cmpint (i1,==, 2);
251   g_assert_cmpint (i2,==, 3);
252   g_free (s) ;
253   s = NULL;
254
255   g_settings_set (settings, "test-tuple", "(s(ii))", "none", 0, 0);
256   g_settings_get (settings, "test-tuple", "(s(ii))", &s, &i1, &i2);
257   g_assert_cmpstr (s, ==, "none");
258   g_assert_cmpint (i1,==, 0);
259   g_assert_cmpint (i2,==, 0);
260   g_free (s);
261   s = NULL;
262
263   g_settings_get (settings, "test-array", "ai", &iter);
264   g_assert_cmpint (g_variant_iter_n_children (iter), ==, 6);
265   g_assert (g_variant_iter_next (iter, "i", &i1));
266   g_assert_cmpint (i1, ==, 0);
267   g_assert (g_variant_iter_next (iter, "i", &i1));
268   g_assert_cmpint (i1, ==, 1);
269   g_assert (g_variant_iter_next (iter, "i", &i1));
270   g_assert_cmpint (i1, ==, 2);
271   g_assert (g_variant_iter_next (iter, "i", &i1));
272   g_assert_cmpint (i1, ==, 3);
273   g_assert (g_variant_iter_next (iter, "i", &i1));
274   g_assert_cmpint (i1, ==, 4);
275   g_assert (g_variant_iter_next (iter, "i", &i1));
276   g_assert_cmpint (i1, ==, 5);
277   g_assert (!g_variant_iter_next (iter, "i", &i1));
278   g_variant_iter_free (iter);
279
280   g_object_unref (settings);
281 }
282
283 static gboolean changed_cb_called;
284
285 static void
286 changed_cb (GSettings   *settings,
287             const gchar *key,
288             gpointer     data)
289 {
290   changed_cb_called = TRUE;
291
292   g_assert_cmpstr (key, ==, data);
293 }
294
295 /* Test that basic change notification with the changed signal works.
296  */
297 void
298 test_changes (void)
299 {
300   GSettings *settings;
301   GSettings *settings2;
302
303   settings = g_settings_new ("org.gtk.test");
304
305   g_signal_connect (settings, "changed",
306                     G_CALLBACK (changed_cb), "greeting");
307
308   changed_cb_called = FALSE;
309
310   g_settings_set (settings, "greeting", "s", "new greeting");
311   g_assert (changed_cb_called);
312
313   settings2 = g_settings_new ("org.gtk.test");
314
315   changed_cb_called = FALSE;
316
317   g_settings_set (settings2, "greeting", "s", "hi");
318   g_assert (changed_cb_called);
319
320   g_object_unref (settings2);
321   g_object_unref (settings);
322 }
323
324 static gboolean changed_cb_called2;
325
326 static void
327 changed_cb2 (GSettings   *settings,
328              const gchar *key,
329              gpointer     data)
330 {
331   gboolean *p = data;
332
333   *p = TRUE;
334 }
335
336 /* Test that changes done to a delay-mode instance
337  * don't appear to the outside world until apply. Also
338  * check that we get change notification when they are
339  * applied.
340  * Also test that the has-unapplied property is properly
341  * maintained.
342  */
343 void
344 test_delay_apply (void)
345 {
346   GSettings *settings;
347   GSettings *settings2;
348   gchar *str;
349
350   settings = g_settings_new ("org.gtk.test");
351   settings2 = g_settings_new ("org.gtk.test");
352
353   g_settings_set (settings2, "greeting", "s", "top o' the morning");
354
355   changed_cb_called = FALSE;
356   changed_cb_called2 = FALSE;
357
358   g_signal_connect (settings, "changed",
359                     G_CALLBACK (changed_cb2), &changed_cb_called);
360   g_signal_connect (settings2, "changed",
361                     G_CALLBACK (changed_cb2), &changed_cb_called2);
362
363   g_settings_delay (settings);
364
365   g_settings_set (settings, "greeting", "s", "greetings from test_delay_apply");
366
367   g_assert (changed_cb_called);
368   g_assert (!changed_cb_called2);
369
370   g_settings_get (settings, "greeting", "s", &str);
371   g_assert_cmpstr (str, ==, "greetings from test_delay_apply");
372   g_free (str);
373   str = NULL;
374
375   g_settings_get (settings2, "greeting", "s", &str);
376   g_assert_cmpstr (str, ==, "top o' the morning");
377   g_free (str);
378   str = NULL;
379
380   g_assert (g_settings_get_has_unapplied (settings));
381   g_assert (!g_settings_get_has_unapplied (settings2));
382
383   changed_cb_called = FALSE;
384   changed_cb_called2 = FALSE;
385
386   g_settings_apply (settings);
387
388   g_assert (!changed_cb_called);
389   g_assert (changed_cb_called2);
390
391   g_settings_get (settings, "greeting", "s", &str);
392   g_assert_cmpstr (str, ==, "greetings from test_delay_apply");
393   g_free (str);
394   str = NULL;
395
396   g_settings_get (settings2, "greeting", "s", &str);
397   g_assert_cmpstr (str, ==, "greetings from test_delay_apply");
398   g_free (str);
399   str = NULL;
400
401   g_assert (!g_settings_get_has_unapplied (settings));
402   g_assert (!g_settings_get_has_unapplied (settings2));
403
404   g_object_unref (settings2);
405   g_object_unref (settings);
406 }
407
408 /* Test that reverting unapplied changes in a delay-apply
409  * settings instance works.
410  */
411 static void
412 test_delay_revert (void)
413 {
414   GSettings *settings;
415   GSettings *settings2;
416   gchar *str;
417
418   settings = g_settings_new ("org.gtk.test");
419   settings2 = g_settings_new ("org.gtk.test");
420
421   g_settings_set (settings2, "greeting", "s", "top o' the morning");
422
423   g_settings_delay (settings);
424
425   g_settings_set (settings, "greeting", "s", "greetings from test_delay_revert");
426
427   g_settings_get (settings, "greeting", "s", &str);
428   g_assert_cmpstr (str, ==, "greetings from test_delay_revert");
429   g_free (str);
430   str = NULL;
431
432   g_settings_get (settings2, "greeting", "s", &str);
433   g_assert_cmpstr (str, ==, "top o' the morning");
434   g_free (str);
435   str = NULL;
436
437   g_assert (g_settings_get_has_unapplied (settings));
438
439   g_settings_revert (settings);
440
441   g_assert (!g_settings_get_has_unapplied (settings));
442
443   g_settings_get (settings, "greeting", "s", &str);
444   g_assert_cmpstr (str, ==, "top o' the morning");
445   g_free (str);
446   str = NULL;
447
448   g_settings_get (settings2, "greeting", "s", &str);
449   g_assert_cmpstr (str, ==, "top o' the morning");
450   g_free (str);
451   str = NULL;
452
453   g_object_unref (settings2);
454   g_object_unref (settings);
455 }
456
457 static void
458 keys_changed_cb (GSettings    *settings,
459                  const GQuark *keys,
460                  gint          n_keys)
461 {
462   gchar *str;
463
464   g_assert_cmpint (n_keys, ==, 2);
465
466   g_assert ((keys[0] == g_quark_from_static_string ("greeting") &&
467              keys[1] == g_quark_from_static_string ("farewell")) ||
468             (keys[1] == g_quark_from_static_string ("greeting") &&
469              keys[0] == g_quark_from_static_string ("farewell")));
470
471   g_settings_get (settings, "greeting", "s", &str);
472   g_assert_cmpstr (str, ==, "greetings from test_atomic");
473   g_free (str);
474   str = NULL;
475
476   g_settings_get (settings, "farewell", "s", &str);
477   g_assert_cmpstr (str, ==, "atomic bye-bye");
478   g_free (str);
479   str = NULL;
480 }
481
482 /* Check that delay-applied changes appear atomically.
483  * More specifically, verify that all changed keys appear
484  * with their new value while handling the change-event signal.
485  */
486 static void
487 test_atomic (void)
488 {
489   GSettings *settings;
490   GSettings *settings2;
491   gchar *str;
492
493   settings = g_settings_new ("org.gtk.test");
494   settings2 = g_settings_new ("org.gtk.test");
495
496   g_settings_set (settings2, "greeting", "s", "top o' the morning");
497
498   changed_cb_called = FALSE;
499   changed_cb_called2 = FALSE;
500
501   g_signal_connect (settings2, "change-event",
502                     G_CALLBACK (keys_changed_cb), NULL);
503
504   g_settings_delay (settings);
505
506   g_settings_set (settings, "greeting", "s", "greetings from test_atomic");
507   g_settings_set (settings, "farewell", "s", "atomic bye-bye");
508
509   g_settings_apply (settings);
510
511   g_settings_get (settings, "greeting", "s", &str);
512   g_assert_cmpstr (str, ==, "greetings from test_atomic");
513   g_free (str);
514   str = NULL;
515
516   g_settings_get (settings, "farewell", "s", &str);
517   g_assert_cmpstr (str, ==, "atomic bye-bye");
518   g_free (str);
519   str = NULL;
520
521   g_settings_get (settings2, "greeting", "s", &str);
522   g_assert_cmpstr (str, ==, "greetings from test_atomic");
523   g_free (str);
524   str = NULL;
525
526   g_settings_get (settings2, "farewell", "s", &str);
527   g_assert_cmpstr (str, ==, "atomic bye-bye");
528   g_free (str);
529   str = NULL;
530
531   g_object_unref (settings2);
532   g_object_unref (settings);
533 }
534
535 #ifndef G_OS_WIN32
536
537 /* On Windows the interaction between the C library locale and libintl
538  * (from GNU gettext) is not like on POSIX, so just skip these tests
539  * for now.
540  *
541  * There are several issues:
542  *
543  * 1) The C library doesn't use LC_MESSAGES, that is implemented only
544  * in libintl (defined in its <libintl.h>).
545  *
546  * 2) The locale names that setlocale() accepts and returns aren't in
547  * the "de_DE" style, but like "German_Germany".
548  *
549  * 3) libintl looks at the Win32 thread locale and not the C library
550  * locale. (And even if libintl would use the C library's locale, as
551  * there are several alternative C library DLLs, libintl might be
552  * linked to a different one than the application code, so they
553  * wouldn't have the same C library locale anyway.)
554  */
555
556 /* Test that translations work for schema defaults.
557  *
558  * This test relies on the de.po file in the same directory
559  * to be compiled into ./de/LC_MESSAGES/test.mo
560  */
561 static void
562 test_l10n (void)
563 {
564   GSettings *settings;
565   gchar *str;
566   gchar *locale;
567
568   bindtextdomain ("test", ".");
569   bind_textdomain_codeset ("test", "UTF-8");
570
571   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
572
573   settings = g_settings_new ("org.gtk.test.localized");
574
575   setlocale (LC_MESSAGES, "C");
576   str = g_settings_get_string (settings, "error-message");
577   setlocale (LC_MESSAGES, locale);
578
579   g_assert_cmpstr (str, ==, "Unnamed");
580   g_free (str);
581   str = NULL;
582
583   setlocale (LC_MESSAGES, "de_DE");
584   str = g_settings_get_string (settings, "error-message");
585   setlocale (LC_MESSAGES, locale);
586
587   g_assert_cmpstr (str, ==, "Unbenannt");
588   g_object_unref (settings);
589   g_free (str);
590   str = NULL;
591
592   g_free (locale);
593 }
594
595 /* Test that message context works as expected with translated
596  * schema defaults. Also, verify that non-ASCII UTF-8 content
597  * works.
598  *
599  * This test relies on the de.po file in the same directory
600  * to be compiled into ./de/LC_MESSAGES/test.mo
601  */
602 static void
603 test_l10n_context (void)
604 {
605   GSettings *settings;
606   gchar *str;
607   gchar *locale;
608
609   bindtextdomain ("test", ".");
610   bind_textdomain_codeset ("test", "UTF-8");
611
612   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
613
614   settings = g_settings_new ("org.gtk.test.localized");
615
616   setlocale (LC_MESSAGES, "C");
617   g_settings_get (settings, "backspace", "s", &str);
618   setlocale (LC_MESSAGES, locale);
619
620   g_assert_cmpstr (str, ==, "BackSpace");
621   g_free (str);
622   str = NULL;
623
624   setlocale (LC_MESSAGES, "de_DE");
625   g_settings_get (settings, "backspace", "s", &str);
626   setlocale (LC_MESSAGES, locale);
627
628   g_assert_cmpstr (str, ==, "Löschen");
629   g_object_unref (settings);
630   g_free (str);
631   str = NULL;
632
633   g_free (locale);
634 }
635
636 #endif
637
638 enum
639 {
640   PROP_0,
641   PROP_BOOL,
642   PROP_INT,
643   PROP_DOUBLE,
644   PROP_STRING
645 };
646
647 typedef struct
648 {
649   GObject parent_instance;
650
651   gboolean bool_prop;
652   gint int_prop;
653   gdouble double_prop;
654   gchar *string_prop;
655 } TestObject;
656
657 typedef struct
658 {
659   GObjectClass parent_class;
660 } TestObjectClass;
661
662 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
663
664 static void
665 test_object_init (TestObject *object)
666 {
667 }
668
669 static void
670 test_object_finalize (GObject *object)
671 {
672   TestObject *testo = (TestObject*)object;
673   g_free (testo->string_prop);
674   G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
675 }
676
677 static void
678 test_object_get_property (GObject    *object,
679                           guint       prop_id,
680                           GValue     *value,
681                           GParamSpec *pspec)
682 {
683   TestObject *test_object = (TestObject *)object;
684
685   switch (prop_id)
686     {
687     case PROP_BOOL:
688       g_value_set_boolean (value, test_object->bool_prop);
689       break;
690     case PROP_INT:
691       g_value_set_int (value, test_object->int_prop);
692       break;
693     case PROP_DOUBLE:
694       g_value_set_double (value, test_object->double_prop);
695       break;
696     case PROP_STRING:
697       g_value_set_string (value, test_object->string_prop);
698       break;
699     default:
700       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
701       break;
702     }
703 }
704
705 static void
706 test_object_set_property (GObject      *object,
707                           guint         prop_id,
708                           const GValue *value,
709                           GParamSpec   *pspec)
710 {
711   TestObject *test_object = (TestObject *)object;
712
713   switch (prop_id)
714     {
715     case PROP_BOOL:
716       test_object->bool_prop = g_value_get_boolean (value);
717       break;
718     case PROP_INT:
719       test_object->int_prop = g_value_get_int (value);
720       break;
721     case PROP_DOUBLE:
722       test_object->double_prop = g_value_get_double (value);
723       break;
724     case PROP_STRING:
725       g_free (test_object->string_prop);
726       test_object->string_prop = g_value_dup_string (value);
727       break;
728     default:
729       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
730       break;
731     }
732 }
733
734 static void
735 test_object_class_init (TestObjectClass *class)
736 {
737   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
738
739   gobject_class->get_property = test_object_get_property;
740   gobject_class->set_property = test_object_set_property;
741   gobject_class->finalize = test_object_finalize;
742
743   g_object_class_install_property (gobject_class, PROP_BOOL,
744     g_param_spec_boolean ("bool", "", "", FALSE, G_PARAM_READWRITE));
745   g_object_class_install_property (gobject_class, PROP_INT,
746     g_param_spec_int ("int", "", "", -G_MAXINT, G_MAXINT, 0, G_PARAM_READWRITE));
747   g_object_class_install_property (gobject_class, PROP_DOUBLE,
748     g_param_spec_double ("double", "", "", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE));
749   g_object_class_install_property (gobject_class, PROP_STRING,
750     g_param_spec_string ("string", "", "", NULL, G_PARAM_READWRITE));
751 }
752
753 static TestObject *
754 test_object_new (void)
755 {
756   return (TestObject*)g_object_new (test_object_get_type (), NULL);
757 }
758
759 /* Test basic binding functionality for simple types.
760  * Verify that with bidirectional bindings, changes on either side
761  * are notified on the other end.
762  */
763 static void
764 test_simple_binding (void)
765 {
766   TestObject *obj;
767   GSettings *settings;
768   gboolean b;
769   gint i;
770   gdouble d;
771   gchar *s;
772
773   settings = g_settings_new ("org.gtk.test.binding");
774   obj = test_object_new ();
775
776   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_DEFAULT);
777
778   g_object_set (obj, "bool", TRUE, NULL);
779   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
780
781   g_settings_set_boolean (settings, "bool", FALSE);
782   g_object_get (obj, "bool", &b, NULL);
783   g_assert_cmpint (b, ==, FALSE);
784
785   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
786
787   g_object_set (obj, "int", 12345, NULL);
788   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
789
790   g_settings_set_int (settings, "int", 54321);
791   g_object_get (obj, "int", &i, NULL);
792   g_assert_cmpint (i, ==, 54321);
793
794   g_settings_bind (settings, "string", obj, "string", G_SETTINGS_BIND_DEFAULT);
795
796   g_object_set (obj, "string", "bu ba", NULL);
797   s = g_settings_get_string (settings, "string");
798   g_assert_cmpstr (s, ==, "bu ba");
799   g_free (s);
800
801   g_settings_set_string (settings, "string", "bla bla");
802   g_object_get (obj, "string", &s, NULL);
803   g_assert_cmpstr (s, ==, "bla bla");
804   g_free (s);
805
806   g_settings_bind (settings, "double", obj, "double", G_SETTINGS_BIND_DEFAULT);
807
808   g_object_set (obj, "double", 203e7, NULL);
809   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, 203e7);
810
811   g_settings_set_double (settings, "double", 207e3);
812   g_object_get (obj, "double", &d, NULL);
813   g_assert_cmpfloat (d, ==, 207e3);
814
815   g_object_unref (obj);
816   g_object_unref (settings);
817 }
818
819 /* Test one-way bindings.
820  * Verify that changes on one side show up on the other,
821  * but not vice versa
822  */
823 static void
824 test_directional_binding (void)
825 {
826   TestObject *obj;
827   GSettings *settings;
828   gboolean b;
829   gint i;
830
831   settings = g_settings_new ("org.gtk.test.binding");
832   obj = test_object_new ();
833
834   g_object_set (obj, "bool", FALSE, NULL);
835   g_settings_set_boolean (settings, "bool", FALSE);
836
837   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET);
838
839   g_settings_set_boolean (settings, "bool", TRUE);
840   g_object_get (obj, "bool", &b, NULL);
841   g_assert_cmpint (b, ==, TRUE);
842
843   g_object_set (obj, "bool", FALSE, NULL);
844   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
845
846   g_object_set (obj, "int", 20, NULL);
847   g_settings_set_int (settings, "int", 20);
848
849   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_SET);
850
851   g_object_set (obj, "int", 32, NULL);
852   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 32);
853
854   g_settings_set_int (settings, "int", 20);
855   g_object_get (obj, "int", &i, NULL);
856   g_assert_cmpint (i, ==, 32);
857
858   g_object_unref (obj);
859   g_object_unref (settings);
860 }
861
862 /* Test that type mismatch is caught when creating a binding
863  */
864 static void
865 test_typesafe_binding (void)
866 {
867   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
868     {
869       TestObject *obj;
870       GSettings *settings;
871
872       settings = g_settings_new ("org.gtk.test.binding");
873       obj = test_object_new ();
874
875       g_settings_bind (settings, "string", obj, "int", G_SETTINGS_BIND_DEFAULT);
876
877       g_object_unref (obj);
878       g_object_unref (settings);
879     }
880   g_test_trap_assert_failed ();
881   g_test_trap_assert_stderr ("*not compatible*");
882 }
883
884 static gboolean
885 string_to_bool (GValue   *value,
886                 GVariant *variant,
887                 gpointer  user_data)
888 {
889   const gchar *s;
890
891   s = g_variant_get_string (variant, NULL);
892   g_value_set_boolean (value, g_strcmp0 (s, "true") == 0);
893
894   return TRUE;
895 }
896
897 static GVariant *
898 bool_to_string (const GValue       *value,
899                 const GVariantType *expected_type,
900                 gpointer            user_data)
901 {
902   if (g_value_get_boolean (value))
903     return g_variant_new_string ("true");
904   else
905     return g_variant_new_string ("false");
906 }
907
908 /* Test custom bindings.
909  * Translate strings to booleans and back
910  */
911 static void
912 test_custom_binding (void)
913 {
914   TestObject *obj;
915   GSettings *settings;
916   gchar *s;
917   gboolean b;
918
919   settings = g_settings_new ("org.gtk.test.binding");
920   obj = test_object_new ();
921
922   g_settings_set_string (settings, "string", "true");
923
924   g_settings_bind_with_mapping (settings, "string",
925                                 obj, "bool",
926                                 G_SETTINGS_BIND_DEFAULT,
927                                 string_to_bool,
928                                 bool_to_string,
929                                 NULL, NULL);
930
931   g_settings_set_string (settings, "string", "false");
932   g_object_get (obj, "bool", &b, NULL);
933   g_assert_cmpint (b, ==, FALSE);
934
935   g_settings_set_string (settings, "string", "not true");
936   g_object_get (obj, "bool", &b, NULL);
937   g_assert_cmpint (b, ==, FALSE);
938
939   g_object_set (obj, "bool", TRUE, NULL);
940   s = g_settings_get_string (settings, "string");
941   g_assert_cmpstr (s, ==, "true");
942
943   g_object_unref (obj);
944   g_object_unref (settings);
945 }
946
947 /* Test that with G_SETTINGS_BIND_NO_CHANGES, the
948  * initial settings value is transported to the object
949  * side, but later settings changes do not affect the
950  * object
951  */
952 static void
953 test_no_change_binding (void)
954 {
955   TestObject *obj;
956   GSettings *settings;
957   gboolean b;
958
959   settings = g_settings_new ("org.gtk.test.binding");
960   obj = test_object_new ();
961
962   g_object_set (obj, "bool", TRUE, NULL);
963   g_settings_set_boolean (settings, "bool", FALSE);
964
965   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET_NO_CHANGES);
966
967   g_object_get (obj, "bool", &b, NULL);
968   g_assert_cmpint (b, ==, FALSE);
969
970   g_settings_set_boolean (settings, "bool", TRUE);
971   g_object_get (obj, "bool", &b, NULL);
972   g_assert_cmpint (b, ==, FALSE);
973
974   g_settings_set_boolean (settings, "bool", FALSE);
975   g_object_set (obj, "bool", TRUE, NULL);
976   b = g_settings_get_boolean (settings, "bool");
977   g_assert_cmpint (b, ==, TRUE);
978
979   g_object_unref (obj);
980   g_object_unref (settings);
981 }
982
983 /*
984  * Test that using a keyfile works
985  */
986 static void
987 test_keyfile (void)
988 {
989   GSettings *settings;
990   GKeyFile *keyfile;
991   gchar *str;
992
993   g_remove ("gsettings.store");
994
995   g_settings_backend_setup_keyfile ("blah", "gsettings.store");
996
997   settings = g_settings_new_with_context ("org.gtk.test", "blah");
998
999   g_settings_set (settings, "greeting", "s", "see if this works");
1000
1001   keyfile = g_key_file_new ();
1002   g_assert (g_key_file_load_from_file (keyfile, "gsettings.store", 0, NULL));
1003
1004   str = g_key_file_get_string (keyfile, "/tests/", "greeting", NULL);
1005   g_assert_cmpstr (str, ==, "'see if this works'");
1006
1007   g_free (str);
1008   g_key_file_free (keyfile);
1009   g_object_unref (settings);
1010 }
1011
1012 int
1013 main (int argc, char *argv[])
1014 {
1015   g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
1016   g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
1017
1018   g_remove ("./store");
1019
1020   g_type_init ();
1021   g_test_init (&argc, &argv, NULL);
1022
1023   g_test_add_func ("/gsettings/basic", test_basic);
1024   g_test_add_func ("/gsettings/no-schema", test_no_schema);
1025   g_test_add_func ("/gsettings/unknown-key", test_unknown_key);
1026   g_test_add_func ("/gsettings/wrong-type", test_wrong_type);
1027   g_test_add_func ("/gsettings/basic-types", test_basic_types);
1028   g_test_add_func ("/gsettings/complex-types", test_complex_types);
1029   g_test_add_func ("/gsettings/changes", test_changes);
1030 #ifndef G_OS_WIN32
1031   g_test_add_func ("/gsettings/l10n", test_l10n);
1032   g_test_add_func ("/gsettings/l10n-context", test_l10n_context);
1033 #endif
1034   g_test_add_func ("/gsettings/delay-apply", test_delay_apply);
1035   g_test_add_func ("/gsettings/delay-revert", test_delay_revert);
1036   g_test_add_func ("/gsettings/atomic", test_atomic);
1037   g_test_add_func ("/gsettings/simple-binding", test_simple_binding);
1038   g_test_add_func ("/gsettings/directional-binding", test_directional_binding);
1039   g_test_add_func ("/gsettings/typesafe-binding", test_typesafe_binding);
1040   g_test_add_func ("/gsettings/custom-binding", test_custom_binding);
1041   g_test_add_func ("/gsettings/no-change-binding", test_no_change_binding);
1042   g_test_add_func ("/gsettings/keyfile", test_keyfile);
1043
1044   return g_test_run ();
1045 }