(root)/
glib-2.79.0/
gobject/
tests/
references.c
       1  /* GObject - GLib Type, Object, Parameter and Signal Library
       2   * Copyright (C) 2005 Red Hat, Inc.
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General
      17   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  #include <glib-object.h>
      21  
      22  /* This test tests weak and toggle references */
      23  
      24  static GObject *global_object;
      25  
      26  static gboolean object_destroyed;
      27  static gboolean weak_ref1_notified;
      28  static gboolean weak_ref2_notified;
      29  static gboolean toggle_ref1_weakened;
      30  static gboolean toggle_ref1_strengthened;
      31  static gboolean toggle_ref2_weakened;
      32  static gboolean toggle_ref2_strengthened;
      33  static gboolean toggle_ref3_weakened;
      34  static gboolean toggle_ref3_strengthened;
      35  
      36  /* TestObject, a parent class for TestObject */
      37  static GType test_object_get_type (void);
      38  #define TEST_TYPE_OBJECT          (test_object_get_type ())
      39  typedef struct _TestObject        TestObject;
      40  typedef struct _TestObjectClass   TestObjectClass;
      41  
      42  struct _TestObject
      43  {
      44    GObject parent_instance;
      45  };
      46  struct _TestObjectClass
      47  {
      48    GObjectClass parent_class;
      49  };
      50  
      51  G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT)
      52  
      53  static void
      54  test_object_finalize (GObject *object)
      55  {
      56    object_destroyed = TRUE;
      57  
      58    G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
      59  }
      60  
      61  static void
      62  test_object_class_init (TestObjectClass *class)
      63  {
      64    GObjectClass *object_class = G_OBJECT_CLASS (class);
      65  
      66    object_class->finalize = test_object_finalize;
      67  }
      68  
      69  static void
      70  test_object_init (TestObject *test_object)
      71  {
      72  }
      73  
      74  static void
      75  clear_flags (void)
      76  {
      77    object_destroyed = FALSE;
      78    weak_ref1_notified = FALSE;
      79    weak_ref2_notified = FALSE;
      80    toggle_ref1_weakened = FALSE;
      81    toggle_ref1_strengthened = FALSE;
      82    toggle_ref2_weakened = FALSE;
      83    toggle_ref2_strengthened = FALSE;
      84    toggle_ref3_weakened = FALSE;
      85    toggle_ref3_strengthened = FALSE;
      86  }
      87  
      88  static void
      89  weak_ref1 (gpointer data,
      90             GObject *object)
      91  {
      92    g_assert_true (object == global_object);
      93    g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
      94  
      95    weak_ref1_notified = TRUE;
      96  }
      97  
      98  static void
      99  weak_ref2 (gpointer data,
     100             GObject *object)
     101  {
     102    g_assert_true (object == global_object);
     103    g_assert_cmpint (GPOINTER_TO_INT (data), ==, 24);
     104  
     105    weak_ref2_notified = TRUE;
     106  }
     107  
     108  static void
     109  toggle_ref1 (gpointer data,
     110               GObject *object,
     111               gboolean is_last_ref)
     112  {
     113    g_assert_true (object == global_object);
     114    g_assert_cmpint (GPOINTER_TO_INT (data), ==, 42);
     115  
     116    if (is_last_ref)
     117      toggle_ref1_weakened = TRUE;
     118    else
     119      toggle_ref1_strengthened = TRUE;
     120  }
     121  
     122  static void
     123  toggle_ref2 (gpointer data,
     124               GObject *object,
     125               gboolean is_last_ref)
     126  {
     127    g_assert_true (object == global_object);
     128    g_assert_cmpint (GPOINTER_TO_INT (data), ==, 24);
     129  
     130    if (is_last_ref)
     131      toggle_ref2_weakened = TRUE;
     132    else
     133      toggle_ref2_strengthened = TRUE;
     134  }
     135  
     136  static void
     137  toggle_ref3 (gpointer data,
     138               GObject *object,
     139               gboolean is_last_ref)
     140  {
     141    g_assert_true (object == global_object);
     142    g_assert_cmpint (GPOINTER_TO_INT (data), ==, 34);
     143  
     144    if (is_last_ref)
     145      {
     146        toggle_ref3_weakened = TRUE;
     147        g_object_remove_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
     148      }
     149    else
     150      toggle_ref3_strengthened = TRUE;
     151  }
     152  
     153  static void
     154  test_references (void)
     155  {
     156    GObject *object;
     157  
     158    /* Test basic weak reference operation */
     159    global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
     160  
     161    g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
     162  
     163    clear_flags ();
     164    g_object_unref (object);
     165    g_assert_true (weak_ref1_notified);
     166    g_assert_true (object_destroyed);
     167  
     168    /* Test two weak references at once
     169     */
     170    global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
     171  
     172    g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
     173    g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
     174  
     175    clear_flags ();
     176    g_object_unref (object);
     177    g_assert_true (weak_ref1_notified);
     178    g_assert_true (weak_ref2_notified);
     179    g_assert_true (object_destroyed);
     180  
     181    /* Test remove weak references */
     182    global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
     183  
     184    g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
     185    g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
     186    g_object_weak_unref (object, weak_ref1, GUINT_TO_POINTER (42));
     187  
     188    clear_flags ();
     189    g_object_unref (object);
     190    g_assert_false (weak_ref1_notified);
     191    g_assert_true (weak_ref2_notified);
     192    g_assert_true (object_destroyed);
     193  
     194    /* Test basic toggle reference operation */
     195    global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
     196  
     197    g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
     198  
     199    clear_flags ();
     200    g_object_unref (object);
     201    g_assert_true (toggle_ref1_weakened);
     202    g_assert_false (toggle_ref1_strengthened);
     203    g_assert_false (object_destroyed);
     204  
     205    clear_flags ();
     206    g_object_ref (object);
     207    g_assert_false (toggle_ref1_weakened);
     208    g_assert_true (toggle_ref1_strengthened);
     209    g_assert_false (object_destroyed);
     210  
     211    g_object_unref (object);
     212  
     213    clear_flags ();
     214    g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
     215    g_assert_false (toggle_ref1_weakened);
     216    g_assert_false (toggle_ref1_strengthened);
     217    g_assert_true (object_destroyed);
     218  
     219    global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
     220  
     221    /* Test two toggle references at once */
     222    g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
     223    g_object_add_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
     224  
     225    clear_flags ();
     226    g_object_unref (object);
     227    g_assert_false (toggle_ref1_weakened);
     228    g_assert_false (toggle_ref1_strengthened);
     229    g_assert_false (toggle_ref2_weakened);
     230    g_assert_false (toggle_ref2_strengthened);
     231    g_assert_false (object_destroyed);
     232  
     233    clear_flags ();
     234    g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
     235    g_assert_false (toggle_ref1_weakened);
     236    g_assert_false (toggle_ref1_strengthened);
     237    g_assert_true (toggle_ref2_weakened);
     238    g_assert_false (toggle_ref2_strengthened);
     239    g_assert_false (object_destroyed);
     240  
     241    clear_flags ();
     242    /* Check that removing a toggle ref with %NULL data works fine. */
     243    g_object_remove_toggle_ref (object, toggle_ref2, NULL);
     244    g_assert_false (toggle_ref1_weakened);
     245    g_assert_false (toggle_ref1_strengthened);
     246    g_assert_false (toggle_ref2_weakened);
     247    g_assert_false (toggle_ref2_strengthened);
     248    g_assert_true (object_destroyed);
     249  
     250    /* Test a toggle reference that removes itself */
     251    global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
     252  
     253    g_object_add_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
     254  
     255    clear_flags ();
     256    g_object_unref (object);
     257    g_assert_true (toggle_ref3_weakened);
     258    g_assert_false (toggle_ref3_strengthened);
     259    g_assert_true (object_destroyed);
     260  }
     261  
     262  int
     263  main (int   argc,
     264        char *argv[])
     265  {
     266    g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
     267                            G_LOG_LEVEL_WARNING |
     268                            G_LOG_LEVEL_CRITICAL);
     269  
     270    g_test_init (&argc, &argv, NULL);
     271  
     272    g_test_add_func ("/gobject/references", test_references);
     273  
     274    return g_test_run ();
     275  }