(root)/
glib-2.79.0/
gobject/
tests/
properties.c
       1  #include <stdlib.h>
       2  #include <gstdio.h>
       3  #include <glib-object.h>
       4  
       5  typedef struct _TestObject {
       6    GObject parent_instance;
       7    gint foo;
       8    gboolean bar;
       9    gchar *baz;
      10    GVariant *var;  /* (nullable) (owned) */
      11    gchar *quux;
      12  } TestObject;
      13  
      14  typedef struct _TestObjectClass {
      15    GObjectClass parent_class;
      16  } TestObjectClass;
      17  
      18  enum { PROP_0, PROP_FOO, PROP_BAR, PROP_BAZ, PROP_VAR, PROP_QUUX, N_PROPERTIES };
      19  
      20  static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      21  
      22  static GType test_object_get_type (void);
      23  G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
      24  
      25  static void
      26  test_object_set_foo (TestObject *obj,
      27                       gint        foo)
      28  {
      29    if (obj->foo != foo)
      30      {
      31        obj->foo = foo;
      32  
      33        g_assert (properties[PROP_FOO] != NULL);
      34        g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]);
      35      }
      36  }
      37  
      38  static void
      39  test_object_set_bar (TestObject *obj,
      40                       gboolean    bar)
      41  {
      42    bar = !!bar;
      43  
      44    if (obj->bar != bar)
      45      {
      46        obj->bar = bar;
      47  
      48        g_assert (properties[PROP_BAR] != NULL);
      49        g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAR]);
      50      }
      51  }
      52  
      53  static void
      54  test_object_set_baz (TestObject  *obj,
      55                       const gchar *baz)
      56  {
      57    if (g_strcmp0 (obj->baz, baz) != 0)
      58      {
      59        g_free (obj->baz);
      60        obj->baz = g_strdup (baz);
      61  
      62        g_assert (properties[PROP_BAZ] != NULL);
      63        g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAZ]);
      64      }
      65  }
      66  
      67  static void
      68  test_object_set_var (TestObject *obj,
      69                       GVariant   *var)
      70  {
      71    GVariant *new_var = NULL;
      72  
      73    if (var == NULL || obj->var == NULL ||
      74        !g_variant_equal (var, obj->var))
      75      {
      76        /* Note: We deliberately don’t sink @var here, to make sure that
      77         * properties_set_property_variant_floating() is testing that GObject
      78         * internally sinks variants. */
      79        new_var = g_variant_ref (var);
      80        g_clear_pointer (&obj->var, g_variant_unref);
      81        obj->var = g_steal_pointer (&new_var);
      82  
      83        g_assert (properties[PROP_VAR] != NULL);
      84        g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_VAR]);
      85      }
      86  }
      87  
      88  static void
      89  test_object_set_quux (TestObject  *obj,
      90                        const gchar *quux)
      91  {
      92    if (g_strcmp0 (obj->quux, quux) != 0)
      93      {
      94        g_free (obj->quux);
      95        obj->quux = g_strdup (quux);
      96  
      97        g_assert (properties[PROP_QUUX] != NULL);
      98        g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_QUUX]);
      99      }
     100  }
     101  
     102  static void
     103  test_object_finalize (GObject *gobject)
     104  {
     105    TestObject *self = (TestObject *) gobject;
     106  
     107    g_free (self->baz);
     108    g_clear_pointer (&self->var, g_variant_unref);
     109    g_free (self->quux);
     110  
     111    /* When the ref_count of an object is zero it is still
     112     * possible to notify the property, but it should do
     113     * nothing and silently quit (bug #705570)
     114     */
     115    g_object_notify (gobject, "foo");
     116    g_object_notify_by_pspec (gobject, properties[PROP_BAR]);
     117  
     118    G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject);
     119  }
     120  
     121  static void
     122  test_object_set_property (GObject *gobject,
     123                            guint prop_id,
     124                            const GValue *value,
     125                            GParamSpec *pspec)
     126  {
     127    TestObject *tobj = (TestObject *) gobject;
     128  
     129    g_assert_cmpint (prop_id, !=, 0);
     130    g_assert_true (prop_id < N_PROPERTIES && pspec == properties[prop_id]);
     131  
     132    switch (prop_id)
     133      {
     134      case PROP_FOO:
     135        test_object_set_foo (tobj, g_value_get_int (value));
     136        break;
     137  
     138      case PROP_BAR:
     139        test_object_set_bar (tobj, g_value_get_boolean (value));
     140        break;
     141  
     142      case PROP_BAZ:
     143        test_object_set_baz (tobj, g_value_get_string (value));
     144        break;
     145  
     146      case PROP_VAR:
     147        test_object_set_var (tobj, g_value_get_variant (value));
     148        break;
     149  
     150      case PROP_QUUX:
     151        test_object_set_quux (tobj, g_value_get_string (value));
     152        break;
     153  
     154      default:
     155        g_assert_not_reached ();
     156      }
     157  }
     158  
     159  static void
     160  test_object_get_property (GObject *gobject,
     161                            guint prop_id,
     162                            GValue *value,
     163                            GParamSpec *pspec)
     164  {
     165    TestObject *tobj = (TestObject *) gobject;
     166  
     167    g_assert_cmpint (prop_id, !=, 0);
     168    g_assert_true (prop_id < N_PROPERTIES && pspec == properties[prop_id]);
     169  
     170    switch (prop_id)
     171      {
     172      case PROP_FOO:
     173        g_value_set_int (value, tobj->foo);
     174        break;
     175  
     176      case PROP_BAR:
     177        g_value_set_boolean (value, tobj->bar);
     178        break;
     179  
     180      case PROP_BAZ:
     181        g_value_set_string (value, tobj->baz);
     182        break;
     183  
     184      case PROP_VAR:
     185        g_value_set_variant (value, tobj->var);
     186        break;
     187  
     188      case PROP_QUUX:
     189        g_value_set_string (value, tobj->quux);
     190        break;
     191  
     192      default:
     193        g_assert_not_reached ();
     194      }
     195  }
     196  
     197  static void
     198  test_object_class_init (TestObjectClass *klass)
     199  {
     200    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     201  
     202    properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
     203                                             -1, G_MAXINT,
     204                                             0,
     205                                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     206    properties[PROP_BAR] = g_param_spec_boolean ("bar", "Bar", "Bar",
     207                                                 FALSE,
     208                                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     209    properties[PROP_BAZ] = g_param_spec_string ("baz", "Baz", "Baz",
     210                                                NULL,
     211                                                G_PARAM_READWRITE);
     212    properties[PROP_VAR] = g_param_spec_variant ("var", "Var", "Var",
     213                                                 G_VARIANT_TYPE_STRING, NULL,
     214                                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     215  
     216    gobject_class->set_property = test_object_set_property;
     217    gobject_class->get_property = test_object_get_property;
     218    gobject_class->finalize = test_object_finalize;
     219  
     220    g_object_class_install_properties (gobject_class, N_PROPERTIES - 1, properties);
     221  
     222    /* We intentionally install this property separately, to test
     223     * that that works, and that property lookup works regardless
     224     * how the property was installed.
     225     */
     226    properties[PROP_QUUX] = g_param_spec_string ("quux", "quux", "quux",
     227                                                 NULL,
     228                                                 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
     229  
     230    g_object_class_install_property (gobject_class, PROP_QUUX, properties[PROP_QUUX]);
     231  }
     232  
     233  static void
     234  test_object_init (TestObject *self)
     235  {
     236    self->foo = 42;
     237    self->bar = TRUE;
     238    self->baz = g_strdup ("Hello");
     239    self->quux = NULL;
     240  }
     241  
     242  static void
     243  properties_install (void)
     244  {
     245    TestObject *obj = g_object_new (test_object_get_type (), NULL);
     246    GParamSpec *pspec;
     247    char *name;
     248  
     249    g_assert (properties[PROP_FOO] != NULL);
     250  
     251    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo");
     252    g_assert (properties[PROP_FOO] == pspec);
     253  
     254    name = g_strdup ("bar");
     255    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name);
     256    g_assert (properties[PROP_BAR] == pspec);
     257    g_free (name);
     258  
     259    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "baz");
     260    g_assert (properties[PROP_BAZ] == pspec);
     261  
     262    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "var");
     263    g_assert (properties[PROP_VAR] == pspec);
     264  
     265    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "quux");
     266    g_assert (properties[PROP_QUUX] == pspec);
     267  
     268    g_object_unref (obj);
     269  }
     270  
     271  typedef struct {
     272    GObject parent_instance;
     273    int value[16];
     274  } ManyProps;
     275  
     276  typedef GObjectClass ManyPropsClass;
     277  
     278  static GParamSpec *props[16];
     279  
     280  GType many_props_get_type (void) G_GNUC_CONST;
     281  
     282  G_DEFINE_TYPE(ManyProps, many_props, G_TYPE_OBJECT)
     283  
     284  static void
     285  many_props_init (ManyProps *self)
     286  {
     287  }
     288  
     289  static void
     290  get_prop (GObject    *object,
     291            guint       prop_id,
     292            GValue     *value,
     293            GParamSpec *pspec)
     294  {
     295    ManyProps *mp = (ManyProps *) object;
     296  
     297    if (prop_id > 0 && prop_id < 13)
     298      g_value_set_int (value, mp->value[prop_id]);
     299    else
     300      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     301  }
     302  
     303  static void
     304  set_prop (GObject      *object,
     305            guint         prop_id,
     306            const GValue *value,
     307            GParamSpec   *pspec)
     308  {
     309    ManyProps *mp = (ManyProps *) object;
     310  
     311    if (prop_id > 0 && prop_id < 13)
     312      mp->value[prop_id] = g_value_get_int (value);
     313    else
     314      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     315  }
     316  
     317  static void
     318  many_props_class_init (ManyPropsClass *class)
     319  {
     320    G_OBJECT_CLASS (class)->get_property = get_prop;
     321    G_OBJECT_CLASS (class)->set_property = set_prop;
     322  
     323    props[1] = g_param_spec_int ("one", NULL, NULL,
     324                                 0, G_MAXINT, 0,
     325                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     326    props[2] = g_param_spec_int ("two", NULL, NULL,
     327                                 0, G_MAXINT, 0,
     328                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     329    props[3] = g_param_spec_int ("three", NULL, NULL,
     330                                 0, G_MAXINT, 0,
     331                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     332    props[4] = g_param_spec_int ("four", NULL, NULL,
     333                                 0, G_MAXINT, 0,
     334                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     335    props[5] = g_param_spec_int ("five", NULL, NULL,
     336                                 0, G_MAXINT, 0,
     337                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     338    props[6] = g_param_spec_int ("six", NULL, NULL,
     339                                 0, G_MAXINT, 0,
     340                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     341    props[7] = g_param_spec_int ("seven", NULL, NULL,
     342                                 0, G_MAXINT, 0,
     343                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     344    props[8] = g_param_spec_int ("eight", NULL, NULL,
     345                                 0, G_MAXINT, 0,
     346                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     347    props[9] = g_param_spec_int ("nine", NULL, NULL,
     348                                 0, G_MAXINT, 0,
     349                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     350    props[10] = g_param_spec_int ("ten", NULL, NULL,
     351                                 0, G_MAXINT, 0,
     352                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     353    props[11] = g_param_spec_int ("eleven", NULL, NULL,
     354                                 0, G_MAXINT, 0,
     355                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     356    props[12] = g_param_spec_int ("twelve", NULL, NULL,
     357                                 0, G_MAXINT, 0,
     358                                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
     359    g_object_class_install_properties (G_OBJECT_CLASS (class), 12, props);
     360  }
     361  
     362  static void
     363  properties_install_many (void)
     364  {
     365    ManyProps *obj = g_object_new (many_props_get_type (), NULL);
     366    GParamSpec *pspec;
     367  
     368    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "one");
     369    g_assert (props[1] == pspec);
     370  
     371    pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "ten");
     372    g_assert (props[10] == pspec);
     373  
     374    g_object_unref (obj);
     375  }
     376  
     377  typedef struct {
     378    const gchar *name;
     379    GParamSpec *pspec;
     380    gboolean    fired;
     381  } TestNotifyClosure;
     382  
     383  static void
     384  on_notify (GObject           *gobject,
     385             GParamSpec        *pspec,
     386             TestNotifyClosure *closure)
     387  {
     388    g_assert (closure->pspec == pspec);
     389    g_assert_cmpstr (closure->name, ==, pspec->name);
     390    closure->fired = TRUE;
     391  }
     392  
     393  static void
     394  properties_notify (void)
     395  {
     396    TestObject *obj = g_object_new (test_object_get_type (), NULL);
     397    TestNotifyClosure closure;
     398  
     399    g_assert (properties[PROP_FOO] != NULL);
     400    g_assert (properties[PROP_QUUX] != NULL);
     401    g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &closure);
     402  
     403    closure.name = "foo";
     404    closure.pspec = properties[PROP_FOO];
     405  
     406    closure.fired = FALSE;
     407    g_object_set (obj, "foo", 47, NULL);
     408    g_assert (closure.fired);
     409  
     410    closure.name = "baz";
     411    closure.pspec = properties[PROP_BAZ];
     412  
     413    closure.fired = FALSE;
     414    g_object_set (obj, "baz", "something new", NULL);
     415    g_assert (closure.fired);
     416  
     417    /* baz lacks explicit notify, so we will see this twice */
     418    closure.fired = FALSE;
     419    g_object_set (obj, "baz", "something new", NULL);
     420    g_assert (closure.fired);
     421  
     422    /* quux on the other hand, ... */
     423    closure.name = "quux";
     424    closure.pspec = properties[PROP_QUUX];
     425  
     426    closure.fired = FALSE;
     427    g_object_set (obj, "quux", "something new", NULL);
     428    g_assert (closure.fired);
     429  
     430    /* no change; no notify */
     431    closure.fired = FALSE;
     432    g_object_set (obj, "quux", "something new", NULL);
     433    g_assert (!closure.fired);
     434  
     435  
     436    g_object_unref (obj);
     437  }
     438  
     439  typedef struct {
     440    GParamSpec *pspec[3];
     441    gint pos;
     442  } Notifys;
     443  
     444  static void
     445  on_notify2 (GObject    *gobject,
     446              GParamSpec *pspec,
     447              Notifys    *n)
     448  {
     449    g_assert (n->pspec[n->pos] == pspec);
     450    n->pos++;
     451  }
     452  
     453  static void
     454  properties_notify_queue (void)
     455  {
     456    TestObject *obj = g_object_new (test_object_get_type (), NULL);
     457    Notifys n;
     458  
     459    g_assert (properties[PROP_FOO] != NULL);
     460  
     461    n.pspec[0] = properties[PROP_BAZ];
     462    n.pspec[1] = properties[PROP_BAR];
     463    n.pspec[2] = properties[PROP_FOO];
     464    n.pos = 0;
     465  
     466    g_signal_connect (obj, "notify", G_CALLBACK (on_notify2), &n);
     467  
     468    g_object_freeze_notify (G_OBJECT (obj));
     469    g_object_set (obj, "foo", 47, NULL);
     470    g_object_set (obj, "bar", TRUE, "foo", 42, "baz", "abc", NULL);
     471    g_object_thaw_notify (G_OBJECT (obj));
     472    g_assert (n.pos == 3);
     473  
     474    g_object_unref (obj);
     475  }
     476  
     477  static void
     478  properties_construct (void)
     479  {
     480    TestObject *obj;
     481    gint val;
     482    gboolean b;
     483    gchar *s;
     484  
     485    g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=630357");
     486  
     487    /* more than 16 args triggers a realloc in g_object_new_valist() */
     488    obj = g_object_new (test_object_get_type (),
     489                        "foo", 1,
     490                        "foo", 2,
     491                        "foo", 3,
     492                        "foo", 4,
     493                        "foo", 5,
     494                        "bar", FALSE,
     495                        "foo", 6,
     496                        "foo", 7,
     497                        "foo", 8,
     498                        "foo", 9,
     499                        "foo", 10,
     500                        "baz", "boo",
     501                        "foo", 11,
     502                        "foo", 12,
     503                        "foo", 13,
     504                        "foo", 14,
     505                        "foo", 15,
     506                        "foo", 16,
     507                        "foo", 17,
     508                        "foo", 18,
     509                        NULL);
     510  
     511    g_object_get (obj, "foo", &val, NULL);
     512    g_assert (val == 18);
     513    g_object_get (obj, "bar", &b, NULL);
     514    g_assert (!b);
     515    g_object_get (obj, "baz", &s, NULL);
     516    g_assert_cmpstr (s, ==, "boo");
     517    g_free (s);
     518  
     519    g_object_unref (obj);
     520  }
     521  
     522  static void
     523  properties_testv_with_no_properties (void)
     524  {
     525    TestObject *test_obj;
     526    const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
     527    GValue values_out[4] = { G_VALUE_INIT };
     528    guint i;
     529  
     530    /* Test newv_with_properties && getv */
     531    test_obj = (TestObject *) g_object_new_with_properties (
     532        test_object_get_type (), 0, NULL, NULL);
     533    g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
     534  
     535    /* It should have init values */
     536    g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 42);
     537    g_assert_true (g_value_get_boolean (&values_out[1]));
     538    g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Hello");
     539    g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, NULL);
     540  
     541    for (i = 0; i < 4; i++)
     542      g_value_unset (&values_out[i]);
     543    g_object_unref (test_obj);
     544  }
     545  
     546  static void
     547  properties_testv_with_valid_properties (void)
     548  {
     549    TestObject *test_obj;
     550    const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
     551  
     552    GValue values_in[4] = { G_VALUE_INIT };
     553    GValue values_out[4] = { G_VALUE_INIT };
     554    guint i;
     555  
     556    g_value_init (&(values_in[0]), G_TYPE_INT);
     557    g_value_set_int (&(values_in[0]), 100);
     558  
     559    g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
     560    g_value_set_boolean (&(values_in[1]), TRUE);
     561  
     562    g_value_init (&(values_in[2]), G_TYPE_STRING);
     563    g_value_set_string (&(values_in[2]), "pigs");
     564  
     565    g_value_init (&(values_in[3]), G_TYPE_STRING);
     566    g_value_set_string (&(values_in[3]), "fly");
     567  
     568    /* Test newv_with_properties && getv */
     569    test_obj = (TestObject *) g_object_new_with_properties (
     570        test_object_get_type (), 4, prop_names, values_in);
     571    g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
     572  
     573    g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
     574    g_assert_true (g_value_get_boolean (&values_out[1]));
     575    g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "pigs");
     576    g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "fly");
     577  
     578    for (i = 0; i < G_N_ELEMENTS (values_out); i++)
     579      g_value_unset (&values_out[i]);
     580  
     581    /* Test newv2 && getv */
     582    g_value_set_string (&(values_in[2]), "Elmo knows");
     583    g_value_set_string (&(values_in[3]), "where you live");
     584    g_object_setv (G_OBJECT (test_obj), 4, prop_names, values_in);
     585  
     586    g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out);
     587  
     588    g_assert_cmpint (g_value_get_int (&values_out[0]), ==, 100);
     589    g_assert_true (g_value_get_boolean (&values_out[1]));
     590  
     591    g_assert_cmpstr (g_value_get_string (&values_out[2]), ==, "Elmo knows");
     592    g_assert_cmpstr (g_value_get_string (&values_out[3]), ==, "where you live");
     593  
     594    for (i = 0; i < G_N_ELEMENTS (values_in); i++)
     595      g_value_unset (&values_in[i]);
     596    for (i = 0; i < G_N_ELEMENTS (values_out); i++)
     597      g_value_unset (&values_out[i]);
     598  
     599    g_object_unref (test_obj);
     600  }
     601  
     602  static void
     603  properties_testv_with_invalid_property_type (void)
     604  {
     605    if (g_test_subprocess ())
     606      {
     607        TestObject *test_obj;
     608        const char *invalid_prop_names[1] = { "foo" };
     609        GValue values_in[1] = { G_VALUE_INIT };
     610  
     611        g_value_init (&(values_in[0]), G_TYPE_STRING);
     612        g_value_set_string (&(values_in[0]), "fly");
     613  
     614        test_obj = (TestObject *) g_object_new_with_properties (
     615            test_object_get_type (), 1, invalid_prop_names, values_in);
     616        /* should give a warning */
     617  
     618        g_object_unref (test_obj);
     619      }
     620    g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
     621    g_test_trap_assert_failed ();
     622    g_test_trap_assert_stderr ("*CRITICAL*foo*gint*gchararray*");
     623  }
     624  
     625  
     626  static void
     627  properties_testv_with_invalid_property_names (void)
     628  {
     629    if (g_test_subprocess ())
     630      {
     631        TestObject *test_obj;
     632        const char *invalid_prop_names[4] = { "foo", "boo", "moo", "poo" };
     633        GValue values_in[4] = { G_VALUE_INIT };
     634  
     635        g_value_init (&(values_in[0]), G_TYPE_INT);
     636        g_value_set_int (&(values_in[0]), 100);
     637  
     638        g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
     639        g_value_set_boolean (&(values_in[1]), TRUE);
     640  
     641        g_value_init (&(values_in[2]), G_TYPE_STRING);
     642        g_value_set_string (&(values_in[2]), "pigs");
     643  
     644        g_value_init (&(values_in[3]), G_TYPE_STRING);
     645        g_value_set_string (&(values_in[3]), "fly");
     646  
     647        test_obj = (TestObject *) g_object_new_with_properties (
     648            test_object_get_type (), 4, invalid_prop_names, values_in);
     649        /* This call should give 3 Critical warnings. Actually, a critical warning
     650         * shouldn't make g_object_new_with_properties to fail when a bad named
     651         * property is given, because, it will just ignore that property. However,
     652         * for test purposes, it is considered that the test doesn't pass.
     653         */
     654  
     655        g_object_unref (test_obj);
     656      }
     657  
     658    g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
     659    g_test_trap_assert_failed ();
     660    g_test_trap_assert_stderr ("*CRITICAL*g_object_new_is_valid_property*boo*");
     661  }
     662  
     663  static void
     664  properties_testv_getv (void)
     665  {
     666    TestObject *test_obj;
     667    const char *prop_names[4] = { "foo", "bar", "baz", "quux" };
     668    GValue values_out_initialized[4] = { G_VALUE_INIT };
     669    GValue values_out_uninitialized[4] = { G_VALUE_INIT };
     670    guint i;
     671  
     672    g_value_init (&(values_out_initialized[0]), G_TYPE_INT);
     673    g_value_init (&(values_out_initialized[1]), G_TYPE_BOOLEAN);
     674    g_value_init (&(values_out_initialized[2]), G_TYPE_STRING);
     675    g_value_init (&(values_out_initialized[3]), G_TYPE_STRING);
     676  
     677    test_obj = (TestObject *) g_object_new_with_properties (
     678        test_object_get_type (), 0, NULL, NULL);
     679  
     680    /* Test g_object_getv for an initialized values array */
     681    g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_initialized);
     682    /* It should have init values */
     683    g_assert_cmpint (g_value_get_int (&values_out_initialized[0]), ==, 42);
     684    g_assert_true (g_value_get_boolean (&values_out_initialized[1]));
     685    g_assert_cmpstr (g_value_get_string (&values_out_initialized[2]), ==, "Hello");
     686    g_assert_cmpstr (g_value_get_string (&values_out_initialized[3]), ==, NULL);
     687  
     688    /* Test g_object_getv for an uninitialized values array */
     689    g_object_getv (G_OBJECT (test_obj), 4, prop_names, values_out_uninitialized);
     690    /* It should have init values */
     691    g_assert_cmpint (g_value_get_int (&values_out_uninitialized[0]), ==, 42);
     692    g_assert_true (g_value_get_boolean (&values_out_uninitialized[1]));
     693    g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[2]), ==, "Hello");
     694    g_assert_cmpstr (g_value_get_string (&values_out_uninitialized[3]), ==, NULL);
     695  
     696    for (i = 0; i < 4; i++)
     697      {
     698        g_value_unset (&values_out_initialized[i]);
     699        g_value_unset (&values_out_uninitialized[i]);
     700      }
     701    g_object_unref (test_obj);
     702  }
     703  
     704  static void
     705  properties_get_property (void)
     706  {
     707    TestObject *test_obj;
     708    struct {
     709      const char *name;
     710      GType gtype;
     711      GValue value;
     712    } test_props[] = {
     713      { "foo", G_TYPE_INT, G_VALUE_INIT },
     714      { "bar", G_TYPE_INVALID, G_VALUE_INIT },
     715      { "bar", G_TYPE_STRING, G_VALUE_INIT },
     716    };
     717    gsize i;
     718  
     719    g_test_summary ("g_object_get_property() accepts uninitialized, "
     720                    "initialized, and transformable values");
     721  
     722    for (i = 0; i < G_N_ELEMENTS (test_props); i++)
     723      {
     724        if (test_props[i].gtype != G_TYPE_INVALID)
     725          g_value_init (&(test_props[i].value), test_props[i].gtype);
     726      }
     727  
     728    test_obj = (TestObject *) g_object_new_with_properties (test_object_get_type (), 0, NULL, NULL);
     729  
     730    g_test_message ("Test g_object_get_property with an initialized value");
     731    g_object_get_property (G_OBJECT (test_obj), test_props[0].name, &(test_props[0].value));
     732    g_assert_cmpint (g_value_get_int (&(test_props[0].value)), ==, 42);
     733  
     734    g_test_message ("Test g_object_get_property with an uninitialized value");
     735    g_object_get_property (G_OBJECT (test_obj), test_props[1].name, &(test_props[1].value));
     736    g_assert_true (g_value_get_boolean (&(test_props[1].value)));
     737  
     738    g_test_message ("Test g_object_get_property with a transformable value");
     739    g_object_get_property (G_OBJECT (test_obj), test_props[2].name, &(test_props[2].value));
     740    g_assert_true (G_VALUE_HOLDS_STRING (&(test_props[2].value)));
     741    g_assert_cmpstr (g_value_get_string (&(test_props[2].value)), ==, "TRUE");
     742  
     743    for (i = 0; i < G_N_ELEMENTS (test_props); i++)
     744      g_value_unset (&(test_props[i].value));
     745  
     746    g_object_unref (test_obj);
     747  }
     748  
     749  static void
     750  properties_set_property_variant_floating (void)
     751  {
     752    TestObject *test_obj = NULL;
     753    GVariant *owned_floating_variant = NULL;
     754    GVariant *floating_variant_ptr = NULL;
     755    GVariant *got_variant = NULL;
     756  
     757    g_test_summary ("Test that setting a property to a floating variant consumes the reference");
     758  
     759    test_obj = (TestObject *) g_object_new (test_object_get_type (), NULL);
     760  
     761    owned_floating_variant = floating_variant_ptr = g_variant_new_string ("this variant has only one floating ref");
     762    g_assert_true (g_variant_is_floating (floating_variant_ptr));
     763  
     764    g_object_set (test_obj, "var", g_steal_pointer (&owned_floating_variant), NULL);
     765  
     766    /* This assumes that the GObject implementation refs, rather than copies and destroys, the incoming variant */
     767    g_assert_false (g_variant_is_floating (floating_variant_ptr));
     768  
     769    g_object_get (test_obj, "var", &got_variant, NULL);
     770    g_assert_false (g_variant_is_floating (got_variant));
     771    g_assert_cmpvariant (got_variant, floating_variant_ptr);
     772  
     773    g_variant_unref (got_variant);
     774    g_object_unref (test_obj);
     775  }
     776  
     777  static void
     778  properties_testv_notify_queue (void)
     779  {
     780    TestObject *test_obj;
     781    const char *prop_names[3] = { "foo", "bar", "baz" };
     782    GValue values_in[3] = { G_VALUE_INIT };
     783    Notifys n;
     784    guint i;
     785  
     786    g_value_init (&(values_in[0]), G_TYPE_INT);
     787    g_value_set_int (&(values_in[0]), 100);
     788  
     789    g_value_init (&(values_in[1]), G_TYPE_BOOLEAN);
     790    g_value_set_boolean (&(values_in[1]), TRUE);
     791  
     792    g_value_init (&(values_in[2]), G_TYPE_STRING);
     793    g_value_set_string (&(values_in[2]), "");
     794  
     795    /* Test newv_with_properties && getv */
     796    test_obj = (TestObject *) g_object_new_with_properties (
     797        test_object_get_type (), 0, NULL, NULL);
     798  
     799    g_assert_nonnull (properties[PROP_FOO]);
     800  
     801    n.pspec[0] = properties[PROP_BAZ];
     802    n.pspec[1] = properties[PROP_BAR];
     803    n.pspec[2] = properties[PROP_FOO];
     804    n.pos = 0;
     805  
     806    g_signal_connect (test_obj, "notify", G_CALLBACK (on_notify2), &n);
     807  
     808    g_object_freeze_notify (G_OBJECT (test_obj));
     809    {
     810      g_object_setv (G_OBJECT (test_obj), 3, prop_names, values_in);
     811  
     812      /* Set "foo" to 70 */
     813      g_value_set_int (&(values_in[0]), 100);
     814      g_object_setv (G_OBJECT (test_obj), 1, prop_names, values_in);
     815    }
     816    g_object_thaw_notify (G_OBJECT (test_obj));
     817    g_assert_cmpint (n.pos, ==, 3);
     818  
     819    for (i = 0; i < 3; i++)
     820      g_value_unset (&values_in[i]);
     821    g_object_unref (test_obj);
     822  }
     823  
     824  int
     825  main (int argc, char *argv[])
     826  {
     827    g_test_init (&argc, &argv, NULL);
     828  
     829    g_test_add_func ("/properties/install", properties_install);
     830    g_test_add_func ("/properties/install-many", properties_install_many);
     831    g_test_add_func ("/properties/notify", properties_notify);
     832    g_test_add_func ("/properties/notify-queue", properties_notify_queue);
     833    g_test_add_func ("/properties/construct", properties_construct);
     834    g_test_add_func ("/properties/get-property", properties_get_property);
     835    g_test_add_func ("/properties/set-property/variant/floating", properties_set_property_variant_floating);
     836  
     837    g_test_add_func ("/properties/testv_with_no_properties",
     838        properties_testv_with_no_properties);
     839    g_test_add_func ("/properties/testv_with_valid_properties",
     840        properties_testv_with_valid_properties);
     841    g_test_add_func ("/properties/testv_with_invalid_property_type",
     842        properties_testv_with_invalid_property_type);
     843    g_test_add_func ("/properties/testv_with_invalid_property_names",
     844        properties_testv_with_invalid_property_names);
     845    g_test_add_func ("/properties/testv_getv", properties_testv_getv);
     846    g_test_add_func ("/properties/testv_notify_queue",
     847        properties_testv_notify_queue);
     848  
     849    return g_test_run ();
     850  }