check for working gettext() before running tests
[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 /* On Windows the interaction between the C library locale and libintl
536  * (from GNU gettext) is not like on POSIX, so just skip these tests
537  * for now.
538  *
539  * There are several issues:
540  *
541  * 1) The C library doesn't use LC_MESSAGES, that is implemented only
542  * in libintl (defined in its <libintl.h>).
543  *
544  * 2) The locale names that setlocale() accepts and returns aren't in
545  * the "de_DE" style, but like "German_Germany".
546  *
547  * 3) libintl looks at the Win32 thread locale and not the C library
548  * locale. (And even if libintl would use the C library's locale, as
549  * there are several alternative C library DLLs, libintl might be
550  * linked to a different one than the application code, so they
551  * wouldn't have the same C library locale anyway.)
552  */
553
554 /* Test that translations work for schema defaults.
555  *
556  * This test relies on the de.po file in the same directory
557  * to be compiled into ./de/LC_MESSAGES/test.mo
558  */
559 static void
560 test_l10n (void)
561 {
562   GSettings *settings;
563   gchar *str;
564   gchar *locale;
565
566   bindtextdomain ("test", ".");
567   bind_textdomain_codeset ("test", "UTF-8");
568
569   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
570
571   settings = g_settings_new ("org.gtk.test.localized");
572
573   setlocale (LC_MESSAGES, "C");
574   str = g_settings_get_string (settings, "error-message");
575   setlocale (LC_MESSAGES, locale);
576
577   g_assert_cmpstr (str, ==, "Unnamed");
578   g_free (str);
579   str = NULL;
580
581   setlocale (LC_MESSAGES, "de_DE");
582   str = g_settings_get_string (settings, "error-message");
583   setlocale (LC_MESSAGES, locale);
584
585   g_assert_cmpstr (str, ==, "Unbenannt");
586   g_object_unref (settings);
587   g_free (str);
588   str = NULL;
589
590   g_free (locale);
591 }
592
593 /* Test that message context works as expected with translated
594  * schema defaults. Also, verify that non-ASCII UTF-8 content
595  * works.
596  *
597  * This test relies on the de.po file in the same directory
598  * to be compiled into ./de/LC_MESSAGES/test.mo
599  */
600 static void
601 test_l10n_context (void)
602 {
603   GSettings *settings;
604   gchar *str;
605   gchar *locale;
606
607   bindtextdomain ("test", ".");
608   bind_textdomain_codeset ("test", "UTF-8");
609
610   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
611
612   settings = g_settings_new ("org.gtk.test.localized");
613
614   setlocale (LC_MESSAGES, "C");
615   g_settings_get (settings, "backspace", "s", &str);
616   setlocale (LC_MESSAGES, locale);
617
618   g_assert_cmpstr (str, ==, "BackSpace");
619   g_free (str);
620   str = NULL;
621
622   setlocale (LC_MESSAGES, "de_DE");
623   g_settings_get (settings, "backspace", "s", &str);
624   setlocale (LC_MESSAGES, locale);
625
626   g_assert_cmpstr (str, ==, "Löschen");
627   g_object_unref (settings);
628   g_free (str);
629   str = NULL;
630
631   g_free (locale);
632 }
633
634 enum
635 {
636   PROP_0,
637   PROP_BOOL,
638   PROP_INT,
639   PROP_INT64,
640   PROP_UINT64,
641   PROP_DOUBLE,
642   PROP_STRING,
643   PROP_NO_READ,
644   PROP_NO_WRITE
645 };
646
647 typedef struct
648 {
649   GObject parent_instance;
650
651   gboolean bool_prop;
652   gint int_prop;
653   gint64 int64_prop;
654   guint64 uint64_prop;
655   gdouble double_prop;
656   gchar *string_prop;
657   gchar *no_read_prop;
658   gchar *no_write_prop;
659 } TestObject;
660
661 typedef struct
662 {
663   GObjectClass parent_class;
664 } TestObjectClass;
665
666 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
667
668 static void
669 test_object_init (TestObject *object)
670 {
671 }
672
673 static void
674 test_object_finalize (GObject *object)
675 {
676   TestObject *testo = (TestObject*)object;
677   g_free (testo->string_prop);
678   G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
679 }
680
681 static void
682 test_object_get_property (GObject    *object,
683                           guint       prop_id,
684                           GValue     *value,
685                           GParamSpec *pspec)
686 {
687   TestObject *test_object = (TestObject *)object;
688
689   switch (prop_id)
690     {
691     case PROP_BOOL:
692       g_value_set_boolean (value, test_object->bool_prop);
693       break;
694     case PROP_INT:
695       g_value_set_int (value, test_object->int_prop);
696       break;
697     case PROP_INT64:
698       g_value_set_int64 (value, test_object->int64_prop);
699       break;
700     case PROP_UINT64:
701       g_value_set_uint64 (value, test_object->uint64_prop);
702       break;
703     case PROP_DOUBLE:
704       g_value_set_double (value, test_object->double_prop);
705       break;
706     case PROP_STRING:
707       g_value_set_string (value, test_object->string_prop);
708       break;
709     case PROP_NO_WRITE:
710       g_value_set_string (value, test_object->no_write_prop);
711       break;
712     default:
713       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
714       break;
715     }
716 }
717
718 static void
719 test_object_set_property (GObject      *object,
720                           guint         prop_id,
721                           const GValue *value,
722                           GParamSpec   *pspec)
723 {
724   TestObject *test_object = (TestObject *)object;
725
726   switch (prop_id)
727     {
728     case PROP_BOOL:
729       test_object->bool_prop = g_value_get_boolean (value);
730       break;
731     case PROP_INT:
732       test_object->int_prop = g_value_get_int (value);
733       break;
734     case PROP_INT64:
735       test_object->int64_prop = g_value_get_int64 (value);
736       break;
737     case PROP_UINT64:
738       test_object->uint64_prop = g_value_get_uint64 (value);
739       break;
740     case PROP_DOUBLE:
741       test_object->double_prop = g_value_get_double (value);
742       break;
743     case PROP_STRING:
744       g_free (test_object->string_prop);
745       test_object->string_prop = g_value_dup_string (value);
746       break;
747     case PROP_NO_READ:
748       g_free (test_object->no_read_prop);
749       test_object->no_read_prop = g_value_dup_string (value);
750       break;
751     default:
752       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
753       break;
754     }
755 }
756
757 static void
758 test_object_class_init (TestObjectClass *class)
759 {
760   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
761
762   gobject_class->get_property = test_object_get_property;
763   gobject_class->set_property = test_object_set_property;
764   gobject_class->finalize = test_object_finalize;
765
766   g_object_class_install_property (gobject_class, PROP_BOOL,
767     g_param_spec_boolean ("bool", "", "", FALSE, G_PARAM_READWRITE));
768   g_object_class_install_property (gobject_class, PROP_INT,
769     g_param_spec_int ("int", "", "", -G_MAXINT, G_MAXINT, 0, G_PARAM_READWRITE));
770   g_object_class_install_property (gobject_class, PROP_INT64,
771     g_param_spec_int64 ("int64", "", "", G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE));
772   g_object_class_install_property (gobject_class, PROP_UINT64,
773     g_param_spec_uint64 ("uint64", "", "", 0, G_MAXUINT64, 0, G_PARAM_READWRITE));
774   g_object_class_install_property (gobject_class, PROP_DOUBLE,
775     g_param_spec_double ("double", "", "", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE));
776   g_object_class_install_property (gobject_class, PROP_STRING,
777     g_param_spec_string ("string", "", "", NULL, G_PARAM_READWRITE));
778   g_object_class_install_property (gobject_class, PROP_NO_WRITE,
779     g_param_spec_string ("no-write", "", "", NULL, G_PARAM_READABLE));
780   g_object_class_install_property (gobject_class, PROP_NO_READ,
781     g_param_spec_string ("no-read", "", "", NULL, G_PARAM_WRITABLE));
782 }
783
784 static TestObject *
785 test_object_new (void)
786 {
787   return (TestObject*)g_object_new (test_object_get_type (), NULL);
788 }
789
790 /* Test basic binding functionality for simple types.
791  * Verify that with bidirectional bindings, changes on either side
792  * are notified on the other end.
793  */
794 static void
795 test_simple_binding (void)
796 {
797   TestObject *obj;
798   GSettings *settings;
799   gboolean b;
800   gint i;
801   gint64 i64;
802   guint64 u64;
803   gdouble d;
804   gchar *s;
805
806   settings = g_settings_new ("org.gtk.test.binding");
807   obj = test_object_new ();
808
809   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_DEFAULT);
810
811   g_object_set (obj, "bool", TRUE, NULL);
812   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
813
814   g_settings_set_boolean (settings, "bool", FALSE);
815   g_object_get (obj, "bool", &b, NULL);
816   g_assert_cmpint (b, ==, FALSE);
817
818   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
819
820   g_object_set (obj, "int", 12345, NULL);
821   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
822
823   g_settings_set_int (settings, "int", 54321);
824   g_object_get (obj, "int", &i, NULL);
825   g_assert_cmpint (i, ==, 54321);
826
827   g_settings_bind (settings, "int64", obj, "int64", G_SETTINGS_BIND_DEFAULT);
828
829   g_object_set (obj, "int64", (gint64) G_MAXINT64, NULL);
830   g_settings_get (settings, "int64", "x", &i64);
831   g_assert_cmpint (i64, ==, G_MAXINT64);
832
833   g_settings_set (settings, "int64", "x", (gint64) G_MININT64);
834   g_object_get (obj, "int64", &i64, NULL);
835   g_assert_cmpint (i64, ==, G_MININT64);
836
837   g_settings_bind (settings, "uint64", obj, "uint64", G_SETTINGS_BIND_DEFAULT);
838
839   g_object_set (obj, "uint64", (guint64) G_MAXUINT64, NULL);
840   g_settings_get (settings, "uint64", "t", &u64);
841   g_assert_cmpuint (u64, ==, G_MAXUINT64);
842
843   g_settings_set (settings, "uint64", "t", (guint64) G_MAXINT64);
844   g_object_get (obj, "uint64", &u64, NULL);
845   g_assert_cmpuint (u64, ==, (guint64) G_MAXINT64);
846
847   g_settings_bind (settings, "string", obj, "string", G_SETTINGS_BIND_DEFAULT);
848
849   g_object_set (obj, "string", "bu ba", NULL);
850   s = g_settings_get_string (settings, "string");
851   g_assert_cmpstr (s, ==, "bu ba");
852   g_free (s);
853
854   g_settings_set_string (settings, "string", "bla bla");
855   g_object_get (obj, "string", &s, NULL);
856   g_assert_cmpstr (s, ==, "bla bla");
857   g_free (s);
858
859   g_settings_bind (settings, "double", obj, "double", G_SETTINGS_BIND_DEFAULT);
860
861   g_object_set (obj, "double", G_MAXFLOAT, NULL);
862   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXFLOAT);
863
864   g_settings_set_double (settings, "double", G_MINFLOAT);
865   g_object_get (obj, "double", &d, NULL);
866   g_assert_cmpfloat (d, ==, G_MINFLOAT);
867
868   g_object_set (obj, "double", G_MAXDOUBLE, NULL);
869   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXDOUBLE);
870
871   g_settings_set_double (settings, "double", -G_MINDOUBLE);
872   g_object_get (obj, "double", &d, NULL);
873   g_assert_cmpfloat (d, ==, -G_MINDOUBLE);
874   g_object_unref (obj);
875   g_object_unref (settings);
876 }
877
878 /* Test one-way bindings.
879  * Verify that changes on one side show up on the other,
880  * but not vice versa
881  */
882 static void
883 test_directional_binding (void)
884 {
885   TestObject *obj;
886   GSettings *settings;
887   gboolean b;
888   gint i;
889
890   settings = g_settings_new ("org.gtk.test.binding");
891   obj = test_object_new ();
892
893   g_object_set (obj, "bool", FALSE, NULL);
894   g_settings_set_boolean (settings, "bool", FALSE);
895
896   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET);
897
898   g_settings_set_boolean (settings, "bool", TRUE);
899   g_object_get (obj, "bool", &b, NULL);
900   g_assert_cmpint (b, ==, TRUE);
901
902   g_object_set (obj, "bool", FALSE, NULL);
903   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
904
905   g_object_set (obj, "int", 20, NULL);
906   g_settings_set_int (settings, "int", 20);
907
908   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_SET);
909
910   g_object_set (obj, "int", 32, NULL);
911   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 32);
912
913   g_settings_set_int (settings, "int", 20);
914   g_object_get (obj, "int", &i, NULL);
915   g_assert_cmpint (i, ==, 32);
916
917   g_object_unref (obj);
918   g_object_unref (settings);
919 }
920
921 /* Test that type mismatch is caught when creating a binding
922  */
923 static void
924 test_typesafe_binding (void)
925 {
926   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
927     {
928       TestObject *obj;
929       GSettings *settings;
930
931       settings = g_settings_new ("org.gtk.test.binding");
932       obj = test_object_new ();
933
934       g_settings_bind (settings, "string", obj, "int", G_SETTINGS_BIND_DEFAULT);
935
936       g_object_unref (obj);
937       g_object_unref (settings);
938     }
939   g_test_trap_assert_failed ();
940   g_test_trap_assert_stderr ("*not compatible*");
941 }
942
943 static gboolean
944 string_to_bool (GValue   *value,
945                 GVariant *variant,
946                 gpointer  user_data)
947 {
948   const gchar *s;
949
950   s = g_variant_get_string (variant, NULL);
951   g_value_set_boolean (value, g_strcmp0 (s, "true") == 0);
952
953   return TRUE;
954 }
955
956 static GVariant *
957 bool_to_string (const GValue       *value,
958                 const GVariantType *expected_type,
959                 gpointer            user_data)
960 {
961   if (g_value_get_boolean (value))
962     return g_variant_new_string ("true");
963   else
964     return g_variant_new_string ("false");
965 }
966
967 /* Test custom bindings.
968  * Translate strings to booleans and back
969  */
970 static void
971 test_custom_binding (void)
972 {
973   TestObject *obj;
974   GSettings *settings;
975   gchar *s;
976   gboolean b;
977
978   settings = g_settings_new ("org.gtk.test.binding");
979   obj = test_object_new ();
980
981   g_settings_set_string (settings, "string", "true");
982
983   g_settings_bind_with_mapping (settings, "string",
984                                 obj, "bool",
985                                 G_SETTINGS_BIND_DEFAULT,
986                                 string_to_bool,
987                                 bool_to_string,
988                                 NULL, NULL);
989
990   g_settings_set_string (settings, "string", "false");
991   g_object_get (obj, "bool", &b, NULL);
992   g_assert_cmpint (b, ==, FALSE);
993
994   g_settings_set_string (settings, "string", "not true");
995   g_object_get (obj, "bool", &b, NULL);
996   g_assert_cmpint (b, ==, FALSE);
997
998   g_object_set (obj, "bool", TRUE, NULL);
999   s = g_settings_get_string (settings, "string");
1000   g_assert_cmpstr (s, ==, "true");
1001
1002   g_object_unref (obj);
1003   g_object_unref (settings);
1004 }
1005
1006 /* Test that with G_SETTINGS_BIND_NO_CHANGES, the
1007  * initial settings value is transported to the object
1008  * side, but later settings changes do not affect the
1009  * object
1010  */
1011 static void
1012 test_no_change_binding (void)
1013 {
1014   TestObject *obj;
1015   GSettings *settings;
1016   gboolean b;
1017
1018   settings = g_settings_new ("org.gtk.test.binding");
1019   obj = test_object_new ();
1020
1021   g_object_set (obj, "bool", TRUE, NULL);
1022   g_settings_set_boolean (settings, "bool", FALSE);
1023
1024   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET_NO_CHANGES);
1025
1026   g_object_get (obj, "bool", &b, NULL);
1027   g_assert_cmpint (b, ==, FALSE);
1028
1029   g_settings_set_boolean (settings, "bool", TRUE);
1030   g_object_get (obj, "bool", &b, NULL);
1031   g_assert_cmpint (b, ==, FALSE);
1032
1033   g_settings_set_boolean (settings, "bool", FALSE);
1034   g_object_set (obj, "bool", TRUE, NULL);
1035   b = g_settings_get_boolean (settings, "bool");
1036   g_assert_cmpint (b, ==, TRUE);
1037
1038   g_object_unref (obj);
1039   g_object_unref (settings);
1040 }
1041
1042 /* Test that binding a non-readable property only
1043  * works in 'GET' mode.
1044  */
1045 static void
1046 test_no_read_binding (void)
1047 {
1048   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1049     {
1050       TestObject *obj;
1051       GSettings *settings;
1052
1053       settings = g_settings_new ("org.gtk.test.binding");
1054       obj = test_object_new ();
1055
1056       g_settings_bind (settings, "string", obj, "no-read", 0);
1057     }
1058   g_test_trap_assert_failed ();
1059   g_test_trap_assert_stderr ("*property*is not readable*");
1060
1061   if (g_test_trap_fork (0, 0))
1062     {
1063       TestObject *obj;
1064       GSettings *settings;
1065
1066       settings = g_settings_new ("org.gtk.test.binding");
1067       obj = test_object_new ();
1068
1069       g_settings_bind (settings, "string", obj, "no-read", G_SETTINGS_BIND_GET);
1070
1071       exit (0);
1072     }
1073   g_test_trap_assert_passed ();
1074 }
1075
1076 /* Test that binding a non-writable property only
1077  * works in 'SET' mode.
1078  */
1079 static void
1080 test_no_write_binding (void)
1081 {
1082   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1083     {
1084       TestObject *obj;
1085       GSettings *settings;
1086
1087       settings = g_settings_new ("org.gtk.test.binding");
1088       obj = test_object_new ();
1089
1090       g_settings_bind (settings, "string", obj, "no-write", 0);
1091     }
1092   g_test_trap_assert_failed ();
1093   g_test_trap_assert_stderr ("*property*is not writable*");
1094
1095   if (g_test_trap_fork (0, 0))
1096     {
1097       TestObject *obj;
1098       GSettings *settings;
1099
1100       settings = g_settings_new ("org.gtk.test.binding");
1101       obj = test_object_new ();
1102
1103       g_settings_bind (settings, "string", obj, "no-write", G_SETTINGS_BIND_SET);
1104
1105       exit (0);
1106     }
1107   g_test_trap_assert_passed ();
1108 }
1109
1110 /*
1111  * Test that using a keyfile works
1112  */
1113 static void
1114 test_keyfile (void)
1115 {
1116   GSettings *settings;
1117   GKeyFile *keyfile;
1118   gchar *str;
1119
1120   g_remove ("gsettings.store");
1121
1122   g_settings_backend_setup_keyfile ("blah", "gsettings.store");
1123
1124   settings = g_settings_new_with_context ("org.gtk.test", "blah");
1125
1126   g_settings_set (settings, "greeting", "s", "see if this works");
1127
1128   keyfile = g_key_file_new ();
1129   g_assert (g_key_file_load_from_file (keyfile, "gsettings.store", 0, NULL));
1130
1131   str = g_key_file_get_string (keyfile, "/tests/", "greeting", NULL);
1132   g_assert_cmpstr (str, ==, "'see if this works'");
1133
1134   g_free (str);
1135   g_key_file_free (keyfile);
1136   g_object_unref (settings);
1137 }
1138
1139 /* Test that getting child schemas works
1140  */
1141 static void
1142 test_child_schema (void)
1143 {
1144   GSettings *settings;
1145   GSettings *child;
1146   guint8 byte;
1147
1148   /* first establish some known conditions */
1149   settings = g_settings_new ("org.gtk.test.basic-types");
1150   g_settings_set (settings, "test-byte", "y", 36);
1151
1152   g_settings_get (settings, "test-byte", "y", &byte);
1153   g_assert_cmpint (byte, ==, 36);
1154
1155   g_object_unref (settings);
1156
1157   settings = g_settings_new ("org.gtk.test");
1158   child = g_settings_get_child (settings, "basic-types");
1159   g_assert (child != NULL);
1160
1161   g_settings_get (child, "test-byte", "y", &byte);
1162   g_assert_cmpint (byte, ==, 36);
1163
1164   g_object_unref (child);
1165   g_object_unref (settings);
1166 }
1167
1168 static gboolean
1169 glib_translations_work (void)
1170 {
1171   gchar *locale;
1172   gchar *orig = "Unnamed";
1173   gchar *str;
1174
1175   locale = g_strdup (setlocale (LC_MESSAGES, NULL));
1176   setlocale (LC_MESSAGES, "de");
1177   str = dgettext ("glib20", orig);
1178   setlocale (LC_MESSAGES, locale);
1179   g_free (locale);
1180
1181   return str != orig;
1182 }
1183
1184 int
1185 main (int argc, char *argv[])
1186 {
1187   setlocale (LC_ALL, "");
1188
1189   g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
1190   g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
1191
1192   g_type_init ();
1193   g_test_init (&argc, &argv, NULL);
1194
1195   g_remove ("gschemas.compiled");
1196   g_assert (g_spawn_command_line_sync ("../glib-compile-schemas --targetdir=. " SRCDIR,
1197                                        NULL, NULL, NULL, NULL));
1198
1199   g_test_add_func ("/gsettings/basic", test_basic);
1200   g_test_add_func ("/gsettings/no-schema", test_no_schema);
1201   g_test_add_func ("/gsettings/unknown-key", test_unknown_key);
1202   g_test_add_func ("/gsettings/wrong-type", test_wrong_type);
1203   g_test_add_func ("/gsettings/basic-types", test_basic_types);
1204   g_test_add_func ("/gsettings/complex-types", test_complex_types);
1205   g_test_add_func ("/gsettings/changes", test_changes);
1206
1207   if (glib_translations_work ())
1208     {
1209       g_test_add_func ("/gsettings/l10n", test_l10n);
1210       g_test_add_func ("/gsettings/l10n-context", test_l10n_context);
1211     }
1212
1213   g_test_add_func ("/gsettings/delay-apply", test_delay_apply);
1214   g_test_add_func ("/gsettings/delay-revert", test_delay_revert);
1215   g_test_add_func ("/gsettings/atomic", test_atomic);
1216   g_test_add_func ("/gsettings/simple-binding", test_simple_binding);
1217   g_test_add_func ("/gsettings/directional-binding", test_directional_binding);
1218   g_test_add_func ("/gsettings/typesafe-binding", test_typesafe_binding);
1219   g_test_add_func ("/gsettings/custom-binding", test_custom_binding);
1220   g_test_add_func ("/gsettings/no-change-binding", test_no_change_binding);
1221   g_test_add_func ("/gsettings/no-read-binding", test_no_read_binding);
1222   g_test_add_func ("/gsettings/no-write-binding", test_no_write_binding);
1223   g_test_add_func ("/gsettings/keyfile", test_keyfile);
1224   g_test_add_func ("/gsettings/child-schema", test_child_schema);
1225
1226   return g_test_run ();
1227 }