GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
unittest-support.c
1 /********************************************************************
2  * unittest-support.c: Support structures for GLib Unit Testing *
3  * Copyright 2011-13 John Ralls <[email protected]> *
4  * Copyright 2011 Muslim Chochlov <[email protected]> *
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 [email protected] *
22 ********************************************************************/
23 
24 #include <config.h>
25 #include <glib/gprintf.h>
26 #include "unittest-support.h"
27 
28 typedef struct
29 {
30  gpointer data;
31  gboolean called;
32  gchar *msg;
33 } TestStruct;
34 
35 static TestStruct tdata;
36 static gboolean
37 test_checked_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
38  const gchar *msg, gpointer user_data);
39 static gboolean
40 test_list_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
41  const gchar *msg, gpointer user_data);
42 
44 test_error_struct_new (gchar *log_domain, GLogLevelFlags log_level, gchar *msg)
45 {
46  TestErrorStruct *err = g_slice_new0 (TestErrorStruct);
47  err->log_domain = g_strdup (log_domain);
48  err->log_level = log_level;
49  err->msg = g_strdup (msg);
50  return err;
51 }
52 
53 void
54 test_error_struct_free (TestErrorStruct *err)
55 {
56  g_free (err->log_domain);
57  g_free (err->msg);
58  g_slice_free (TestErrorStruct, err);
59 }
60 
61 GSList*
62 test_log_set_handler (GSList *list, TestErrorStruct *error, GLogFunc handler)
63 {
64  TestLogHandler *hdlr = g_slice_new0 (TestLogHandler);
65  hdlr->error = error;
66  hdlr->handler = g_log_set_handler (error->log_domain, error->log_level,
67  handler, error);
68  return g_slist_prepend (list, hdlr);
69 }
70 
71 GSList*
72 test_log_set_fatal_handler (GSList *list, TestErrorStruct *error,
73  GLogFunc handler)
74 {
75  TestLogHandler *hdlr = g_slice_new0 (TestLogHandler);
76  GTestLogFatalFunc f_hdlr = handler == (GLogFunc)test_list_handler ?
77  (GTestLogFatalFunc)test_list_nohit_handler :
78  (GTestLogFatalFunc)test_checked_nohit_handler;
79  hdlr->error = error;
80  hdlr->handler = g_log_set_handler (error->log_domain, error->log_level,
81  handler, error);
82  g_test_log_set_fatal_handler (f_hdlr, error);
83  return g_slist_prepend (list, hdlr);
84 }
85 
86 void
87 test_free_log_handler (gpointer item)
88 {
89  TestLogHandler *handler = (TestLogHandler*)item;
90  g_log_remove_handler (handler->error->log_domain, handler->handler);
91  test_error_struct_free (handler->error);
92  g_slice_free (TestLogHandler, handler);
93 }
94 
95 gboolean
96 test_null_handler (const char *log_domain, GLogLevelFlags log_level,
97  const gchar *msg, gpointer user_data )
98 {
99  //Silent, remember?
100 
101  return FALSE;
102 }
103 
104 static gchar*
105 test_log_level (GLogLevelFlags flags)
106 {
107  const gchar *message[] = {"RECURSIVE", "FATAL", "ERROR", "CRITICAL",
108  "WARNING", "MESSAGE", "INFO", "DEBUG"
109  };
110  guint i = 0, last = 0, max_bit = 7;
111  gchar *msg = NULL;
112 
113  for (i = 0; i <= max_bit; i++)
114  if (flags & 1 << i)
115  {
116  gchar *tmp_msg = msg;
117  gchar *sep = (last < 2 ? " " : "|");
118  last = i;
119  msg = (tmp_msg ? g_strjoin (sep, tmp_msg, message[i], NULL)
120  : g_strdup (message[i]));
121  if (tmp_msg)
122  g_free (tmp_msg);
123  }
124 
125  if (msg == NULL)
126  msg = g_strdup ("");
127  return msg;
128 }
129 
130 static GList *message_queue = NULL;
131 
132 void
133 test_add_error (TestErrorStruct *error)
134 {
135  message_queue = g_list_append (message_queue, error);
136 }
137 
138 void
139 test_clear_error_list (void)
140 {
141  g_list_free (message_queue);
142  message_queue = NULL;
143 }
144 
145 static gboolean
146 do_test_list_handler (const char *log_domain, GLogLevelFlags log_level,
147  const gchar *msg, gpointer user_data, gboolean hits)
148 {
149  GList *list = g_list_first (message_queue);
150  const guint fatal = G_LOG_FLAG_FATAL;
151 
152  while (list)
153  {
154  TestErrorStruct *error = (TestErrorStruct*)list->data;
155  if (!g_strcmp0 (log_domain, error->log_domain)
156  && ((log_level | fatal) == (error->log_level | fatal))
157  && !g_strcmp0 (msg, error->msg))
158  {
159  if (hits)
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_handler (log_domain, log_level, msg, user_data);
167 }
168 
169 gboolean
170 test_list_handler (const char *log_domain, GLogLevelFlags log_level,
171  const gchar *msg, gpointer user_data)
172 {
173  return do_test_list_handler (log_domain, log_level, msg, user_data, TRUE);
174 }
175 
176 gboolean
177 test_list_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
178  const gchar *msg, gpointer user_data)
179 {
180  return do_test_list_handler (log_domain, log_level, msg, user_data, FALSE);
181 }
182 
183 static gboolean
184 do_test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
185  const gchar *msg, gpointer user_data, gboolean hits)
186 {
187  TestErrorStruct *tdata = (TestErrorStruct*)user_data;
188 
189  if ((tdata == NULL)
190  || (tdata->log_domain != NULL
191  && g_strcmp0 (tdata->log_domain, log_domain))
192  || (tdata->log_level && tdata->log_level != log_level)
193  || (tdata->msg && g_strcmp0 (tdata->msg, msg)))
194  {
195  gchar *level = test_log_level (log_level);
196  g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
197  g_free (level);
198  g_assert (log_level ^ G_LOG_FLAG_FATAL);
199  return FALSE;
200  }
201  if (hits)
202  ++(tdata->hits);
203  return FALSE;
204 
205 }
206 
207 gboolean
208 test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
209  const gchar *msg, gpointer user_data )
210 {
211  return do_test_checked_handler (log_domain, log_level, msg,
212  user_data, TRUE);
213 }
214 
215 static gboolean
216 test_checked_nohit_handler (const char *log_domain, GLogLevelFlags log_level,
217  const gchar *msg, gpointer user_data )
218 {
219  return do_test_checked_handler (log_domain, log_level, msg,
220  user_data, FALSE);
221 }
222 
223 gboolean
224 test_log_handler (const char *log_domain, GLogLevelFlags log_level,
225  const gchar *msg, gpointer user_data )
226 {
227  gchar *level = test_log_level (log_level);
228  g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
229  g_free (level);
230  g_assert (log_level ^ G_LOG_FLAG_FATAL);
231  return FALSE;
232 }
233 
234 void
235 test_set_called( const gboolean val )
236 {
237  tdata.called = val;
238 }
239 
240 gboolean
241 test_reset_called( void )
242 {
243  const gboolean called = tdata.called;
244  tdata.called = FALSE;
245  return called;
246 }
247 
248 void
249 test_set_data( const gpointer val )
250 {
251  tdata.data = val;
252 }
253 
254 gpointer
255 test_reset_data( void )
256 {
257  const gpointer data = tdata.data;
258  tdata.data = NULL;
259  return data;
260 }
261 
262 void
263 test_free( gpointer data )
264 {
265  if (!data) return;
266  g_free(data);
267 }
268 
269 
270 typedef struct
271 {
272  QofInstance *entity;
273  QofEventId event_type;
274  gpointer event_data;
275  gint hdlr;
276  guint hits;
277 } _TestSignal;
278 
279 static void
280 mock_signal_handler (QofInstance *entity, QofEventId event_type,
281  gpointer handler_data, gpointer event_data)
282 {
283  _TestSignal *signal = (_TestSignal*)handler_data;
284  if ((signal->entity == entity || signal->entity == NULL)
285  && signal->event_type == event_type)
286  {
287  if (signal->event_data)
288  g_assert (signal->event_data == event_data);
289  signal->hits += 1;
290  }
291 }
292 
293 TestSignal
294 test_signal_new (QofInstance *entity, QofEventId event_type,
295  gpointer event_data)
296 {
297  _TestSignal *sig = g_slice_new (_TestSignal);
298  sig->entity = entity;
299  sig->event_type = event_type;
300  sig->event_data = event_data;
301  sig->hits = 0;
302  sig->hdlr = qof_event_register_handler (mock_signal_handler, (gpointer)sig);
303  return (TestSignal)sig;
304 }
305 
306 void
307 test_signal_free (TestSignal sigp)
308 {
309  _TestSignal *sig = (_TestSignal *)sigp;
310  qof_event_unregister_handler (sig->hdlr);
311  g_slice_free (_TestSignal, sig);
312 }
313 
314 guint
315 test_signal_return_hits (TestSignal sigp)
316 {
317  _TestSignal *sig = (_TestSignal *)sigp;
318  return sig->hits;
319 }
320 
321 static void
322 notify_destroy (gpointer pdata, GObject *obj)
323 {
324  gboolean *data = (gboolean*)pdata;
325  if (! (*data)) *data = TRUE;
326 }
327 
328 gboolean
329 test_object_checked_destroy (GObject *obj)
330 {
331  gboolean is_destroyed = FALSE;
332  if (!obj || ! G_IS_OBJECT (obj)) return FALSE;
333  g_object_weak_ref (obj, notify_destroy, &is_destroyed);
334  g_object_unref (obj);
335  return is_destroyed;
336 }
gint qof_event_register_handler(QofEventHandler handler, gpointer handler_data)
Register a handler for events.
gint QofEventId
Definition: qofevent.h:45
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.