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