gio/tests/socket-client, socket-server: fix for win32
[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_INT64,
644   PROP_UINT64,
645   PROP_DOUBLE,
646   PROP_STRING,
647   PROP_NO_READ,
648   PROP_NO_WRITE
649 };
650
651 typedef struct
652 {
653   GObject parent_instance;
654
655   gboolean bool_prop;
656   gint int_prop;
657   gint64 int64_prop;
658   guint64 uint64_prop;
659   gdouble double_prop;
660   gchar *string_prop;
661   gchar *no_read_prop;
662   gchar *no_write_prop;
663 } TestObject;
664
665 typedef struct
666 {
667   GObjectClass parent_class;
668 } TestObjectClass;
669
670 G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
671
672 static void
673 test_object_init (TestObject *object)
674 {
675 }
676
677 static void
678 test_object_finalize (GObject *object)
679 {
680   TestObject *testo = (TestObject*)object;
681   g_free (testo->string_prop);
682   G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
683 }
684
685 static void
686 test_object_get_property (GObject    *object,
687                           guint       prop_id,
688                           GValue     *value,
689                           GParamSpec *pspec)
690 {
691   TestObject *test_object = (TestObject *)object;
692
693   switch (prop_id)
694     {
695     case PROP_BOOL:
696       g_value_set_boolean (value, test_object->bool_prop);
697       break;
698     case PROP_INT:
699       g_value_set_int (value, test_object->int_prop);
700       break;
701     case PROP_INT64:
702       g_value_set_int64 (value, test_object->int64_prop);
703       break;
704     case PROP_UINT64:
705       g_value_set_uint64 (value, test_object->uint64_prop);
706       break;
707     case PROP_DOUBLE:
708       g_value_set_double (value, test_object->double_prop);
709       break;
710     case PROP_STRING:
711       g_value_set_string (value, test_object->string_prop);
712       break;
713     case PROP_NO_WRITE:
714       g_value_set_string (value, test_object->no_write_prop);
715       break;
716     default:
717       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
718       break;
719     }
720 }
721
722 static void
723 test_object_set_property (GObject      *object,
724                           guint         prop_id,
725                           const GValue *value,
726                           GParamSpec   *pspec)
727 {
728   TestObject *test_object = (TestObject *)object;
729
730   switch (prop_id)
731     {
732     case PROP_BOOL:
733       test_object->bool_prop = g_value_get_boolean (value);
734       break;
735     case PROP_INT:
736       test_object->int_prop = g_value_get_int (value);
737       break;
738     case PROP_INT64:
739       test_object->int64_prop = g_value_get_int64 (value);
740       break;
741     case PROP_UINT64:
742       test_object->uint64_prop = g_value_get_uint64 (value);
743       break;
744     case PROP_DOUBLE:
745       test_object->double_prop = g_value_get_double (value);
746       break;
747     case PROP_STRING:
748       g_free (test_object->string_prop);
749       test_object->string_prop = g_value_dup_string (value);
750       break;
751     case PROP_NO_READ:
752       g_free (test_object->no_read_prop);
753       test_object->no_read_prop = g_value_dup_string (value);
754       break;
755     default:
756       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
757       break;
758     }
759 }
760
761 static void
762 test_object_class_init (TestObjectClass *class)
763 {
764   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
765
766   gobject_class->get_property = test_object_get_property;
767   gobject_class->set_property = test_object_set_property;
768   gobject_class->finalize = test_object_finalize;
769
770   g_object_class_install_property (gobject_class, PROP_BOOL,
771     g_param_spec_boolean ("bool", "", "", FALSE, G_PARAM_READWRITE));
772   g_object_class_install_property (gobject_class, PROP_INT,
773     g_param_spec_int ("int", "", "", -G_MAXINT, G_MAXINT, 0, G_PARAM_READWRITE));
774   g_object_class_install_property (gobject_class, PROP_INT64,
775     g_param_spec_int64 ("int64", "", "", G_MININT64, G_MAXINT64, 0, G_PARAM_READWRITE));
776   g_object_class_install_property (gobject_class, PROP_UINT64,
777     g_param_spec_uint64 ("uint64", "", "", 0, G_MAXUINT64, 0, G_PARAM_READWRITE));
778   g_object_class_install_property (gobject_class, PROP_DOUBLE,
779     g_param_spec_double ("double", "", "", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE));
780   g_object_class_install_property (gobject_class, PROP_STRING,
781     g_param_spec_string ("string", "", "", NULL, G_PARAM_READWRITE));
782   g_object_class_install_property (gobject_class, PROP_NO_WRITE,
783     g_param_spec_string ("no-write", "", "", NULL, G_PARAM_READABLE));
784   g_object_class_install_property (gobject_class, PROP_NO_READ,
785     g_param_spec_string ("no-read", "", "", NULL, G_PARAM_WRITABLE));
786 }
787
788 static TestObject *
789 test_object_new (void)
790 {
791   return (TestObject*)g_object_new (test_object_get_type (), NULL);
792 }
793
794 /* Test basic binding functionality for simple types.
795  * Verify that with bidirectional bindings, changes on either side
796  * are notified on the other end.
797  */
798 static void
799 test_simple_binding (void)
800 {
801   TestObject *obj;
802   GSettings *settings;
803   gboolean b;
804   gint i;
805   gint64 i64;
806   guint64 u64;
807   gdouble d;
808   gchar *s;
809
810   settings = g_settings_new ("org.gtk.test.binding");
811   obj = test_object_new ();
812
813   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_DEFAULT);
814
815   g_object_set (obj, "bool", TRUE, NULL);
816   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
817
818   g_settings_set_boolean (settings, "bool", FALSE);
819   g_object_get (obj, "bool", &b, NULL);
820   g_assert_cmpint (b, ==, FALSE);
821
822   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_DEFAULT);
823
824   g_object_set (obj, "int", 12345, NULL);
825   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 12345);
826
827   g_settings_set_int (settings, "int", 54321);
828   g_object_get (obj, "int", &i, NULL);
829   g_assert_cmpint (i, ==, 54321);
830
831   g_settings_bind (settings, "int64", obj, "int64", G_SETTINGS_BIND_DEFAULT);
832
833   g_object_set (obj, "int64", (gint64) G_MAXINT64, NULL);
834   g_settings_get (settings, "int64", "x", &i64);
835   g_assert_cmpint (i64, ==, G_MAXINT64);
836
837   g_settings_set (settings, "int64", "x", (gint64) G_MININT64);
838   g_object_get (obj, "int64", &i64, NULL);
839   g_assert_cmpint (i64, ==, G_MININT64);
840
841   g_settings_bind (settings, "uint64", obj, "uint64", G_SETTINGS_BIND_DEFAULT);
842
843   g_object_set (obj, "uint64", (guint64) G_MAXUINT64, NULL);
844   g_settings_get (settings, "uint64", "t", &u64);
845   g_assert_cmpuint (u64, ==, G_MAXUINT64);
846
847   g_settings_set (settings, "uint64", "t", (guint64) G_MAXINT64);
848   g_object_get (obj, "uint64", &u64, NULL);
849   g_assert_cmpuint (u64, ==, (guint64) G_MAXINT64);
850
851   g_settings_bind (settings, "string", obj, "string", G_SETTINGS_BIND_DEFAULT);
852
853   g_object_set (obj, "string", "bu ba", NULL);
854   s = g_settings_get_string (settings, "string");
855   g_assert_cmpstr (s, ==, "bu ba");
856   g_free (s);
857
858   g_settings_set_string (settings, "string", "bla bla");
859   g_object_get (obj, "string", &s, NULL);
860   g_assert_cmpstr (s, ==, "bla bla");
861   g_free (s);
862
863   g_settings_bind (settings, "double", obj, "double", G_SETTINGS_BIND_DEFAULT);
864
865   g_object_set (obj, "double", G_MAXFLOAT, NULL);
866   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXFLOAT);
867
868   g_settings_set_double (settings, "double", G_MINFLOAT);
869   g_object_get (obj, "double", &d, NULL);
870   g_assert_cmpfloat (d, ==, G_MINFLOAT);
871
872   g_object_set (obj, "double", G_MAXDOUBLE, NULL);
873   g_assert_cmpfloat (g_settings_get_double (settings, "double"), ==, G_MAXDOUBLE);
874
875   g_settings_set_double (settings, "double", -G_MINDOUBLE);
876   g_object_get (obj, "double", &d, NULL);
877   g_assert_cmpfloat (d, ==, -G_MINDOUBLE);
878   g_object_unref (obj);
879   g_object_unref (settings);
880 }
881
882 /* Test one-way bindings.
883  * Verify that changes on one side show up on the other,
884  * but not vice versa
885  */
886 static void
887 test_directional_binding (void)
888 {
889   TestObject *obj;
890   GSettings *settings;
891   gboolean b;
892   gint i;
893
894   settings = g_settings_new ("org.gtk.test.binding");
895   obj = test_object_new ();
896
897   g_object_set (obj, "bool", FALSE, NULL);
898   g_settings_set_boolean (settings, "bool", FALSE);
899
900   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET);
901
902   g_settings_set_boolean (settings, "bool", TRUE);
903   g_object_get (obj, "bool", &b, NULL);
904   g_assert_cmpint (b, ==, TRUE);
905
906   g_object_set (obj, "bool", FALSE, NULL);
907   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
908
909   g_object_set (obj, "int", 20, NULL);
910   g_settings_set_int (settings, "int", 20);
911
912   g_settings_bind (settings, "int", obj, "int", G_SETTINGS_BIND_SET);
913
914   g_object_set (obj, "int", 32, NULL);
915   g_assert_cmpint (g_settings_get_int (settings, "int"), ==, 32);
916
917   g_settings_set_int (settings, "int", 20);
918   g_object_get (obj, "int", &i, NULL);
919   g_assert_cmpint (i, ==, 32);
920
921   g_object_unref (obj);
922   g_object_unref (settings);
923 }
924
925 /* Test that type mismatch is caught when creating a binding
926  */
927 static void
928 test_typesafe_binding (void)
929 {
930   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
931     {
932       TestObject *obj;
933       GSettings *settings;
934
935       settings = g_settings_new ("org.gtk.test.binding");
936       obj = test_object_new ();
937
938       g_settings_bind (settings, "string", obj, "int", G_SETTINGS_BIND_DEFAULT);
939
940       g_object_unref (obj);
941       g_object_unref (settings);
942     }
943   g_test_trap_assert_failed ();
944   g_test_trap_assert_stderr ("*not compatible*");
945 }
946
947 static gboolean
948 string_to_bool (GValue   *value,
949                 GVariant *variant,
950                 gpointer  user_data)
951 {
952   const gchar *s;
953
954   s = g_variant_get_string (variant, NULL);
955   g_value_set_boolean (value, g_strcmp0 (s, "true") == 0);
956
957   return TRUE;
958 }
959
960 static GVariant *
961 bool_to_string (const GValue       *value,
962                 const GVariantType *expected_type,
963                 gpointer            user_data)
964 {
965   if (g_value_get_boolean (value))
966     return g_variant_new_string ("true");
967   else
968     return g_variant_new_string ("false");
969 }
970
971 /* Test custom bindings.
972  * Translate strings to booleans and back
973  */
974 static void
975 test_custom_binding (void)
976 {
977   TestObject *obj;
978   GSettings *settings;
979   gchar *s;
980   gboolean b;
981
982   settings = g_settings_new ("org.gtk.test.binding");
983   obj = test_object_new ();
984
985   g_settings_set_string (settings, "string", "true");
986
987   g_settings_bind_with_mapping (settings, "string",
988                                 obj, "bool",
989                                 G_SETTINGS_BIND_DEFAULT,
990                                 string_to_bool,
991                                 bool_to_string,
992                                 NULL, NULL);
993
994   g_settings_set_string (settings, "string", "false");
995   g_object_get (obj, "bool", &b, NULL);
996   g_assert_cmpint (b, ==, FALSE);
997
998   g_settings_set_string (settings, "string", "not true");
999   g_object_get (obj, "bool", &b, NULL);
1000   g_assert_cmpint (b, ==, FALSE);
1001
1002   g_object_set (obj, "bool", TRUE, NULL);
1003   s = g_settings_get_string (settings, "string");
1004   g_assert_cmpstr (s, ==, "true");
1005
1006   g_object_unref (obj);
1007   g_object_unref (settings);
1008 }
1009
1010 /* Test that with G_SETTINGS_BIND_NO_CHANGES, the
1011  * initial settings value is transported to the object
1012  * side, but later settings changes do not affect the
1013  * object
1014  */
1015 static void
1016 test_no_change_binding (void)
1017 {
1018   TestObject *obj;
1019   GSettings *settings;
1020   gboolean b;
1021
1022   settings = g_settings_new ("org.gtk.test.binding");
1023   obj = test_object_new ();
1024
1025   g_object_set (obj, "bool", TRUE, NULL);
1026   g_settings_set_boolean (settings, "bool", FALSE);
1027
1028   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_GET_NO_CHANGES);
1029
1030   g_object_get (obj, "bool", &b, NULL);
1031   g_assert_cmpint (b, ==, FALSE);
1032
1033   g_settings_set_boolean (settings, "bool", TRUE);
1034   g_object_get (obj, "bool", &b, NULL);
1035   g_assert_cmpint (b, ==, FALSE);
1036
1037   g_settings_set_boolean (settings, "bool", FALSE);
1038   g_object_set (obj, "bool", TRUE, NULL);
1039   b = g_settings_get_boolean (settings, "bool");
1040   g_assert_cmpint (b, ==, TRUE);
1041
1042   g_object_unref (obj);
1043   g_object_unref (settings);
1044 }
1045
1046 /* Test that binding a non-readable property only
1047  * works in 'GET' mode.
1048  */
1049 static void
1050 test_no_read_binding (void)
1051 {
1052   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1053     {
1054       TestObject *obj;
1055       GSettings *settings;
1056
1057       settings = g_settings_new ("org.gtk.test.binding");
1058       obj = test_object_new ();
1059
1060       g_settings_bind (settings, "string", obj, "no-read", 0);
1061     }
1062   g_test_trap_assert_failed ();
1063   g_test_trap_assert_stderr ("*property*is not readable*");
1064
1065   if (g_test_trap_fork (0, 0))
1066     {
1067       TestObject *obj;
1068       GSettings *settings;
1069
1070       settings = g_settings_new ("org.gtk.test.binding");
1071       obj = test_object_new ();
1072
1073       g_settings_bind (settings, "string", obj, "no-read", G_SETTINGS_BIND_GET);
1074
1075       exit (0);
1076     }
1077   g_test_trap_assert_passed ();
1078 }
1079
1080 /* Test that binding a non-writable property only
1081  * works in 'SET' mode.
1082  */
1083 static void
1084 test_no_write_binding (void)
1085 {
1086   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
1087     {
1088       TestObject *obj;
1089       GSettings *settings;
1090
1091       settings = g_settings_new ("org.gtk.test.binding");
1092       obj = test_object_new ();
1093
1094       g_settings_bind (settings, "string", obj, "no-write", 0);
1095     }
1096   g_test_trap_assert_failed ();
1097   g_test_trap_assert_stderr ("*property*is not writable*");
1098
1099   if (g_test_trap_fork (0, 0))
1100     {
1101       TestObject *obj;
1102       GSettings *settings;
1103
1104       settings = g_settings_new ("org.gtk.test.binding");
1105       obj = test_object_new ();
1106
1107       g_settings_bind (settings, "string", obj, "no-write", G_SETTINGS_BIND_SET);
1108
1109       exit (0);
1110     }
1111   g_test_trap_assert_passed ();
1112 }
1113
1114 /*
1115  * Test that using a keyfile works
1116  */
1117 static void
1118 test_keyfile (void)
1119 {
1120   GSettings *settings;
1121   GKeyFile *keyfile;
1122   gchar *str;
1123
1124   g_remove ("gsettings.store");
1125
1126   g_settings_backend_setup_keyfile ("blah", "gsettings.store");
1127
1128   settings = g_settings_new_with_context ("org.gtk.test", "blah");
1129
1130   g_settings_set (settings, "greeting", "s", "see if this works");
1131
1132   keyfile = g_key_file_new ();
1133   g_assert (g_key_file_load_from_file (keyfile, "gsettings.store", 0, NULL));
1134
1135   str = g_key_file_get_string (keyfile, "/tests/", "greeting", NULL);
1136   g_assert_cmpstr (str, ==, "'see if this works'");
1137
1138   g_free (str);
1139   g_key_file_free (keyfile);
1140   g_object_unref (settings);
1141 }
1142
1143 /* Test that getting child schemas works
1144  */
1145 static void
1146 test_child_schema (void)
1147 {
1148   GSettings *settings;
1149   GSettings *child;
1150   guint8 byte;
1151
1152   /* first establish some known conditions */
1153   settings = g_settings_new ("org.gtk.test.basic-types");
1154   g_settings_set (settings, "test-byte", "y", 36);
1155
1156   g_settings_get (settings, "test-byte", "y", &byte);
1157   g_assert_cmpint (byte, ==, 36);
1158
1159   g_object_unref (settings);
1160
1161   settings = g_settings_new ("org.gtk.test");
1162   child = g_settings_get_child (settings, "basic-types");
1163   g_assert (child != NULL);
1164
1165   g_settings_get (child, "test-byte", "y", &byte);
1166   g_assert_cmpint (byte, ==, 36);
1167
1168   g_object_unref (child);
1169   g_object_unref (settings);
1170 }
1171
1172 int
1173 main (int argc, char *argv[])
1174 {
1175   setlocale (LC_ALL, "");
1176
1177   g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
1178   g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
1179
1180   g_type_init ();
1181   g_test_init (&argc, &argv, NULL);
1182
1183   g_remove ("gschemas.compiled");
1184   g_assert (g_spawn_command_line_sync ("../gschema-compile --targetdir=. " SRCDIR,
1185                                        NULL, NULL, NULL, NULL));
1186
1187   g_test_add_func ("/gsettings/basic", test_basic);
1188   g_test_add_func ("/gsettings/no-schema", test_no_schema);
1189   g_test_add_func ("/gsettings/unknown-key", test_unknown_key);
1190   g_test_add_func ("/gsettings/wrong-type", test_wrong_type);
1191   g_test_add_func ("/gsettings/basic-types", test_basic_types);
1192   g_test_add_func ("/gsettings/complex-types", test_complex_types);
1193   g_test_add_func ("/gsettings/changes", test_changes);
1194 #ifndef G_OS_WIN32
1195   g_test_add_func ("/gsettings/l10n", test_l10n);
1196   g_test_add_func ("/gsettings/l10n-context", test_l10n_context);
1197 #endif
1198   g_test_add_func ("/gsettings/delay-apply", test_delay_apply);
1199   g_test_add_func ("/gsettings/delay-revert", test_delay_revert);
1200   g_test_add_func ("/gsettings/atomic", test_atomic);
1201   g_test_add_func ("/gsettings/simple-binding", test_simple_binding);
1202   g_test_add_func ("/gsettings/directional-binding", test_directional_binding);
1203   g_test_add_func ("/gsettings/typesafe-binding", test_typesafe_binding);
1204   g_test_add_func ("/gsettings/custom-binding", test_custom_binding);
1205   g_test_add_func ("/gsettings/no-change-binding", test_no_change_binding);
1206   g_test_add_func ("/gsettings/no-read-binding", test_no_read_binding);
1207   g_test_add_func ("/gsettings/no-write-binding", test_no_write_binding);
1208   g_test_add_func ("/gsettings/keyfile", test_keyfile);
1209   g_test_add_func ("/gsettings/child-schema", test_child_schema);
1210
1211   return g_test_run ();
1212 }