Home | History | Annotate | Download | only in gobject
      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