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 _MwsSignalLoggerEmission MwsSignalLoggerEmission;
31 : :
32 : : void mws_signal_logger_emission_free (MwsSignalLoggerEmission *self);
33 : : void mws_signal_logger_emission_get_params (MwsSignalLoggerEmission *self,
34 : : ...);
35 : :
36 [ + + ]: 1152 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (MwsSignalLoggerEmission, mws_signal_logger_emission_free)
37 : :
38 : : typedef struct _MwsSignalLogger MwsSignalLogger;
39 : :
40 : : MwsSignalLogger *mws_signal_logger_new (void);
41 : : void mws_signal_logger_free (MwsSignalLogger *self);
42 : : gulong mws_signal_logger_connect (MwsSignalLogger *self,
43 : : gpointer obj,
44 : : const gchar *signal_name);
45 : :
46 [ + + ]: 84 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (MwsSignalLogger, mws_signal_logger_free)
47 : :
48 : : gsize mws_signal_logger_get_n_emissions (MwsSignalLogger *self);
49 : : gboolean mws_signal_logger_pop_emission (MwsSignalLogger *self,
50 : : gpointer *out_obj,
51 : : gchar **out_obj_type_name,
52 : : gchar **out_signal_name,
53 : : MwsSignalLoggerEmission **out_emission);
54 : : gchar *mws_signal_logger_format_emission (gpointer obj,
55 : : const gchar *obj_type_name,
56 : : const gchar *signal_name,
57 : : const MwsSignalLoggerEmission *emission);
58 : : gchar *mws_signal_logger_format_emissions (MwsSignalLogger *self);
59 : :
60 : : /**
61 : : * mws_signal_logger_assert_no_emissions:
62 : : * @self: a #MwsSignalLogger
63 : : *
64 : : * Assert that there are no signal emissions currently in the logged stack.
65 : : *
66 : : * Since: 0.1.0
67 : : */
68 : : #define mws_signal_logger_assert_no_emissions(self) \
69 : : G_STMT_START { \
70 : : if (mws_signal_logger_get_n_emissions (self) > 0) \
71 : : { \
72 : : g_autofree gchar *ane_list = mws_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 : : mws_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 : : * mws_signal_logger_assert_emission_pop:
84 : : * @self: a #MwsSignalLogger
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 : : * mws_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 mws_signal_logger_get_params().
93 : : *
94 : : * If a signal emission can’t be popped, or if it doesn’t match @signal_name and
95 : : * @obj, an assertion fails, and some debug output is printed.
96 : : *
97 : : * Since: 0.1.0
98 : : */
99 : : #define mws_signal_logger_assert_emission_pop(self, obj, signal_name, ...) \
100 : : G_STMT_START { \
101 : : gpointer aep_obj = NULL; \
102 : : g_autofree gchar *aep_obj_type_name = NULL; \
103 : : g_autofree gchar *aep_signal_name = NULL; \
104 : : g_autoptr(MwsSignalLoggerEmission) aep_emission = NULL; \
105 : : if (mws_signal_logger_pop_emission (self, &aep_obj, &aep_obj_type_name, \
106 : : &aep_signal_name, \
107 : : &aep_emission)) \
108 : : { \
109 : : if (aep_obj == G_OBJECT (obj) && \
110 : : g_str_equal (aep_signal_name, signal_name)) \
111 : : { \
112 : : /* Passed the test! */ \
113 : : mws_signal_logger_emission_get_params (aep_emission, __VA_ARGS__); \
114 : : } \
115 : : else \
116 : : { \
117 : : g_autofree gchar *aep_args = \
118 : : mws_signal_logger_format_emission (aep_obj,\
119 : : aep_obj_type_name,\
120 : : aep_signal_name,\
121 : : aep_emission); \
122 : : g_autofree gchar *aep_message = \
123 : : g_strdup_printf ("Expected emission of %s::%s from %p, but saw: %s", \
124 : : G_OBJECT_TYPE_NAME (obj), signal_name, obj, \
125 : : aep_args); \
126 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
127 : : aep_message); \
128 : : } \
129 : : } \
130 : : else \
131 : : { \
132 : : g_autofree gchar *assert_emission_pop_message = \
133 : : g_strdup_printf ("Expected emission of %s::%s from %p, but saw no emissions", \
134 : : G_OBJECT_TYPE_NAME (obj), signal_name, obj); \
135 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
136 : : assert_emission_pop_message); \
137 : : } \
138 : : } G_STMT_END
139 : :
140 : : /**
141 : : * mws_signal_logger_assert_notify_emission_pop:
142 : : * @self: a #MwsSignalLogger
143 : : * @obj: a #GObject instance to assert the emission matches
144 : : * @property_name: property name to assert the #GObject::notify signal matches
145 : : *
146 : : * Assert that a signal emission can be popped off the log (using
147 : : * mws_signal_logger_pop_emission()) and that it is an emission of
148 : : * #GObject::notify for @property_name on @obj. To examine the #GParamSpec for
149 : : * the notify emission, use mws_signal_logger_assert_emission_pop() instead.
150 : : *
151 : : * If a signal emission can’t be popped, or if it doesn’t match
152 : : * #GObject::notify, @property_name and @obj, an assertion fails, and some debug
153 : : * output is printed.
154 : : *
155 : : * Since: 0.1.0
156 : : */
157 : : #define mws_signal_logger_assert_notify_emission_pop(self, obj, property_name) \
158 : : G_STMT_START { \
159 : : gpointer anep_obj = NULL; \
160 : : g_autofree gchar *anep_obj_type_name = NULL; \
161 : : g_autofree gchar *anep_signal_name = NULL; \
162 : : g_autoptr(MwsSignalLoggerEmission) anep_emission = NULL; \
163 : : if (mws_signal_logger_pop_emission (self, &anep_obj, &anep_obj_type_name, \
164 : : &anep_signal_name, \
165 : : &anep_emission)) \
166 : : { \
167 : : if (anep_obj == G_OBJECT (obj) && \
168 : : (g_str_equal (anep_signal_name, "notify") || \
169 : : g_str_equal (anep_signal_name, "notify::" property_name))) \
170 : : { \
171 : : /* FIXME: We should be able to use g_autoptr() here. \
172 : : * See: https://bugzilla.gnome.org/show_bug.cgi?id=796139 */ \
173 : : GParamSpec *anep_pspec = NULL; \
174 : : \
175 : : /* A GObject::notify signal was emitted. Is it for the right property? */ \
176 : : mws_signal_logger_emission_get_params (anep_emission, &anep_pspec); \
177 : : \
178 : : if (!g_str_equal (g_param_spec_get_name (anep_pspec), property_name)) \
179 : : { \
180 : : g_autofree gchar *anep_args = \
181 : : mws_signal_logger_format_emission (anep_obj,\
182 : : anep_obj_type_name,\
183 : : anep_signal_name,\
184 : : anep_emission); \
185 : : g_autofree gchar *anep_message = \
186 : : g_strdup_printf ("Expected emission of %s::%s::%s from %p, but saw notify::%s instead: %s", \
187 : : G_OBJECT_TYPE_NAME (obj), "notify", property_name, obj, \
188 : : g_param_spec_get_name (anep_pspec), anep_args); \
189 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
190 : : anep_message); \
191 : : } \
192 : : \
193 : : g_param_spec_unref (anep_pspec); \
194 : : } \
195 : : else \
196 : : { \
197 : : g_autofree gchar *anep_args = \
198 : : mws_signal_logger_format_emission (anep_obj,\
199 : : anep_obj_type_name,\
200 : : anep_signal_name,\
201 : : anep_emission); \
202 : : g_autofree gchar *anep_message = \
203 : : g_strdup_printf ("Expected emission of %s::%s::%s from %p, but saw: %s", \
204 : : G_OBJECT_TYPE_NAME (obj), "notify", property_name, obj, \
205 : : anep_args); \
206 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
207 : : anep_message); \
208 : : } \
209 : : } \
210 : : else \
211 : : { \
212 : : g_autofree gchar *assert_emission_pop_message = \
213 : : g_strdup_printf ("Expected emission of %s::%s::%s from %p, but saw no emissions", \
214 : : G_OBJECT_TYPE_NAME (obj), "notify", property_name, obj); \
215 : : g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
216 : : assert_emission_pop_message); \
217 : : } \
218 : : } G_STMT_END
219 : :
220 : : G_END_DECLS
|