1 /* GObject - GLib Type, Object, Parameter and Signal Library 2 * Copyright (C) 2001, 2003 Red Hat, Inc. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library 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. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General 15 * Public License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20 #undef G_LOG_DOMAIN 21 #define G_LOG_DOMAIN "TestIfaceInit" 22 23 #undef G_DISABLE_ASSERT 24 #undef G_DISABLE_CHECKS 25 #undef G_DISABLE_CAST_CHECKS 26 27 #include <glib-object.h> 28 29 #include "testcommon.h" 30 31 /* What this test tests is the ability to add interfaces dynamically; in 32 * particular adding interfaces to a class while that class is being 33 * initialized. 34 * 35 * The test defines 5 interfaces: 36 * 37 * - TestIface1 is added before the class is initialized 38 * - TestIface2 is added in base_object_base_init() 39 * - TestIface3 is added in test_iface1_base_init() 40 * - TestIface4 is added in test_object_class_init() 41 * - TestIface5 is added in test_object_test_iface1_init() 42 * - TestIface6 is added after the class is initialized 43 */ 44 45 /* All 6 interfaces actually share the same class structure, though 46 * we use separate typedefs 47 */ 48 typedef struct _TestIfaceClass TestIfaceClass; 49 50 struct _TestIfaceClass 51 { 52 GTypeInterface base_iface; 53 guint val; 54 guint base_val; 55 guint default_val; 56 }; 57 58 #define TEST_TYPE_IFACE1 (test_iface1_get_type ()) 59 #define TEST_IFACE1_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE1, TestIface1Class)) 60 typedef struct _TestIface1 TestIface1; 61 typedef struct _TestIfaceClass TestIface1Class; 62 63 static void test_iface1_base_init (TestIface1Class *iface); 64 static void test_iface1_default_init (TestIface1Class *iface, gpointer class_data); 65 66 static DEFINE_IFACE(TestIface1, test_iface1, test_iface1_base_init, test_iface1_default_init) 67 68 #define TEST_TYPE_IFACE2 (test_iface2_get_type ()) 69 #define TEST_IFACE2_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE2, TestIface2Class)) 70 typedef struct _TestIface2 TestIface2; 71 typedef struct _TestIfaceClass TestIface2Class; 72 73 static void test_iface2_base_init (TestIface2Class *iface); 74 75 static DEFINE_IFACE(TestIface2, test_iface2, test_iface2_base_init, NULL) 76 77 #define TEST_TYPE_IFACE3 (test_iface3_get_type ()) 78 #define TEST_IFACE3_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE3, TestIface3Class)) 79 typedef struct _TestIface3 TestIface3; 80 typedef struct _TestIfaceClass TestIface3Class; 81 82 static void test_iface3_base_init (TestIface3Class *iface); 83 84 static DEFINE_IFACE(TestIface3, test_iface3, test_iface3_base_init, NULL) 85 86 #define TEST_TYPE_IFACE4 (test_iface4_get_type ()) 87 #define TEST_IFACE4_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE4, TestIface4Class)) 88 typedef struct _TestIface4 TestIface4; 89 typedef struct _TestIfaceClass TestIface4Class; 90 91 static void test_iface4_base_init (TestIface4Class *iface); 92 93 static DEFINE_IFACE(TestIface4, test_iface4, test_iface4_base_init, NULL) 94 95 #define TEST_TYPE_IFACE5 (test_iface5_get_type ()) 96 #define TEST_IFACE5_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE5, TestIface5Class)) 97 typedef struct _TestIface5 TestIface5; 98 typedef struct _TestIfaceClass TestIface5Class; 99 100 static void test_iface5_base_init (TestIface5Class *iface); 101 102 static DEFINE_IFACE(TestIface5, test_iface5, test_iface5_base_init, NULL) 103 104 #define TEST_TYPE_IFACE6 (test_iface6_get_type ()) 105 #define TEST_IFACE6_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_IFACE6, TestIface6Class)) 106 typedef struct _TestIface6 TestIface6; 107 typedef struct _TestIfaceClass TestIface6Class; 108 109 static void test_iface6_base_init (TestIface6Class *iface); 110 111 static DEFINE_IFACE(TestIface6, test_iface6, test_iface6_base_init, NULL) 112 113 /* 114 * BaseObject, a parent class for TestObject 115 */ 116 #define BASE_TYPE_OBJECT (base_object_get_type ()) 117 typedef struct _BaseObject BaseObject; 118 typedef struct _BaseObjectClass BaseObjectClass; 119 120 struct _BaseObject 121 { 122 GObject parent_instance; 123 }; 124 struct _BaseObjectClass 125 { 126 GObjectClass parent_class; 127 }; 128 129 /* 130 * TestObject, a parent class for TestObject 131 */ 132 #define TEST_TYPE_OBJECT (test_object_get_type ()) 133 typedef struct _TestObject TestObject; 134 typedef struct _TestObjectClass TestObjectClass; 135 136 struct _TestObject 137 { 138 BaseObject parent_instance; 139 }; 140 struct _TestObjectClass 141 { 142 BaseObjectClass parent_class; 143 }; 144 145 #define TEST_CALLED_ONCE() G_STMT_START { \ 146 static gboolean called = 0; \ 147 g_assert (!called); \ 148 called = TRUE; \ 149 } G_STMT_END 150 151 #define CHECK_IFACE_TWICE(iface) G_STMT_START { \ 152 static guint n_calls = 0; \ 153 n_calls++; \ 154 g_assert (n_calls <= 2); \ 155 g_assert (G_TYPE_IS_INTERFACE (((GTypeInterface*) iface)->g_type)); \ 156 if (n_calls == 1) \ 157 g_assert (((GTypeInterface*) iface)->g_instance_type == 0); \ 158 else \ 159 g_assert (G_TYPE_IS_OBJECT (((GTypeInterface*) iface)->g_instance_type)); \ 160 } G_STMT_END 161 162 #define ADD_IFACE(n) G_STMT_START { \ 163 static GInterfaceInfo iface_info = { \ 164 (GInterfaceInitFunc)test_object_test_iface##n##_init, \ 165 NULL, NULL }; \ 166 \ 167 g_type_add_interface_static (TEST_TYPE_OBJECT, \ 168 test_iface##n##_get_type (), \ 169 &iface_info); \ 170 \ 171 } G_STMT_END 172 173 static gboolean base1, base2, base3, base4, base5, base6; 174 static gboolean iface1, iface2, iface3, iface4, iface5, iface6; 175 176 static void test_object_test_iface1_init (TestIface1Class *iface); 177 static void test_object_test_iface2_init (TestIface1Class *iface); 178 static void test_object_test_iface3_init (TestIface3Class *iface); 179 static void test_object_test_iface4_init (TestIface4Class *iface); 180 static void test_object_test_iface5_init (TestIface5Class *iface); 181 static void test_object_test_iface6_init (TestIface6Class *iface); 182 183 static GType test_object_get_type (void); 184 185 static void 186 test_object_test_iface1_init (TestIface1Class *iface) 187 { 188 TEST_CALLED_ONCE(); 189 190 g_assert (iface->default_val == 0x111111); 191 192 iface->val = 0x10001; 193 194 ADD_IFACE(5); 195 196 iface1 = TRUE; 197 } 198 199 static void 200 test_object_test_iface2_init (TestIface2Class *iface) 201 { 202 TEST_CALLED_ONCE(); 203 204 iface->val = 0x20002; 205 206 iface2 = TRUE; 207 } 208 209 static void 210 test_object_test_iface3_init (TestIface3Class *iface) 211 { 212 TEST_CALLED_ONCE(); 213 214 iface->val = 0x30003; 215 216 iface3 = TRUE; 217 } 218 219 static void 220 test_object_test_iface4_init (TestIface4Class *iface) 221 { 222 TEST_CALLED_ONCE(); 223 224 iface->val = 0x40004; 225 226 iface4 = TRUE; 227 } 228 229 static void 230 test_object_test_iface5_init (TestIface5Class *iface) 231 { 232 TEST_CALLED_ONCE(); 233 234 iface->val = 0x50005; 235 236 iface5 = TRUE; 237 } 238 239 static void 240 test_object_test_iface6_init (TestIface6Class *iface) 241 { 242 TEST_CALLED_ONCE(); 243 244 iface->val = 0x60006; 245 246 iface6 = TRUE; 247 } 248 249 static void 250 test_iface1_default_init (TestIface1Class *iface, 251 gpointer class_data) 252 { 253 TEST_CALLED_ONCE(); 254 g_assert (iface->base_iface.g_type == TEST_TYPE_IFACE1); 255 g_assert (iface->base_iface.g_instance_type == 0); 256 g_assert (iface->base_val == 0x110011); 257 g_assert (iface->val == 0); 258 g_assert (iface->default_val == 0); 259 iface->default_val = 0x111111; 260 } 261 262 static void 263 test_iface1_base_init (TestIface1Class *iface) 264 { 265 static guint n_calls = 0; 266 n_calls++; 267 g_assert (n_calls <= 2); 268 269 if (n_calls == 1) 270 { 271 iface->base_val = 0x110011; 272 g_assert (iface->default_val == 0); 273 } 274 else 275 { 276 g_assert (iface->base_val == 0x110011); 277 g_assert (iface->default_val == 0x111111); 278 } 279 280 if (n_calls == 1) 281 ADD_IFACE(3); 282 283 base1 = TRUE; 284 } 285 286 static void 287 test_iface2_base_init (TestIface2Class *iface) 288 { 289 CHECK_IFACE_TWICE (iface); 290 291 iface->base_val = 0x220022; 292 293 base2 = TRUE; 294 } 295 296 static void 297 test_iface3_base_init (TestIface3Class *iface) 298 { 299 CHECK_IFACE_TWICE (iface); 300 301 iface->base_val = 0x330033; 302 303 base3 = TRUE; 304 } 305 306 static void 307 test_iface4_base_init (TestIface4Class *iface) 308 { 309 CHECK_IFACE_TWICE (iface); 310 311 iface->base_val = 0x440044; 312 313 base4 = TRUE; 314 } 315 316 static void 317 test_iface5_base_init (TestIface5Class *iface) 318 { 319 CHECK_IFACE_TWICE (iface); 320 321 iface->base_val = 0x550055; 322 323 base5 = TRUE; 324 } 325 326 static void 327 test_iface6_base_init (TestIface6Class *iface) 328 { 329 CHECK_IFACE_TWICE (iface); 330 331 iface->base_val = 0x660066; 332 333 base6 = TRUE; 334 } 335 336 static void 337 base_object_base_init (BaseObjectClass *class) 338 { 339 static int n_called = 0; 340 n_called++; 341 342 /* The second time this is called is for TestObject */ 343 if (n_called == 2) 344 { 345 ADD_IFACE(2); 346 347 /* No interface base init functions should have been called yet 348 */ 349 g_assert (!base1 && !base2 && !base3 && !base4 && !base5 && !base6); 350 g_assert (!iface1 && !iface2 && !iface3 && !iface4 && !iface5 && !iface6); 351 } 352 } 353 354 static void 355 test_object_class_init (TestObjectClass *class) 356 { 357 ADD_IFACE(4); 358 359 /* At this point, the base init functions for all interfaces that have 360 * been added should be called, but no interface init functions. 361 */ 362 g_assert (base1 && base2 && base3 && base4 && !base5 && !base6); 363 g_assert (!iface1 && !iface2 && !iface3 && !iface4 && !iface5 && !iface6); 364 } 365 366 static DEFINE_TYPE(BaseObject, base_object, 367 NULL, base_object_base_init, NULL, 368 G_TYPE_OBJECT) 369 static DEFINE_TYPE(TestObject, test_object, 370 test_object_class_init, NULL, NULL, 371 BASE_TYPE_OBJECT) 372 373 int 374 main (int argc, 375 char *argv[]) 376 { 377 TestObject *object; 378 TestObjectClass *object_class; 379 TestIfaceClass *iface; 380 381 g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) | 382 G_LOG_LEVEL_WARNING | 383 G_LOG_LEVEL_CRITICAL); 384 g_type_init (); 385 386 /* We force the interfaces to be registered in a different order 387 * than we add them, so our logic doesn't always deal with interfaces 388 * added at the end. 389 */ 390 (void)TEST_TYPE_IFACE4; 391 (void)TEST_TYPE_IFACE2; 392 (void)TEST_TYPE_IFACE6; 393 (void)TEST_TYPE_IFACE5; 394 (void)TEST_TYPE_IFACE3; 395 (void)TEST_TYPE_IFACE1; 396 397 ADD_IFACE(1); 398 399 object_class = g_type_class_ref (TEST_TYPE_OBJECT); 400 401 ADD_IFACE(6); 402 403 /* All base and interface init functions should have been called 404 */ 405 g_assert (base1 && base2 && base3 && base4 && base5 && base6); 406 g_assert (iface1 && iface2 && iface3 && iface4 && iface5 && iface6); 407 408 object = g_object_new (TEST_TYPE_OBJECT, NULL); 409 410 iface = TEST_IFACE1_GET_CLASS (object); 411 g_assert (iface && iface->val == 0x10001 && iface->base_val == 0x110011); 412 iface = TEST_IFACE3_GET_CLASS (object); 413 g_assert (iface && iface->val == 0x30003 && iface->base_val == 0x330033); 414 iface = TEST_IFACE4_GET_CLASS (object); 415 g_assert (iface && iface->val == 0x40004 && iface->base_val == 0x440044); 416 iface = TEST_IFACE5_GET_CLASS (object); 417 g_assert (iface && iface->val == 0x50005 && iface->base_val == 0x550055); 418 iface = TEST_IFACE6_GET_CLASS (object); 419 g_assert (iface && iface->val == 0x60006 && iface->base_val == 0x660066); 420 421 return 0; 422 } 423