QOF  0.7.5
test-event.c
1 /***************************************************************************
2  * test-event.c
3  *
4  * Sat Feb 11 11:00:02 2006
5  * Copyright 2006 Neil Williams
6  * linux@codehelp.co.uk
7  ****************************************************************************/
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor
22  * Boston, MA 02110-1301, USA
23  */
24 
25 #include <glib.h>
26 #include <glib/gprintf.h>
27 #include "qof.h"
28 #include "test-engine-stuff.h"
29 #include "test-stuff.h"
30 
31 #define OBJ_NAME "somename"
32 #define OBJ_AMOUNT "anamount"
33 #define OBJ_DATE "nottoday"
34 #define OBJ_GUID "unique"
35 #define OBJ_DISCOUNT "hefty"
36 #define OBJ_VERSION "early"
37 #define OBJ_MINOR "tiny"
38 #define OBJ_ACTIVE "ofcourse"
39 #define OBJ_FLAG "tiny_flag"
40 #define OBJ_EVENT_NAME "test-event-object"
41 #define OBJ_EVENT_DESC "test object for events"
42 
43 /* set to TRUE to get QSF XML output
44  * requires QSF available (i.e. make install) */
45 static gboolean debug = FALSE;
46 
47 /* deliberately make these global to the file to pick up
48 errors where developers access handlers directly. This practice
49 will be deprecated in qofevent. */
50 static guint test, foo;
51 
52 /* simple object structure */
53 typedef struct e_obj
54 {
55  QofInstance inst;
56  gchar *Name;
57  gchar flag;
58  QofNumeric Amount;
59  QofTime *date;
60  gdouble discount; /* cheap pun, I know. */
61  gboolean active;
62  gint32 version;
63  gint64 minor;
64 } event_obj;
65 
66 static event_obj *
67 event_create (QofBook * book)
68 {
69  event_obj *e;
70 
71  g_return_val_if_fail (book, NULL);
72  e = g_new0 (event_obj, 1);
73  qof_instance_init (&e->inst, OBJ_EVENT_NAME, book);
74  e->date = qof_time_get_current ();
75  e->discount = get_random_double ();
76  e->active = get_random_boolean ();
77  e->version = get_random_int_in_range (1, 10000);
78  e->minor = get_random_int_in_range (100000, 99999999);
79  e->flag = get_random_character ();
80  e->Name = get_random_string ();
81  e->Amount = get_random_qof_numeric ();
82  qof_event_gen (&e->inst.entity, QOF_EVENT_CREATE, NULL);
83  return e;
84 }
85 
86 static void
87 event_setFlag (event_obj * e, gchar f)
88 {
89  g_return_if_fail (e);
90  e->flag = f;
91 }
92 
93 static gchar
94 event_getFlag (event_obj * e)
95 {
96  g_return_val_if_fail (e, 'n');
97  return e->flag;
98 }
99 
100 static void
101 event_setMinor (event_obj * e, gint64 h)
102 {
103  g_return_if_fail (e != NULL);
104  e->minor = h;
105 }
106 
107 static gint64
108 event_getMinor (event_obj * e)
109 {
110  g_return_val_if_fail (e, 0);
111  return e->minor;
112 }
113 
114 static void
115 event_setVersion (event_obj * e, gint32 h)
116 {
117  g_return_if_fail (e);
118  e->version = h;
119 }
120 
121 static gint32
122 event_getVersion (event_obj * e)
123 {
124  if (!e)
125  return 0;
126  return e->version;
127 }
128 
129 static void
130 event_setActive (event_obj * e, gboolean h)
131 {
132  if (!e)
133  return;
134  e->active = h;
135 }
136 
137 static gboolean
138 event_getActive (event_obj * e)
139 {
140  if (!e)
141  return FALSE;
142  return e->active;
143 }
144 
145 static void
146 event_setDiscount (event_obj * e, double h)
147 {
148  if (!e)
149  return;
150  e->discount = h;
151 }
152 
153 static double
154 event_getDiscount (event_obj * e)
155 {
156  if (!e)
157  return 0;
158  return e->discount;
159 }
160 
161 static void
162 event_setDate (event_obj * e, QofTime *h)
163 {
164  if (!e)
165  return;
166  e->date = h;
167 }
168 
169 static QofTime*
170 event_getDate (event_obj * e)
171 {
172  if (!e)
173  return NULL;
174  return e->date;
175 }
176 
177 static void
178 event_setName (event_obj * e, gchar * h)
179 {
180  if (!e || !h)
181  return;
182  e->Name = strdup (h);
183 }
184 
185 static gchar *
186 event_getName (event_obj * e)
187 {
188  if (!e)
189  return NULL;
190  return e->Name;
191 }
192 
193 static void
194 event_setAmount (event_obj * e, QofNumeric h)
195 {
196  if (!e)
197  return;
198  e->Amount = h;
199 }
200 
201 static QofNumeric
202 event_getAmount (event_obj * e)
203 {
204  if (!e)
205  return qof_numeric_zero ();
206  return e->Amount;
207 }
208 
209 static QofObject event_object_def = {
210  .interface_version = QOF_OBJECT_VERSION,
211  .e_type = OBJ_EVENT_NAME,
212  .type_label = OBJ_EVENT_DESC,
213  .create = (gpointer) event_create,
214  .book_begin = NULL,
215  .book_end = NULL,
216  .is_dirty = NULL,
217  .mark_clean = NULL,
218  .foreach = qof_collection_foreach,
219  .printable = NULL,
220  .version_cmp = (gint (*)(gpointer, gpointer))
222 };
223 
224 static gboolean
225 event_objRegister (void)
226 {
227  static QofParam params[] = {
228  {OBJ_NAME, QOF_TYPE_STRING, (QofAccessFunc) event_getName,
229  (QofSetterFunc) event_setName, NULL},
230  {OBJ_AMOUNT, QOF_TYPE_NUMERIC, (QofAccessFunc) event_getAmount,
231  (QofSetterFunc) event_setAmount, NULL},
232  {OBJ_DATE, QOF_TYPE_TIME, (QofAccessFunc) event_getDate,
233  (QofSetterFunc) event_setDate, NULL},
234  {OBJ_DISCOUNT, QOF_TYPE_DOUBLE, (QofAccessFunc) event_getDiscount,
235  (QofSetterFunc) event_setDiscount, NULL},
236  {OBJ_ACTIVE, QOF_TYPE_BOOLEAN, (QofAccessFunc) event_getActive,
237  (QofSetterFunc) event_setActive, NULL},
238  {OBJ_VERSION, QOF_TYPE_INT32, (QofAccessFunc) event_getVersion,
239  (QofSetterFunc) event_setVersion, NULL},
240  {OBJ_MINOR, QOF_TYPE_INT64, (QofAccessFunc) event_getMinor,
241  (QofSetterFunc) event_setMinor, NULL},
242  {OBJ_FLAG, QOF_TYPE_CHAR, (QofAccessFunc) event_getFlag,
243  (QofSetterFunc) event_setFlag, NULL},
245  NULL, NULL},
246  {QOF_PARAM_GUID, QOF_TYPE_GUID, (QofAccessFunc) qof_instance_get_guid,
247  NULL, NULL},
248  {NULL, NULL, NULL, NULL, NULL},
249  };
250 
251  qof_class_register (OBJ_EVENT_NAME, NULL, params);
252 
253  return qof_object_register (&event_object_def);
254 }
255 
256 typedef struct event_context_s
257 {
258  QofEventId event_type;
259  QofEntity *entity_original;
260  QofEntity *entity_modified;
261  const QofParam *param;
262  gboolean destroy_used;
263  guint counter;
264  guint old_test_id;
265  guint old_foo_id;
266 } event_context;
267 
268 static void
269 test_event_handler (QofEntity *ent, QofEventId event_type,
270  gpointer handler_data,
271  gpointer user_data __attribute__ ((unused)))
272 {
273  event_context *context;
274 
275  context = (event_context *) handler_data;
276  do_test ((ent != NULL), "Null ent in test");
277  do_test ((context != NULL), "Null context");
278  switch (event_type)
279  {
280  case QOF_EVENT_NONE:
281  {
282  break;
283  }
284  case QOF_EVENT_CREATE:
285  {
286  break;
287  }
288  case QOF_EVENT_MODIFY:
289  {
290  do_test ((context->entity_original != NULL),
291  "No original entity");
292  do_test ((context->event_type == QOF_EVENT_MODIFY),
293  "wrong event sent: test (QOF_EVENT_MODIFY)");
294  break;
295  }
296  case QOF_EVENT_DESTROY:
297  {
298  do_test ((context->entity_original != NULL),
299  "No original entity");
300  do_test ((context->event_type == QOF_EVENT_DESTROY),
301  "wrong event sent: test (QOF_EVENT_DESTROY)");
302  do_test ((context->destroy_used),
303  "destroy sent without being called");
304  /* make sure we can unregister an earlier handler */
306  break;
307  }
308  case QOF_EVENT_ADD:
309  {
310  do_test ((context->entity_original != NULL),
311  "No original entity: test");
312  break;
313  }
314  case QOF_EVENT_REMOVE:
315  {
316  do_test ((context->entity_original != NULL),
317  "No original entity: test");
318  break;
319  }
320  case QOF_EVENT_ALL:
321  {
322  do_test ((context->entity_original != NULL),
323  "No original entity: test");
324  break;
325  }
326  }
327 }
328 
329 static void
330 foo_event_handler (QofEntity *ent, QofEventId event_type,
331  gpointer handler_data,
332  gpointer user_data __attribute__ ((unused)))
333 {
334  event_context *context;
335 
336  context = (event_context *) handler_data;
337  do_test ((context != NULL), "Null context");
338  do_test ((ent != NULL), "Null entity for foo");
339  switch (event_type)
340  {
341  case QOF_EVENT_NONE:
342  {
343  break;
344  }
345  case QOF_EVENT_CREATE:
346  {
347  break;
348  }
349  case QOF_EVENT_MODIFY:
350  {
351  break;
352  }
353  case QOF_EVENT_DESTROY:
354  {
355  do_test ((context->entity_original != NULL),
356  "No original entity");
357  do_test ((context->event_type == QOF_EVENT_DESTROY),
358  "wrong event sent: foo (QOF_EVENT_DESTROY)");
359  do_test ((context->destroy_used),
360  "destroy sent without being called");
361  /* make sure we can unregister a later handler */
363  break;
364  }
365  case QOF_EVENT_ADD:
366  {
367  break;
368  }
369  case QOF_EVENT_REMOVE:
370  {
371  break;
372  }
373  case QOF_EVENT_ALL:
374  {
375  break;
376  }
377  }
378 }
379 
380 static void
381 create_data (QofSession * original, event_context * context)
382 {
383  QofBook *start;
384  event_obj *e, *e2;
385 
386  start = qof_session_get_book (original);
387  e = (event_obj *) qof_object_new_instance (OBJ_EVENT_NAME, start);
388  do_test ((NULL != &e->inst), "instance init");
389  e2 = (event_obj *) qof_object_new_instance (OBJ_EVENT_NAME, start);
390  switch (context->counter)
391  {
392  case 0:
393  { /* empty test */
394  do_test ((e != NULL), "empty check");
395  break;
396  }
397  case 1:
398  { /* create a temporary entity, modify it and destroy it */
399  event_obj *e1;
400 
401  do_test ((context->old_foo_id == foo), "forward foo");
402  do_test ((context->old_test_id == test), "forward test");
403  context->entity_original = (QofEntity *) e;
404  e1 = (event_obj *) qof_object_new_instance (OBJ_EVENT_NAME,
405  start);
406  do_test ((NULL != &e1->inst), "temporary instance init");
407  context->entity_modified = (QofEntity *) e1;
408  context->param =
409  qof_class_get_parameter (OBJ_EVENT_NAME, OBJ_NAME);
410  context->event_type = QOF_EVENT_MODIFY;
411  event_setName (e, event_getName (e1));
413  context->event_type = QOF_EVENT_DESTROY;
414  context->destroy_used = TRUE;
415  /* this block unregisters both handlers on DESTROY in turn.
416  Here, foo is unregistered within test */
417  qof_event_gen ((QofEntity *) e1, QOF_EVENT_DESTROY, NULL);
418  qof_entity_release ((QofEntity *) e1);
419  g_free (e1);
420  e1 = NULL;
421  context->destroy_used = FALSE;
422  context->event_type = QOF_EVENT_NONE;
423  context->entity_modified = NULL;
424  context->param = NULL;
425  /* repeat the test in reverse. */
427  test =
428  qof_event_register_handler (test_event_handler,
429  context);
430  foo =
431  qof_event_register_handler (foo_event_handler,
432  context);
433  do_test ((context->old_foo_id < foo), "reverse foo");
434  do_test ((context->old_test_id < test), "reverse test");
435  /* test is unregistered within foo */
436  e1 = (event_obj *) qof_object_new_instance (OBJ_EVENT_NAME,
437  start);
438  context->entity_modified = (QofEntity *) e1;
439  context->event_type = QOF_EVENT_DESTROY;
440  context->destroy_used = TRUE;
441  qof_event_gen ((QofEntity *) e1, QOF_EVENT_DESTROY, NULL);
442  qof_entity_release ((QofEntity *) e1);
443  g_free (e1);
444  e1 = NULL;
445  context->destroy_used = FALSE;
446  context->event_type = QOF_EVENT_NONE;
447  context->entity_original = NULL;
448  context->entity_modified = NULL;
449  test =
450  qof_event_register_handler (test_event_handler,
451  context);
452  context->old_foo_id = foo;
453  context->old_test_id = test;
454  break;
455  }
456  case 2:
457  { /* create the second test entity */
458  context->entity_original = (QofEntity *) e;
459  do_test ((NULL != &e2->inst), "second instance init");
460  context->entity_modified = (QofEntity *) e2;
461  break;
462  }
463  case 3:
464  { /* destroy the entity e2 */
465  context->event_type = QOF_EVENT_DESTROY;
466  context->destroy_used = TRUE;
467  qof_event_gen ((QofEntity *) e2, QOF_EVENT_DESTROY, NULL);
468  qof_entity_release ((QofEntity *) e2);
469  g_free (e2);
470  e2 = NULL;
471  context->destroy_used = FALSE;
472  context->event_type = QOF_EVENT_NONE;
473  context->entity_modified = NULL;
474  break;
475  }
476  case 4:
477  { /* destroy the original entity e */
478  context->event_type = QOF_EVENT_DESTROY;
479  context->destroy_used = TRUE;
482  g_free (e);
483  e = NULL;
484  context->destroy_used = FALSE;
485  context->event_type = QOF_EVENT_NONE;
486  context->entity_original = NULL;
487  break;
488  }
489  }
490 }
491 
492 int
493 main (void)
494 {
495  QofSession *original;
496  event_context context;
497  guint count;
498 
499  qof_init ();
500  event_objRegister ();
501  original = qof_session_new ();
502  if (debug)
503  {
504  qof_session_begin (original, QOF_STDOUT, TRUE, FALSE);
505  }
506  context.event_type = QOF_EVENT_NONE;
507  context.entity_original = NULL;
508  context.entity_modified = NULL;
509  context.destroy_used = FALSE;
510  context.param = NULL;
511  /* events are unregistered in reverse order, so to test for
512  a bug when unregistering a later module from an earlier one,
513  register the foo module first and unregister it from within
514  a later handler. */
515  foo = qof_event_register_handler (foo_event_handler, &context);
516  test = qof_event_register_handler (test_event_handler, &context);
517  context.old_test_id = test;
518  context.old_foo_id = foo;
519  for (count = 0; count < 25; count++)
520  {
521  context.counter = (count % 5);
522  create_data (original, &context);
523  }
524  print_test_results ();
525  qof_close ();
526  return get_rv();
527 }