accumulator: Fix leak in test
[platform/upstream/glib.git] / tests / gobject / accumulator.c
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 "TestAccumulator"
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 "testmarshal.h"
32 #include "testcommon.h"
33
34 /* What this test tests is the behavior of signal accumulators
35  * Two accumulators are tested:
36  *
37  * 1: A custom accumulator that appends the returned strings
38  * 2: The standard g_signal_accumulator_true_handled that stops
39  *    emission on TRUE returns.
40  */
41
42 /*
43  * TestObject, a parent class for TestObject
44  */
45 #define TEST_TYPE_OBJECT          (test_object_get_type ())
46 typedef struct _TestObject        TestObject;
47 typedef struct _TestObjectClass   TestObjectClass;
48
49 struct _TestObject
50 {
51   GObject parent_instance;
52 };
53 struct _TestObjectClass
54 {
55   GObjectClass parent_class;
56
57   gchar*   (*test_signal1) (TestObject *tobject,
58                             gint        param);
59   gboolean (*test_signal2) (TestObject *tobject,
60                             gint        param);
61   GVariant* (*test_signal3) (TestObject *tobject,
62                              gboolean *weak_ptr);
63 };
64
65 static GType test_object_get_type (void);
66
67 static gboolean
68 test_signal1_accumulator (GSignalInvocationHint *ihint,
69                           GValue                *return_accu,
70                           const GValue          *handler_return,
71                           gpointer               data)
72 {
73   const gchar *accu_string = g_value_get_string (return_accu);
74   const gchar *new_string = g_value_get_string (handler_return);
75   gchar *result_string;
76
77   if (accu_string)
78     result_string = g_strconcat (accu_string, new_string, NULL);
79   else if (new_string)
80     result_string = g_strdup (new_string);
81   else
82     result_string = NULL;
83
84   g_value_set_string_take_ownership (return_accu, result_string);
85
86   return TRUE;
87 }
88
89 static gchar *
90 test_object_signal1_callback_before (TestObject *tobject,
91                                      gint        param,
92                                      gpointer    data)
93 {
94   return g_strdup ("<before>");
95 }
96
97 static gchar *
98 test_object_real_signal1 (TestObject *tobject,
99                           gint        param)
100 {
101   return g_strdup ("<default>");
102 }
103
104 static gchar *
105 test_object_signal1_callback_after (TestObject *tobject,
106                                     gint        param,
107                                     gpointer    data)
108 {
109   return g_strdup ("<after>");
110 }
111
112 static gboolean
113 test_object_signal2_callback_before (TestObject *tobject,
114                                      gint        param)
115 {
116   switch (param)
117     {
118     case 1: return TRUE;
119     case 2: return FALSE;
120     case 3: return FALSE;
121     case 4: return FALSE;
122     }
123
124   g_assert_not_reached ();
125   return FALSE;
126 }
127
128 static gboolean
129 test_object_real_signal2 (TestObject *tobject,
130                           gint        param)
131 {
132   switch (param)
133     {
134     case 1: g_assert_not_reached (); return FALSE;
135     case 2: return TRUE;
136     case 3: return FALSE;
137     case 4: return FALSE;
138     }
139   
140   g_assert_not_reached ();
141   return FALSE;
142 }
143
144 static gboolean
145 test_object_signal2_callback_after (TestObject *tobject,
146                                      gint        param)
147 {
148   switch (param)
149     {
150     case 1: g_assert_not_reached (); return FALSE;
151     case 2: g_assert_not_reached (); return FALSE;
152     case 3: return TRUE;
153     case 4: return FALSE;
154     }
155       
156   g_assert_not_reached ();
157   return FALSE;
158 }
159
160 static gboolean
161 test_signal3_accumulator (GSignalInvocationHint *ihint,
162                           GValue                *return_accu,
163                           const GValue          *handler_return,
164                           gpointer               data)
165 {
166   GVariant *variant;
167
168   variant = g_value_get_variant (handler_return);
169   g_assert (!g_variant_is_floating (variant));
170
171   g_value_set_variant (return_accu, variant);
172
173   return variant == NULL;
174 }
175
176 /* To be notified when the variant is finalised, we construct
177  * it from data with a custom GDestroyNotify.
178  */
179
180 typedef struct {
181   char *mem;
182   gsize n;
183   gboolean *weak_ptr;
184 } VariantData;
185
186 static void
187 free_data (VariantData *data)
188 {
189   *(data->weak_ptr) = TRUE;
190   g_free (data->mem);
191   g_slice_free (VariantData, data);
192 }
193
194 static GVariant *
195 test_object_real_signal3 (TestObject *tobject,
196                           gboolean *weak_ptr)
197 {
198   GVariant *variant;
199   VariantData *data;
200
201   variant = g_variant_ref_sink (g_variant_new_uint32 (42));
202   data = g_slice_new (VariantData);
203   data->weak_ptr = weak_ptr;
204   data->n = g_variant_get_size (variant);
205   data->mem = g_malloc (data->n);
206   g_variant_store (variant, data->mem);
207   g_variant_unref (variant);
208
209   variant = g_variant_new_from_data (G_VARIANT_TYPE ("u"),
210                                      data->mem,
211                                      data->n,
212                                      TRUE,
213                                      (GDestroyNotify) free_data,
214                                      data);
215   return g_variant_ref_sink (variant);
216 }
217
218 static void
219 test_object_class_init (TestObjectClass *class)
220 {
221   class->test_signal1 = test_object_real_signal1;
222   class->test_signal2 = test_object_real_signal2;
223   class->test_signal3 = test_object_real_signal3;
224   
225   g_signal_new ("test-signal1",
226                 G_OBJECT_CLASS_TYPE (class),
227                 G_SIGNAL_RUN_LAST,
228                 G_STRUCT_OFFSET (TestObjectClass, test_signal1),
229                 test_signal1_accumulator, NULL,
230                 test_marshal_STRING__INT,
231                 G_TYPE_STRING, 1, G_TYPE_INT);
232   g_signal_new ("test-signal2",
233                 G_OBJECT_CLASS_TYPE (class),
234                 G_SIGNAL_RUN_LAST,
235                 G_STRUCT_OFFSET (TestObjectClass, test_signal2),
236                 g_signal_accumulator_true_handled, NULL,
237                 test_marshal_BOOLEAN__INT,
238                 G_TYPE_BOOLEAN, 1, G_TYPE_INT);
239   g_signal_new ("test-signal3",
240                 G_OBJECT_CLASS_TYPE (class),
241                 G_SIGNAL_RUN_LAST,
242                 G_STRUCT_OFFSET (TestObjectClass, test_signal3),
243                 test_signal3_accumulator, NULL,
244                 test_marshal_VARIANT__POINTER,
245                 G_TYPE_VARIANT, 1, G_TYPE_POINTER);
246 }
247
248 static DEFINE_TYPE(TestObject, test_object,
249                    test_object_class_init, NULL, NULL,
250                    G_TYPE_OBJECT)
251
252 int
253 main (int   argc,
254       char *argv[])
255 {
256   TestObject *object;
257   gchar *string_result;
258   gboolean bool_result;
259   gboolean variant_finalised;
260   GVariant *variant_result;
261         
262   g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
263                           G_LOG_LEVEL_WARNING |
264                           G_LOG_LEVEL_CRITICAL);
265
266   object = g_object_new (TEST_TYPE_OBJECT, NULL);
267
268   g_signal_connect (object, "test-signal1",
269                     G_CALLBACK (test_object_signal1_callback_before), NULL);
270   g_signal_connect_after (object, "test-signal1",
271                           G_CALLBACK (test_object_signal1_callback_after), NULL);
272   
273   g_signal_emit_by_name (object, "test-signal1", 0, &string_result);
274   g_assert (strcmp (string_result, "<before><default><after>") == 0);
275   g_free (string_result);
276
277   g_signal_connect (object, "test-signal2",
278                     G_CALLBACK (test_object_signal2_callback_before), NULL);
279   g_signal_connect_after (object, "test-signal2",
280                           G_CALLBACK (test_object_signal2_callback_after), NULL);
281   
282   bool_result = FALSE;
283   g_signal_emit_by_name (object, "test-signal2", 1, &bool_result);
284   g_assert (bool_result == TRUE);
285   bool_result = FALSE;
286   g_signal_emit_by_name (object, "test-signal2", 2, &bool_result);
287   g_assert (bool_result == TRUE);
288   bool_result = FALSE;
289   g_signal_emit_by_name (object, "test-signal2", 3, &bool_result);
290   g_assert (bool_result == TRUE);
291   bool_result = TRUE;
292   g_signal_emit_by_name (object, "test-signal2", 4, &bool_result);
293   g_assert (bool_result == FALSE);
294
295   variant_finalised = FALSE;
296   variant_result = NULL;
297   g_signal_emit_by_name (object, "test-signal3", &variant_finalised, &variant_result);
298   g_assert (variant_result != NULL);
299   g_assert (!g_variant_is_floating (variant_result));
300
301   /* Test that variant_result had refcount 1 */
302   g_assert (!variant_finalised);
303   g_variant_unref (variant_result);
304   g_assert (variant_finalised);
305
306   g_object_unref (object);
307
308   return 0;
309 }