1 | /* GLib testing framework examples and tests |
2 | * Copyright (C) 2008 Imendio AB |
3 | * Authors: Tim Janik |
4 | * |
5 | * This work is provided "as is"; redistribution and modification |
6 | * in whole or in part, in any medium, physical or electronic is |
7 | * permitted without restriction. |
8 | * |
9 | * This work is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
12 | * |
13 | * In no event shall the authors or contributors be liable for any |
14 | * direct, indirect, incidental, special, exemplary, or consequential |
15 | * damages (including, but not limited to, procurement of substitute |
16 | * goods or services; loss of use, data, or profits; or business |
17 | * interruption) however caused and on any theory of liability, whether |
18 | * in contract, strict liability, or tort (including negligence or |
19 | * otherwise) arising in any way out of the use of this software, even |
20 | * if advised of the possibility of such damage. |
21 | */ |
22 | #include <glib.h> |
23 | #include <glib-object.h> |
24 | |
25 | /* This test tests the macros for defining dynamic types. |
26 | */ |
27 | |
28 | static GMutex sync_mutex; |
29 | static gboolean loaded = FALSE; |
30 | |
31 | /* MODULE */ |
32 | typedef struct _TestModule TestModule; |
33 | typedef struct _TestModuleClass TestModuleClass; |
34 | |
35 | #define TEST_TYPE_MODULE (test_module_get_type ()) |
36 | #define TEST_MODULE(module) (G_TYPE_CHECK_INSTANCE_CAST ((module), TEST_TYPE_MODULE, TestModule)) |
37 | #define TEST_MODULE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), TEST_TYPE_MODULE, TestModuleClass)) |
38 | #define TEST_IS_MODULE(module) (G_TYPE_CHECK_INSTANCE_TYPE ((module), TEST_TYPE_MODULE)) |
39 | #define TEST_IS_MODULE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), TEST_TYPE_MODULE)) |
40 | #define TEST_MODULE_GET_CLASS(module) (G_TYPE_INSTANCE_GET_CLASS ((module), TEST_TYPE_MODULE, TestModuleClass)) |
41 | typedef void (*TestModuleRegisterFunc) (GTypeModule *module); |
42 | |
43 | struct _TestModule |
44 | { |
45 | GTypeModule parent_instance; |
46 | |
47 | TestModuleRegisterFunc register_func; |
48 | }; |
49 | |
50 | struct _TestModuleClass |
51 | { |
52 | GTypeModuleClass parent_class; |
53 | }; |
54 | |
55 | static GType test_module_get_type (void); |
56 | |
57 | static gboolean |
58 | test_module_load (GTypeModule *module) |
59 | { |
60 | TestModule *test_module = TEST_MODULE (module); |
61 | |
62 | test_module->register_func (module); |
63 | |
64 | return TRUE; |
65 | } |
66 | |
67 | static void |
68 | test_module_unload (GTypeModule *module) |
69 | { |
70 | } |
71 | |
72 | static void |
73 | test_module_class_init (TestModuleClass *class) |
74 | { |
75 | GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class); |
76 | |
77 | module_class->load = test_module_load; |
78 | module_class->unload = test_module_unload; |
79 | } |
80 | |
81 | static GType test_module_get_type (void) |
82 | { |
83 | static GType object_type = 0; |
84 | |
85 | if (!object_type) { |
86 | static const GTypeInfo object_info = |
87 | { |
88 | sizeof (TestModuleClass), |
89 | (GBaseInitFunc) NULL, |
90 | (GBaseFinalizeFunc) NULL, |
91 | (GClassInitFunc) test_module_class_init, |
92 | (GClassFinalizeFunc) NULL, |
93 | NULL, |
94 | sizeof (TestModule), |
95 | 0, |
96 | (GInstanceInitFunc)NULL, |
97 | NULL, |
98 | }; |
99 | object_type = g_type_register_static (G_TYPE_TYPE_MODULE, type_name: "TestModule" , info: &object_info, flags: 0); |
100 | } |
101 | return object_type; |
102 | } |
103 | |
104 | |
105 | static GTypeModule * |
106 | test_module_new (TestModuleRegisterFunc register_func) |
107 | { |
108 | TestModule *test_module = g_object_new (TEST_TYPE_MODULE, NULL); |
109 | GTypeModule *module = G_TYPE_MODULE (test_module); |
110 | |
111 | test_module->register_func = register_func; |
112 | |
113 | /* Register the types initially */ |
114 | g_type_module_use (module); |
115 | g_type_module_unuse (module); |
116 | |
117 | return G_TYPE_MODULE (module); |
118 | } |
119 | |
120 | |
121 | |
122 | #define DYNAMIC_OBJECT_TYPE (dynamic_object_get_type ()) |
123 | |
124 | typedef GObject DynamicObject; |
125 | typedef struct _DynamicObjectClass DynamicObjectClass; |
126 | |
127 | struct _DynamicObjectClass |
128 | { |
129 | GObjectClass parent_class; |
130 | guint val; |
131 | }; |
132 | |
133 | static GType dynamic_object_get_type (void); |
134 | G_DEFINE_DYNAMIC_TYPE(DynamicObject, dynamic_object, G_TYPE_OBJECT) |
135 | |
136 | static void |
137 | dynamic_object_class_init (DynamicObjectClass *class) |
138 | { |
139 | class->val = 42; |
140 | g_assert (loaded == FALSE); |
141 | loaded = TRUE; |
142 | } |
143 | |
144 | static void |
145 | dynamic_object_class_finalize (DynamicObjectClass *class) |
146 | { |
147 | g_assert (loaded == TRUE); |
148 | loaded = FALSE; |
149 | } |
150 | |
151 | static void |
152 | dynamic_object_init (DynamicObject *dynamic_object) |
153 | { |
154 | } |
155 | |
156 | |
157 | static void |
158 | module_register (GTypeModule *module) |
159 | { |
160 | dynamic_object_register_type (type_module: module); |
161 | } |
162 | |
163 | #define N_THREADS 100 |
164 | #define N_REFS 10000 |
165 | |
166 | static gpointer |
167 | ref_unref_thread (gpointer data) |
168 | { |
169 | gint i; |
170 | /* first, synchronize with other threads, |
171 | */ |
172 | if (g_test_verbose()) |
173 | g_printerr (format: "WAITING!\n" ); |
174 | g_mutex_lock (mutex: &sync_mutex); |
175 | g_mutex_unlock (mutex: &sync_mutex); |
176 | if (g_test_verbose ()) |
177 | g_printerr (format: "STARTING\n" ); |
178 | |
179 | /* ref/unref the klass 10000000 times */ |
180 | for (i = N_REFS; i; i--) { |
181 | if (g_test_verbose ()) |
182 | if (i % 10) |
183 | g_printerr (format: "%d\n" , i); |
184 | g_type_class_unref (g_class: g_type_class_ref (type: (GType) data)); |
185 | } |
186 | |
187 | if (g_test_verbose()) |
188 | g_printerr (format: "DONE !\n" ); |
189 | |
190 | return NULL; |
191 | } |
192 | |
193 | static void |
194 | test_multithreaded_dynamic_type_init (void) |
195 | { |
196 | GTypeModule *module; |
197 | DynamicObjectClass *class; |
198 | /* Create N_THREADS threads that are going to just ref/unref a class */ |
199 | GThread *threads[N_THREADS]; |
200 | guint i; |
201 | |
202 | module = test_module_new (register_func: module_register); |
203 | g_assert (module != NULL); |
204 | |
205 | /* Not loaded until we call ref for the first time */ |
206 | class = g_type_class_peek (DYNAMIC_OBJECT_TYPE); |
207 | g_assert (class == NULL); |
208 | g_assert (!loaded); |
209 | |
210 | /* pause newly created threads */ |
211 | g_mutex_lock (mutex: &sync_mutex); |
212 | |
213 | /* create threads */ |
214 | for (i = 0; i < N_THREADS; i++) { |
215 | threads[i] = g_thread_new (name: "test" , func: ref_unref_thread, data: (gpointer) DYNAMIC_OBJECT_TYPE); |
216 | } |
217 | |
218 | /* execute threads */ |
219 | g_mutex_unlock (mutex: &sync_mutex); |
220 | |
221 | for (i = 0; i < N_THREADS; i++) { |
222 | g_thread_join (thread: threads[i]); |
223 | } |
224 | } |
225 | |
226 | enum |
227 | { |
228 | PROP_0, |
229 | PROP_FOO |
230 | }; |
231 | |
232 | typedef struct _DynObj DynObj; |
233 | typedef struct _DynObjClass DynObjClass; |
234 | typedef struct _DynIfaceInterface DynIfaceInterface; |
235 | |
236 | struct _DynObj |
237 | { |
238 | GObject obj; |
239 | |
240 | gint foo; |
241 | }; |
242 | |
243 | struct _DynObjClass |
244 | { |
245 | GObjectClass class; |
246 | }; |
247 | |
248 | struct _DynIfaceInterface |
249 | { |
250 | GTypeInterface iface; |
251 | }; |
252 | |
253 | static void dyn_obj_iface_init (DynIfaceInterface *iface); |
254 | |
255 | static GType dyn_iface_get_type (void); |
256 | G_DEFINE_INTERFACE (DynIface, dyn_iface, G_TYPE_OBJECT) |
257 | |
258 | static GType dyn_obj_get_type (void); |
259 | G_DEFINE_DYNAMIC_TYPE_EXTENDED(DynObj, dyn_obj, G_TYPE_OBJECT, 0, |
260 | G_IMPLEMENT_INTERFACE_DYNAMIC(dyn_iface_get_type (), dyn_obj_iface_init)) |
261 | |
262 | |
263 | static void |
264 | dyn_iface_default_init (DynIfaceInterface *iface) |
265 | { |
266 | g_object_interface_install_property (g_iface: iface, |
267 | pspec: g_param_spec_int (name: "foo" , NULL, NULL, minimum: 0, maximum: 100, default_value: 0, flags: G_PARAM_READWRITE)); |
268 | } |
269 | |
270 | static void |
271 | dyn_obj_iface_init (DynIfaceInterface *iface) |
272 | { |
273 | } |
274 | |
275 | static void |
276 | dyn_obj_init (DynObj *obj) |
277 | { |
278 | obj->foo = 0; |
279 | } |
280 | |
281 | static void |
282 | set_prop (GObject *object, |
283 | guint prop_id, |
284 | const GValue *value, |
285 | GParamSpec *pspec) |
286 | { |
287 | DynObj *obj = (DynObj *)object; |
288 | |
289 | switch (prop_id) |
290 | { |
291 | case PROP_FOO: |
292 | obj->foo = g_value_get_int (value); |
293 | break; |
294 | default: |
295 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
296 | break; |
297 | } |
298 | } |
299 | |
300 | static void |
301 | get_prop (GObject *object, |
302 | guint prop_id, |
303 | GValue *value, |
304 | GParamSpec *pspec) |
305 | { |
306 | DynObj *obj = (DynObj *)object; |
307 | |
308 | switch (prop_id) |
309 | { |
310 | case PROP_FOO: |
311 | g_value_set_int (value, v_int: obj->foo); |
312 | break; |
313 | default: |
314 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
315 | break; |
316 | } |
317 | } |
318 | |
319 | static void |
320 | dyn_obj_class_init (DynObjClass *class) |
321 | { |
322 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
323 | |
324 | object_class->set_property = set_prop; |
325 | object_class->get_property = get_prop; |
326 | |
327 | g_object_class_override_property (oclass: object_class, property_id: PROP_FOO, name: "foo" ); |
328 | } |
329 | |
330 | static void |
331 | dyn_obj_class_finalize (DynObjClass *class) |
332 | { |
333 | } |
334 | |
335 | static void |
336 | mod_register (GTypeModule *module) |
337 | { |
338 | dyn_obj_register_type (type_module: module); |
339 | } |
340 | |
341 | static void |
342 | test_dynamic_interface_properties (void) |
343 | { |
344 | GTypeModule *module; |
345 | DynObj *obj; |
346 | gint val; |
347 | |
348 | module = test_module_new (register_func: mod_register); |
349 | g_assert (module != NULL); |
350 | |
351 | obj = g_object_new (object_type: dyn_obj_get_type (), first_property_name: "foo" , 1, NULL); |
352 | g_object_get (object: obj, first_property_name: "foo" , &val, NULL); |
353 | g_assert_cmpint (val, ==, 1); |
354 | |
355 | g_object_unref (object: obj); |
356 | } |
357 | |
358 | int |
359 | main (int argc, |
360 | char *argv[]) |
361 | { |
362 | g_test_init (argc: &argc, argv: &argv, NULL); |
363 | |
364 | g_test_add_func (testpath: "/GObject/threaded-dynamic-ref-unref-init" , test_func: test_multithreaded_dynamic_type_init); |
365 | g_test_add_func (testpath: "/GObject/dynamic-interface-properties" , test_func: test_dynamic_interface_properties); |
366 | |
367 | return g_test_run(); |
368 | } |
369 | |