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 "TestIfaceProperties" 22 23 #undef G_DISABLE_ASSERT 24 #undef G_DISABLE_CHECKS 25 #undef G_DISABLE_CAST_CHECKS 26 27 #include <string.h> 28 29 #include <glib-object.h> 30 31 #include "testcommon.h" 32 33 /* This test tests interface properties, implementing interface 34 * properties and #GParamSpecOverride. 35 * 36 * Four properties are tested: 37 * 38 * prop1: Defined in TestIface, Implemented in BaseObject with a GParamSpecOverride 39 * prop2: Defined in TestIface, Implemented in BaseObject with a new property 40 * prop3: Defined in TestIface, Implemented in BaseObject, Overridden in DerivedObject 41 * prop4: Defined in BaseObject, Overridden in DerivedObject 42 */ 43 44 static GType base_object_get_type (); 45 static GType derived_object_get_type (); 46 47 enum { 48 BASE_PROP_0, 49 BASE_PROP1, 50 BASE_PROP2, 51 BASE_PROP3, 52 BASE_PROP4 53 }; 54 55 enum { 56 DERIVED_PROP_0, 57 DERIVED_PROP3, 58 DERIVED_PROP4 59 }; 60 61 /* 62 * BaseObject, a parent class for DerivedObject 63 */ 64 #define BASE_TYPE_OBJECT (base_object_get_type ()) 65 #define BASE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BASE_TYPE_OBJECT, BaseObject)) 66 typedef struct _BaseObject BaseObject; 67 typedef struct _BaseObjectClass BaseObjectClass; 68 69 struct _BaseObject 70 { 71 GObject parent_instance; 72 73 gint val1; 74 gint val2; 75 gint val3; 76 gint val4; 77 }; 78 struct _BaseObjectClass 79 { 80 GObjectClass parent_class; 81 }; 82 83 GObjectClass *base_parent_class; 84 85 /* 86 * DerivedObject, the child class of DerivedObject 87 */ 88 #define DERIVED_TYPE_OBJECT (derived_object_get_type ()) 89 typedef struct _DerivedObject DerivedObject; 90 typedef struct _DerivedObjectClass DerivedObjectClass; 91 92 struct _DerivedObject 93 { 94 BaseObject parent_instance; 95 }; 96 struct _DerivedObjectClass 97 { 98 BaseObjectClass parent_class; 99 }; 100 101 /* 102 * The interface 103 */ 104 typedef struct _TestIfaceClass TestIfaceClass; 105 106 struct _TestIfaceClass 107 { 108 GTypeInterface base_iface; 109 }; 110 111 #define TEST_TYPE_IFACE (test_iface_get_type ()) 112 113 /* The paramspecs installed on our interface 114 */ 115 static GParamSpec *iface_spec1, *iface_spec2, *iface_spec3; 116 117 /* The paramspecs inherited by our derived object 118 */ 119 static GParamSpec *inherited_spec1, *inherited_spec2, *inherited_spec3, *inherited_spec4; 120 121 static void 122 test_iface_default_init (TestIfaceClass *iface_vtable) 123 { 124 inherited_spec1 = iface_spec1 = g_param_spec_int ("prop1", 125 "Prop1", 126 "Property 1", 127 G_MININT, /* min */ 128 0xFFFF, /* max */ 129 42, /* default */ 130 G_PARAM_READWRITE | G_PARAM_CONSTRUCT); 131 g_object_interface_install_property (iface_vtable, iface_spec1); 132 133 iface_spec2 = g_param_spec_int ("prop2", 134 "Prop2", 135 "Property 2", 136 G_MININT, /* min */ 137 G_MAXINT, /* max */ 138 0, /* default */ 139 G_PARAM_WRITABLE); 140 g_object_interface_install_property (iface_vtable, iface_spec2); 141 142 inherited_spec3 = iface_spec3 = g_param_spec_int ("prop3", 143 "Prop3", 144 "Property 3", 145 G_MININT, /* min */ 146 G_MAXINT, /* max */ 147 0, /* default */ 148 G_PARAM_READWRITE); 149 g_object_interface_install_property (iface_vtable, iface_spec3); 150 } 151 152 static DEFINE_IFACE (TestIface, test_iface, NULL, test_iface_default_init) 153 154 155 static GObject* 156 base_object_constructor (GType type, 157 guint n_construct_properties, 158 GObjectConstructParam *construct_properties) 159 { 160 /* The constructor is the one place where a GParamSpecOverride is visible 161 * to the outside world, so we do a bunch of checks here 162 */ 163 GValue value1 = { 0, }; 164 GValue value2 = { 0, }; 165 GParamSpec *pspec; 166 167 g_assert (n_construct_properties == 1); 168 169 pspec = construct_properties->pspec; 170 171 /* Check we got the param spec we expected 172 */ 173 g_assert (G_IS_PARAM_SPEC_OVERRIDE (pspec)); 174 g_assert (pspec->param_id == BASE_PROP1); 175 g_assert (strcmp (g_param_spec_get_name (pspec), "prop1") == 0); 176 g_assert (g_param_spec_get_redirect_target (pspec) == iface_spec1); 177 178 /* Test redirection of the nick and blurb to the redirect target 179 */ 180 g_assert (strcmp (g_param_spec_get_nick (pspec), "Prop1") == 0); 181 g_assert (strcmp (g_param_spec_get_blurb (pspec), "Property 1") == 0); 182 183 /* Test forwarding of the various GParamSpec methods to the redirect target 184 */ 185 g_value_init (&value1, G_TYPE_INT); 186 g_value_init (&value2, G_TYPE_INT); 187 188 g_param_value_set_default (pspec, &value1); 189 g_assert (g_value_get_int (&value1) == 42); 190 191 g_value_reset (&value1); 192 g_value_set_int (&value1, 0x10000); 193 g_assert (g_param_value_validate (pspec, &value1)); 194 g_assert (g_value_get_int (&value1) == 0xFFFF); 195 g_assert (!g_param_value_validate (pspec, &value1)); 196 197 g_value_reset (&value1); 198 g_value_set_int (&value1, 1); 199 g_value_set_int (&value2, 2); 200 g_assert (g_param_values_cmp (pspec, &value1, &value2) < 0); 201 g_assert (g_param_values_cmp (pspec, &value2, &value1) > 0); 202 203 g_value_unset (&value1); 204 g_value_unset (&value2); 205 206 return base_parent_class->constructor (type, 207 n_construct_properties, 208 construct_properties); 209 } 210 211 static void 212 base_object_set_property (GObject *object, 213 guint prop_id, 214 const GValue *value, 215 GParamSpec *pspec) 216 { 217 BaseObject *base_object = BASE_OBJECT (object); 218 219 switch (prop_id) 220 { 221 case BASE_PROP1: 222 g_assert (pspec == inherited_spec1); 223 base_object->val1 = g_value_get_int (value); 224 break; 225 case BASE_PROP2: 226 g_assert (pspec == inherited_spec2); 227 base_object->val2 = g_value_get_int (value); 228 break; 229 case BASE_PROP3: 230 g_assert_not_reached (); 231 break; 232 case BASE_PROP4: 233 g_assert_not_reached (); 234 break; 235 default: 236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 237 break; 238 } 239 } 240 241 static void 242 base_object_get_property (GObject *object, 243 guint prop_id, 244 GValue *value, 245 GParamSpec *pspec) 246 { 247 BaseObject *base_object = BASE_OBJECT (object); 248 249 switch (prop_id) 250 { 251 case BASE_PROP1: 252 g_assert (pspec == inherited_spec1); 253 g_value_set_int (value, base_object->val1); 254 break; 255 case BASE_PROP2: 256 g_assert (pspec == inherited_spec2); 257 g_value_set_int (value, base_object->val2); 258 break; 259 case BASE_PROP3: 260 g_assert_not_reached (); 261 break; 262 case BASE_PROP4: 263 g_assert_not_reached (); 264 break; 265 default: 266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 267 break; 268 } 269 } 270 271 static void 272 base_object_notify (GObject *object, 273 GParamSpec *pspec) 274 { 275 /* The property passed to notify is the redirect target, not the 276 * GParamSpecOverride 277 */ 278 g_assert (pspec == inherited_spec1 || 279 pspec == inherited_spec2 || 280 pspec == inherited_spec3 || 281 pspec == inherited_spec4); 282 } 283 284 static void 285 base_object_class_init (BaseObjectClass *class) 286 { 287 GObjectClass *object_class = G_OBJECT_CLASS (class); 288 289 base_parent_class= g_type_class_peek_parent (class); 290 291 object_class->constructor = base_object_constructor; 292 object_class->set_property = base_object_set_property; 293 object_class->get_property = base_object_get_property; 294 object_class->notify = base_object_notify; 295 296 g_object_class_override_property (object_class, BASE_PROP1, "prop1"); 297 298 /* We override this one using a real property, not GParamSpecOverride 299 * We change the flags from READONLY to READWRITE to show that we 300 * can make the flags less restrictive 301 */ 302 inherited_spec2 = g_param_spec_int ("prop2", 303 "Prop2", 304 "Property 2", 305 G_MININT, /* min */ 306 G_MAXINT, /* max */ 307 0, /* default */ 308 G_PARAM_READWRITE); 309 g_object_class_install_property (object_class, BASE_PROP2, inherited_spec2); 310 311 g_object_class_override_property (object_class, BASE_PROP3, "prop3"); 312 313 inherited_spec4 = g_param_spec_int ("prop4", 314 "Prop4", 315 "Property 4", 316 G_MININT, /* min */ 317 G_MAXINT, /* max */ 318 0, /* default */ 319 G_PARAM_READWRITE); 320 g_object_class_install_property (object_class, BASE_PROP4, inherited_spec4); 321 } 322 323 static void 324 base_object_init (BaseObject *base_object) 325 { 326 base_object->val1 = 42; 327 } 328 329 static DEFINE_TYPE_FULL (BaseObject, base_object, 330 base_object_class_init, NULL, base_object_init, 331 G_TYPE_OBJECT, 332 INTERFACE (NULL, TEST_TYPE_IFACE)) 333 334 static void 335 derived_object_set_property (GObject *object, 336 guint prop_id, 337 const GValue *value, 338 GParamSpec *pspec) 339 { 340 BaseObject *base_object = BASE_OBJECT (object); 341 342 switch (prop_id) 343 { 344 case DERIVED_PROP3: 345 g_assert (pspec == inherited_spec3); 346 base_object->val3 = g_value_get_int (value); 347 break; 348 case DERIVED_PROP4: 349 g_assert (pspec == inherited_spec4); 350 base_object->val4 = g_value_get_int (value); 351 break; 352 default: 353 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 354 break; 355 } 356 } 357 358 static void 359 derived_object_get_property (GObject *object, 360 guint prop_id, 361 GValue *value, 362 GParamSpec *pspec) 363 { 364 BaseObject *base_object = BASE_OBJECT (object); 365 366 switch (prop_id) 367 { 368 case DERIVED_PROP3: 369 g_assert (pspec == inherited_spec3); 370 g_value_set_int (value, base_object->val3); 371 break; 372 case DERIVED_PROP4: 373 g_assert (pspec == inherited_spec4); 374 g_value_set_int (value, base_object->val4); 375 break; 376 default: 377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 378 break; 379 } 380 } 381 382 static void 383 derived_object_class_init (DerivedObjectClass *class) 384 { 385 GObjectClass *object_class = G_OBJECT_CLASS (class); 386 387 object_class->set_property = derived_object_set_property; 388 object_class->get_property = derived_object_get_property; 389 390 /* Overriding a property that is itself overridding an interface property */ 391 g_object_class_override_property (object_class, DERIVED_PROP3, "prop3"); 392 393 /* Overriding a property not from an interface */ 394 g_object_class_override_property (object_class, DERIVED_PROP4, "prop4"); 395 } 396 397 static DEFINE_TYPE (DerivedObject, derived_object, 398 derived_object_class_init, NULL, NULL, 399 BASE_TYPE_OBJECT) 400 401 /* Helper function for testing ...list_properties() 402 */ 403 static void 404 assert_in_properties (GParamSpec *param_spec, 405 GParamSpec **properties, 406 gint n_properties) 407 { 408 gint i; 409 gboolean found = FALSE; 410 411 for (i = 0; i < n_properties; i++) 412 { 413 if (properties[i] == param_spec) 414 found = TRUE; 415 } 416 417 g_assert (found); 418 } 419 420 int 421 main (gint argc, 422 gchar *argv[]) 423 { 424 BaseObject *object; 425 GObjectClass *object_class; 426 TestIfaceClass *iface_vtable; 427 GParamSpec **properties; 428 gint n_properties; 429 430 gint val1, val2, val3, val4; 431 432 g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) | 433 G_LOG_LEVEL_WARNING | 434 G_LOG_LEVEL_CRITICAL); 435 g_type_init (); 436 437 object = g_object_new (DERIVED_TYPE_OBJECT, NULL); 438 439 /* Test setting and getting the properties 440 */ 441 g_object_set (object, 442 "prop1", 0x0101, 443 "prop2", 0x0202, 444 "prop3", 0x0303, 445 "prop4", 0x0404, 446 NULL); 447 g_object_get (object, 448 "prop1", &val1, 449 "prop2", &val2, 450 "prop3", &val3, 451 "prop4", &val4, 452 NULL); 453 454 g_assert (val1 == 0x0101); 455 g_assert (val2 == 0x0202); 456 g_assert (val3 == 0x0303); 457 g_assert (val4 == 0x0404); 458 459 /* Test that the right spec is passed on explicit notifications 460 */ 461 g_object_freeze_notify (G_OBJECT (object)); 462 g_object_notify (G_OBJECT (object), "prop1"); 463 g_object_notify (G_OBJECT (object), "prop2"); 464 g_object_notify (G_OBJECT (object), "prop3"); 465 g_object_notify (G_OBJECT (object), "prop4"); 466 g_object_thaw_notify (G_OBJECT (object)); 467 468 /* Test g_object_class_find_property() for overridden properties 469 */ 470 object_class = G_OBJECT_GET_CLASS (object); 471 472 g_assert (g_object_class_find_property (object_class, "prop1") == inherited_spec1); 473 g_assert (g_object_class_find_property (object_class, "prop2") == inherited_spec2); 474 g_assert (g_object_class_find_property (object_class, "prop3") == inherited_spec3); 475 g_assert (g_object_class_find_property (object_class, "prop4") == inherited_spec4); 476 477 /* Test g_object_class_list_properties() for overridden properties 478 */ 479 properties = g_object_class_list_properties (object_class, &n_properties); 480 g_assert (n_properties == 4); 481 assert_in_properties (inherited_spec1, properties, n_properties); 482 assert_in_properties (inherited_spec2, properties, n_properties); 483 assert_in_properties (inherited_spec3, properties, n_properties); 484 assert_in_properties (inherited_spec4, properties, n_properties); 485 g_free (properties); 486 487 /* Test g_object_interface_find_property() 488 */ 489 iface_vtable = g_type_default_interface_peek (TEST_TYPE_IFACE); 490 491 g_assert (g_object_interface_find_property (iface_vtable, "prop1") == iface_spec1); 492 g_assert (g_object_interface_find_property (iface_vtable, "prop2") == iface_spec2); 493 g_assert (g_object_interface_find_property (iface_vtable, "prop3") == iface_spec3); 494 495 /* Test g_object_interface_list_properties() 496 */ 497 properties = g_object_interface_list_properties (iface_vtable, &n_properties); 498 g_assert (n_properties == 3); 499 assert_in_properties (iface_spec1, properties, n_properties); 500 assert_in_properties (iface_spec2, properties, n_properties); 501 assert_in_properties (iface_spec3, properties, n_properties); 502 g_free (properties); 503 504 g_object_unref (object); 505 506 return 0; 507 } 508