(root)/
glib-2.79.0/
gobject/
tests/
custom-dispatch.c
       1  /* custom-dispatch.c: Test GObjectClass.dispatch_properties_changed
       2   * Copyright (C) 2022 Red Hat, Inc.
       3   *
       4   * SPDX-License-Identifier: LicenseRef-old-glib-tests
       5   *
       6   * This work is provided "as is"; redistribution and modification
       7   * in whole or in part, in any medium, physical or electronic is
       8   * permitted without restriction.
       9   *
      10   * This work is distributed in the hope that it will be useful,
      11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
      13   *
      14   * In no event shall the authors or contributors be liable for any
      15   * direct, indirect, incidental, special, exemplary, or consequential
      16   * damages (including, but not limited to, procurement of substitute
      17   * goods or services; loss of use, data, or profits; or business
      18   * interruption) however caused and on any theory of liability, whether
      19   * in contract, strict liability, or tort (including negligence or
      20   * otherwise) arising in any way out of the use of this software, even
      21   * if advised of the possibility of such damage.
      22   */
      23  
      24  #include <glib-object.h>
      25  
      26  typedef struct {
      27    GObject parent_instance;
      28    int foo;
      29  } TestObject;
      30  
      31  typedef struct {
      32    GObjectClass parent_class;
      33  } TestObjectClass;
      34  
      35  typedef enum {
      36    PROP_FOO = 1,
      37    N_PROPERTIES,
      38  } TestObjectProperty;
      39  
      40  static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      41  
      42  static GType test_object_get_type (void);
      43  G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
      44  
      45  static void
      46  test_object_set_foo (TestObject *obj,
      47                       gint        foo)
      48  {
      49    if (obj->foo != foo)
      50      {
      51        obj->foo = foo;
      52  
      53        g_assert (properties[PROP_FOO] != NULL);
      54        g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]);
      55      }
      56  }
      57  
      58  static void
      59  test_object_set_property (GObject *gobject,
      60                            guint prop_id,
      61                            const GValue *value,
      62                            GParamSpec *pspec)
      63  {
      64    TestObject *tobj = (TestObject *) gobject;
      65  
      66    switch ((TestObjectProperty)prop_id)
      67      {
      68      case PROP_FOO:
      69        test_object_set_foo (tobj, g_value_get_int (value));
      70        break;
      71  
      72      default:
      73        g_assert_not_reached ();
      74      }
      75  }
      76  
      77  static void
      78  test_object_get_property (GObject *gobject,
      79                            guint prop_id,
      80                            GValue *value,
      81                            GParamSpec *pspec)
      82  {
      83    TestObject *tobj = (TestObject *) gobject;
      84  
      85    switch ((TestObjectProperty)prop_id)
      86      {
      87      case PROP_FOO:
      88        g_value_set_int (value, tobj->foo);
      89        break;
      90  
      91      default:
      92        g_assert_not_reached ();
      93      }
      94  }
      95  
      96  static int dispatch_properties_called;
      97  
      98  static void
      99  test_object_dispatch_properties_changed (GObject     *object,
     100                                           guint        n_pspecs,
     101                                           GParamSpec **pspecs)
     102  {
     103    dispatch_properties_called++;
     104  
     105    G_OBJECT_CLASS (test_object_parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs);
     106  }
     107  
     108  
     109  static void
     110  test_object_class_init (TestObjectClass *klass)
     111  {
     112    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     113  
     114    properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "Foo",
     115                                             -1, G_MAXINT,
     116                                             0,
     117                                             G_PARAM_READWRITE |
     118                                             G_PARAM_STATIC_STRINGS |
     119                                             G_PARAM_EXPLICIT_NOTIFY);
     120  
     121    gobject_class->set_property = test_object_set_property;
     122    gobject_class->get_property = test_object_get_property;
     123    gobject_class->dispatch_properties_changed = test_object_dispatch_properties_changed;
     124  
     125    g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
     126  }
     127  
     128  static void
     129  test_object_init (TestObject *self)
     130  {
     131    self->foo = 42;
     132  }
     133  
     134  static gboolean
     135  object_has_notify_signal_handlers (gpointer instance)
     136  {
     137    guint signal_id = g_signal_lookup ("notify", G_TYPE_OBJECT);
     138  
     139    return g_signal_handler_find (instance, G_SIGNAL_MATCH_ID, signal_id, 0, NULL, NULL, NULL) != 0;
     140  }
     141  
     142  static void
     143  test_custom_dispatch_init (void)
     144  {
     145    TestObject *obj;
     146  
     147    g_test_summary ("Test that custom dispatch_properties_changed is called "
     148                    "on initialization");
     149  
     150    dispatch_properties_called = 0;
     151    obj = g_object_new (test_object_get_type (), "foo", 5, NULL);
     152  
     153    g_assert_false (object_has_notify_signal_handlers (obj));
     154  
     155    g_assert_cmpint (dispatch_properties_called, ==, 1);
     156    g_object_set (obj, "foo", 11, NULL);
     157    g_assert_cmpint (dispatch_properties_called, ==, 2);
     158  
     159    g_object_unref (obj);
     160  }
     161  
     162  /* This instance init behavior is the thing we are testing:
     163   *
     164   * 1. Don't connect any notify handlers
     165   * 2. Change the the foo property
     166   * 3. Verify that our custom dispatch_properties_changed is called
     167   */
     168  static void
     169  test_custom_dispatch_set (void)
     170  {
     171    TestObject *obj;
     172  
     173    g_test_summary ("Test that custom dispatch_properties_changed is called regardless of connected notify handlers");
     174  
     175    dispatch_properties_called = 0;
     176    obj = g_object_new (test_object_get_type (), NULL);
     177  
     178    g_assert_false (object_has_notify_signal_handlers (obj));
     179  
     180    g_assert_cmpint (dispatch_properties_called, ==, 0);
     181    g_object_set (obj, "foo", 11, NULL);
     182    g_assert_cmpint (dispatch_properties_called, ==, 1);
     183    g_object_set (obj, "foo", 11, NULL);
     184    g_assert_cmpint (dispatch_properties_called, ==, 1);
     185  
     186    g_object_unref (obj);
     187  }
     188  
     189  int
     190  main (int argc, char *argv[])
     191  {
     192    g_test_init (&argc, &argv, NULL);
     193  
     194    g_test_add_func ("/properties/custom-dispatch/init", test_custom_dispatch_init);
     195    g_test_add_func ("/properties/custom-dispatch/set", test_custom_dispatch_set);
     196  
     197    return g_test_run ();
     198  }