1 /* properties-introspection.c: Test the properties introspection API
2 *
3 * SPDX-FileCopyrightText: 2023 Emmanuele Bassi
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7 /* This test is isolated so we can control the initialization of
8 * GObjectClass, and the global GParamSpecPool
9 */
10
11 #include <stdlib.h>
12 #include <glib-object.h>
13
14 G_DECLARE_INTERFACE (MyTestable, my_testable, MY, TESTABLE, GObject)
15
16 struct _MyTestableInterface
17 {
18 GTypeInterface g_iface;
19 };
20
21 G_DEFINE_INTERFACE (MyTestable, my_testable, G_TYPE_OBJECT)
22
23 static void
24 my_testable_default_init (MyTestableInterface *iface)
25 {
26 g_object_interface_install_property (iface,
27 g_param_spec_int ("check", NULL, NULL, -1, 10, 0, G_PARAM_READWRITE));
28 }
29
30 static void
31 properties_introspection (void)
32 {
33 g_test_summary ("Verify that introspecting properties on an interface initializes the GParamSpecPool.");
34
35 if (g_test_subprocess ())
36 {
37 gpointer klass = g_type_default_interface_ref (my_testable_get_type ());
38 g_assert_nonnull (klass);
39
40 GParamSpec *pspec = g_object_interface_find_property (klass, "check");
41 g_assert_nonnull (pspec);
42
43 g_type_default_interface_unref (klass);
44 return;
45 }
46
47 g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
48 g_test_trap_assert_passed ();
49 g_test_trap_assert_stderr ("");
50 }
51
52 static gpointer
53 inspect_func (gpointer data)
54 {
55 unsigned int *n_checks = data; /* (atomic) */
56
57 gpointer klass = NULL;
58 do
59 {
60 klass = g_type_default_interface_ref (my_testable_get_type ());
61 }
62 while (klass == NULL);
63
64 GParamSpec *pspec = NULL;
65 do
66 {
67 pspec = g_object_interface_find_property (klass, "check");
68 }
69 while (pspec == NULL);
70
71 g_type_default_interface_unref (klass);
72
73 g_atomic_int_inc (n_checks);
74
75 return NULL;
76 }
77
78 #define N_THREADS 10
79
80 static void
81 properties_collision (void)
82 {
83 GThread *threads[N_THREADS];
84 unsigned int n_checks = 0; /* (atomic) */
85
86 g_test_summary ("Verify that multiple threads create a single GParamSpecPool.");
87
88 for (unsigned int i = 0; i < N_THREADS; i++)
89 {
90 char *t_name = g_strdup_printf ("inspect [%d]", i);
91 threads[i] = g_thread_new (t_name, inspect_func, &n_checks);
92 g_assert_nonnull (threads[i]);
93 g_free (t_name);
94 }
95
96 while (g_atomic_int_get (&n_checks) != N_THREADS)
97 g_usleep (50);
98
99 for (unsigned int i = 0; i < N_THREADS; i++)
100 g_thread_join (threads[i]);
101 }
102
103 #undef N_THREADS
104
105 int
106 main (int argc, char *argv[])
107 {
108 g_test_init (&argc, &argv, NULL);
109
110 g_test_add_func ("/properties/introspection", properties_introspection);
111 g_test_add_func ("/properties/collision", properties_collision);
112
113 return g_test_run ();
114 }