GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
utest-Transaction.c
1 /********************************************************************
2  * utest-Transaction.c: GLib g_test test suite for Transaction.c. *
3  * Copyright 2012 John Ralls <[email protected]> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program 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 *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, you can retrieve it from *
17  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html *
18  * or contact: *
19  * *
20  * Free Software Foundation Voice: +1-617-542-5942 *
21  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
22  * Boston, MA 02110-1301, USA [email protected] *
23  ********************************************************************/
24 #include <config.h>
25 #include <string.h>
26 #include <glib.h>
27 #include <unittest-support.h>
28 /* Add specific headers for this class */
29 #include "../Transaction.h"
30 #include "../TransactionP.h"
31 #include "../Split.h"
32 #include "../Account.h"
33 #include "../gnc-lot.h"
34 #include "../gnc-event.h"
35 #include <qof.h>
36 #include <qofbackend-p.h>
37 
38 #ifdef HAVE_GLIB_2_38
39 #define _Q "'"
40 #else
41 #define _Q "`"
42 #endif
43 #if defined(__clang__) && (__clang_major__ == 5 || (__clang_major__ == 3 && __clang_minor__ < 5))
44 #define USE_CLANG_FUNC_SIG 1
45 #endif
46 
47 static const gchar *suitename = "/engine/Transaction";
48 void test_suite_transaction ( void );
49 
50 /* Copied from Transaction.c. Changing these values will break
51  * existing databases, which is a good reason to fail a test.
52  */
53 static const char *trans_notes_str = "notes";
54 static const char *void_reason_str = "void-reason";
55 static const char *void_time_str = "void-time";
56 static const char *void_former_notes_str = "void-former-notes";
57 const char *trans_is_closing_str = "book_closing";
58 #define TRANS_DATE_DUE_KVP "trans-date-due"
59 #define TRANS_TXN_TYPE_KVP "trans-txn-type"
60 #define TRANS_READ_ONLY_REASON "trans-read-only"
61 #define TRANS_REVERSED_BY "reversed-by"
62 
63 #define ISO_DATELENGTH 32 /* length of an iso 8601 date string. */
64 
65 
66 typedef struct
67 {
68  Transaction *txn;
69  Account *acc1;
70  Account *acc2;
71  gnc_commodity *curr;
72  gnc_commodity *comm;
73  TransTestFunctions *func;
74  GSList *hdlrs;
75 } Fixture;
76 
77 typedef struct
78 {
79  Fixture base;
80  Transaction *gains_txn;
81  Account *gains_acc;
82 } GainsFixture;
83 
84 typedef struct
85 {
86  QofBackend be;
87  gchar last_call[12];
88  QofBackendError result_err;
89 } MockBackend;
90 
91 static void
92 mock_backend_set_error (MockBackend *mbe, QofBackendError err)
93 {
94  mbe->result_err = err;
95 }
96 
97 static void
98 mock_backend_rollback (QofBackend *be, QofInstance *foo)
99 {
100  MockBackend *mbe = (MockBackend *)be;
101  g_strlcpy (mbe->last_call, "rollback", sizeof (mbe->last_call));
102  mbe->be.last_err = mbe->result_err;
103 }
104 
105 static MockBackend*
106 mock_backend_new (void)
107 {
108  MockBackend *mbe = g_new0 (MockBackend, 1);
109  mbe->be.rollback = mock_backend_rollback;
110  memset (mbe->last_call, 0, sizeof (mbe->last_call));
111  return mbe;
112 }
113 
114 static void
115 setup (Fixture *fixture, gconstpointer pData)
116 {
117  QofBook *book = qof_book_new ();
118  MockBackend *mbe = mock_backend_new ();
119  Split *split1 = NULL, *split2 = NULL;
120  Transaction *txn;
121  Timespec entered = gnc_dmy2timespec (20, 4, 2012);
122  Timespec posted = gnc_dmy2timespec (21, 4, 2012);
123  KvpFrame *frame = kvp_frame_new ();
124 
125  qof_book_set_backend (book, (QofBackend*)mbe);
126  split1 = xaccMallocSplit (book);
127  split2 = xaccMallocSplit (book);
128  txn = xaccMallocTransaction (book);
129  fixture->txn = txn;
130  fixture->curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY", "GNR", "", 240);
131  fixture->comm = gnc_commodity_new (book, "Wildebeest Fund", "FUND", "WBFXX", "", 1000);
132  fixture->acc1 = xaccMallocAccount (book);
133  fixture->acc2 = xaccMallocAccount (book);
134  xaccAccountSetCommodity (fixture->acc1, fixture->comm);
135  xaccAccountSetCommodity (fixture->acc2, fixture->curr);
136  txn->date_posted.tv_sec = posted.tv_sec;
137  txn->date_posted.tv_nsec = posted.tv_nsec;
138  txn->date_entered.tv_sec = entered.tv_sec;
139  txn->date_entered.tv_nsec = entered.tv_nsec;
140  split1->memo = CACHE_INSERT ("foo");
141  split1->action = CACHE_INSERT ("bar");
142  split1->amount = gnc_numeric_create (100000, 1000);
143  split1->value = gnc_numeric_create (3200, 240);
144  split2->amount = gnc_numeric_create (-3200, 240);
145  split2->value = gnc_numeric_create (-3200, 240);
146  split1->acc = fixture->acc1;
147  split2->acc = fixture->acc2;
148  txn->num = CACHE_INSERT ("123");
149  txn->description = CACHE_INSERT ("Waldo Pepper");
150  xaccTransBeginEdit (txn);
151  {
152  xaccTransSetCurrency (txn, fixture->curr);
153  xaccSplitSetParent (split1, txn);
154  xaccSplitSetParent (split2, txn);
155  kvp_frame_set_string (frame, trans_notes_str, "Salt pork sausage");
156  kvp_frame_set_double (frame, "/qux/quux/corge", 123.456);
157  qof_instance_set_slots (QOF_INSTANCE (txn), frame);
158  }
159  xaccTransCommitEdit (txn);
160  xaccAccountSortSplits(fixture->acc1, FALSE);
161  xaccAccountSortSplits(fixture->acc2, FALSE);
162  xaccAccountRecomputeBalance(fixture->acc1);
163  xaccAccountRecomputeBalance(fixture->acc2);
164  qof_instance_mark_clean (QOF_INSTANCE (split1));
165  qof_instance_mark_clean (QOF_INSTANCE (split2));
166  qof_instance_mark_clean (QOF_INSTANCE (txn));
167  fixture->func = _utest_trans_fill_functions();
168  fixture->hdlrs = NULL;
169 }
170 
171 static void
172 setup_with_gains (GainsFixture *fixture, gconstpointer pData)
173 {
174  QofBook *book;
175  Fixture *base = &(fixture->base);
176  Split *gains_split1 = NULL, *gains_split2 = NULL;
177  Split *base_split = NULL;
178 
179  setup (base, NULL);
180 
181  book = qof_instance_get_book (QOF_INSTANCE (base->txn));
182  fixture->gains_txn = xaccMallocTransaction (book);
183  fixture->gains_acc = xaccMallocAccount (book);
184  xaccAccountSetCommodity (fixture->gains_acc, base->curr);
185  gains_split1 = xaccMallocSplit (book);
186  gains_split2 = xaccMallocSplit (book);
187  gains_split1->acc = base->acc1;
188  gains_split2->acc = fixture->gains_acc;
189  gains_split1->amount = gnc_numeric_create (30, 240);
190  gains_split1->value = gnc_numeric_create (30, 240);
191  gains_split2->amount = gnc_numeric_create (-30, 240);
192  gains_split2->value = gnc_numeric_create (-30, 240);
193  xaccTransBeginEdit (fixture->gains_txn);
194  {
195  xaccTransSetCurrency (fixture->gains_txn, base->curr);
196  xaccSplitSetParent (gains_split1, fixture->gains_txn);
197  xaccSplitSetParent (gains_split2, fixture->gains_txn);
198  }
199  xaccTransCommitEdit (fixture->gains_txn);
200  base_split = g_list_nth_data (base->txn->splits, 1);
201  base_split->gains_split = gains_split1;
202 }
203 
204 
205 /* Add a log handler to the handlers list to be cleared at teardown */
206 
207 
208 static void
209 teardown (Fixture *fixture, gconstpointer pData)
210 {
211  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
213 
214  test_destroy (fixture->txn);
215  test_destroy (fixture->acc1);
216  test_destroy (fixture->acc2);
217  test_destroy (fixture->curr);
218  test_destroy (fixture->comm);
219  g_free (mbe);
220  test_destroy (book);
221  g_slist_free_full (fixture->hdlrs, test_free_log_handler);
222  test_clear_error_list();
223 }
224 
225 static void
226 teardown_with_gains (GainsFixture *fixture, gconstpointer pData)
227 {
228  Fixture *base = &(fixture->base);
229  test_destroy (fixture->gains_acc);
230  teardown (base, NULL);
231 }
232 
233 /* check_open
234 void check_open (const Transaction *trans)// Local: 1:0:0
235 */
236 static void
237 test_check_open (Fixture *fixture, gconstpointer pData)
238 {
239  gchar *msg = g_strdup_printf ("[check_open()] transaction %p not open for editing", fixture->txn);
240  GLogLevelFlags loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
241  TestErrorStruct *check = test_error_struct_new ("gnc.engine", loglevel,
242  msg);
243  g_free (msg);
244  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
245  (GLogFunc)test_checked_handler);
246  check_open (fixture->txn);
247  g_assert_cmpint (check->hits, ==, 1);
248  xaccTransBeginEdit (fixture->txn);
249  check_open (fixture->txn);
250  g_assert_cmpint (check->hits, ==, 1);
251  /* Don't commit the edit, there's nothing to balance! */
252  xaccTransRollbackEdit (fixture->txn);
253 }
254 /* xaccTransStillHasSplit
255 gboolean
256 xaccTransStillHasSplit(const Transaction *trans, const Split *s)// C: 8 in 3 Local: 7:0:0
257 */
258 static void
259 test_xaccTransStillHasSplit (Fixture *fixture, gconstpointer pData)
260 {
261  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
262  Split *split = xaccMallocSplit (book);
263  g_assert (!xaccTransStillHasSplit (fixture->txn, split));
264  xaccSplitSetParent (split, fixture->txn);
265  g_assert (xaccTransStillHasSplit (fixture->txn, split));
266  qof_instance_set_destroying (split, TRUE);
267  g_assert (!xaccTransStillHasSplit (fixture->txn, split));
268  qof_instance_set_destroying (split, FALSE);
269  g_assert (xaccTransStillHasSplit (fixture->txn, split));
270  xaccSplitSetParent (split, NULL);
271  g_assert (!xaccTransStillHasSplit (fixture->txn, split));
272 
273  test_destroy (split);
274 }
275 // Make Static
276 /* mark_trans
277 void mark_trans (Transaction *trans)// Local: 3:0:0
278 */
279 #define check_split_dirty(xsplit, test) \
280 { \
281  gboolean sort_dirty, balance_dirty; \
282  Split *split = xsplit; \
283  g_object_get (split->acc, \
284  "sort-dirty", &sort_dirty, \
285  "balance-dirty", &balance_dirty, \
286  NULL); \
287  g_assert_cmpint (sort_dirty, ==, test); \
288  g_assert_cmpint (balance_dirty, ==, test); \
289 }
290 
291 static void
292 test_mark_trans (Fixture *fixture, gconstpointer pData)
293 {
294  gboolean dirty_split = FALSE;
295  GList *splits = NULL;
296 
297  for (splits = (fixture->txn)->splits; splits; splits = splits->next)
298  {
299  if (!splits->data) continue;
300  g_assert (!qof_instance_get_dirty_flag (splits->data));
301  check_split_dirty (splits->data, FALSE);
302  }
303  fixture->func->mark_trans (fixture->txn);
304  g_assert (!qof_instance_get_dirty_flag (fixture->txn));
305  for (splits = (fixture->txn)->splits; splits; splits = splits->next)
306  {
307  if (!splits->data) continue;
308  g_assert (!qof_instance_get_dirty_flag (splits->data));
309  check_split_dirty (splits->data, TRUE);
310  }
311 }
312 /* gen_event_trans
313 void gen_event_trans (Transaction *trans)// Local: 2:0:0
314 */
315 static void
316 test_gen_event_trans (Fixture *fixture, gconstpointer pData)
317 {
318  Split *split = fixture->txn->splits->data;
319  GNCLot *lot = gnc_lot_new (qof_instance_get_book (QOF_INSTANCE (fixture->txn)));
320  TestSignal sig1 = test_signal_new (QOF_INSTANCE (fixture->acc1),
321  GNC_EVENT_ITEM_CHANGED, split);
322  TestSignal sig2 = test_signal_new (QOF_INSTANCE (lot),
323  QOF_EVENT_MODIFY, NULL);
324  gnc_lot_add_split (lot, split);
325  test_signal_assert_hits (sig1, 1);
326  test_signal_assert_hits (sig2, 3);
327  fixture->func->gen_event_trans (fixture->txn);
328  test_signal_assert_hits (sig1, 2);
329  test_signal_assert_hits (sig2, 4);
330 
331  test_signal_free (sig1);
332  test_signal_free (sig2);
333  test_destroy (lot);
334 }
335 /* gnc_transaction_init
336 G_DEFINE_TYPE(Transaction, gnc_transaction, QOF_TYPE_INSTANCE)
337 static void
338 gnc_transaction_init(Transaction* trans)*/
339 static void
340 test_gnc_transaction_init ()
341 {
342  Transaction *txn = g_object_new (GNC_TYPE_TRANSACTION, NULL);
343  g_assert_cmpstr (txn->num, ==, "");
344  g_assert_cmpstr (txn->description, ==, "");
345  g_assert (txn->common_currency == NULL);
346  g_assert (txn->splits == NULL);
347  g_assert_cmpint (txn->date_entered.tv_sec, ==, 0);
348  g_assert_cmpint (txn->date_entered.tv_nsec, ==, 0);
349  g_assert_cmpint (txn->date_posted.tv_sec, ==, 0);
350  g_assert_cmpint (txn->date_posted.tv_nsec, ==, 0);
351  g_assert_cmpint (txn->marker, ==, 0);
352  g_assert (txn->orig == NULL);
353 
354  test_destroy (txn);
355 }
356 /* gnc_transaction_dispose
357 static void
358 gnc_transaction_dispose(GObject *txnp)*/
359 static void
360 test_gnc_transaction_dispose ()
361 {
362  QofBook *book = qof_book_new ();
363  Transaction *txn = g_object_new (GNC_TYPE_TRANSACTION, "book", book, NULL);
364  Split *split = g_object_new (GNC_TYPE_SPLIT, "book", book, NULL);
365  Split *s_ref = split;
366  gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY",
367  "GNR", "", 240), *t_curr = NULL;
368  gnc_commodity *c_ref = curr;
369  g_object_add_weak_pointer (G_OBJECT (split), (gpointer*) &s_ref);
370  g_object_add_weak_pointer (G_OBJECT (curr), (gpointer*) &c_ref);
371  txn->splits = g_list_append (txn->splits, split);
372  txn->common_currency = curr;
373 
374  g_assert (txn->splits != NULL);
375  g_assert (s_ref != NULL);
376  g_assert (c_ref != NULL);
377 
378  g_object_run_dispose (G_OBJECT (txn));
379  /* If gnc_transaction_dispose was written correctly, txn->splits and
380  * txn->curr would be null and all of the splits would be destroyed,
381  * so all of these would be equal instead of unequal.
382  */
383  g_assert (txn->splits != NULL);
384  g_assert (txn->common_currency != NULL);
385  g_assert (s_ref != NULL);
386  g_assert (c_ref != NULL);
387  /* And these would be unnecessary -- in fact, they would assert */
388  test_destroy (split);
389  test_destroy (curr);
390 
391  test_destroy (txn);
392  test_destroy (book);
393 }
394 /* gnc_transaction_finalize
395 static void
396 gnc_transaction_finalize(GObject* txnp)*/
397 static void
398 test_gnc_transaction_finalize ()
399 {
400  Transaction *txn = g_object_new (GNC_TYPE_TRANSACTION, NULL);
401  test_destroy (txn);
402 }
403 /* gnc_transaction_get_property
404  * gnc_transaction_set_property
405 static void
406 gnc_transaction_set_property(GObject* object,*/
407 static void
408 test_gnc_transaction_set_get_property (Fixture *fixture, gconstpointer pData)
409 {
410  QofBook *book = qof_book_new ();
411  Transaction *txn = g_object_new (GNC_TYPE_TRANSACTION, "book", book, NULL);
412  gchar *num = "42", *desc = "The Answer", *t_num = NULL, *t_desc = NULL, *phony = NULL;
413  gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY",
414  "GNR", "", 240), *t_curr = NULL;
415  Timespec now = timespec_now (), *t_entered = NULL, *t_posted = NULL;
416  time_t secs = (time_t)now.tv_sec;
417  gchar *msg1 = "g_object_set_valist: object class " _Q "Transaction' has no property named " _Q "bogus'";
418  gchar *msg2 = g_strdup_printf ("[xaccTransSetDateInternal] addr=%p set date to %" G_GUINT64_FORMAT ".%09ld %s",
419  txn, now.tv_sec, now.tv_nsec, ctime (&secs));
420  GLogLevelFlags loglevel1 = G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL;
421  GLogLevelFlags loglevel2 = G_LOG_LEVEL_INFO;
422  TestErrorStruct *check1 = test_error_struct_new ("GLib-GObject",
423  loglevel1, msg1);
424  TestErrorStruct *check2 = test_error_struct_new ("gnc.engine",
425  loglevel2, msg2);
426  g_free (msg2);
427  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check1,
428  (GLogFunc)test_checked_handler);
429  fixture->hdlrs = test_log_set_handler (fixture->hdlrs, check2,
430  (GLogFunc)test_checked_handler);
431  g_assert_cmpstr (txn->num, ==, "");
432  g_assert_cmpstr (txn->description, ==, "");
433  g_assert (txn->common_currency == NULL);
434  g_assert_cmpint (txn->date_entered.tv_sec, ==, 0);
435  g_assert_cmpint (txn->date_entered.tv_nsec, ==, 0);
436  g_assert_cmpint (txn->date_posted.tv_sec, ==, 0);
437  g_assert_cmpint (txn->date_posted.tv_nsec, ==, 0);
438  /* Kick up the edit counter to keep from committing */
439  xaccTransBeginEdit (txn);
440  g_object_set (G_OBJECT (txn),
441  "num", num,
442  "description", desc,
443  "currency", curr,
444  "post-date", &now,
445  "enter-date", &now,
446  "bogus", phony,
447  NULL);
448 
449  g_assert_cmpstr (txn->num, ==, num);
450  g_assert_cmpstr (txn->description, ==, desc);
451  g_assert (txn->common_currency == curr);
452  g_assert (timespec_equal (&(txn->date_entered), &now));
453  g_assert (timespec_equal (&(txn->date_posted), &now));
454  g_assert_cmpint (check1->hits, ==, 1);
455  g_assert_cmpint (check2->hits, ==, 2);
456 
457  g_free (check1->msg);
458  check1->msg = g_strdup ("g_object_get_valist: object class " _Q "Transaction' has no property named " _Q "bogus'");
459  g_object_get (G_OBJECT (txn),
460  "num", &t_num,
461  "description", &t_desc,
462  "currency", &t_curr,
463  "post-date", &t_posted,
464  "enter-date", &t_entered,
465  "bogus", &phony,
466  NULL);
467 
468  g_assert_cmpstr (t_num, ==, num);
469  g_assert_cmpstr (t_desc, ==, desc);
470  g_assert (t_curr == curr);
471  g_assert (timespec_equal (t_entered, &now));
472  g_assert (timespec_equal (t_posted, &now));
473  g_assert_cmpint (check1->hits, ==, 2);
474  g_assert_cmpint (check2->hits, ==, 2);
475  xaccTransRollbackEdit (txn);
476  test_destroy (txn);
477  test_destroy (curr);
478  test_destroy (book);
479  g_free (t_entered);
480 }
481 /* gnc_transaction_class_init
482  * xaccInitTransaction
483 No way to really test class_init directly -- though the above tests cover everything pretty well indirectly. xaccInitTransaction is a useless one-line function that sets the book in the parent QofInstance.
484  */
485 static void
486 test_xaccMallocTransaction (Fixture *fixture, gconstpointer pData)
487 {
488  QofBook *book = qof_book_new ();
489  TestSignal sig1 = test_signal_new (NULL, QOF_EVENT_CREATE,NULL);
490  Transaction *txn;
491 #ifdef USE_CLANG_FUNC_SIG
492 #define _func "Transaction *xaccMallocTransaction(QofBook *)"
493 #else
494 #define _func "xaccMallocTransaction"
495 #endif
496  gchar *msg = _func ": assertion " _Q "book' failed";
497 #undef _func
498  gchar *logdomain = "gnc.engine";
499  guint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
500  TestErrorStruct *check = test_error_struct_new ("gnc.engine", loglevel,
501  msg);
502  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
503  (GLogFunc)test_checked_handler);
504  test_signal_assert_hits (sig1, 0);
505  txn = xaccMallocTransaction (NULL);
506  g_assert (txn == NULL);
507  g_assert_cmpint (check->hits, ==, 1);
508  test_signal_assert_hits (sig1, 0);
509 
510  txn = xaccMallocTransaction (book);
511  g_assert (txn != NULL);
512  g_assert_cmpint (check->hits, ==, 1);
513  test_signal_assert_hits (sig1, 1);
514 
515  test_destroy (txn);
516  test_destroy (book);
517  test_signal_free (sig1);
518 }
519 /* xaccTransSortSplits
520 void
521 xaccTransSortSplits (Transaction *trans)// Local: 1:0:0
522 */
523 static void
524 test_xaccTransSortSplits (Fixture *fixture, gconstpointer pData)
525 {
526  Transaction *txn = fixture->txn;
527  QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
528  Split *split1 = txn->splits->data;
529  Split *split2 = txn->splits->next->data;
530  Split *split[3];
531  guint i;
532  GList *node;
533  gnc_numeric values[3];
534 
535  values[0] = gnc_numeric_create (100, 240);
536  values[1] = gnc_numeric_create (75, 240);
537  values[2] = gnc_numeric_create (-125, 240);
538  /* Prevent xaccTransCommitEdit in xaccSplitSetParent from doing anything */
539  xaccTransBeginEdit (txn);
540  for (i = 0; i < G_N_ELEMENTS (split); i++)
541  {
542  split[i] = xaccMallocSplit (book);
543  split[i]->value = values[i];
544  split[i]->acc = fixture->acc1;
545  xaccSplitSetParent (split[i], txn);
546  }
547 
548  node = txn->splits;
549  g_assert (node->data == split1);
550  node = g_list_next (node);
551  g_assert (node->data == split2);
552  node = g_list_next (node);
553  g_assert (node->data == split[0]);
554  node = g_list_next (node);
555  g_assert (node->data == split[1]);
556  node = g_list_next (node);
557  g_assert (node->data == split[2]);
558 
559  xaccTransSortSplits (txn);
560 
561  node = txn->splits;
562  g_assert (node->data == split1);
563  node = g_list_next (node);
564  g_assert (node->data == split[0]);
565  node = g_list_next (node);
566  g_assert (node->data == split[1]);
567  node = g_list_next (node);
568  g_assert (node->data == split2);
569  node = g_list_next (node);
570  g_assert (node->data == split[2]);
571 
572  xaccTransCommitEdit (txn);
573 }
574 /* dupe_trans
575 static Transaction *
576 dupe_trans (const Transaction *from)// Local: 1:0:0
577 */
578 static void
579 test_dupe_trans (Fixture *fixture, gconstpointer pData)
580 {
581  Timespec posted = gnc_dmy2timespec (12, 7, 2011);
582  Timespec entered = gnc_dmy2timespec (14, 7, 2011);
583  Transaction *newtxn = NULL, *oldtxn = fixture->txn;
584  QofBook *old_book = qof_instance_get_book (QOF_INSTANCE (oldtxn));
585  GList *newnode, *oldnode = oldtxn->splits;
586 
587  oldtxn->date_posted = posted;
588  oldtxn->date_entered = entered;
589  kvp_frame_set_string (oldtxn->inst.kvp_data, "/foo/bar/baz",
590  "The Great Waldo Pepper");
591 
592  newtxn = fixture->func->dupe_trans (oldtxn);
593 
594  g_assert_cmpstr (newtxn->num, ==, oldtxn->num);
595  g_assert_cmpstr (newtxn->description, ==, oldtxn->description);
596  for (newnode = newtxn->splits; newnode && oldnode;
597  newnode = g_list_next (newnode))
598  {
599  g_assert (xaccSplitEqual (newnode->data, oldnode->data,
600  TRUE, FALSE, TRUE));
601  oldnode = g_list_next (oldnode);
602  }
603  g_assert (newnode == NULL);
604  g_assert (oldnode == NULL);
605  g_assert (timespec_equal (&(newtxn->date_posted), &posted));
606  g_assert (timespec_equal (&(newtxn->date_entered), &entered));
607  g_assert (qof_instance_version_cmp (QOF_INSTANCE (newtxn),
608  QOF_INSTANCE (oldtxn)) == 0);
609  g_assert (newtxn->orig == NULL);
610  g_assert (newtxn->common_currency == fixture->curr);
611  g_assert (newtxn->inst.e_type == NULL);
612  g_assert (guid_equal (qof_instance_get_guid (QOF_INSTANCE (newtxn)),
613  guid_null ()));
614  g_assert (qof_instance_get_book (QOF_INSTANCE (newtxn)) == old_book);
615  g_assert (kvp_frame_compare (oldtxn->inst.kvp_data, newtxn->inst.kvp_data) == 0);
616 
617  test_destroy (newtxn);
618 }
619 /* xaccTransClone
620 Transaction *
621 xaccTransClone (const Transaction *from)// C: 1 Local: 1:0:0
622 */
623 static void
624 test_xaccTransClone (Fixture *fixture, gconstpointer pData)
625 {
626  Timespec posted = gnc_dmy2timespec (12, 7, 2011);
627  Timespec entered = gnc_dmy2timespec (14, 7, 2011);
628  Transaction *newtxn = NULL, *oldtxn = fixture->txn;
629  QofBook *old_book = qof_instance_get_book (QOF_INSTANCE (oldtxn));
630  GList *newnode, *oldnode;
631  int foo, bar;
632 
633  oldtxn->date_posted = posted;
634  oldtxn->date_entered = entered;
635  newtxn = xaccTransClone (oldtxn);
636 
637  g_assert_cmpstr (newtxn->num, ==, oldtxn->num);
638  g_assert_cmpstr (newtxn->description, ==, oldtxn->description);
639 
640  g_assert_cmpint (xaccTransCountSplits (oldtxn), ==,
641  xaccTransCountSplits (newtxn));
642 
643  xaccTransSortSplits (newtxn);
644  xaccTransSortSplits (oldtxn);
645 
646  oldnode = oldtxn->splits;
647  for (newnode = newtxn->splits; newnode && oldnode;
648  newnode = g_list_next (newnode))
649  {
650  g_assert (xaccSplitEqual (newnode->data, oldnode->data,
651  FALSE, FALSE, FALSE));
652  oldnode = g_list_next (oldnode);
653  }
654  g_assert (newnode == NULL);
655  g_assert (oldnode == NULL);
656  g_assert (timespec_equal (&(newtxn->date_posted), &posted));
657  g_assert (timespec_equal (&(newtxn->date_entered), &entered));
658  g_assert (qof_instance_version_cmp (QOF_INSTANCE (newtxn),
659  QOF_INSTANCE (oldtxn)) == 0);
660  g_assert_cmpint (qof_instance_get_version_check (newtxn), ==,
661  qof_instance_get_version_check (oldtxn));
662  g_assert (newtxn->orig == NULL);
663  g_assert (newtxn->common_currency == fixture->curr);
664 
665  g_assert (qof_instance_get_book (QOF_INSTANCE (newtxn)) == old_book);
666  g_assert (kvp_frame_compare (oldtxn->inst.kvp_data, newtxn->inst.kvp_data) == 0);
667 
668  test_destroy (newtxn);
669 }
670 
671 /* xaccTransCopyOnto
672 void
673 xaccTransCopyOnto (const Transaction *from_trans, Transaction *to_trans)//Register 2
674 convenience function for xaccTransCopyFromClipboard (from_trans, to_trans, NULL, NULL, TRUE)
675 */
676 /* xaccTransCopyFromClipboard
677 void
678 xaccTransCopyFromClipboard (const Transaction *from_trans,
679  Transaction *to_trans,
680  const Account *from_acc,
681  Account *to_acc, gboolean no_date) // Register 2
682 */
683 static void
684 test_xaccTransCopyFromClipBoard (Fixture *fixture, gconstpointer pData)
685 {
686  Transaction *txn = fixture->txn;
687  QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
688  Account *acc1 = xaccMallocAccount (book);
689  Transaction *to_txn = xaccMallocTransaction (book);
690  Timespec now = timespec_now();
691  Timespec never = {0, 0};
692  KvpFrame *to_frame = to_txn->inst.kvp_data;
693 
694  xaccAccountSetCommodity (acc1, fixture->comm);
695  xaccTransCopyFromClipBoard (txn, to_txn, fixture->acc1, acc1, FALSE);
696  g_assert (gnc_commodity_equal (txn->common_currency,
697  to_txn->common_currency));
698  g_assert (timespec_equal (&(to_txn->date_entered), &now));
699  g_assert (timespec_equal (&(to_txn->date_posted), &txn->date_posted));
700  g_assert_cmpstr (txn->num, ==, to_txn->num);
701  /* Notes also tests that KVP is copied */
702  g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
703  g_assert_cmpstr (xaccTransGetDescription (txn), ==,
704  xaccTransGetDescription (to_txn));
705  g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
706  g_assert_cmpint (xaccTransCountSplits (txn), ==,
707  xaccTransCountSplits (to_txn));
708 }
709 
710 static void
711 test_xaccTransCopyFromClipBoard_no_start (Fixture *fixture, gconstpointer pData)
712 {
713  Transaction *txn = fixture->txn;
714  QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
715  Account *acc1 = xaccMallocAccount (book);
716  Transaction *to_txn = xaccMallocTransaction (book);
717  Timespec now = timespec_now();
718  Timespec never = {0, 0};
719 
720  xaccAccountSetCommodity (acc1, fixture->comm);
721  xaccTransCopyFromClipBoard (txn, to_txn, fixture->acc1, acc1, TRUE);
722  g_assert (gnc_commodity_equal (txn->common_currency,
723  to_txn->common_currency));
724  g_assert (timespec_equal (&(to_txn->date_entered), &now));
725  g_assert (timespec_equal (&(to_txn->date_posted), &never));
726  g_assert_cmpstr (to_txn->num, ==, txn->num);
727  /* Notes also tests that KVP is copied */
728  g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
729  g_assert_cmpstr (xaccTransGetDescription (txn), ==,
730  xaccTransGetDescription (to_txn));
731  g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
732  g_assert_cmpint (xaccTransCountSplits (txn), ==,
733  xaccTransCountSplits (to_txn));
734 }
735 
736 /* xaccFreeTransaction
737 static void
738 xaccFreeTransaction (Transaction *trans)// Local: 4:0:0
739 */
740 static void
741 test_xaccFreeTransaction (Fixture *fixture, gconstpointer pData)
742 {
743  Transaction *txn = fixture->txn;
744  Transaction *orig = xaccMallocTransaction (qof_instance_get_book (QOF_INSTANCE (txn)));
745  Split *split = txn->splits->data;
746  gchar *txn_num = "321";
747  g_object_add_weak_pointer (G_OBJECT (txn->splits->data), (gpointer)&split);
748  /* so the "free" doesn't, leaving the structure for us to test */
749  g_object_ref (txn);
750  g_object_ref (orig);
751  orig->num = CACHE_INSERT (txn_num);
752  txn->orig = orig;
753 
754  fixture->func->xaccFreeTransaction (txn);
755 
756  g_assert (split == NULL);
757  g_assert (txn->splits == NULL);
758  g_assert_cmpint (GPOINTER_TO_INT(txn->num), ==, 1);
759  g_assert (txn->description == NULL);
760  g_assert_cmpint (txn->date_entered.tv_sec, ==, 0);
761  g_assert_cmpint (txn->date_entered.tv_nsec, ==, 0);
762  g_assert_cmpint (txn->date_posted.tv_sec, ==, 0);
763  g_assert_cmpint (txn->date_posted.tv_nsec, ==, 0);
764  g_assert_cmpint (GPOINTER_TO_INT(orig->num), ==, 1);
765  g_assert (txn->orig == NULL);
766  test_destroy (orig);
767 
768  g_test_log_set_fatal_handler ((GTestLogFatalFunc) test_log_handler, NULL);
769 
770 }
771 /* compare_split_guids
772 static gint
773 compare_split_guids (gconstpointer a, gconstpointer b)// Local: 0:1:0
774 
775 Pass-through function, test with TransEqual
776 */
777 /* xaccTransEqual
778 gboolean
779 xaccTransEqual(const Transaction *ta, const Transaction *tb,// C: 2 in 2 Local: 0:0:0
780 */
781 #define DATE_BUF_SIZE 100
782 static void
783 test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
784 {
785 
786  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
787  QofBook *book2 = qof_book_new ();
788  Transaction *txn0 = fixture->txn;
789  Transaction *clone = xaccTransClone (txn0);
790  Transaction *txn1 = xaccTransClone (txn0);
791  const GncGUID *guid_f_txn = qof_instance_get_guid (txn0);
792  gchar entered[DATE_BUF_SIZE], posted[DATE_BUF_SIZE];
793  gchar *msg1 = "[xaccTransEqual] one is NULL";
794  gchar *msg2 = NULL;
795  gchar *cleanup_fmt = "[trans_cleanup_commit] get rid of rollback trans=%p";
796  gchar split_guid0[GUID_ENCODING_LENGTH + 1];
797  gchar split_guid1[GUID_ENCODING_LENGTH + 1];
798  gchar *logdomain = "gnc.engine";
799  guint loglevel = G_LOG_LEVEL_INFO;
800  TestErrorStruct *check = test_error_struct_new (logdomain, loglevel, msg1);
801  TestErrorStruct check2 = {loglevel, logdomain, msg2, 0};
802  TestErrorStruct check3 = {loglevel, logdomain, "", 0};
803  TestErrorStruct *cleanup = test_error_struct_new (logdomain, loglevel, "");
804  Split *split0 = xaccTransGetSplit (txn0, 0);
805  Split *split1;
806  test_add_error (check);
807  test_add_error (&check2);
808  test_add_error (cleanup);
809 
810  fixture->hdlrs = test_log_set_handler (fixture->hdlrs, check,
811  (GLogFunc)test_list_handler);
812  /* Booleans are check_guids, check_splits, check_balances, assume_ordered */
813  g_assert (xaccTransEqual (NULL, NULL, TRUE, TRUE, TRUE, TRUE));
814  g_assert (!xaccTransEqual (txn0, NULL, TRUE, TRUE, TRUE, TRUE));
815  g_assert (!xaccTransEqual (NULL, txn0, TRUE, TRUE, TRUE, TRUE));
816  g_assert (xaccTransEqual (txn0, txn0, TRUE, TRUE, TRUE, TRUE));
817 
818  qof_instance_set_book (txn1, book2);
819  qof_instance_set_guid (txn1, guid_f_txn);
820  g_assert_cmpint (check->hits, ==, 2);
821  check->hits = 0;
822 
823  g_assert_cmpint (xaccTransCountSplits (txn0), ==,
824  xaccTransCountSplits (txn1));
825 
826  g_free (check->msg);
827  check->msg = g_strdup ("[xaccTransEqual] GUIDs differ");
828  g_assert (!xaccTransEqual (clone, txn0, TRUE, TRUE, TRUE, TRUE));
829  qof_instance_set_guid (clone, guid_f_txn);
830  g_assert (xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
831  g_assert_cmpint (check->hits, ==, 1);
832  xaccTransBeginEdit (clone);
833  cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
834  /* This changes the amount and value of the first split */
835  xaccTransSetCurrency (clone, fixture->comm);
836  xaccTransCommitEdit (clone);
837  g_free (cleanup->msg);
838  g_free (check->msg);
839  check->msg = g_strdup_printf ("[xaccTransEqual] commodities differ %s vs %s", gnc_commodity_get_unique_name (fixture->comm), gnc_commodity_get_unique_name (fixture->curr));
840  g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
841  g_assert_cmpint (check->hits, ==, 2);
842 
843  gnc_timespec_to_iso8601_buff (clone->date_posted, posted);
844  gnc_timespec_to_iso8601_buff (clone->date_entered, entered);
845  xaccTransBeginEdit (clone);
846  cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
847  /* This puts the value of the first split back, but leaves the amount changed */
848  xaccTransSetCurrency (clone, fixture->curr);
849  clone->date_posted.tv_sec = txn0->date_entered.tv_sec;
850  xaccTransCommitEdit (clone);
851  g_free (cleanup->msg);
852  g_free (check->msg);
853  check->msg = g_strdup_printf ("[xaccTransEqual] date posted differs: '%s' vs '%s'", entered, posted);
854  g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
855  g_assert_cmpint (check->hits, ==, 3);
856 
857  xaccTransBeginEdit (clone);
858  cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
859  clone->date_posted.tv_sec = txn0->date_posted.tv_sec;
860  clone->date_entered.tv_sec = txn0->date_posted.tv_sec;
861  xaccTransCommitEdit (clone);
862  g_free (cleanup->msg);
863  g_free (check->msg);
864  check->msg = g_strdup_printf ("[xaccTransEqual] date entered differs: '%s' vs '%s'", posted, entered);
865  g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
866  g_assert_cmpint (check->hits, ==, 4);
867 
868  xaccTransBeginEdit (clone);
869  cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
870  clone->date_entered.tv_sec = txn0->date_entered.tv_sec;
871  clone->num = "123";
872  xaccTransCommitEdit (clone);
873  g_free (cleanup->msg);
874  g_free (check->msg);
875  check->msg = g_strdup ("[xaccTransEqual] num differs: 123 vs 123");
876  g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
877  g_assert_cmpint (check->hits, ==, 5);
878  g_assert (xaccTransEqual (txn1, clone, TRUE, FALSE, TRUE, TRUE));
879  g_assert_cmpint (check->hits, ==, 5);
880 
881  txn1->num = "321";
882  g_free (check->msg);
883  check->msg = g_strdup ("[xaccTransEqual] num differs: 321 vs 123");
884  g_assert (!xaccTransEqual (txn1, txn0, TRUE, FALSE, TRUE, TRUE));
885  g_assert_cmpint (check->hits, ==, 6);
886 
887  clone->num = CACHE_INSERT("123");
888  txn1->num = "123";
889  clone->description = "salt pork";
890  g_free (check->msg);
891  check->msg = g_strdup ("[xaccTransEqual] descriptions differ: salt pork vs Waldo Pepper");
892  g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
893  g_assert_cmpint (check->hits, ==, 7);
894  g_assert (xaccTransEqual (txn1, txn0, TRUE, FALSE, TRUE, TRUE));
895  g_assert_cmpint (check->hits, ==, 7);
896  g_assert (!xaccTransEqual (clone, txn1, TRUE, FALSE, TRUE, TRUE));
897  g_assert_cmpint (check->hits, ==, 8);
898 
899  xaccTransBeginEdit (clone);
900  cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
901  clone->description = CACHE_INSERT ("Waldo Pepper");
902  kvp_frame_set_double (qof_instance_get_slots (QOF_INSTANCE (clone)),
903  "/qux/quux/corge", 654.321);
904  xaccTransCommitEdit (clone);
905  g_free (cleanup->msg);
906  g_free (check->msg);
907  check->msg = g_strdup ("[xaccTransEqual] kvp frames differ:\n{\n notes => KVP_VALUE_STRING(Salt pork sausage),\n qux => KVP_VALUE_FRAME({\n quux => KVP_VALUE_FRAME({\n corge => KVP_VALUE_DOUBLE(654.321),\n}\n),\n}\n),\n}\n\n\nvs\n\n{\n notes => KVP_VALUE_STRING(Salt pork sausage),\n qux => KVP_VALUE_FRAME({\n quux => KVP_VALUE_FRAME({\n corge => KVP_VALUE_DOUBLE(123.456),\n}\n),\n}\n),\n}\n");
908 
909  g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
910 
911  g_assert_cmpint (check->hits, ==, 9);
912  xaccTransBeginEdit (clone);
913  cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
914  clone->description = CACHE_INSERT ("Waldo Pepper");
915  kvp_frame_set_double (qof_instance_get_slots (QOF_INSTANCE (clone)),
916  "/qux/quux/corge", 123.456);
917  xaccTransCommitEdit (clone);
918  g_free (cleanup->msg);
919  g_free (check->msg);
920  check->msg = g_strdup ("[xaccSplitEqual] GUIDs differ");
921  split1 = xaccTransGetSplit (clone, 0);
922  guid_to_string_buff (qof_instance_get_guid (split0), split_guid0);
923  guid_to_string_buff (qof_instance_get_guid (split1), split_guid1);
924  check2.msg = g_strdup_printf (
925  "[xaccTransEqual] splits %s and %s differ", split_guid1, split_guid0);
926 
927  g_assert (!xaccTransEqual (clone, txn0, TRUE, TRUE, TRUE, TRUE));
928  g_assert (xaccTransEqual (clone, txn0, FALSE, FALSE, FALSE, TRUE));
929  g_assert_cmpint (check->hits, ==, 10);
930  g_assert_cmpint (check2.hits, ==, 1);
931 
932  g_free (check->msg);
933  g_free (check2.msg);
934  check->msg = g_strdup("[xaccSplitEqual] amounts differ: 13333/1000 vs 100000/1000");
935  check2.msg = g_strdup_printf (
936  "[xaccTransEqual] splits %s and %s differ", split_guid0, split_guid0);
937  qof_instance_set_guid (split1, qof_instance_get_guid (split0));
938  g_assert (!xaccTransEqual (clone, txn0, TRUE, TRUE, TRUE, TRUE));
939  g_assert (xaccTransEqual (clone, txn0, TRUE, FALSE, FALSE, TRUE));
940  g_assert_cmpint (check->hits, ==, 11);
941  g_assert_cmpint (check2.hits, ==, 2);
942 
943  qof_instance_set_guid (xaccTransGetSplit (txn1, 0),
944  qof_instance_get_guid (split0));
945  qof_instance_set_guid (xaccTransGetSplit (txn1, 1),
947  g_free (check->msg);
948  {
949  Split* split00 = xaccTransGetSplit (txn0, 0);
950  Split* split01 = xaccTransGetSplit (txn0, 1);
951  Split* split10 = xaccTransGetSplit (txn1, 0);
952  Split* split11 = xaccTransGetSplit (txn1, 1);
953  gchar *bal00 = gnc_numeric_to_string (split00->balance);
954  gchar *bal01 = gnc_numeric_to_string (split01->balance);
955  gchar *bal10 = gnc_numeric_to_string (split10->balance);
956  gchar *bal11 = gnc_numeric_to_string (split11->balance);
957  check->msg = g_strdup_printf("[xaccSplitEqualCheckBal] balances differ: %s vs %s", bal10, bal00);
958  check3.msg = g_strdup_printf("[xaccSplitEqualCheckBal] balances differ: %s vs %s", bal11, bal01);
959 
960  test_add_error (&check3);
961  g_assert (!xaccTransEqual (txn1, txn0, TRUE, TRUE, TRUE, TRUE));
962  g_assert (xaccTransEqual (txn1, txn0, TRUE, TRUE, FALSE, TRUE));
963  g_assert_cmpint (check->hits, ==, 12);
964  g_assert_cmpint (check2.hits, ==, 3);
965  g_assert_cmpint (check3.hits, ==, 0);
966 
967  split10->balance = split00->balance;
968  split11->balance = split01->balance;
969  g_assert (xaccTransEqual (txn1, txn0, TRUE, TRUE, TRUE, TRUE));
970  }
971  g_free (check3.msg);
972  g_free (check2.msg);
973 }
974 /* xaccTransUseTradingAccounts
975 xaccTransUseTradingAccounts
976 Returns true if the transaction should include trading account splits if
977 it involves more than one commodity.
978 gboolean xaccTransUseTradingAccounts(const Transaction *trans)// C: 10 in 7 Local: 2:0:0
979 Pass-through, no need to test.
980 */
981 /* xaccTransLookup
982 Transaction *
983 xaccTransLookup (const GncGUID *guid, QofBook *book)// C: 22 in 7 Local: 1:0:0
984 */
985 static void
986 test_xaccTransLookup (Fixture *fixture, gconstpointer pData)
987 {
988  Transaction *txn = fixture->txn;
989  QofInstance *inst = QOF_INSTANCE (txn);
990  g_assert (xaccTransLookup (qof_instance_get_guid (inst),
991  qof_instance_get_book (inst)) == txn);
992 }
993 /* xaccTransGetImbalanceValue
994 gnc_numeric
995 xaccTransGetImbalanceValue (const Transaction * trans)// C: 11 in 5 Local: 1:1:0
996 */
997 static void
998 test_xaccTransGetImbalanceValue (Fixture *fixture, gconstpointer pData)
999 {
1000  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1001  Split *split1 = xaccMallocSplit (book);
1002  g_assert (gnc_numeric_equal (xaccTransGetImbalanceValue (fixture->txn),
1003  gnc_numeric_zero ()));
1004  split1->acc = fixture->acc1;
1005  split1->memo = CACHE_INSERT ("foo");
1006  split1->action = CACHE_INSERT ("bar");
1007  split1->amount = gnc_numeric_create (100000, 1000);
1008  split1->value = gnc_numeric_create (3200, 240);
1009  xaccTransBeginEdit (fixture->txn);
1010  xaccSplitSetParent (split1, fixture->txn);
1011 
1012  g_assert (gnc_numeric_equal (xaccTransGetImbalanceValue (fixture->txn),
1013  split1->value));
1014  xaccTransCommitEdit (fixture->txn);
1015 }
1016 /* xaccTransGetImbalance
1017 MonetaryList *
1018 xaccTransGetImbalance (const Transaction * trans)// C: 15 in 6 Local: 1:0:0
1019 */
1020 static void
1021 test_xaccTransGetImbalance (Fixture *fixture, gconstpointer pData)
1022 {
1023  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1024  Split *split1 = xaccMallocSplit (book);
1025  MonetaryList *mlist;
1026  g_assert (xaccTransGetImbalance (NULL) == NULL);
1027  mlist = xaccTransGetImbalance (fixture->txn);
1028  g_assert_cmpint (g_list_length (mlist), ==, 0);
1029 
1030  split1->acc = fixture->acc1;
1031  split1->memo = CACHE_INSERT ("foo");
1032  split1->action = CACHE_INSERT ("bar");
1033  split1->amount = gnc_numeric_create (100000, 1000);
1034  split1->value = gnc_numeric_create (3200, 240);
1035  xaccTransBeginEdit (fixture->txn);
1036  xaccSplitSetParent (split1, fixture->txn);
1037  mlist = xaccTransGetImbalance (fixture->txn);
1038  g_assert_cmpint (g_list_length (mlist), ==, 1);
1039  xaccTransCommitEdit (fixture->txn);
1040  gnc_monetary_list_free (mlist);
1041 }
1042 
1043 static void
1044 test_xaccTransGetImbalance_trading (Fixture *fixture,
1045  gconstpointer pData)
1046 {
1047  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1048  Split *split1 = xaccMallocSplit (book);
1049  Split *split2 = xaccMallocSplit (book);
1050  Account *acc1 = xaccMallocAccount (book);
1051  Account *acc2 = xaccMallocAccount (book);
1052  gnc_numeric value;
1053  MonetaryList *mlist;
1054  qof_book_begin_edit (book);
1055  qof_instance_set (QOF_INSTANCE (book),
1056  "trading-accts", "t",
1057  NULL);
1058  qof_book_commit_edit (book);
1059 
1060  /* Without trading splits, the list is unbalanced */
1061  mlist = xaccTransGetImbalance (fixture->txn);
1062  g_assert_cmpint (g_list_length (mlist), ==, 2);
1063  gnc_monetary_list_free (mlist);
1064 
1065  xaccAccountSetCommodity (acc1, fixture->comm);
1066  xaccAccountSetCommodity (acc2, fixture->curr);
1069  /* The setup transaction is unbalanced in a trading-accounts environment. */
1070  g_assert (!xaccTransIsBalanced (fixture->txn));
1071  /* Make it look like a proper trading accounts transactionm */
1072  split1->acc = acc1;
1073  split1->memo = CACHE_INSERT ("foo");
1074  split1->action = CACHE_INSERT ("bar");
1075  split1->amount = gnc_numeric_create (-10000, 100);
1076  split1->value = gnc_numeric_create (-3200, 240);
1077  split2->acc = acc2;
1078  split2->memo = CACHE_INSERT ("foo");
1079  split2->action = CACHE_INSERT ("bar");
1080  split2->amount = gnc_numeric_create (3000, 240);
1081  split2->value = gnc_numeric_create (3200, 240);
1082  xaccTransBeginEdit (fixture->txn);
1083  xaccSplitSetParent (split1, fixture->txn);
1084  mlist = xaccTransGetImbalance (fixture->txn);
1085  g_assert_cmpint (g_list_length (mlist), ==, 1);
1086  gnc_monetary_list_free (mlist);
1087  xaccSplitSetParent (split2, fixture->txn);
1088  mlist = xaccTransGetImbalance (fixture->txn);
1089  g_assert_cmpint (g_list_length (mlist), ==, 1);
1090  gnc_monetary_list_free (mlist);
1091  split2->amount = gnc_numeric_create (3000, 240);
1092  split2->value = gnc_numeric_create (3000, 240);
1093  mlist = xaccTransGetImbalance (fixture->txn);
1094  g_assert_cmpint (g_list_length (mlist), ==, 1);
1095  gnc_monetary_list_free (mlist);
1096  split2->amount = gnc_numeric_create (3200, 240);
1097  split2->value = gnc_numeric_create (3200, 240);
1098  mlist = xaccTransGetImbalance (fixture->txn);
1099  g_assert_cmpint (g_list_length (mlist), ==, 0);
1100  gnc_monetary_list_free (mlist);
1101 
1102  xaccTransCommitEdit (fixture->txn);
1103  test_destroy (acc1);
1104  test_destroy (acc2);
1105 }
1106 
1107 
1108 /* xaccTransIsBalanced
1109 gboolean
1110 xaccTransIsBalanced (const Transaction *trans)// C: 4 in 4 Local: 1:0:0
1111 */
1112 static void
1113 test_xaccTransIsBalanced (Fixture *fixture, gconstpointer pData)
1114 {
1115  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1116  Split *split1 = xaccMallocSplit (book);
1117  g_assert (!xaccTransIsBalanced (NULL));
1118  g_assert (xaccTransIsBalanced (fixture->txn));
1119 
1120  split1->acc = fixture->acc1;
1121  split1->memo = CACHE_INSERT ("foo");
1122  split1->action = CACHE_INSERT ("bar");
1123  split1->amount = gnc_numeric_create (100000, 1000);
1124  split1->value = gnc_numeric_create (3200, 240);
1125  xaccTransBeginEdit (fixture->txn);
1126  xaccSplitSetParent (split1, fixture->txn);
1127  g_assert (! xaccTransIsBalanced (fixture->txn));
1128  xaccTransCommitEdit (fixture->txn);
1129 }
1130 
1131 
1132 static void
1133 test_xaccTransIsBalanced_trading (Fixture *fixture, gconstpointer pData)
1134 {
1135  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1136  Split *split1 = xaccMallocSplit (book);
1137  Split *split2 = xaccMallocSplit (book);
1138  Account *acc1 = xaccMallocAccount (book);
1139  Account *acc2 = xaccMallocAccount (book);
1140 
1141  qof_book_begin_edit (book);
1142  qof_instance_set (QOF_INSTANCE (book),
1143  "trading-accts", "t",
1144  NULL);
1145  qof_book_commit_edit (book);
1146 
1147  xaccAccountSetCommodity (acc1, fixture->curr);
1148  xaccAccountSetCommodity (acc2, fixture->comm);
1151  /* The setup transaction is unbalanced in a trading-accounts environment. */
1152  g_assert (!xaccTransIsBalanced (fixture->txn));
1153  split1->acc = acc1;
1154  split1->memo = CACHE_INSERT ("foo");
1155  split1->action = CACHE_INSERT ("bar");
1156  split1->amount = gnc_numeric_create (3200, 240);
1157  split1->value = gnc_numeric_create (3200, 240);
1158  split2->acc = acc2;
1159  split2->memo = CACHE_INSERT ("foo");
1160  split2->action = CACHE_INSERT ("bar");
1161  split2->amount = gnc_numeric_create (-10000, 100);
1162  split2->value = gnc_numeric_create (-3000, 240);
1163  xaccTransBeginEdit (fixture->txn);
1164  xaccSplitSetParent (split1, fixture->txn);
1165  g_assert (!xaccTransIsBalanced (fixture->txn));
1166  xaccSplitSetParent (split2, fixture->txn);
1167  g_assert (!xaccTransIsBalanced (fixture->txn));
1168  split2->amount = gnc_numeric_create (-11000, 100);
1169  split2->value = gnc_numeric_create (-3200, 240);
1170  g_assert (!xaccTransIsBalanced (fixture->txn));
1171  split2->amount = gnc_numeric_create (-10000, 100);
1172  split2->value = gnc_numeric_create (-3200, 240);
1173  g_assert (xaccTransIsBalanced (fixture->txn));
1174  xaccTransRollbackEdit (fixture->txn);
1175 
1176  test_destroy (acc2);
1177  test_destroy (acc1);
1178 }
1179 /* xaccTransGetAccountValue
1180 gnc_numeric
1181 xaccTransGetAccountValue (const Transaction *trans,// SCM: 6 in 6 Local: 0:0:0
1182 */
1183 static void
1184 test_xaccTransGetAccountValue (Fixture *fixture, gconstpointer pData)
1185 {
1186  gnc_numeric val1 = {3200, 240}, val2 = {-3200, 240};
1187 
1188  g_assert (gnc_numeric_zero_p (xaccTransGetAccountValue (fixture->txn, NULL)));
1189  g_assert (gnc_numeric_zero_p (xaccTransGetAccountValue (NULL, fixture->acc1)));
1190  g_assert (gnc_numeric_eq (xaccTransGetAccountValue (fixture->txn, fixture->acc1), val1));
1191  g_assert (gnc_numeric_eq (xaccTransGetAccountValue (fixture->txn, fixture->acc2), val2));
1192 
1193 }
1194 /* xaccTransGetAccountAmount
1195 gnc_numeric
1196 xaccTransGetAccountAmount (const Transaction *trans, const Account *acc)// C: 2 in 1 Local: 0:0:0
1197 */
1198 static void
1199 test_xaccTransGetAccountAmount (Fixture *fixture, gconstpointer pData)
1200 {
1201  gnc_numeric amt1 = {100000, 1000}, amt2 = {-3200, 240};
1202 
1203  g_assert (gnc_numeric_zero_p (xaccTransGetAccountAmount (fixture->txn, NULL)));
1204  g_assert (gnc_numeric_zero_p (xaccTransGetAccountAmount (NULL, fixture->acc1)));
1205  g_assert (gnc_numeric_eq (xaccTransGetAccountAmount (fixture->txn, fixture->acc1), amt1));
1206  g_assert (gnc_numeric_eq (xaccTransGetAccountAmount (fixture->txn, fixture->acc2), amt2));
1207 
1208 }
1209 /* xaccTransGetRateForCommodity
1210 gboolean
1211 xaccTransGetRateForCommodity(const Transaction *trans,
1212  const gnc_commodity *split_com,
1213  const Split *split, gnc_numeric *rate)
1214 */
1215 static void
1216 test_xaccTransGetRateForCommodity (Fixture *fixture, gconstpointer pData)
1217 {
1218  gnc_numeric rate = gnc_numeric_zero ();
1219  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1220  Split *split0 = xaccMallocSplit (book);
1221  Split *split1 = xaccTransFindSplitByAccount(fixture->txn, fixture->acc1);
1222  g_assert (!xaccTransGetRateForCommodity (NULL, fixture->comm,
1223  split0, &rate));
1224  g_assert (!xaccTransGetRateForCommodity (fixture->txn, NULL,
1225  split0, &rate));
1226  g_assert (!xaccTransGetRateForCommodity (fixture->txn, fixture->comm,
1227  NULL, &rate));
1228  g_assert (xaccTransGetRateForCommodity (fixture->txn, fixture->curr,
1229  split0, &rate));
1230  g_assert (gnc_numeric_equal (rate, gnc_numeric_create (1, 1)));
1231  rate = gnc_numeric_zero ();
1232  g_assert (!xaccTransGetRateForCommodity (fixture->txn, fixture->comm,
1233  split0, &rate));
1234  g_assert (gnc_numeric_zero_p (rate));
1235 
1236  g_assert (xaccTransGetRateForCommodity (fixture->txn, fixture->comm,
1237  split1, &rate));
1238  g_assert (gnc_numeric_equal (rate, gnc_numeric_create (1800, 240)));
1239 
1240 }
1241 /* xaccTransGetAccountConvRate
1242 gnc_numeric
1243 xaccTransGetAccountConvRate(const Transaction *txn, const Account *acc)// C: 5 in 4 Local: 0:0:0
1244 */
1245 static void
1246 test_xaccTransGetAccountConvRate (Fixture *fixture, gconstpointer pData)
1247 {
1248  gchar *msg1 = "[xaccTransGetAccountConvRate()] How can amount be nonzero and value be zero?";
1249  guint loglevel = G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL;
1250  TestErrorStruct *check = test_error_struct_new ("gnc.engine", loglevel,
1251  msg1);
1252  Split *split1 = xaccTransFindSplitByAccount(fixture->txn, fixture->acc1);
1253  gnc_numeric rate;
1254 
1255  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
1256  (GLogFunc)test_checked_handler);
1257 
1258  g_assert (gnc_numeric_equal (xaccTransGetAccountConvRate (fixture->txn,
1259  fixture->acc2),
1260  gnc_numeric_create (1, 1)));
1261 
1262  g_assert (gnc_numeric_equal (xaccTransGetAccountConvRate (fixture->txn,
1263  fixture->acc1),
1264  gnc_numeric_create (1800, 240)));
1265  g_assert_cmpint (check->hits, ==, 0);
1266  split1->value = gnc_numeric_zero();
1267  rate = xaccTransGetAccountConvRate (fixture->txn, fixture->acc1);
1268  g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_OVERFLOW);
1269  g_assert_cmpint (check->hits, ==, 1);
1270 }
1271 /* xaccTransGetAccountBalance
1272 gnc_numeric
1273 xaccTransGetAccountBalance (const Transaction *trans,// C: 1 Local: 0:0:0
1274 */
1275 static void
1276 test_xaccTransGetAccountBalance (Fixture *fixture, gconstpointer pData)
1277 {
1278 #ifdef USE_CLANG_FUNC_SIG
1279 #define _func "gnc_numeric xaccTransGetAccountBalance(const Transaction *, const Account *)"
1280 #else
1281 #define _func "xaccTransGetAccountBalance"
1282 #endif
1283  gchar *msg1 = _func ": assertion " _Q "account && trans' failed";
1284 #undef _func
1285  guint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
1286  TestErrorStruct *check = test_error_struct_new ("gnc.engine", loglevel,
1287  msg1);
1288  Split *split1 = xaccTransFindSplitByAccount(fixture->txn, fixture->acc1);
1289  gnc_numeric rate;
1290 
1291  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
1292  (GLogFunc)test_checked_handler);
1293 
1294  rate = xaccTransGetAccountBalance (NULL, fixture->acc1);
1295  g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_ARG);
1296  g_assert_cmpint (check->hits, ==, 1);
1297 
1298  rate = xaccTransGetAccountBalance (fixture->txn, NULL);
1299  g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_ARG);
1300  g_assert_cmpint (check->hits, ==, 2);
1301 
1302  rate = xaccTransGetAccountBalance (fixture->txn, fixture->acc1);
1303  g_assert (gnc_numeric_equal (rate, gnc_numeric_create (100000, 1000)));
1304  g_assert_cmpint (check->hits, ==, 2);
1305 
1306  rate = xaccTransGetAccountBalance (fixture->txn, fixture->acc2);
1307  g_assert (gnc_numeric_equal (rate, gnc_numeric_create (-3200, 240)));
1308  g_assert_cmpint (check->hits, ==, 2);
1309 
1310 }
1311 /* xaccTransGetCurrency
1312 gnc_commodity *
1313 xaccTransGetCurrency (const Transaction *trans)// C: 33 in 17 SCM: 34 in 26 Local: 2:0:0
1314 Simple Getter. No need to test.
1315 */
1316 /* xaccTransSetCurrency
1317 void
1318 xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr)// C: 22 in 18 SCM: 3 in 3 Local: 1:0:0
1319 */
1320 static void
1321 test_xaccTransSetCurrency (Fixture *fixture, gconstpointer pData)
1322 {
1323  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1324  gnc_commodity *curr = gnc_commodity_new (book, "Japanese Yen", "CURRENCY", "JPY", "Â¥", 1);
1325  Split *split1 = xaccTransFindSplitByAccount (fixture->txn, fixture->acc1);
1326  gnc_numeric old_val = xaccSplitGetValue (split1);
1327  /* Prevent commit in xaccTransSetCurrency() */
1328  xaccTransBeginEdit(fixture->txn);
1329  xaccTransSetCurrency (fixture->txn, curr);
1330  g_assert (fixture->txn->common_currency == curr);
1331  g_assert_cmpint (xaccSplitGetValue (split1).denom, ==,
1333  g_assert_cmpint (xaccSplitGetValue (split1).num, ==,
1334  old_val.num / old_val.denom);
1335 }
1336 /* xaccTransBeginEdit
1337 void
1338 xaccTransBeginEdit (Transaction *trans)// C: 72 in 28 SCM: 5 in 5 Local: 16:0:0
1339 */
1340 static void
1341 test_xaccTransBeginEdit ()
1342 {
1343  QofBook *book = qof_book_new ();
1344  Transaction *txn = xaccMallocTransaction (book);
1345  Transaction *dupe = NULL;
1346  gchar *msg1 = "[xaccOpenLog] Attempt to open disabled transaction log";
1347  gchar *msg2 = "[xaccTransWriteLog] Attempt to write disabled transaction log";
1348  guint loglevel = G_LOG_LEVEL_INFO;
1349  gchar *logdomain = "gnc.translog";
1350  TestErrorStruct *check1 = test_error_struct_new (logdomain, loglevel, msg1);
1351  TestErrorStruct *check2 = test_error_struct_new (logdomain, loglevel, msg2);
1352  guint hdlr = g_log_set_handler (logdomain, loglevel,
1353  (GLogFunc)test_list_handler, NULL);
1354  test_add_error (check1);
1355  test_add_error (check2);
1356 
1357 
1358  g_assert_cmpint (0, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1359  g_assert (txn->orig == NULL);
1360  xaccTransBeginEdit (txn);
1361  g_assert_cmpint (1, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1362  dupe = txn->orig;
1363  g_assert (txn->orig != NULL);
1364  g_assert_cmpint (1, ==, check1->hits);
1365  g_assert_cmpint (1, ==, check2->hits);
1366  xaccTransBeginEdit (txn);
1367  g_assert_cmpint (2, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1368  g_assert (txn->orig == dupe);
1369  g_assert_cmpint (1, ==, check1->hits);
1370  g_assert_cmpint (1, ==, check2->hits);
1371  xaccTransRollbackEdit (txn);
1372  xaccTransRollbackEdit (txn);
1373  g_assert_cmpint (0, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1374  g_assert (txn->orig == NULL);
1375  qof_book_mark_readonly (book);
1376  xaccTransBeginEdit (txn);
1377  dupe = txn->orig;
1378  g_assert_cmpint (1, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1379  g_assert (txn->orig == dupe);
1380  g_assert_cmpint (1, ==, check1->hits);
1381  g_assert_cmpint (2, ==, check2->hits);
1382  xaccTransRollbackEdit (txn);
1383  g_assert_cmpint (0, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1384  g_assert (txn->orig == NULL);
1385  qof_book_destroy (book);
1386  xaccTransBeginEdit (txn);
1387  g_assert_cmpint (1, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
1388  g_assert (txn->orig == NULL);
1389  g_assert_cmpint (1, ==, check1->hits);
1390  g_assert_cmpint (2, ==, check2->hits);
1391 
1392  g_log_remove_handler (logdomain, hdlr);
1393  test_clear_error_list ();
1394  test_error_struct_free (check1);
1395  test_error_struct_free (check2);
1396  /* qof_book_destroy has already removed enough of the innards that
1397  trying to unref the txn and book crashes. */
1398 }
1399 /* xaccTransDestroy
1400 void
1401 xaccTransDestroy (Transaction *trans)// C: 26 in 15 SCM: 4 in 4 Local: 3:0:0
1402 */
1403 static void
1404 test_xaccTransDestroy (Fixture *fixture, gconstpointer pData)
1405 {
1406  Transaction *txn = fixture->txn;
1407  QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
1408  Transaction *dupe = xaccTransClone (txn);
1409 
1410  xaccTransBeginEdit (txn);
1411  g_assert (!qof_instance_get_destroying (QOF_INSTANCE (txn)));
1412  g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
1413  xaccTransDestroy (txn);
1414  g_assert (qof_instance_get_destroying (QOF_INSTANCE (txn)));
1415  g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
1416  xaccTransRollbackEdit (txn);
1417  qof_book_mark_readonly (book);
1418  xaccTransBeginEdit (txn);
1419  xaccTransDestroy (txn);
1420  g_assert (qof_instance_get_destroying (QOF_INSTANCE (txn)));
1421  g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
1422  xaccTransRollbackEdit (txn);
1423 
1424  test_destroy (dupe);
1425 }
1426 /* destroy_gains
1427 static void
1428 destroy_gains (Transaction *trans)// Local: 1:0:0 -- from do_destroy
1429 */
1430 static void
1431 test_destroy_gains (GainsFixture *fixture, gconstpointer pData)
1432 {
1433  /* Don't try to test with a NULL transaction, this is an internal
1434  * function that isn't protected.
1435  */
1436  Fixture *base = &(fixture->base);
1437  Split *base_split = g_list_nth_data (base->txn->splits, 1);
1438  xaccTransBeginEdit (fixture->gains_txn); /* Protect it from being actually destroyed */
1439  base->func->destroy_gains (base->txn);
1440  g_assert (qof_instance_get_destroying (QOF_INSTANCE (fixture->gains_txn)));
1441  g_assert (base_split->gains_split == NULL);
1442  xaccTransCommitEdit (fixture->gains_txn);
1443 }
1444 /* do_destroy
1445 static void
1446 do_destroy (Transaction *trans)// Local: 1:1:0 callback passed to qof_commit_edit_part2 in XaccTransCommitEdit
1447 
1448 NB: This function has a weird three-step process for destroying and freeing the splits, which isn't really testable.
1449 */
1450 static void
1451 test_do_destroy (GainsFixture *fixture, gconstpointer pData)
1452 {
1453  Fixture *base = &(fixture->base);
1454  Split *base_split = g_list_nth_data (base->txn->splits, 1);
1455  QofBook *book = qof_instance_get_book (base->txn);
1456  TestSignal sig = test_signal_new (QOF_INSTANCE (base->txn),
1457  QOF_EVENT_DESTROY, NULL);
1458  g_object_add_weak_pointer (G_OBJECT (base->txn->splits->data),
1459  (gpointer)&base_split);
1460  g_object_ref (base->txn);
1461  g_object_ref (fixture->gains_txn);
1462 
1463  base->func->do_destroy (base->txn);
1464  g_assert_cmpint (test_signal_return_hits (sig), ==, 1);
1465  g_assert (base->txn->description == NULL);
1466  g_assert_cmpint (GPOINTER_TO_INT(base->txn->num), ==, 1);
1467  g_assert (qof_instance_get_destroying (QOF_INSTANCE (fixture->gains_txn)));
1468  g_assert (base_split == NULL);
1469 
1470  test_signal_free (sig);
1471 }
1472 /* xaccEnableDataScrubbing
1473  * xaccDisableDataScrubbing
1474  Trivial setters
1475 */
1476 /* was_trans_emptied
1477 static gboolean was_trans_emptied(Transaction *trans)// Local: 1:0:0 xaccTransCommitEdit
1478 */
1479 static void
1480 test_was_trans_emptied (Fixture *fixture, gconstpointer pData)
1481 {
1482  GList *list = fixture->txn->splits;
1483  g_assert (!fixture->func->was_trans_emptied (fixture->txn));
1484  fixture->txn->splits = NULL;
1485  g_assert (fixture->func->was_trans_emptied (fixture->txn));
1486  /* Restore the list so teardown can free the splits */
1487  fixture->txn->splits = list;
1488 }
1489 /* trans_on_error
1490 static void trans_on_error(Transaction *trans, QofBackendError errcode)// Local: 0:1:0 callback for qof_commit_edit_part2, xaccTransCommitEdit
1491 */
1492 
1493 static QofBackendError errorvalue = 0;
1494 static void
1495 commit_error_cb (gpointer data, QofBackendError errcode)
1496 {
1497  errorvalue = errcode;
1498 }
1499 
1500 static void
1501 test_trans_on_error (Fixture *fixture, gconstpointer pData)
1502 {
1504  gchar *msg =
1505  "[trans_on_error()] Another user has modified this transaction\n"
1506  "\tjust a moment ago. Please look at their changes,\n"
1507  "\tand try again, if needed.\n";
1508  gchar *logdomain = "gnc.engine";
1509  guint loglevel = G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL;
1510  TestErrorStruct *check = test_error_struct_new (logdomain, loglevel, msg);
1511  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
1512  (GLogFunc)test_checked_handler);
1513  gnc_engine_add_commit_error_callback ((EngineCommitErrorCallback)commit_error_cb, NULL);
1514  xaccTransBeginEdit (fixture->txn);
1515  g_assert_cmpint (qof_instance_get_editlevel (fixture->txn), ==, 1);
1516  fixture->func->trans_on_error (fixture->txn, errcode);
1517  g_assert_cmpint (check->hits, ==, 1);
1518  g_assert_cmpint ((guint)errorvalue, ==, (guint)errcode);
1519  g_assert_cmpint (qof_instance_get_editlevel (fixture->txn), ==, 0);
1520  errorvalue = 0;
1521 }
1522 /* trans_cleanup_commit
1523 static void trans_cleanup_commit(Transaction *trans)// Local: 0:1:0 callback for qof_commit_edit_part2, xaccTransCommitEdit
1524 */
1525 static void
1526 test_trans_cleanup_commit (Fixture *fixture, gconstpointer pData)
1527 {
1528  QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
1529  Split *destr_split = xaccMallocSplit (book);
1530  Split *bogus_split = xaccMallocSplit (book);
1531  Split *split0 = fixture->txn->splits->data;
1532  Account *acct0 = split0->acc;
1533  Transaction *orig = NULL;
1534  TestSignal *sig_d_remove = test_signal_new (QOF_INSTANCE (destr_split),
1535  QOF_EVENT_REMOVE, NULL);
1536  TestSignal *sig_b_remove = test_signal_new (QOF_INSTANCE (bogus_split),
1537  QOF_EVENT_REMOVE, NULL);
1538  TestSignal *sig_d_destroy = test_signal_new (QOF_INSTANCE (destr_split),
1539  QOF_EVENT_DESTROY, NULL);
1540  TestSignal *sig_b_modify = test_signal_new (QOF_INSTANCE (bogus_split),
1541  QOF_EVENT_MODIFY, NULL);
1542  TestSignal *sig_t_modify = test_signal_new (QOF_INSTANCE (fixture->txn),
1543  QOF_EVENT_MODIFY, NULL);
1544  TestSignal *sig_a_changed = test_signal_new (QOF_INSTANCE (acct0),
1545  GNC_EVENT_ITEM_CHANGED, NULL);
1546 
1547  xaccTransBeginEdit (fixture->txn);
1548  orig = fixture->txn->orig;
1549  g_object_ref (orig);
1550  /* Check the txn-isn't-the-parent path */
1551  fixture->txn->splits = g_list_prepend (fixture->txn->splits, destr_split);
1552  fixture->txn->splits = g_list_prepend (fixture->txn->splits, bogus_split);
1553  qof_instance_set_dirty (QOF_INSTANCE (destr_split));
1554  qof_instance_set_dirty (QOF_INSTANCE (bogus_split));
1555  qof_instance_set_destroying (QOF_INSTANCE (destr_split), TRUE);
1556  /*Reverse the splits list so we can check later that it got sorted */
1557  fixture->txn->splits = g_list_reverse (fixture->txn->splits);
1558  g_assert (fixture->txn->splits->data != split0);
1559  fixture->func->trans_cleanup_commit (fixture->txn);
1560 
1561  g_assert_cmpint (test_signal_return_hits (sig_d_remove), ==, 1);
1562  g_assert_cmpint (test_signal_return_hits (sig_b_remove), ==, 1);
1563  g_assert_cmpint (test_signal_return_hits (sig_d_destroy), ==, 0);
1564  g_assert_cmpint (test_signal_return_hits (sig_b_modify), ==, 0);
1565  g_assert_cmpint (test_signal_return_hits (sig_t_modify), ==, 1);
1566  g_assert_cmpint (test_signal_return_hits (sig_a_changed), ==, 1);
1567  g_assert_cmpint (g_list_index (fixture->txn->splits, destr_split), ==, -1);
1568  g_assert_cmpint (g_list_index (fixture->txn->splits, bogus_split), ==, -1);
1569  g_assert (fixture->txn->orig == NULL);
1570  g_assert (fixture->txn->splits->data == split0);
1571  g_assert (qof_instance_get_destroying (destr_split));
1572  /* Note that the function itself aborts if qof_instance_editlevel != 0 */
1573 
1574  /* load things back up and test the txn-is-the-parent path */
1575  qof_instance_increase_editlevel (fixture->txn);
1576  destr_split->parent = fixture->txn;
1577  bogus_split->parent = fixture->txn;
1578  fixture->txn->splits = g_list_prepend (fixture->txn->splits, destr_split);
1579  fixture->txn->splits = g_list_prepend (fixture->txn->splits, bogus_split);
1580 
1581  fixture->txn->orig = orig;
1582  orig->num = fixture->txn->num;
1583  g_object_ref (orig);
1584  fixture->func->trans_cleanup_commit (fixture->txn);
1585 
1586  g_assert_cmpint (test_signal_return_hits (sig_d_remove), ==, 2);
1587  g_assert_cmpint (test_signal_return_hits (sig_b_remove), ==, 1);
1588  g_assert_cmpint (test_signal_return_hits (sig_d_destroy), ==, 1);
1589  g_assert_cmpint (test_signal_return_hits (sig_b_modify), ==, 1);
1590  g_assert_cmpint (test_signal_return_hits (sig_t_modify), ==, 2);
1591  g_assert_cmpint (test_signal_return_hits (sig_a_changed), ==, 2);
1592  g_assert_cmpint (g_list_index (fixture->txn->splits, destr_split), ==, -1);
1593  g_assert_cmpint (g_list_index (fixture->txn->splits, bogus_split), ==, 0);
1594  g_assert_cmpint (GPOINTER_TO_INT(orig->num), ==, 1);
1595  test_destroy (orig);
1596 
1597 }
1598 /* xaccTransCommitEdit
1599 void
1600 xaccTransCommitEdit (Transaction *trans)// C: 88 in 28 SCM: 5 in 5 Local: 16:0:0
1601 Setup has to run transCommitEdit, so we have to do our own setup for this function.
1602 */
1603 static void
1604 test_xaccTransCommitEdit (void)
1605 {
1606  QofBook *book = qof_book_new ();
1607  Split *split1 = xaccMallocSplit (book);
1608  Split *split2 = xaccMallocSplit (book);
1609  Transaction *txn = xaccMallocTransaction (book);
1610  Account *acc1 = xaccMallocAccount (book);
1611  Account *acc2 = xaccMallocAccount (book);
1612  gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand",
1613  "CURRENCY", "GNR", "", 240);
1614  gnc_commodity *comm = gnc_commodity_new (book, "Wildebeest Fund",
1615  "FUND", "WBFXX", "", 1000);
1616 
1617  Timespec posted = gnc_dmy2timespec (21, 4, 2012);
1618 
1619  TestSignal *sig_1_modify = test_signal_new (QOF_INSTANCE (split1),
1620  QOF_EVENT_MODIFY, NULL);
1621  TestSignal *sig_2_modify = test_signal_new (QOF_INSTANCE (split2),
1622  QOF_EVENT_MODIFY, NULL);
1623  TestSignal *sig_txn_destroy = test_signal_new (QOF_INSTANCE (txn),
1624  QOF_EVENT_DESTROY, NULL);
1625 
1626 
1627  xaccAccountSetCommodity (acc1, comm);
1628  xaccAccountSetCommodity (acc2, curr);
1629  txn->date_posted.tv_sec = posted.tv_sec;
1630  txn->date_posted.tv_nsec = posted.tv_nsec;
1631  split1->memo = CACHE_INSERT ("foo");
1632  split1->action = CACHE_INSERT ("bar");
1633  split1->amount = gnc_numeric_create (100000, 1000);
1634  split1->value = gnc_numeric_create (3200, 240);
1635  /* Note, deliberately imblanced to force xaccTransScrubImbalance
1636  * to create a balance split, thus showing that it got called.
1637  */
1638  split2->amount = gnc_numeric_create (-3000, 240);
1639  split2->value = gnc_numeric_create (-3000, 240);
1640  split1->acc = acc1;
1641  split2->acc = acc2;
1642  txn->num = CACHE_INSERT ("123");
1643  txn->description = CACHE_INSERT ("Waldo Pepper");
1644  xaccTransBeginEdit (txn);
1645  {
1646  xaccTransSetCurrency (txn, curr);
1647  xaccSplitSetParent (split1, txn);
1648  xaccSplitSetParent (split2, txn);
1649  }
1650  /* Setup's done, now test: */
1651  xaccTransCommitEdit (txn);
1652 
1653  g_assert_cmpint (txn->date_entered.tv_sec, !=, 0);
1654  /* Signals make sure that trans_cleanup_commit got called */
1655  g_assert_cmpint (test_signal_return_hits (sig_1_modify), ==, 1);
1656  g_assert_cmpint (test_signal_return_hits (sig_2_modify), ==, 1);
1657  g_assert_cmpint (g_list_length (txn->splits), ==, 3);
1658 
1659  xaccTransBeginEdit (txn);
1660  g_list_free (txn->splits);
1661  txn->splits = NULL;
1662  xaccTransCommitEdit (txn);
1663  g_assert_cmpint (test_signal_return_hits (sig_txn_destroy), ==, 1);
1664 
1665  test_signal_free (sig_1_modify);
1666  test_signal_free (sig_2_modify);
1667  test_signal_free (sig_txn_destroy);
1668  test_destroy (split1);
1669  test_destroy (split2);
1670  test_destroy (acc1);
1671  test_destroy (acc2);
1672  test_destroy (curr);
1673  test_destroy (comm);
1674  test_destroy (book);
1675 }
1676 /* xaccTransRollbackEdit
1677 void
1678 xaccTransRollbackEdit (Transaction *trans)// C: 2 in 2 Local: 1:0:0
1679 */
1680 static void
1681 test_xaccTransRollbackEdit (Fixture *fixture, gconstpointer pData)
1682 {
1683  Transaction *txn = fixture->txn;
1684  Transaction *orig = NULL;
1685  QofBook *book = qof_instance_get_book (txn);
1686  Timespec new_post = timespec_now ();
1687  Timespec new_entered = timespecCanonicalDayTime (timespec_now ());
1688  Timespec orig_post = txn->date_posted;
1689  Timespec orig_entered = txn->date_entered;
1690  KvpFrame *base_frame = NULL;
1691  TestSignal *sig_account = test_signal_new (QOF_INSTANCE (fixture->acc1),
1692  GNC_EVENT_ITEM_CHANGED, NULL);
1694  Split *split_00 = txn->splits->data, *split_01 = txn->splits->next->data;
1695  Split *split_02 = xaccMallocSplit (book);
1696  Split *split_10 = NULL, *split_11 = NULL;
1697 
1698  xaccTransBeginEdit (txn);
1699  qof_instance_set_destroying (txn, TRUE);
1700  orig = txn->orig;
1701  base_frame = orig->inst.kvp_data; /* DupeTransaction copies the kvp_frame */
1702  g_object_ref (orig); /* Keep rollback from actually freeing it */
1703  txn->num = "321";
1704  txn->description = "salt peanuts";
1705  txn->common_currency = NULL;
1706  txn->inst.kvp_data = NULL;
1707  txn->date_entered = new_entered;
1708  txn->date_posted = new_post;
1709  txn->splits->data = split_01;
1710  txn->splits->next->data = split_00;
1711  qof_instance_set_dirty (QOF_INSTANCE (split_01));
1712  xaccSplitSetParent (split_02, txn);
1713  g_object_ref (split_02);
1714  split_10 = xaccDupeSplit(orig->splits->data);
1715  g_object_ref (split_10);
1716  split_11 = xaccDupeSplit(orig->splits->next->data);
1717  g_object_ref (split_11);
1718  qof_instance_increase_editlevel (QOF_INSTANCE (txn)); /* So it's 2 */
1719  xaccTransRollbackEdit (txn);
1720  g_assert (txn->orig == orig);
1721  qof_instance_reset_editlevel (QOF_INSTANCE (txn)); /* Now it's 0 */
1722  xaccTransRollbackEdit (txn);
1723  g_assert (txn->orig == orig);
1724  qof_instance_increase_editlevel (QOF_INSTANCE (txn)); /* And back to 1 */
1725  xaccTransRollbackEdit (txn);
1726  g_assert (txn->orig == NULL);
1727  g_assert_cmpstr (txn->num, ==, "123");
1728  g_assert_cmpint (GPOINTER_TO_INT(orig->num), ==, 1);
1729  g_assert_cmpstr (txn->description, ==, "Waldo Pepper");
1730  g_assert (txn->inst.kvp_data == base_frame);
1731  g_assert (txn->common_currency == fixture->curr);
1732  g_assert (timespec_equal (&(txn->date_posted), &orig_post));
1733  g_assert (timespec_equal (&(txn->date_entered), &orig_entered));
1734  g_assert_cmpuint (test_signal_return_hits (sig_account), ==, 1);
1735  g_assert_cmpuint (g_list_length (txn->splits), ==, 2);
1736  g_assert_cmpint (GPOINTER_TO_INT(split_02->memo), ==, 1);
1737  g_assert (xaccSplitEqual (txn->splits->data, split_10,
1738  FALSE, FALSE, FALSE));
1739  g_assert (xaccSplitEqual (txn->splits->next->data, split_10,
1740  FALSE, FALSE, FALSE));
1741  g_assert_cmpstr (mbe->last_call, ==, "rollback");
1742  g_assert_cmpuint (qof_instance_get_editlevel (QOF_INSTANCE (txn)), ==, 0);
1743  g_assert (qof_instance_get_destroying (txn) == FALSE);
1744  test_signal_free (sig_account);
1745  g_object_unref (split_10);
1746  g_object_unref (split_11);
1747  g_object_unref (split_02);
1748  g_object_unref (orig);
1749 
1750 }
1751 /* A second xaccTransRollbackEdit test to check the backend error handling */
1752 static void
1753 test_xaccTransRollbackEdit_BackendErrors (Fixture *fixture, gconstpointer pData)
1754 {
1756  guint loglevel = G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL;
1757  gchar *msg = "[xaccTransRollbackEdit()] Rollback Failed. Ouch!";
1758  TestErrorStruct *check = test_error_struct_new ("gnc.engine",
1759  loglevel, msg);
1760  fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
1761  (GLogFunc)test_checked_handler);
1762  g_object_ref (fixture->txn);
1763  xaccTransBeginEdit (fixture->txn);
1764  mock_backend_set_error (mbe, ERR_BACKEND_MODIFIED);
1765  xaccTransRollbackEdit (fixture->txn);
1766  g_assert_cmpint (check->hits, ==, 1);
1767  g_assert_cmpstr (mbe->last_call, ==, "rollback");
1768  memset (mbe->last_call, 0, sizeof (mbe->last_call));
1769  xaccTransBeginEdit (fixture->txn);
1770  mock_backend_set_error (mbe, ERR_BACKEND_MOD_DESTROY);
1771  xaccTransRollbackEdit (fixture->txn);
1772  g_assert_cmpint (GPOINTER_TO_INT(fixture->txn->num), ==, 1);
1773  g_assert_cmpstr (mbe->last_call, ==, "rollback");
1774 
1775 }
1776 /* xaccTransIsOpen C: 23 in 7 SCM: 1 Local: 0:0:0
1777  * xaccTransOrder C: 2 in 2 SCM: 12 in 12 Local: 0:1:0
1778 
1779  * Simple convenience functions. No test required.
1780  */
1781 /* xaccTransOrder_num_action
1782 int
1783 xaccTransOrder_num_action (const Transaction *ta, const char *actna,
1784  const Transaction *tb, const char *actnb)// C: 1 Local: 1:0:0
1785 */
1786 static void
1787 test_xaccTransOrder_num_action (Fixture *fixture, gconstpointer pData)
1788 {
1789  Transaction *txnA = fixture->txn;
1790  Transaction *txnB = fixture->func->dupe_trans (txnA);
1791 
1792  g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, NULL, NULL), ==, -1);
1793  g_assert_cmpint (xaccTransOrder_num_action (NULL, NULL, txnA, NULL), ==, 1);
1794  g_assert_cmpint (xaccTransOrder_num_action (NULL, NULL, NULL, NULL), ==, 0);
1795  g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==,
1796  qof_instance_guid_compare (txnA, txnB));
1797  txnB->description = CACHE_INSERT ("Salt Peanuts");
1798  g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), >=, 1);
1799  txnB->date_entered.tv_sec += 1;
1800  g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, -1);
1801  txnB->num = CACHE_INSERT ("101");
1802  g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, 1);
1803  txnB->num = CACHE_INSERT ("one-oh-one");
1804  g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, 1);
1805  g_assert_cmpint (xaccTransOrder_num_action (txnA, "24", txnB, "42"), ==, -1);
1806  txnB->date_posted.tv_sec -= 1;
1807  g_assert_cmpint (xaccTransOrder_num_action (txnA, "24", txnB, "42"), ==, 1);
1808 
1809  fixture->func->xaccFreeTransaction (txnB);
1810 }
1811 /* xaccTransSetDateInternal Local: 7:0:0
1812  * set_gains_date_dirty Local: 4:0:0
1813  * xaccTransSetDatePostedSecs C: 17 in 13 Local: 0:0:0
1814  * xaccTransSetDatePostedGDate C: 1 Local: 1:0:0
1815  * xaccTransSetDateEnteredSecs C: 10 in 9 Local: 0:0:0
1816  * xaccTransSetDatePostedTS C: 9 in 8 Local: 2:0:0
1817  * xaccTransSetDateEnteredTS C: 3 in 3 Local: 1:0:0
1818  * xaccTransSetDate C: 43 in 23 SCM: 2 in 2 Local: 0:0:0
1819  * xaccTransSetDateDueTS C: 2 in 2 Local: 0:0:0
1820  * xaccTransSetTxnType C: 4 in 3 Local: 0:0:0
1821  * xaccTransClearReadOnly C: 4 in 2 Local: 1:0:0
1822  * xaccTransSetReadOnly C: 2 in 2 Local: 1:0:0
1823  * qofTransSetNum Local: 0:1:0
1824  * xaccTransSetNum C: 13 in 12 SCM: 3 in 3 Local: 2:0:0
1825  * qofTransSetDescription Local: 0:0:0
1826  * xaccTransSetDescription C: 20 in 18 SCM: 5 in 3 Local: 2:0:0
1827  * qofTransSetNotes Local: 0:0:0
1828  * xaccTransSetNotes C: 5 in 5 SCM: 3 in 3 Local: 1:0:0
1829  * xaccTransSetIsClosingTxn C: 1 Local: 0:0:0
1830  * xaccTransGetSplit C: 57 in 24 SCM: 30 in 21 Local: 0:0:0
1831  * xaccTransGetSplitIndex C: 7 in 2 Local: 0:0:0
1832  * xaccTransGetSplitList C: 23 in 15 SCM: 19 in 15 Local: 2:1:0
1833  * xaccTransCountSplits C: 17 in 9 SCM: 2 in 2 Local: 0:0:0
1834  * xaccTransGetNum C: 15 in 12 SCM: 13 in 13 Local: 0:1:0
1835  * xaccTransGetDescription C: 43 in 23 SCM: 9 in 9 Local: 0:2:0
1836  * xaccTransGetNotes C: 8 in 6 SCM: 7 in 7 Local: 0:1:0
1837  * xaccTransGetIsClosingTxn SCM: 1 Local: 0:1:0
1838  * xaccTransGetDate C: 42 in 19 Local: 0:0:0
1839  * xaccTransGetDatePostedTS C: 6 in 5 Local: 1:0:0
1840  * xaccTransGetDateEnteredTS C: 1 Local: 0:0:0
1841  * xaccTransRetDatePostedTS C: 10 in 6 Local: 1:1:0
1842  * xaccTransGetDatePostedGDate C: 1 Local: 1:0:0
1843  * xaccTransRetDateEnteredTS C: 1 Local: 0:1:0
1844  * xaccTransGetDateDueTS C: 1 Local: 1:0:0
1845  * xaccTransRetDateDueTS C: 1 SCM: 2 in 2 Local: 0:1:0
1846  * xaccTransGetTxnType C: 3 in 2 SCM: 12 in 6 Local: 0:1:0
1847  * xaccTransGetReadOnly C: 7 in 5 Local: 1:0:0
1848  * xaccTransIsReadonlyByPostedDate C: 2 in 2 Local: 0:0:0
1849  * xaccTransHasReconciledSplitsByAccount Local: 1:0:0
1850  * xaccTransHasReconciledSplits C: 4 in 3 Local: 0:0:0
1851  * xaccTransHasSplitsInStateByAccount Local: 1:0:0
1852  * xaccTransHasSplitsInState C: 4 in 1 Local: 0:0:0
1853  * counter_thunk Local: 0:1:0
1854  * gnc_book_count_transactions C: 3 in 2 Local: 0:0:0
1855  * xaccTransGetVoidStatus C: 3 in 2 SCM: 1 Local: 0:1:0
1856 
1857  * An absurdly long list of trivial accessors which don't need to be tested.
1858  */
1859 
1860 /* xaccTransVoid
1861 void
1862 xaccTransVoid(Transaction *trans, const char *reason)// C: 1 SCM: 2 in 2 Local: 0:0:0
1863 * xaccTransUnvoid
1864 void
1865 xaccTransUnvoid (Transaction *trans)// C: 1 Local: 0:0:0
1866 */
1867 
1868 static void
1869 test_xaccTransVoid (Fixture *fixture, gconstpointer pData)
1870 {
1871  /* Actual function variables start here. */
1872  KvpFrame *frame = fixture->txn->inst.kvp_data;
1873  gchar *void_reason = "Voided for Unit Test";
1874  gchar *txn_notes = g_strdup (kvp_frame_get_string (frame, trans_notes_str));
1875  KvpValue *val;
1876  Timespec now = timespec_now ();
1877  char iso8601_str[ISO_DATELENGTH + 1] = "";
1878  GList *split = NULL;
1879 
1880  xaccTransVoid (fixture->txn, void_reason);
1881  g_assert_cmpstr (kvp_frame_get_string (frame, trans_notes_str), ==,
1882  "Voided transaction");
1883  g_assert_cmpstr (kvp_frame_get_string (frame, void_former_notes_str), ==,
1884  txn_notes);
1885  g_assert_cmpstr (kvp_frame_get_string (frame, void_reason_str), ==,
1886  void_reason);
1887  gnc_timespec_to_iso8601_buff (now, iso8601_str);
1888  g_assert_cmpstr (kvp_frame_get_string (frame, void_time_str), ==,
1889  iso8601_str);
1890  g_assert_cmpstr (kvp_frame_get_string (frame, TRANS_READ_ONLY_REASON), ==,
1891  "Transaction Voided");
1892  for (split = fixture->txn->splits; split; split=g_list_next (split))
1893  {
1894  g_assert (gnc_numeric_zero_p (((Split*)(split->data))->value));
1895  g_assert (gnc_numeric_zero_p (((Split*)(split->data))->amount));
1896  }
1897 
1898  xaccTransUnvoid (fixture->txn);
1899 
1900  g_assert_cmpstr (kvp_frame_get_string (frame, trans_notes_str), ==,
1901  txn_notes);
1902  g_assert (kvp_frame_get_slot (frame, void_former_notes_str) == NULL);
1903  g_assert (kvp_frame_get_slot (frame, void_reason_str) == NULL);
1904  g_assert (kvp_frame_get_slot (frame, void_time_str) == NULL);
1905  g_assert (kvp_frame_get_slot (frame, TRANS_READ_ONLY_REASON) == NULL);
1906  for (split = fixture->txn->splits; split; split=g_list_next (split))
1907  {
1908  g_assert (!gnc_numeric_zero_p (((Split*)(split->data))->value));
1909  g_assert (!gnc_numeric_zero_p (((Split*)(split->data))->amount));
1910  }
1911 
1912  g_free (txn_notes);
1913 
1914 }
1915 /* xaccTransReverse
1916 Transaction *
1917 xaccTransReverse (Transaction *orig)// C: 2 in 2 Local: 0:0:0
1918 */
1919 static void
1920 test_xaccTransReverse (Fixture *fixture, gconstpointer pData)
1921 {
1922  Transaction *rev = xaccTransReverse (fixture->txn);
1923  KvpFrame *frame = fixture->txn->inst.kvp_data;
1924  GList *orig_splits = NULL, *rev_splits = NULL;
1925 
1926  g_assert (guid_equal (kvp_frame_get_guid (frame, TRANS_REVERSED_BY),
1927  xaccTransGetGUID (rev)));
1928 
1929  g_assert (qof_instance_is_dirty (QOF_INSTANCE (rev)));
1930  g_assert_cmpint (g_list_length (fixture->txn->splits), ==,
1931  g_list_length (rev->splits));
1932  for (orig_splits = fixture->txn->splits,
1933  rev_splits = g_list_reverse (rev->splits);
1934  orig_splits && rev_splits;
1935  orig_splits = g_list_next (orig_splits),
1936  rev_splits = g_list_next (rev_splits))
1937  {
1938  Split *orig_split = orig_splits->data;
1939  Split *rev_split = rev_splits->data;
1940  g_assert (gnc_numeric_equal (orig_split->amount,
1941  gnc_numeric_neg (rev_split->amount)));
1942  g_assert (gnc_numeric_equal (orig_split->value,
1943  gnc_numeric_neg (rev_split->value)));
1944  g_assert_cmpint (xaccSplitGetReconcile (rev_split), ==, NREC);
1945  }
1946 
1947  fixture->func->xaccFreeTransaction (rev);
1948 }
1949 /* xaccTransGetReversedBy C: 2 in 2 Local: 0:0:0
1950  * Trivial getter.
1951  */
1952 /* xaccTransScrubSplits C: 1 Local: 0:0:0
1953  * Trival pass-through.
1954  */
1955 /* xaccTransScrubGainsDate
1956 static void
1957 xaccTransScrubGainsDate (Transaction *trans)// Local: 1:0:0
1958 */
1959 static void
1960 test_xaccTransScrubGainsDate_no_dirty (GainsFixture *fixture,
1961  gconstpointer pData)
1962 {
1963  Split *base_split = g_list_nth_data (fixture->base.txn->splits, 1);
1964  Split *gains_split = base_split->gains_split;
1965 
1966  base_split->gains = GAINS_STATUS_GAINS;
1967  gains_split->gains = GAINS_STATUS_GAINS;
1968 
1969  fixture->base.func->xaccTransScrubGainsDate (fixture->base.txn);
1970 
1971  g_assert (!timespec_equal (&(fixture->base.txn->date_posted),
1972  &(fixture->gains_txn->date_posted)));
1973  g_assert_cmphex (base_split->gains & GAINS_STATUS_DATE_DIRTY, ==, 0);
1974  g_assert_cmphex (base_split->gains_split->gains & GAINS_STATUS_DATE_DIRTY,
1975  ==, 0);
1976 }
1977 
1978 static void
1979 test_xaccTransScrubGainsDate_base_dirty (GainsFixture *fixture,
1980  gconstpointer pData)
1981 {
1982  Split *base_split = g_list_nth_data (fixture->base.txn->splits, 1);
1983  Split *gains_split = base_split->gains_split;
1984 
1985  base_split->gains = GAINS_STATUS_GAINS | GAINS_STATUS_DATE_DIRTY;
1986  gains_split->gains = GAINS_STATUS_GAINS;
1987 
1988  fixture->base.func->xaccTransScrubGainsDate (fixture->base.txn);
1989 
1990  g_assert (timespec_equal (&(fixture->base.txn->date_posted),
1991  &(fixture->gains_txn->date_posted)));
1992  g_assert_cmphex (base_split->gains & GAINS_STATUS_DATE_DIRTY, ==, 0);
1993  g_assert_cmphex (base_split->gains_split->gains & GAINS_STATUS_DATE_DIRTY,
1994  ==, 0);
1995 }
1996 
1997 static void
1998 test_xaccTransScrubGainsDate_gains_dirty (GainsFixture *fixture,
1999  gconstpointer pData)
2000 {
2001  Split *base_split = g_list_nth_data (fixture->base.txn->splits, 1);
2002  Split *gains_split = base_split->gains_split;
2003 
2004  base_split->gains = GAINS_STATUS_GAINS;
2005  gains_split->gains = GAINS_STATUS_GAINS | GAINS_STATUS_DATE_DIRTY;
2006 
2007  fixture->base.func->xaccTransScrubGainsDate (fixture->base.txn);
2008 
2009  g_assert (timespec_equal (&(fixture->base.txn->date_posted),
2010  &(fixture->gains_txn->date_posted)));
2011  g_assert_cmphex (base_split->gains & GAINS_STATUS_DATE_DIRTY, ==, 0);
2012  g_assert_cmphex (base_split->gains_split->gains & GAINS_STATUS_DATE_DIRTY,
2013  ==, 0);
2014 }
2015 
2016 /* xaccTransScrubGains Local: 1:0:0
2017  * Non-trivial, but it passes through selected splits to functions in
2018  * cap-gains.c and Scrub3.c that are beyond the scope of this test
2019  * program.
2020  */
2021 /* xaccTransFindSplitByAccount C: 7 in 5 Local: 0:0:0
2022  * destroy_tx_on_book_close Local: 0:1:0
2023  * gnc_transaction_book_end Local: 0:1:0
2024  * trans_is_balanced_p Local: 0:1:0
2025  * Trivial pass-through.
2026  */
2027 
2028 
2029 void
2030 test_suite_transaction (void)
2031 {
2032  GNC_TEST_ADD (suitename, "check open", Fixture, NULL, setup, test_check_open, teardown);
2033  GNC_TEST_ADD (suitename, "xaccTransStillHasSplit", Fixture, NULL, setup, test_xaccTransStillHasSplit, teardown);
2034  GNC_TEST_ADD (suitename, "mark trans", Fixture, NULL, setup, test_mark_trans, teardown);
2035  GNC_TEST_ADD (suitename, "gen event trans", Fixture, NULL, setup, test_gen_event_trans, teardown);
2036  GNC_TEST_ADD_FUNC (suitename, "gnc transaction init", test_gnc_transaction_init);
2037  GNC_TEST_ADD_FUNC (suitename, "gnc transaction dispose", test_gnc_transaction_dispose);
2038  GNC_TEST_ADD_FUNC (suitename, "gnc transaction finalize", test_gnc_transaction_finalize);
2039  GNC_TEST_ADD (suitename, "gnc transaction set/get property", Fixture, NULL, setup, test_gnc_transaction_set_get_property, teardown);
2040  GNC_TEST_ADD (suitename, "xaccMallocTransaction", Fixture, NULL, setup, test_xaccMallocTransaction, teardown);
2041  GNC_TEST_ADD (suitename, "xaccTransSortSplits", Fixture, NULL, setup, test_xaccTransSortSplits, teardown);
2042  GNC_TEST_ADD (suitename, "dupe_trans", Fixture, NULL, setup, test_dupe_trans, teardown);
2043  GNC_TEST_ADD (suitename, "xaccTransClone", Fixture, NULL, setup, test_xaccTransClone, teardown);
2044  GNC_TEST_ADD (suitename, "xaccTransCopyFromClipBoard", Fixture, NULL, setup, test_xaccTransCopyFromClipBoard, teardown);
2045  GNC_TEST_ADD (suitename, "xaccTransCopyFromClipBoard No-Start", Fixture, NULL, setup, test_xaccTransCopyFromClipBoard_no_start, teardown);
2046  GNC_TEST_ADD (suitename, "xaccFreeTransaction", Fixture, NULL, setup, test_xaccFreeTransaction, teardown);
2047 // GNC_TEST_ADD (suitename, "compare split guids", Fixture, NULL, setup, test_compare_split_guids, teardown);
2048  GNC_TEST_ADD (suitename, "xaccTransEqual", Fixture, NULL, setup, test_xaccTransEqual, teardown);
2049  GNC_TEST_ADD (suitename, "xaccTransLookup", Fixture, NULL, setup, test_xaccTransLookup, teardown);
2050  GNC_TEST_ADD (suitename, "xaccTransGetImbalanceValue", Fixture, NULL, setup, test_xaccTransGetImbalanceValue, teardown);
2051  GNC_TEST_ADD (suitename, "xaccTransGetImbalance", Fixture, NULL, setup, test_xaccTransGetImbalance, teardown);
2052  GNC_TEST_ADD (suitename, "xaccTransGetImbalance Trading Accounts", Fixture, NULL, setup, test_xaccTransGetImbalance_trading, teardown);
2053  GNC_TEST_ADD (suitename, "xaccTransIsBalanced", Fixture, NULL, setup, test_xaccTransIsBalanced, teardown);
2054  GNC_TEST_ADD (suitename, "xaccTransIsBalanced Trading Accounts", Fixture, NULL, setup, test_xaccTransIsBalanced_trading, teardown);
2055  GNC_TEST_ADD (suitename, "xaccTransGetAccountValue", Fixture, NULL, setup, test_xaccTransGetAccountValue, teardown);
2056  GNC_TEST_ADD (suitename, "xaccTransGetRateForCommodity", Fixture, NULL, setup, test_xaccTransGetRateForCommodity, teardown);
2057  GNC_TEST_ADD (suitename, "xaccTransGetAccountAmount", Fixture, NULL, setup, test_xaccTransGetAccountAmount, teardown);
2058  GNC_TEST_ADD (suitename, "xaccTransGetAccountConvRate", Fixture, NULL, setup, test_xaccTransGetAccountConvRate, teardown);
2059  GNC_TEST_ADD (suitename, "xaccTransGetAccountBalance", Fixture, NULL, setup, test_xaccTransGetAccountBalance, teardown);
2060 
2061  GNC_TEST_ADD (suitename, "xaccTransSetCurrency", Fixture, NULL, setup, test_xaccTransSetCurrency, teardown);
2062  GNC_TEST_ADD_FUNC (suitename, "xaccTransBeginEdit", test_xaccTransBeginEdit);
2063  GNC_TEST_ADD (suitename, "xaccTransDestroy", Fixture, NULL, setup, test_xaccTransDestroy, teardown);
2064  GNC_TEST_ADD (suitename, "destroy gains", GainsFixture, NULL, setup_with_gains, test_destroy_gains, teardown_with_gains);
2065  GNC_TEST_ADD (suitename, "do destroy", GainsFixture, NULL, setup_with_gains, test_do_destroy, teardown_with_gains);
2066  GNC_TEST_ADD (suitename, "was trans emptied", Fixture, NULL, setup, test_was_trans_emptied, teardown);
2067  GNC_TEST_ADD (suitename, "trans on error", Fixture, NULL, setup, test_trans_on_error, teardown);
2068  GNC_TEST_ADD (suitename, "trans cleanup commit", Fixture, NULL, setup, test_trans_cleanup_commit, teardown);
2069  GNC_TEST_ADD_FUNC (suitename, "xaccTransCommitEdit", test_xaccTransCommitEdit);
2070  GNC_TEST_ADD (suitename, "xaccTransRollbackEdit", Fixture, NULL, setup, test_xaccTransRollbackEdit, teardown);
2071  GNC_TEST_ADD (suitename, "xaccTransRollbackEdit - Backend Errors", Fixture, NULL, setup, test_xaccTransRollbackEdit_BackendErrors, teardown);
2072  GNC_TEST_ADD (suitename, "xaccTransOrder_num_action", Fixture, NULL, setup, test_xaccTransOrder_num_action, teardown);
2073  GNC_TEST_ADD (suitename, "xaccTransVoid", Fixture, NULL, setup, test_xaccTransVoid, teardown);
2074  GNC_TEST_ADD (suitename, "xaccTransReverse", Fixture, NULL, setup, test_xaccTransReverse, teardown);
2075  GNC_TEST_ADD (suitename, "xaccTransScrubGainsDate", GainsFixture, NULL, setup_with_gains, test_xaccTransScrubGainsDate_no_dirty, teardown_with_gains);
2076  GNC_TEST_ADD (suitename, "xaccTransScrubGainsDate", GainsFixture, NULL, setup_with_gains, test_xaccTransScrubGainsDate_base_dirty, teardown_with_gains);
2077  GNC_TEST_ADD (suitename, "xaccTransScrubGainsDate", GainsFixture, NULL, setup_with_gains, test_xaccTransScrubGainsDate_gains_dirty, teardown_with_gains);
2078 
2079 }
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Definition: Account.c:2208
int qof_instance_version_cmp(const QofInstance *left, const QofInstance *right)
QofIdType e_type
Definition: qofinstance.h:69
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
gboolean gnc_numeric_equal(gnc_numeric a, gnc_numeric b)
gchar * gnc_timespec_to_iso8601_buff(Timespec ts, gchar *buff)
int gnc_commodity_get_fraction(const gnc_commodity *cm)
const GncGUID * qof_instance_get_guid(gconstpointer)
Split * xaccTransGetSplit(const Transaction *trans, int i)
Definition: Transaction.c:2144
#define qof_instance_is_dirty
Definition: qofinstance.h:165
QofBook * qof_instance_get_book(gconstpointer)
gnc_numeric xaccTransGetAccountBalance(const Transaction *trans, const Account *account)
Definition: Transaction.c:1310
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:59
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Timespec timespecCanonicalDayTime(Timespec t)
gboolean qof_instance_get_destroying(gconstpointer ptr)
void qof_instance_set(QofInstance *inst, const gchar *first_param,...)
Wrapper for g_object_set Group setting multiple parameters in a single begin/commit/rollback.
gint kvp_frame_compare(const KvpFrame *fa, const KvpFrame *fb)
char xaccSplitGetReconcile(const Split *split)
Definition: Split.c:1980
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
void xaccAccountSortSplits(Account *acc, gboolean force)
Definition: Account.c:1781
QofBook * qof_book_new(void)
gboolean timespec_equal(const Timespec *ta, const Timespec *tb)
void gnc_lot_add_split(GNCLot *lot, Split *split)
Definition: gnc-lot.c:569
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
gboolean gnc_numeric_zero_p(gnc_numeric a)
void gnc_engine_add_commit_error_callback(EngineCommitErrorCallback cb, gpointer data)
Definition: gnc-engine.c:197
void qof_book_mark_readonly(QofBook *book)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
gboolean xaccTransIsBalanced(const Transaction *trans)
Definition: Transaction.c:1124
gchar * gnc_numeric_to_string(gnc_numeric n)
Timespec gnc_dmy2timespec(gint day, gint month, gint year)
int xaccTransOrder_num_action(const Transaction *ta, const char *actna, const Transaction *tb, const char *actnb)
Definition: Transaction.c:1833
Definition: guid.h:65
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1402
gboolean xaccSplitEqual(const Split *sa, const Split *sb, gboolean check_guids, gboolean check_balances, gboolean check_txn_splits)
Definition: Split.c:815
const char * xaccTransGetNotes(const Transaction *trans)
Definition: Transaction.c:2197
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
Definition: Transaction.c:1024
int xaccTransCountSplits(const Transaction *trans)
Definition: Transaction.c:2170
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Definition: Transaction.c:857
gnc_numeric xaccTransGetImbalanceValue(const Transaction *trans)
Definition: Transaction.c:1036
void xaccTransVoid(Transaction *trans, const char *reason)
Definition: Transaction.c:2495
Transaction * xaccTransClone(const Transaction *from)
Definition: Transaction.c:679
gboolean guid_equal(const GncGUID *guid_1, const GncGUID *guid_2)
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
gboolean qof_instance_get_dirty_flag(gconstpointer ptr)
void gnc_monetary_list_free(MonetaryList *list)
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
void xaccTransCopyFromClipBoard(const Transaction *from_trans, Transaction *to_trans, const Account *from_acc, Account *to_acc, gboolean no_date)
Definition: Transaction.c:742
void xaccAccountRecomputeBalance(Account *acc)
Definition: Account.c:2058
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
void xaccTransUnvoid(Transaction *trans)
Definition: Transaction.c:2552
gboolean gnc_numeric_eq(gnc_numeric a, gnc_numeric b)
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
#define xaccTransGetGUID(X)
Definition: Transaction.h:755
Transaction * xaccTransReverse(Transaction *orig)
Definition: Transaction.c:2579
private api for data storage backend
void kvp_frame_set_double(KvpFrame *frame, const gchar *path, double dval)
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
const GncGUID * guid_null(void)
void qof_instance_set_book(gconstpointer inst, QofBook *book)
Timespec timespec_now(void)
gint qof_instance_guid_compare(const gconstpointer ptr1, const gconstpointer ptr2)
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
Definition: Transaction.c:1052
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
const char * gnc_commodity_get_unique_name(const gnc_commodity *cm)
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
KvpFrame * kvp_frame_new(void)
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
void xaccTransSortSplits(Transaction *trans)
Definition: Transaction.c:564
void kvp_frame_set_string(KvpFrame *frame, const gchar *path, const gchar *str)
Store a copy of the string at the indicated path.
struct KvpValueImpl KvpValue
Definition: kvp_frame.h:80
void xaccTransRollbackEdit(Transaction *trans)
Definition: Transaction.c:1661
gnc_numeric xaccTransGetAccountAmount(const Transaction *trans, const Account *acc)
Definition: Transaction.c:1186
void qof_book_destroy(QofBook *book)
gnc_numeric xaccTransGetAccountValue(const Transaction *trans, const Account *acc)
Definition: Transaction.c:1170
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
#define NREC
Definition: Split.h:70