Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright © 2018 Endless Mobile, Inc.
4 : : *
5 : : * This library is free software; you can redistribute it and/or
6 : : * modify it under the terms of the GNU Lesser General Public
7 : : * License as published by the Free Software Foundation; either
8 : : * version 2.1 of the License, or (at your option) any later version.
9 : : *
10 : : * This library 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. See the GNU
13 : : * Lesser General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU Lesser General Public
16 : : * License along with this library; if not, write to the Free Software
17 : : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : : *
19 : : * Authors:
20 : : * - Philip Withnall <withnall@endlessm.com>
21 : : */
22 : :
23 : : #pragma once
24 : :
25 : : #include <glib.h>
26 : : #include <glib-object.h>
27 : :
28 : : G_BEGIN_DECLS
29 : :
30 : : typedef struct _GtSignalLoggerEmission GtSignalLoggerEmission;
31 : :
32 : : void gt_signal_logger_emission_free (GtSignalLoggerEmission *emission);
33 : : void gt_signal_logger_emission_get_params (GtSignalLoggerEmission *self,
34 : : ...);
35 : :
36 [ # # ]: 0 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtSignalLoggerEmission, gt_signal_logger_emission_free)
37 : :
38 : : typedef struct _GtSignalLogger GtSignalLogger;
39 : :
40 : : GtSignalLogger *gt_signal_logger_new (void);
41 : : void gt_signal_logger_free (GtSignalLogger *self);
42 : : gulong gt_signal_logger_connect (GtSignalLogger *self,
43 : : gpointer obj,
44 : : const gchar *signal_name);
45 : :
46 [ + + ]: 4 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (GtSignalLogger, gt_signal_logger_free)
47 : :
48 : : gsize gt_signal_logger_get_n_emissions (GtSignalLogger *self);
49 : : gboolean gt_signal_logger_pop_emission (GtSignalLogger *self,
50 : : gpointer *out_obj,
51 : : gchar **out_obj_type_name,
52 : : gchar **out_signal_name,
53 : : GtSignalLoggerEmission **out_emission);
54 : : gchar *gt_signal_logger_format_emission (gpointer obj,
55 : : const gchar *obj_type_name,
56 : : const gchar *signal_name,
57 : : const GtSignalLoggerEmission *emission);
58 : : gchar *gt_signal_logger_format_emissions (GtSignalLogger *self);
59 : :
60 : : /**
61 : : * gt_signal_logger_assert_no_emissions:
62 : : * @self: a #GtSignalLogger
63 : : *
64 : : * Assert that there are no signal emissions currently in the logged stack.
65 : : *
66 : : * Since: 0.1.0
67 : : */
68 : : #define gt_signal_logger_assert_no_emissions(self) \
69 : : G_STMT_START { \
70 : : if (gt_signal_logger_get_n_emissions (self) > 0) \
71 : : { \
72 : : g_autofree gchar *ane_list = gt_signal_logger_format_emissions (self); \
73 : : g_autofree gchar *ane_message = \
74 : : g_strdup_printf ("Expected no signal emissions, but saw %" G_GSIZE_FORMAT ":\n%s", \
75 : : gt_signal_logger_get_n_emissions (self), \
76 : : ane_list); \
77 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
78 : : ane_message); \
79 : : }\
80 : : } G_STMT_END
81 : :
82 : : /**
83 : : * gt_signal_logger_assert_emission_pop:
84 : : * @self: a #GtSignalLogger
85 : : * @obj: a #GObject instance to assert the emission matches
86 : : * @signal_name: signal name to assert the emission matches
87 : : * @...: return locations for the signal parameters
88 : : *
89 : : * Assert that a signal emission can be popped off the log (using
90 : : * gt_signal_logger_pop_emission()) and that it is an emission of @signal_name
91 : : * on @obj. The parameters from the emission will be returned in the return
92 : : * locations given in the varargs, as with
93 : : * gt_signal_logger_emission_get_params().
94 : : *
95 : : * If a signal emission can’t be popped, or if it doesn’t match @signal_name and
96 : : * @obj, an assertion fails, and some debug output is printed.
97 : : *
98 : : * Since: 0.1.0
99 : : */
100 : : #define gt_signal_logger_assert_emission_pop(self, obj, signal_name, ...) \
101 : : G_STMT_START { \
102 : : gpointer aep_obj = NULL; \
103 : : g_autofree gchar *aep_obj_type_name = NULL; \
104 : : g_autofree gchar *aep_signal_name = NULL; \
105 : : g_autoptr(GtSignalLoggerEmission) aep_emission = NULL; \
106 : : if (gt_signal_logger_pop_emission (self, &aep_obj, &aep_obj_type_name, \
107 : : &aep_signal_name, \
108 : : &aep_emission)) \
109 : : { \
110 : : if (aep_obj == G_OBJECT (obj) && \
111 : : g_str_equal (aep_signal_name, signal_name)) \
112 : : { \
113 : : /* Passed the test! */ \
114 : : gt_signal_logger_emission_get_params (aep_emission, __VA_ARGS__); \
115 : : } \
116 : : else \
117 : : { \
118 : : g_autofree gchar *aep_args = \
119 : : gt_signal_logger_format_emission (aep_obj,\
120 : : aep_obj_type_name,\
121 : : aep_signal_name,\
122 : : aep_emission); \
123 : : g_autofree gchar *aep_message = \
124 : : g_strdup_printf ("Expected emission of %s::%s from %p, but saw: %s", \
125 : : G_OBJECT_TYPE_NAME (obj), signal_name, obj, \
126 : : aep_args); \
127 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
128 : : aep_message); \
129 : : } \
130 : : } \
131 : : else \
132 : : { \
133 : : g_autofree gchar *assert_emission_pop_message = \
134 : : g_strdup_printf ("Expected emission of %s::%s from %p, but saw no emissions", \
135 : : G_OBJECT_TYPE_NAME (obj), signal_name, obj); \
136 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
137 : : assert_emission_pop_message); \
138 : : } \
139 : : } G_STMT_END
140 : :
141 : : /**
142 : : * gt_signal_logger_assert_notify_emission_pop:
143 : : * @self: a #GtSignalLogger
144 : : * @obj: a #GObject instance to assert the emission matches
145 : : * @property_name: property name to assert the #GObject::notify signal matches
146 : : *
147 : : * Assert that a signal emission can be popped off the log (using
148 : : * gt_signal_logger_pop_emission()) and that it is an emission of
149 : : * #GObject::notify for @property_name on @obj. To examine the #GParamSpec for
150 : : * the notify emission, use gt_signal_logger_assert_emission_pop() instead.
151 : : *
152 : : * If a signal emission can’t be popped, or if it doesn’t match
153 : : * #GObject::notify, @property_name and @obj, an assertion fails, and some debug
154 : : * output is printed.
155 : : *
156 : : * Since: 0.1.0
157 : : */
158 : : #define gt_signal_logger_assert_notify_emission_pop(self, obj, property_name) \
159 : : G_STMT_START { \
160 : : gpointer anep_obj = NULL; \
161 : : g_autofree gchar *anep_obj_type_name = NULL; \
162 : : g_autofree gchar *anep_signal_name = NULL; \
163 : : g_autoptr(GtSignalLoggerEmission) anep_emission = NULL; \
164 : : if (gt_signal_logger_pop_emission (self, &anep_obj, &anep_obj_type_name, \
165 : : &anep_signal_name, \
166 : : &anep_emission)) \
167 : : { \
168 : : if (anep_obj == G_OBJECT (obj) && \
169 : : (g_str_equal (anep_signal_name, "notify") || \
170 : : g_str_equal (anep_signal_name, "notify::" property_name))) \
171 : : { \
172 : : /* FIXME: We should be able to use g_autoptr() here. \
173 : : * See: https://bugzilla.gnome.org/show_bug.cgi?id=796139 */ \
174 : : GParamSpec *anep_pspec = NULL; \
175 : : \
176 : : /* A GObject::notify signal was emitted. Is it for the right property? */ \
177 : : gt_signal_logger_emission_get_params (anep_emission, &anep_pspec); \
178 : : \
179 : : if (!g_str_equal (g_param_spec_get_name (anep_pspec), property_name)) \
180 : : { \
181 : : g_autofree gchar *anep_args = \
182 : : gt_signal_logger_format_emission (anep_obj,\
183 : : anep_obj_type_name,\
184 : : anep_signal_name,\
185 : : anep_emission); \
186 : : g_autofree gchar *anep_message = \
187 : : g_strdup_printf ("Expected emission of %s::%s::%s from %p, but saw notify::%s instead: %s", \
188 : : G_OBJECT_TYPE_NAME (obj), "notify", property_name, obj, \
189 : : g_param_spec_get_name (anep_pspec), anep_args); \
190 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
191 : : anep_message); \
192 : : } \
193 : : \
194 : : g_param_spec_unref (anep_pspec); \
195 : : } \
196 : : else \
197 : : { \
198 : : g_autofree gchar *anep_args = \
199 : : gt_signal_logger_format_emission (anep_obj,\
200 : : anep_obj_type_name,\
201 : : anep_signal_name,\
202 : : anep_emission); \
203 : : g_autofree gchar *anep_message = \
204 : : g_strdup_printf ("Expected emission of %s::%s::%s from %p, but saw: %s", \
205 : : G_OBJECT_TYPE_NAME (obj), "notify", property_name, obj, \
206 : : anep_args); \
207 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
208 : : anep_message); \
209 : : } \
210 : : } \
211 : : else \
212 : : { \
213 : : g_autofree gchar *assert_emission_pop_message = \
214 : : g_strdup_printf ("Expected emission of %s::%s::%s from %p, but saw no emissions", \
215 : : G_OBJECT_TYPE_NAME (obj), "notify", property_name, obj); \
216 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
217 : : assert_emission_pop_message); \
218 : : } \
219 : : } G_STMT_END
220 : :
221 : : G_END_DECLS
|