GnuCash c935c2f+
Loading...
Searching...
No Matches
unittest-support.c
1/********************************************************************
2 * unittest-support.c: Support structures for GLib Unit Testing *
3 * Copyright 2011-13 John Ralls <jralls@ceridwen.us> *
4 * Copyright 2011 Muslim Chochlov <muslim.chochlov@gmail.com> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program 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 *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22********************************************************************/
23
24#include <config.h>
25#include <glib/gprintf.h>
26#include "unittest-support.h"
27
28typedef struct
29{
30 gpointer data;
31 gboolean called;
32 char *msg;
34
35static TestStruct tdata;
36static gboolean
37test_checked_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
38 const gchar *msg, gpointer user_data);
39static gboolean
40test_list_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
41 const gchar *msg, gpointer user_data);
42
44test_error_struct_new (const char *log_domain, GLogLevelFlags log_level,
45 const char *msg)
46{
47 TestErrorStruct *err = g_slice_new0 (TestErrorStruct);
48 err->log_domain = g_strdup (log_domain);
49 err->log_level = log_level;
50 err->msg = g_strdup (msg);
51 return err;
52}
53
54void
55test_error_struct_free (TestErrorStruct *err)
56{
57 g_free (err->log_domain);
58 g_free (err->msg);
59 g_slice_free (TestErrorStruct, err);
60}
61
62GSList*
63test_log_set_handler (GSList *list, TestErrorStruct *error, GLogFunc handler)
64{
65 TestLogHandler *hdlr = g_slice_new0 (TestLogHandler);
66 hdlr->error = error;
67 hdlr->handler = g_log_set_handler (error->log_domain, error->log_level,
68 handler, error);
69 return g_slist_prepend (list, hdlr);
70}
71
72GSList*
73test_log_set_fatal_handler (GSList *list, TestErrorStruct *error,
74 GLogFunc handler)
75{
76 TestLogHandler *hdlr = g_slice_new0 (TestLogHandler);
77 GTestLogFatalFunc f_hdlr = handler == (GLogFunc)test_list_handler ?
78 (GTestLogFatalFunc)test_list_nohit_handler :
79 (GTestLogFatalFunc)test_checked_nohit_handler;
80 hdlr->error = error;
81 hdlr->handler = g_log_set_handler (error->log_domain, error->log_level,
82 handler, error);
83 g_test_log_set_fatal_handler (f_hdlr, error);
84 return g_slist_prepend (list, hdlr);
85}
86
87void
88test_free_log_handler (gpointer item)
89{
90 TestLogHandler *handler = (TestLogHandler*)item;
91 g_log_remove_handler (handler->error->log_domain, handler->handler);
92 test_error_struct_free (handler->error);
93 g_slice_free (TestLogHandler, handler);
94}
95
96gboolean
97test_null_handler (const char *log_domain, GLogLevelFlags log_level,
98 const gchar *msg, gpointer user_data )
99{
100 //Silent, remember?
101
102 return FALSE;
103}
104
105static gchar*
106test_log_level (GLogLevelFlags flags)
107{
108 const gchar *message[] = {"RECURSIVE", "FATAL", "ERROR", "CRITICAL",
109 "WARNING", "MESSAGE", "INFO", "DEBUG"
110 };
111 guint i = 0, last = 0, max_bit = 7;
112 gchar *msg = NULL;
113
114 for (i = 0; i <= max_bit; i++)
115 if (flags & 1 << i)
116 {
117 gchar *tmp_msg = msg;
118 gchar *sep = (last < 2 ? " " : "|");
119 last = i;
120 msg = (tmp_msg ? g_strjoin (sep, tmp_msg, message[i], NULL)
121 : g_strdup (message[i]));
122 if (tmp_msg)
123 g_free (tmp_msg);
124 }
125
126 if (msg == NULL)
127 msg = g_strdup ("");
128 return msg;
129}
130
131static GList *message_queue = NULL;
132
133void
134test_add_error (TestErrorStruct *error)
135{
136 message_queue = g_list_append (message_queue, error);
137}
138
139void
140test_clear_error_list (void)
141{
142 g_list_free (message_queue);
143 message_queue = NULL;
144}
145
146
147gboolean
148test_list_substring_handler (const char *log_domain, GLogLevelFlags log_level,
149 const gchar *msg, gpointer user_data)
150{
151 GList *list = g_list_first (message_queue);
152 const guint fatal = G_LOG_FLAG_FATAL;
153 while (list)
154 {
155 TestErrorStruct *error = (TestErrorStruct*)list->data;
156 if (!g_strcmp0 (log_domain, error->log_domain)
157 && ((log_level | fatal) == (error->log_level | fatal))
158 && g_strrstr (msg, error->msg))
159 {
160 ++(error->hits);
161 return FALSE;
162 }
163 list = g_list_next (list);
164 }
165 /* No list or no matches, fall through */
166 return test_checked_substring_handler (log_domain, log_level, msg, user_data);
167}
168
169static gboolean
170do_test_list_handler (const char *log_domain, GLogLevelFlags log_level,
171 const gchar *msg, gpointer user_data, gboolean hits)
172{
173 GList *list = g_list_first (message_queue);
174 const guint fatal = G_LOG_FLAG_FATAL;
175
176 while (list)
177 {
178 TestErrorStruct *error = (TestErrorStruct*)list->data;
179 if (!g_strcmp0 (log_domain, error->log_domain)
180 && ((log_level | fatal) == (error->log_level | fatal))
181 && !g_strcmp0 (msg, error->msg))
182 {
183 if (hits)
184 ++(error->hits);
185 return FALSE;
186 }
187 list = g_list_next (list);
188 }
189 /* No list or no matches, fall through */
190 return test_checked_handler (log_domain, log_level, msg, user_data);
191}
192
193gboolean
194test_list_handler (const char *log_domain, GLogLevelFlags log_level,
195 const gchar *msg, gpointer user_data)
196{
197 return do_test_list_handler (log_domain, log_level, msg, user_data, TRUE);
198}
199
200gboolean
201test_list_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
202 const gchar *msg, gpointer user_data)
203{
204 return do_test_list_handler (log_domain, log_level, msg, user_data, FALSE);
205}
206
207static gboolean
208do_test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
209 const gchar *msg, gpointer user_data, gboolean hits)
210{
211 TestErrorStruct *tdata = (TestErrorStruct*)user_data;
212
213 if ((tdata == NULL)
214 || (tdata->log_domain != NULL
215 && g_strcmp0 (tdata->log_domain, log_domain))
216 || (tdata->log_level && tdata->log_level != log_level)
217 || (tdata->msg && g_strcmp0 (tdata->msg, msg)))
218 {
219 gchar *level = test_log_level (log_level);
220 g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
221 g_free (level);
222 g_assert_true (log_level ^ G_LOG_FLAG_FATAL);
223 return FALSE;
224 }
225 if (hits)
226 ++(tdata->hits);
227 return FALSE;
228
229}
230
231gboolean
232test_checked_substring_handler (const char *log_domain, GLogLevelFlags log_level,
233 const gchar *msg, gpointer user_data)
234{
235 TestErrorStruct *tdata = (TestErrorStruct*)user_data;
236 if ((tdata == NULL)
237 || (tdata->log_domain != NULL
238 && g_strcmp0 (log_domain, tdata->log_domain))
239 || (tdata->log_level && tdata->log_level != log_level)
240 || (tdata->msg && !g_strrstr (msg, tdata->msg)))
241 {
242 gchar *level = test_log_level (log_level);
243 g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
244 g_free (level);
245 g_assert_true (log_level ^ G_LOG_FLAG_FATAL);
246 return FALSE;
247 }
248 ++(tdata->hits);
249 return FALSE;
250}
251
252gboolean
253test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
254 const gchar *msg, gpointer user_data )
255{
256 return do_test_checked_handler (log_domain, log_level, msg,
257 user_data, TRUE);
258}
259
260static gboolean
261test_checked_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
262 const gchar *msg, gpointer user_data )
263{
264 return do_test_checked_handler (log_domain, log_level, msg,
265 user_data, FALSE);
266}
267
268gboolean
269test_log_handler (const char *log_domain, GLogLevelFlags log_level,
270 const gchar *msg, gpointer user_data )
271{
272 gchar *level = test_log_level (log_level);
273 g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
274 g_free (level);
275 g_assert_true (log_level ^ G_LOG_FLAG_FATAL);
276 return FALSE;
277}
278
279void
280test_set_called( const gboolean val )
281{
282 tdata.called = val;
283}
284
285gboolean
286test_reset_called( void )
287{
288 const gboolean called = tdata.called;
289 tdata.called = FALSE;
290 return called;
291}
292
293void
294test_set_data( const gpointer val )
295{
296 tdata.data = val;
297}
298
299gpointer
300test_reset_data( void )
301{
302 const gpointer data = tdata.data;
303 tdata.data = NULL;
304 return data;
305}
306
307void
308test_free( gpointer data )
309{
310 if (!data) return;
311 g_free(data);
312}
313
314
315typedef struct
316{
317 QofInstance *entity;
318 QofEventId event_type;
319 gpointer event_data;
320 gint hdlr;
321 guint hits;
323
324static void
325mock_signal_handler (QofInstance *entity, QofEventId event_type,
326 gpointer handler_data, gpointer event_data)
327{
328 _TestSignal *signal = (_TestSignal*)handler_data;
329 if ((signal->entity == entity || signal->entity == NULL)
330 && signal->event_type == event_type)
331 {
332 if (signal->event_data)
333 g_assert_true (signal->event_data == event_data);
334 signal->hits += 1;
335 }
336}
337
339test_signal_new (QofInstance *entity, QofEventId event_type,
340 gpointer event_data)
341{
342 _TestSignal *sig = g_slice_new (_TestSignal);
343 sig->entity = entity;
344 sig->event_type = event_type;
345 sig->event_data = event_data;
346 sig->hits = 0;
347 sig->hdlr = qof_event_register_handler (mock_signal_handler, (gpointer)sig);
348 return (TestSignal)sig;
349}
350
351void
352test_signal_free (TestSignal sigp)
353{
354 _TestSignal *sig = (_TestSignal *)sigp;
356 g_slice_free (_TestSignal, sig);
357}
358
359guint
360test_signal_return_hits (TestSignal sigp)
361{
362 _TestSignal *sig = (_TestSignal *)sigp;
363 return sig->hits;
364}
365
366static void
367notify_destroy (gpointer pdata, GObject *obj)
368{
369 gboolean *data = (gboolean*)pdata;
370 if (! (*data)) *data = TRUE;
371}
372
373gboolean
374test_object_checked_destroy (GObject *obj)
375{
376 gboolean is_destroyed = FALSE;
377 if (!obj || ! G_IS_OBJECT (obj)) return FALSE;
378 g_object_weak_ref (obj, notify_destroy, &is_destroyed);
379 g_object_unref (obj);
380 return is_destroyed;
381}
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition qofevent.cpp:103
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition qofevent.cpp:73
gint QofEventId
Define the type of events allowed.
Definition qofevent.h:45
Struct to pass as user_data for the handlers.
Holds a handler instance with its TestErrorStruct, handler id, and whether it's a list handler.
Macros and logging-capture functions to ease writing GLib-testing based unit tests.
gpointer TestSignal
TestSignal is an opaque struct used to mock handling signals emitted by functions-under-test.