Files
gnucash/libgnucash/engine/test/utest-Transaction.cpp
lmat 08aa0104ef Change kvp string representation
The nested representation was very noisy. Now, the string representation
shows one line per value with the full prefix which is also more
expressive than the old version.
2017-12-21 07:39:32 -05:00

2067 lines
86 KiB
C++

/********************************************************************
* utest-Transaction.c: GLib g_test test suite for Transaction.c. *
* Copyright 2012 John Ralls <jralls@ceridwen.us> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, you can retrieve it from *
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html *
* or contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
********************************************************************/
extern "C"
{
#include <config.h>
#include <string.h>
#include <glib.h>
#include <unittest-support.h>
/* Add specific headers for this class */
#include "../Transaction.h"
#include "../TransactionP.h"
#include "../Split.h"
#include "../Account.h"
#include "../gnc-lot.h"
#include "../gnc-event.h"
#include <qof.h>
#if defined(__clang__) && (__clang_major__ == 5 || (__clang_major__ == 3 && __clang_minor__ < 5))
#define USE_CLANG_FUNC_SIG 1
#endif
static const gchar *suitename = "/engine/Transaction";
void test_suite_transaction ( void );
}
#include <qof-backend.hpp>
#include <kvp-frame.hpp>
/* Copied from Transaction.c. Changing these values will break
* existing databases, which is a good reason to fail a test.
*/
static const char *trans_notes_str = "notes";
static const char *void_reason_str = "void-reason";
static const char *void_time_str = "void-time";
static const char *void_former_notes_str = "void-former-notes";
const char *trans_is_closing_str = "book_closing";
#define TRANS_DATE_DUE_KVP "trans-date-due"
#define TRANS_TXN_TYPE_KVP "trans-txn-type"
#define TRANS_READ_ONLY_REASON "trans-read-only"
#define TRANS_REVERSED_BY "reversed-by"
#define ISO_DATELENGTH 32 /* length of an iso 8601 date string. */
typedef struct
{
Transaction *txn;
Account *acc1;
Account *acc2;
gnc_commodity *curr;
gnc_commodity *comm;
TransTestFunctions *func;
GSList *hdlrs;
} Fixture;
typedef struct
{
Fixture base;
Transaction *gains_txn;
Account *gains_acc;
} GainsFixture;
class TransMockBackend : public QofBackend
{
public:
TransMockBackend() : QofBackend(), m_last_call{"Constructor"},
m_result_err{ERR_BACKEND_NO_ERR} {}
void session_begin(QofSession*, const char*, bool, bool, bool) override {
m_last_call = "session_begin";
}
void session_end() override {
m_last_call = "session_end";
}
void load(QofBook*, QofBackendLoadType) override {
m_last_call = "load";
}
void sync(QofBook*) override {
m_last_call = "sync";
}
void safe_sync(QofBook*) override {
m_last_call = "safe_sync";
}
void rollback(QofInstance*) override {
set_error(m_result_err);
m_last_call = "rollback";
}
void inject_error(QofBackendError err) {
m_result_err = err;
}
std::string m_last_call;
private:
QofBackendError m_result_err;
};
static void
setup (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_book_new ();
TransMockBackend *mbe = new TransMockBackend;
Transaction *txn;
Timespec entered = gnc_dmy2timespec (20, 4, 2012);
Timespec posted = gnc_dmy2timespec (21, 4, 2012);
auto frame = new KvpFrame ();
qof_book_set_backend (book, mbe);
auto split1 = xaccMallocSplit (book);
auto split2 = xaccMallocSplit (book);
txn = xaccMallocTransaction (book);
fixture->txn = txn;
fixture->curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY", "GNR", "", 240);
fixture->comm = gnc_commodity_new (book, "Wildebeest Fund", "FUND", "WBFXX", "", 1000);
fixture->acc1 = xaccMallocAccount (book);
fixture->acc2 = xaccMallocAccount (book);
xaccAccountSetCommodity (fixture->acc1, fixture->comm);
xaccAccountSetCommodity (fixture->acc2, fixture->curr);
txn->date_posted.tv_sec = posted.tv_sec;
txn->date_posted.tv_nsec = posted.tv_nsec;
txn->date_entered.tv_sec = entered.tv_sec;
txn->date_entered.tv_nsec = entered.tv_nsec;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (100000, 1000);
split1->value = gnc_numeric_create (3200, 240);
split2->amount = gnc_numeric_create (-3200, 240);
split2->value = gnc_numeric_create (-3200, 240);
split1->acc = fixture->acc1;
split2->acc = fixture->acc2;
txn->num = static_cast<char*>(CACHE_INSERT ("123"));
txn->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
xaccTransBeginEdit (txn);
{
xaccTransSetCurrency (txn, fixture->curr);
xaccSplitSetParent (split1, txn);
xaccSplitSetParent (split2, txn);
frame->set(trans_notes_str, new KvpValue("Salt pork sausage"));
frame->set_path("/qux/quux/corge", new KvpValue(123.456));
qof_instance_set_slots (QOF_INSTANCE (txn), frame);
}
xaccTransCommitEdit (txn);
xaccAccountSortSplits(fixture->acc1, FALSE);
xaccAccountSortSplits(fixture->acc2, FALSE);
xaccAccountRecomputeBalance(fixture->acc1);
xaccAccountRecomputeBalance(fixture->acc2);
qof_instance_mark_clean (QOF_INSTANCE (split1));
qof_instance_mark_clean (QOF_INSTANCE (split2));
qof_instance_mark_clean (QOF_INSTANCE (txn));
fixture->func = _utest_trans_fill_functions();
fixture->hdlrs = NULL;
}
static void
setup_with_gains (GainsFixture *fixture, gconstpointer pData)
{
QofBook *book;
Fixture *base = &(fixture->base);
setup (base, NULL);
book = qof_instance_get_book (QOF_INSTANCE (base->txn));
fixture->gains_txn = xaccMallocTransaction (book);
fixture->gains_acc = xaccMallocAccount (book);
xaccAccountSetCommodity (fixture->gains_acc, base->curr);
auto gains_split1 = xaccMallocSplit (book);
auto gains_split2 = xaccMallocSplit (book);
gains_split1->acc = base->acc1;
gains_split2->acc = fixture->gains_acc;
gains_split1->amount = gnc_numeric_create (30, 240);
gains_split1->value = gnc_numeric_create (30, 240);
gains_split2->amount = gnc_numeric_create (-30, 240);
gains_split2->value = gnc_numeric_create (-30, 240);
xaccTransBeginEdit (fixture->gains_txn);
{
xaccTransSetCurrency (fixture->gains_txn, base->curr);
xaccSplitSetParent (gains_split1, fixture->gains_txn);
xaccSplitSetParent (gains_split2, fixture->gains_txn);
}
xaccTransCommitEdit (fixture->gains_txn);
auto base_split = static_cast<Split*>(g_list_nth_data (base->txn->splits, 1));
base_split->gains_split = gains_split1;
}
/* Add a log handler to the handlers list to be cleared at teardown */
static void
teardown (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto mbe = static_cast<TransMockBackend*>(qof_book_get_backend (book));
test_destroy (fixture->txn);
test_destroy (fixture->acc1);
test_destroy (fixture->acc2);
test_destroy (fixture->curr);
test_destroy (fixture->comm);
delete mbe;
qof_book_destroy(book);
g_slist_free_full (fixture->hdlrs, test_free_log_handler);
test_clear_error_list();
}
static void
teardown_with_gains (GainsFixture *fixture, gconstpointer pData)
{
Fixture *base = &(fixture->base);
test_destroy (fixture->gains_acc);
teardown (base, NULL);
}
/* check_open
void check_open (const Transaction *trans)// Local: 1:0:0
*/
static void
test_check_open (Fixture *fixture, gconstpointer pData)
{
auto msg = g_strdup_printf ("[check_open()] transaction %p not open for editing", fixture->txn);
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL |
G_LOG_FLAG_FATAL);
auto check = test_error_struct_new ("gnc.engine", loglevel, msg);
g_free (msg);
fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
(GLogFunc)test_checked_handler);
check_open (fixture->txn);
g_assert_cmpint (check->hits, ==, 1);
xaccTransBeginEdit (fixture->txn);
check_open (fixture->txn);
g_assert_cmpint (check->hits, ==, 1);
/* Don't commit the edit, there's nothing to balance! */
xaccTransRollbackEdit (fixture->txn);
}
/* xaccTransStillHasSplit
gboolean
xaccTransStillHasSplit(const Transaction *trans, const Split *s)// C: 8 in 3 Local: 7:0:0
*/
static void
test_xaccTransStillHasSplit (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split = xaccMallocSplit (book);
g_assert (!xaccTransStillHasSplit (fixture->txn, split));
xaccSplitSetParent (split, fixture->txn);
g_assert (xaccTransStillHasSplit (fixture->txn, split));
qof_instance_set_destroying (split, TRUE);
g_assert (!xaccTransStillHasSplit (fixture->txn, split));
qof_instance_set_destroying (split, FALSE);
g_assert (xaccTransStillHasSplit (fixture->txn, split));
xaccSplitSetParent (split, NULL);
g_assert (!xaccTransStillHasSplit (fixture->txn, split));
test_destroy (split);
}
// Make Static
/* mark_trans
void mark_trans (Transaction *trans)// Local: 3:0:0
*/
#define check_split_dirty(xsplit, test) \
{ \
gboolean sort_dirty, balance_dirty; \
auto split = xsplit; \
g_object_get (split->acc, \
"sort-dirty", &sort_dirty, \
"balance-dirty", &balance_dirty, \
NULL); \
g_assert_cmpint (sort_dirty, ==, test); \
g_assert_cmpint (balance_dirty, ==, test); \
}
static void
test_mark_trans (Fixture *fixture, gconstpointer pData)
{
gboolean dirty_split = FALSE;
GList *splits = NULL;
for (splits = (fixture->txn)->splits; splits; splits = splits->next)
{
if (!splits->data) continue;
g_assert (!qof_instance_get_dirty_flag (splits->data));
check_split_dirty (static_cast<Split*>(splits->data), FALSE);
}
fixture->func->mark_trans (fixture->txn);
g_assert (!qof_instance_get_dirty_flag (fixture->txn));
for (splits = (fixture->txn)->splits; splits; splits = splits->next)
{
if (!splits->data) continue;
g_assert (!qof_instance_get_dirty_flag (splits->data));
check_split_dirty (static_cast<Split*>(splits->data), TRUE);
}
}
/* gen_event_trans
void gen_event_trans (Transaction *trans)// Local: 2:0:0
*/
static void
test_gen_event_trans (Fixture *fixture, gconstpointer pData)
{
auto split = static_cast<Split*>(fixture->txn->splits->data);
GNCLot *lot = gnc_lot_new (qof_instance_get_book (QOF_INSTANCE (fixture->txn)));
TestSignal sig1 = test_signal_new (QOF_INSTANCE (fixture->acc1),
GNC_EVENT_ITEM_CHANGED, split);
TestSignal sig2 = test_signal_new (QOF_INSTANCE (lot),
QOF_EVENT_MODIFY, NULL);
gnc_lot_add_split (lot, split);
test_signal_assert_hits (sig1, 1);
test_signal_assert_hits (sig2, 3);
fixture->func->gen_event_trans (fixture->txn);
test_signal_assert_hits (sig1, 2);
test_signal_assert_hits (sig2, 4);
test_signal_free (sig1);
test_signal_free (sig2);
test_destroy (lot);
}
/* gnc_transaction_init
G_DEFINE_TYPE(Transaction, gnc_transaction, QOF_TYPE_INSTANCE)
static void
gnc_transaction_init(Transaction* trans)*/
static void
test_gnc_transaction_init ()
{
auto txn = static_cast<Transaction*>(g_object_new (GNC_TYPE_TRANSACTION, NULL));
g_assert_cmpstr (txn->num, ==, "");
g_assert_cmpstr (txn->description, ==, "");
g_assert (txn->common_currency == NULL);
g_assert (txn->splits == NULL);
g_assert_cmpint (txn->date_entered.tv_sec, ==, 0);
g_assert_cmpint (txn->date_entered.tv_nsec, ==, 0);
g_assert_cmpint (txn->date_posted.tv_sec, ==, 0);
g_assert_cmpint (txn->date_posted.tv_nsec, ==, 0);
g_assert_cmpint (txn->marker, ==, 0);
g_assert (txn->orig == NULL);
test_destroy (txn);
}
/* gnc_transaction_dispose
static void
gnc_transaction_dispose(GObject *txnp)*/
static void
test_gnc_transaction_dispose ()
{
QofBook *book = qof_book_new ();
auto txn = static_cast<Transaction*>(g_object_new (GNC_TYPE_TRANSACTION, "book", book, NULL));
auto split = static_cast<Split*>(g_object_new (GNC_TYPE_SPLIT, "book", book, NULL));
auto s_ref = split;
gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY",
"GNR", "", 240), *t_curr = NULL;
gnc_commodity *c_ref = curr;
g_object_add_weak_pointer (G_OBJECT (split), (gpointer*) &s_ref);
g_object_add_weak_pointer (G_OBJECT (curr), (gpointer*) &c_ref);
txn->splits = g_list_append (txn->splits, split);
txn->common_currency = curr;
g_assert (txn->splits != NULL);
g_assert (s_ref != NULL);
g_assert (c_ref != NULL);
g_object_run_dispose (G_OBJECT (txn));
/* If gnc_transaction_dispose was written correctly, txn->splits and
* txn->curr would be null and all of the splits would be destroyed,
* so all of these would be equal instead of unequal.
*/
g_assert (txn->splits != NULL);
g_assert (txn->common_currency != NULL);
g_assert (s_ref != NULL);
g_assert (c_ref != NULL);
/* And these would be unnecessary -- in fact, they would assert */
test_destroy (split);
test_destroy (curr);
test_destroy (txn);
qof_book_destroy (book);
}
/* gnc_transaction_finalize
static void
gnc_transaction_finalize(GObject* txnp)*/
static void
test_gnc_transaction_finalize ()
{
auto txn = static_cast<Transaction*>(g_object_new (GNC_TYPE_TRANSACTION, NULL));
test_destroy (txn);
}
/* gnc_transaction_get_property
* gnc_transaction_set_property
static void
gnc_transaction_set_property(GObject* object,*/
static void
test_gnc_transaction_set_get_property (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_book_new ();
auto txn = static_cast<Transaction*>(g_object_new (GNC_TYPE_TRANSACTION, "book", book, NULL));
auto num = "42", desc = "The Answer";
gchar *t_num = NULL, *t_desc = NULL;
gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY",
"GNR", "", 240), *t_curr = NULL;
Timespec now = timespec_now (), *t_entered = NULL, *t_posted = NULL;
g_assert_cmpstr (txn->num, ==, "");
g_assert_cmpstr (txn->description, ==, "");
g_assert (txn->common_currency == NULL);
g_assert_cmpint (txn->date_entered.tv_sec, ==, 0);
g_assert_cmpint (txn->date_entered.tv_nsec, ==, 0);
g_assert_cmpint (txn->date_posted.tv_sec, ==, 0);
g_assert_cmpint (txn->date_posted.tv_nsec, ==, 0);
/* Kick up the edit counter to keep from committing */
xaccTransBeginEdit (txn);
g_object_set (G_OBJECT (txn),
"num", num,
"description", desc,
"currency", curr,
"post-date", &now,
"enter-date", &now,
NULL);
g_assert_cmpstr (txn->num, ==, num);
g_assert_cmpstr (txn->description, ==, desc);
g_assert (txn->common_currency == curr);
g_assert (timespec_equal (&(txn->date_entered), &now));
g_assert (timespec_equal (&(txn->date_posted), &now));
g_object_get (G_OBJECT (txn),
"num", &t_num,
"description", &t_desc,
"currency", &t_curr,
"post-date", &t_posted,
"enter-date", &t_entered,
NULL);
g_assert_cmpstr (t_num, ==, num);
g_assert_cmpstr (t_desc, ==, desc);
g_assert (t_curr == curr);
g_assert (timespec_equal (t_entered, &now));
g_assert (timespec_equal (t_posted, &now));
xaccTransRollbackEdit (txn);
test_destroy (txn);
test_destroy (curr);
qof_book_destroy (book);
g_free (t_entered);
}
/* gnc_transaction_class_init
* xaccInitTransaction
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.
*/
static void
test_xaccMallocTransaction (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_book_new ();
TestSignal sig1 = test_signal_new (NULL, QOF_EVENT_CREATE,NULL);
Transaction *txn;
#ifdef USE_CLANG_FUNC_SIG
#define _func "Transaction *xaccMallocTransaction(QofBook *)"
#else
#define _func "xaccMallocTransaction"
#endif
auto msg = _func ": assertion 'book' failed";
#undef _func
auto logdomain = "gnc.engine";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
auto check = test_error_struct_new ("gnc.engine", loglevel, msg);
fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
(GLogFunc)test_checked_handler);
test_signal_assert_hits (sig1, 0);
txn = xaccMallocTransaction (NULL);
g_assert (txn == NULL);
g_assert_cmpint (check->hits, ==, 1);
test_signal_assert_hits (sig1, 0);
txn = xaccMallocTransaction (book);
g_assert (txn != NULL);
g_assert_cmpint (check->hits, ==, 1);
test_signal_assert_hits (sig1, 1);
test_destroy (txn);
qof_book_destroy (book);
test_signal_free (sig1);
}
/* xaccTransSortSplits
void
xaccTransSortSplits (Transaction *trans)// Local: 1:0:0
*/
static void
test_xaccTransSortSplits (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
auto split1 = static_cast<Split*>(txn->splits->data);
auto split2 = static_cast<Split*>(txn->splits->next->data);
Split *split[3];
guint i;
GList *node;
gnc_numeric values[3];
values[0] = gnc_numeric_create (100, 240);
values[1] = gnc_numeric_create (75, 240);
values[2] = gnc_numeric_create (-125, 240);
/* Prevent xaccTransCommitEdit in xaccSplitSetParent from doing anything */
xaccTransBeginEdit (txn);
for (i = 0; i < G_N_ELEMENTS (split); i++)
{
split[i] = xaccMallocSplit (book);
split[i]->value = values[i];
split[i]->acc = fixture->acc1;
xaccSplitSetParent (split[i], txn);
}
node = txn->splits;
g_assert (node->data == split1);
node = g_list_next (node);
g_assert (node->data == split2);
node = g_list_next (node);
g_assert (node->data == split[0]);
node = g_list_next (node);
g_assert (node->data == split[1]);
node = g_list_next (node);
g_assert (node->data == split[2]);
xaccTransSortSplits (txn);
node = txn->splits;
g_assert (node->data == split1);
node = g_list_next (node);
g_assert (node->data == split[0]);
node = g_list_next (node);
g_assert (node->data == split[1]);
node = g_list_next (node);
g_assert (node->data == split2);
node = g_list_next (node);
g_assert (node->data == split[2]);
xaccTransCommitEdit (txn);
}
/* dupe_trans
static Transaction *
dupe_trans (const Transaction *from)// Local: 1:0:0
*/
static void
test_dupe_trans (Fixture *fixture, gconstpointer pData)
{
Timespec posted = gnc_dmy2timespec (12, 7, 2011);
Timespec entered = gnc_dmy2timespec (14, 7, 2011);
Transaction *newtxn = NULL, *oldtxn = fixture->txn;
QofBook *old_book = qof_instance_get_book (QOF_INSTANCE (oldtxn));
GList *newnode, *oldnode = oldtxn->splits;
oldtxn->date_posted = posted;
oldtxn->date_entered = entered;
oldtxn->inst.kvp_data->set("/foo/bar/baz",
new KvpValue("The Great Waldo Pepper"));
newtxn = fixture->func->dupe_trans (oldtxn);
g_assert_cmpstr (newtxn->num, ==, oldtxn->num);
g_assert_cmpstr (newtxn->description, ==, oldtxn->description);
for (newnode = newtxn->splits; newnode && oldnode;
newnode = g_list_next (newnode))
{
g_assert (xaccSplitEqual (static_cast<Split*>(newnode->data),
static_cast<Split*>(oldnode->data),
TRUE, FALSE, TRUE));
oldnode = g_list_next (oldnode);
}
g_assert (newnode == NULL);
g_assert (oldnode == NULL);
g_assert (timespec_equal (&(newtxn->date_posted), &posted));
g_assert (timespec_equal (&(newtxn->date_entered), &entered));
g_assert (qof_instance_version_cmp (QOF_INSTANCE (newtxn),
QOF_INSTANCE (oldtxn)) == 0);
g_assert (newtxn->orig == NULL);
g_assert (newtxn->common_currency == fixture->curr);
g_assert (newtxn->inst.e_type == NULL);
g_assert (guid_equal (qof_instance_get_guid (QOF_INSTANCE (newtxn)),
guid_null ()));
g_assert (qof_instance_get_book (QOF_INSTANCE (newtxn)) == old_book);
g_assert (compare (oldtxn->inst.kvp_data, newtxn->inst.kvp_data) == 0);
test_destroy (newtxn);
}
/* xaccTransClone
Transaction *
xaccTransClone (const Transaction *from)// C: 1 Local: 1:0:0
*/
static void
test_xaccTransClone (Fixture *fixture, gconstpointer pData)
{
Timespec posted = gnc_dmy2timespec (12, 7, 2011);
Timespec entered = gnc_dmy2timespec (14, 7, 2011);
Transaction *newtxn = NULL, *oldtxn = fixture->txn;
QofBook *old_book = qof_instance_get_book (QOF_INSTANCE (oldtxn));
GList *newnode, *oldnode;
int foo, bar;
oldtxn->date_posted = posted;
oldtxn->date_entered = entered;
newtxn = xaccTransClone (oldtxn);
g_assert_cmpstr (newtxn->num, ==, oldtxn->num);
g_assert_cmpstr (newtxn->description, ==, oldtxn->description);
g_assert_cmpint (xaccTransCountSplits (oldtxn), ==,
xaccTransCountSplits (newtxn));
xaccTransSortSplits (newtxn);
xaccTransSortSplits (oldtxn);
oldnode = oldtxn->splits;
for (newnode = newtxn->splits; newnode && oldnode;
newnode = g_list_next (newnode))
{
g_assert (xaccSplitEqual (static_cast<Split*>(newnode->data),
static_cast<Split*>(oldnode->data),
FALSE, FALSE, FALSE));
oldnode = g_list_next (oldnode);
}
g_assert (newnode == NULL);
g_assert (oldnode == NULL);
g_assert (timespec_equal (&(newtxn->date_posted), &posted));
g_assert (timespec_equal (&(newtxn->date_entered), &entered));
g_assert (qof_instance_version_cmp (QOF_INSTANCE (newtxn),
QOF_INSTANCE (oldtxn)) == 0);
g_assert_cmpint (qof_instance_get_version_check (newtxn), ==,
qof_instance_get_version_check (oldtxn));
g_assert (newtxn->orig == NULL);
g_assert (newtxn->common_currency == fixture->curr);
g_assert (qof_instance_get_book (QOF_INSTANCE (newtxn)) == old_book);
g_assert (compare (oldtxn->inst.kvp_data, newtxn->inst.kvp_data) == 0);
test_destroy (newtxn);
}
/* xaccTransCopyOnto
void
xaccTransCopyOnto (const Transaction *from_trans, Transaction *to_trans)//Register 2
convenience function for xaccTransCopyFromClipboard (from_trans, to_trans, NULL, NULL, TRUE)
*/
/* xaccTransCopyFromClipboard
void
xaccTransCopyFromClipboard (const Transaction *from_trans,
Transaction *to_trans,
const Account *from_acc,
Account *to_acc, gboolean no_date) // Register 2
*/
static void
test_xaccTransCopyFromClipBoard (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
Account *acc1 = xaccMallocAccount (book);
Transaction *to_txn = xaccMallocTransaction (book);
Timespec now = timespec_now();
Timespec never = {0, 0};
auto to_frame = to_txn->inst.kvp_data;
xaccAccountSetCommodity (acc1, fixture->comm);
xaccTransCopyFromClipBoard (txn, to_txn, fixture->acc1, acc1, FALSE);
g_assert (gnc_commodity_equal (txn->common_currency,
to_txn->common_currency));
g_assert (timespec_equal (&(to_txn->date_entered), &now));
g_assert (timespec_equal (&(to_txn->date_posted), &txn->date_posted));
g_assert_cmpstr (txn->num, ==, to_txn->num);
/* Notes also tests that KVP is copied */
g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
g_assert_cmpstr (xaccTransGetDescription (txn), ==,
xaccTransGetDescription (to_txn));
g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
g_assert_cmpint (xaccTransCountSplits (txn), ==,
xaccTransCountSplits (to_txn));
}
static void
test_xaccTransCopyFromClipBoard_no_start (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
Account *acc1 = xaccMallocAccount (book);
Transaction *to_txn = xaccMallocTransaction (book);
Timespec now = timespec_now();
Timespec never = {0, 0};
xaccAccountSetCommodity (acc1, fixture->comm);
xaccTransCopyFromClipBoard (txn, to_txn, fixture->acc1, acc1, TRUE);
g_assert (gnc_commodity_equal (txn->common_currency,
to_txn->common_currency));
g_assert (timespec_equal (&(to_txn->date_entered), &now));
g_assert (timespec_equal (&(to_txn->date_posted), &never));
g_assert_cmpstr (to_txn->num, ==, txn->num);
/* Notes also tests that KVP is copied */
g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
g_assert_cmpstr (xaccTransGetDescription (txn), ==,
xaccTransGetDescription (to_txn));
g_assert_cmpstr (xaccTransGetNotes (txn), ==, xaccTransGetNotes (to_txn));
g_assert_cmpint (xaccTransCountSplits (txn), ==,
xaccTransCountSplits (to_txn));
}
/* xaccFreeTransaction
static void
xaccFreeTransaction (Transaction *trans)// Local: 4:0:0
*/
static void
test_xaccFreeTransaction (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
Transaction *orig = xaccMallocTransaction (qof_instance_get_book (QOF_INSTANCE (txn)));
auto split = static_cast<Split*>(txn->splits->data);
auto txn_num = "321";
g_object_add_weak_pointer (G_OBJECT (txn->splits->data),
reinterpret_cast<void**>(&split));
/* so the "free" doesn't, leaving the structure for us to test */
g_object_ref (txn);
g_object_ref (orig);
orig->num = static_cast<char*>(CACHE_INSERT (txn_num));
txn->orig = orig;
fixture->func->xaccFreeTransaction (txn);
g_assert (split == NULL);
g_assert (txn->splits == NULL);
g_assert_cmpint (GPOINTER_TO_INT(txn->num), ==, 1);
g_assert (txn->description == NULL);
g_assert_cmpint (txn->date_entered.tv_sec, ==, 0);
g_assert_cmpint (txn->date_entered.tv_nsec, ==, 0);
g_assert_cmpint (txn->date_posted.tv_sec, ==, 0);
g_assert_cmpint (txn->date_posted.tv_nsec, ==, 0);
g_assert_cmpint (GPOINTER_TO_INT(orig->num), ==, 1);
g_assert (txn->orig == NULL);
test_destroy (orig);
g_test_log_set_fatal_handler ((GTestLogFatalFunc) test_log_handler, NULL);
}
/* compare_split_guids
static gint
compare_split_guids (gconstpointer a, gconstpointer b)// Local: 0:1:0
Pass-through function, test with TransEqual
*/
/* xaccTransEqual
gboolean
xaccTransEqual(const Transaction *ta, const Transaction *tb,// C: 2 in 2 Local: 0:0:0
*/
#define DATE_BUF_SIZE 100
static void
test_xaccTransEqual (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
QofBook *book2 = qof_book_new ();
Transaction *txn0 = fixture->txn;
Transaction *clone = xaccTransClone (txn0);
Transaction *txn1 = xaccTransClone (txn0);
const GncGUID *guid_f_txn = qof_instance_get_guid (txn0);
gchar entered[DATE_BUF_SIZE], posted[DATE_BUF_SIZE];
auto msg1 = "[xaccTransEqual] one is NULL";
gchar *msg2 = NULL;
auto cleanup_fmt = "[trans_cleanup_commit] get rid of rollback trans=%p";
gchar split_guid0[GUID_ENCODING_LENGTH + 1];
gchar split_guid1[GUID_ENCODING_LENGTH + 1];
auto logdomain = "gnc.engine";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_INFO);
auto check = test_error_struct_new (logdomain, loglevel, msg1);
auto check2 = test_error_struct_new(logdomain, loglevel, msg2);
auto check3 = test_error_struct_new(logdomain, loglevel, "");
auto cleanup = test_error_struct_new (logdomain, loglevel, "");
auto split0 = xaccTransGetSplit (txn0, 0);
test_add_error (check);
test_add_error (check2);
test_add_error (cleanup);
fixture->hdlrs = test_log_set_handler (fixture->hdlrs, check,
(GLogFunc)test_list_handler);
/* Booleans are check_guids, check_splits, check_balances, assume_ordered */
g_assert (xaccTransEqual (NULL, NULL, TRUE, TRUE, TRUE, TRUE));
g_assert (!xaccTransEqual (txn0, NULL, TRUE, TRUE, TRUE, TRUE));
g_assert (!xaccTransEqual (NULL, txn0, TRUE, TRUE, TRUE, TRUE));
g_assert (xaccTransEqual (txn0, txn0, TRUE, TRUE, TRUE, TRUE));
qof_instance_set_book (txn1, book2);
qof_instance_set_guid (txn1, guid_f_txn);
g_assert_cmpint (check->hits, ==, 2);
check->hits = 0;
g_assert_cmpint (xaccTransCountSplits (txn0), ==,
xaccTransCountSplits (txn1));
g_free (check->msg);
check->msg = g_strdup ("[xaccTransEqual] GUIDs differ");
g_assert (!xaccTransEqual (clone, txn0, TRUE, TRUE, TRUE, TRUE));
qof_instance_set_guid (clone, guid_f_txn);
g_assert (xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 1);
xaccTransBeginEdit (clone);
cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
/* This changes the amount and value of the first split */
xaccTransSetCurrency (clone, fixture->comm);
xaccTransCommitEdit (clone);
g_free (cleanup->msg);
g_free (check->msg);
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));
g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 2);
gnc_timespec_to_iso8601_buff (clone->date_posted, posted);
gnc_timespec_to_iso8601_buff (clone->date_entered, entered);
xaccTransBeginEdit (clone);
cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
/* This puts the value of the first split back, but leaves the amount changed */
xaccTransSetCurrency (clone, fixture->curr);
clone->date_posted.tv_sec = txn0->date_entered.tv_sec;
xaccTransCommitEdit (clone);
g_free (cleanup->msg);
g_free (check->msg);
check->msg = g_strdup_printf ("[xaccTransEqual] date posted differs: '%s' vs '%s'", entered, posted);
g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 3);
xaccTransBeginEdit (clone);
cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
clone->date_posted.tv_sec = txn0->date_posted.tv_sec;
clone->date_entered.tv_sec = txn0->date_posted.tv_sec;
xaccTransCommitEdit (clone);
g_free (cleanup->msg);
g_free (check->msg);
check->msg = g_strdup_printf ("[xaccTransEqual] date entered differs: '%s' vs '%s'", posted, entered);
g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 4);
xaccTransBeginEdit (clone);
cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
clone->date_entered.tv_sec = txn0->date_entered.tv_sec;
clone->num = g_strdup("123");
xaccTransCommitEdit (clone);
g_free (cleanup->msg);
g_free (check->msg);
check->msg = g_strdup ("[xaccTransEqual] num differs: 123 vs 123");
g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 5);
g_assert (xaccTransEqual (txn1, clone, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 5);
txn1->num = g_strdup("321");
g_free (check->msg);
check->msg = g_strdup ("[xaccTransEqual] num differs: 321 vs 123");
g_assert (!xaccTransEqual (txn1, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 6);
g_free(clone->num);
clone->num = static_cast<char*>(CACHE_INSERT("123"));
g_free(txn1->num);
txn1->num = g_strdup("123");
clone->description = g_strdup("salt pork");
g_free (check->msg);
check->msg = g_strdup ("[xaccTransEqual] descriptions differ: salt pork vs Waldo Pepper");
g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 7);
g_assert (xaccTransEqual (txn1, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 7);
g_assert (!xaccTransEqual (clone, txn1, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 8);
xaccTransBeginEdit (clone);
cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
g_free(clone->description);
clone->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
auto frame = qof_instance_get_slots (QOF_INSTANCE (clone));
frame->set("/qux/quux/corge", new KvpValue(654.321));
xaccTransCommitEdit (clone);
g_free (cleanup->msg);
g_free (check->msg);
check->msg = g_strdup ("[xaccTransEqual] kvp frames differ:\nnotes/Salt pork sausage (char *)\nqux/quux/corge/654.321 (double)\n\n\n\n\nvs\n\nnotes/Salt pork sausage (char *)\nqux/quux/corge/123.456 (double)\n\n\n");
g_assert (!xaccTransEqual (clone, txn0, TRUE, FALSE, TRUE, TRUE));
g_assert_cmpint (check->hits, ==, 9);
xaccTransBeginEdit (clone);
cleanup->msg = g_strdup_printf (cleanup_fmt, clone->orig);
clone->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
frame->set("/qux/quux/corge", new KvpValue(123.456));
xaccTransCommitEdit (clone);
g_free (cleanup->msg);
g_free (check->msg);
check->msg = g_strdup ("[xaccSplitEqual] GUIDs differ");
auto split1 = xaccTransGetSplit (clone, 0);
guid_to_string_buff (qof_instance_get_guid (split0), split_guid0);
guid_to_string_buff (qof_instance_get_guid (split1), split_guid1);
check2->msg = g_strdup_printf (
"[xaccTransEqual] splits %s and %s differ", split_guid1, split_guid0);
g_assert (!xaccTransEqual (clone, txn0, TRUE, TRUE, TRUE, TRUE));
g_assert (xaccTransEqual (clone, txn0, FALSE, FALSE, FALSE, TRUE));
g_assert_cmpint (check->hits, ==, 10);
g_assert_cmpint (check2->hits, ==, 1);
g_free (check->msg);
g_free (check2->msg);
check2->msg = g_strdup_printf (
"[xaccTransEqual] splits %s and %s differ", split_guid0, split_guid0);
qof_instance_set_guid (split1, qof_instance_get_guid (split0));
g_assert (!xaccTransEqual (clone, txn0, TRUE, TRUE, TRUE, TRUE));
g_assert (xaccTransEqual (clone, txn0, TRUE, FALSE, FALSE, TRUE));
g_assert_cmpint (check->hits, ==, 10);
g_assert_cmpint (check2->hits, ==, 2);
qof_instance_set_guid (xaccTransGetSplit (txn1, 0),
qof_instance_get_guid (split0));
qof_instance_set_guid (xaccTransGetSplit (txn1, 1),
qof_instance_get_guid (xaccTransGetSplit (txn0, 1)));
{
Split* split00 = xaccTransGetSplit (txn0, 0);
Split* split01 = xaccTransGetSplit (txn0, 1);
Split* split10 = xaccTransGetSplit (txn1, 0);
Split* split11 = xaccTransGetSplit (txn1, 1);
auto bal00 = gnc_numeric_to_string (split00->balance);
auto bal01 = gnc_numeric_to_string (split01->balance);
auto bal10 = gnc_numeric_to_string (split10->balance);
auto bal11 = gnc_numeric_to_string (split11->balance);
check->msg = g_strdup_printf("[xaccSplitEqualCheckBal] balances differ: %s vs %s", bal10, bal00);
check3->msg = g_strdup_printf("[xaccSplitEqualCheckBal] balances differ: %s vs %s", bal11, bal01);
test_add_error (check3);
g_assert (!xaccTransEqual (txn1, txn0, TRUE, TRUE, TRUE, TRUE));
g_assert (xaccTransEqual (txn1, txn0, TRUE, TRUE, FALSE, TRUE));
g_assert_cmpint (check->hits, ==, 11);
g_assert_cmpint (check2->hits, ==, 3);
g_assert_cmpint (check3->hits, ==, 0);
split10->balance = split00->balance;
split11->balance = split01->balance;
g_assert (xaccTransEqual (txn1, txn0, TRUE, TRUE, TRUE, TRUE));
}
g_free (check3->msg);
g_free (check2->msg);
}
/* xaccTransUseTradingAccounts
xaccTransUseTradingAccounts
Returns true if the transaction should include trading account splits if
it involves more than one commodity.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)// C: 10 in 7 Local: 2:0:0
Pass-through, no need to test.
*/
/* xaccTransLookup
Transaction *
xaccTransLookup (const GncGUID *guid, QofBook *book)// C: 22 in 7 Local: 1:0:0
*/
static void
test_xaccTransLookup (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
QofInstance *inst = QOF_INSTANCE (txn);
g_assert (xaccTransLookup (qof_instance_get_guid (inst),
qof_instance_get_book (inst)) == txn);
}
/* xaccTransGetImbalanceValue
gnc_numeric
xaccTransGetImbalanceValue (const Transaction * trans)// C: 11 in 5 Local: 1:1:0
*/
static void
test_xaccTransGetImbalanceValue (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split1 = xaccMallocSplit (book);
g_assert (gnc_numeric_equal (xaccTransGetImbalanceValue (fixture->txn),
gnc_numeric_zero ()));
split1->acc = fixture->acc1;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (100000, 1000);
split1->value = gnc_numeric_create (3200, 240);
xaccTransBeginEdit (fixture->txn);
xaccSplitSetParent (split1, fixture->txn);
g_assert (gnc_numeric_equal (xaccTransGetImbalanceValue (fixture->txn),
split1->value));
xaccTransCommitEdit (fixture->txn);
}
/* xaccTransGetImbalance
MonetaryList *
xaccTransGetImbalance (const Transaction * trans)// C: 15 in 6 Local: 1:0:0
*/
static void
test_xaccTransGetImbalance (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split1 = xaccMallocSplit (book);
MonetaryList *mlist;
g_assert (xaccTransGetImbalance (NULL) == NULL);
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 0);
split1->acc = fixture->acc1;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (100000, 1000);
split1->value = gnc_numeric_create (3200, 240);
xaccTransBeginEdit (fixture->txn);
xaccSplitSetParent (split1, fixture->txn);
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 1);
xaccTransCommitEdit (fixture->txn);
gnc_monetary_list_free (mlist);
}
static void
test_xaccTransGetImbalance_trading (Fixture *fixture,
gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split1 = xaccMallocSplit (book);
auto split2 = xaccMallocSplit (book);
Account *acc1 = xaccMallocAccount (book);
Account *acc2 = xaccMallocAccount (book);
gnc_numeric value;
MonetaryList *mlist;
qof_book_begin_edit (book);
qof_instance_set (QOF_INSTANCE (book),
"trading-accts", "t",
NULL);
qof_book_commit_edit (book);
/* Without trading splits, the list is unbalanced */
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 2);
gnc_monetary_list_free (mlist);
xaccAccountSetCommodity (acc1, fixture->comm);
xaccAccountSetCommodity (acc2, fixture->curr);
xaccAccountSetType (acc1, ACCT_TYPE_TRADING);
xaccAccountSetType (acc2, ACCT_TYPE_TRADING);
/* The setup transaction is unbalanced in a trading-accounts environment. */
g_assert (!xaccTransIsBalanced (fixture->txn));
/* Make it look like a proper trading accounts transactionm */
split1->acc = acc1;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (-10000, 100);
split1->value = gnc_numeric_create (-3200, 240);
split2->acc = acc2;
split2->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split2->action = static_cast<char*>(CACHE_INSERT ("bar"));
split2->amount = gnc_numeric_create (3000, 240);
split2->value = gnc_numeric_create (3200, 240);
xaccTransBeginEdit (fixture->txn);
xaccSplitSetParent (split1, fixture->txn);
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 1);
gnc_monetary_list_free (mlist);
xaccSplitSetParent (split2, fixture->txn);
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 1);
gnc_monetary_list_free (mlist);
split2->amount = gnc_numeric_create (3000, 240);
split2->value = gnc_numeric_create (3000, 240);
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 1);
gnc_monetary_list_free (mlist);
split2->amount = gnc_numeric_create (3200, 240);
split2->value = gnc_numeric_create (3200, 240);
mlist = xaccTransGetImbalance (fixture->txn);
g_assert_cmpint (g_list_length (mlist), ==, 0);
gnc_monetary_list_free (mlist);
xaccTransCommitEdit (fixture->txn);
test_destroy (acc1);
test_destroy (acc2);
}
/* xaccTransIsBalanced
gboolean
xaccTransIsBalanced (const Transaction *trans)// C: 4 in 4 Local: 1:0:0
*/
static void
test_xaccTransIsBalanced (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split1 = xaccMallocSplit (book);
g_assert (!xaccTransIsBalanced (NULL));
g_assert (xaccTransIsBalanced (fixture->txn));
split1->acc = fixture->acc1;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (100000, 1000);
split1->value = gnc_numeric_create (3200, 240);
xaccTransBeginEdit (fixture->txn);
xaccSplitSetParent (split1, fixture->txn);
g_assert (! xaccTransIsBalanced (fixture->txn));
xaccTransCommitEdit (fixture->txn);
}
static void
test_xaccTransIsBalanced_trading (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split1 = xaccMallocSplit (book);
auto split2 = xaccMallocSplit (book);
Account *acc1 = xaccMallocAccount (book);
Account *acc2 = xaccMallocAccount (book);
qof_book_begin_edit (book);
qof_instance_set (QOF_INSTANCE (book),
"trading-accts", "t",
NULL);
qof_book_commit_edit (book);
xaccAccountSetCommodity (acc1, fixture->curr);
xaccAccountSetCommodity (acc2, fixture->comm);
xaccAccountSetType (acc1, ACCT_TYPE_TRADING);
xaccAccountSetType (acc2, ACCT_TYPE_TRADING);
/* The setup transaction is unbalanced in a trading-accounts environment. */
g_assert (!xaccTransIsBalanced (fixture->txn));
split1->acc = acc1;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (3200, 240);
split1->value = gnc_numeric_create (3200, 240);
split2->acc = acc2;
split2->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split2->action = static_cast<char*>(CACHE_INSERT ("bar"));
split2->amount = gnc_numeric_create (-10000, 100);
split2->value = gnc_numeric_create (-3000, 240);
xaccTransBeginEdit (fixture->txn);
xaccSplitSetParent (split1, fixture->txn);
g_assert (!xaccTransIsBalanced (fixture->txn));
xaccSplitSetParent (split2, fixture->txn);
g_assert (!xaccTransIsBalanced (fixture->txn));
split2->amount = gnc_numeric_create (-11000, 100);
split2->value = gnc_numeric_create (-3200, 240);
g_assert (!xaccTransIsBalanced (fixture->txn));
split2->amount = gnc_numeric_create (-10000, 100);
split2->value = gnc_numeric_create (-3200, 240);
g_assert (xaccTransIsBalanced (fixture->txn));
xaccTransRollbackEdit (fixture->txn);
test_destroy (acc2);
test_destroy (acc1);
}
/* xaccTransGetAccountValue
gnc_numeric
xaccTransGetAccountValue (const Transaction *trans,// SCM: 6 in 6 Local: 0:0:0
*/
static void
test_xaccTransGetAccountValue (Fixture *fixture, gconstpointer pData)
{
gnc_numeric val1 = {3200, 240}, val2 = {-3200, 240};
g_assert (gnc_numeric_zero_p (xaccTransGetAccountValue (fixture->txn, NULL)));
g_assert (gnc_numeric_zero_p (xaccTransGetAccountValue (NULL, fixture->acc1)));
g_assert (gnc_numeric_eq (xaccTransGetAccountValue (fixture->txn, fixture->acc1), val1));
g_assert (gnc_numeric_eq (xaccTransGetAccountValue (fixture->txn, fixture->acc2), val2));
}
/* xaccTransGetAccountAmount
gnc_numeric
xaccTransGetAccountAmount (const Transaction *trans, const Account *acc)// C: 2 in 1 Local: 0:0:0
*/
static void
test_xaccTransGetAccountAmount (Fixture *fixture, gconstpointer pData)
{
gnc_numeric amt1 = {100000, 1000}, amt2 = {-3200, 240};
g_assert (gnc_numeric_zero_p (xaccTransGetAccountAmount (fixture->txn, NULL)));
g_assert (gnc_numeric_zero_p (xaccTransGetAccountAmount (NULL, fixture->acc1)));
g_assert (gnc_numeric_eq (xaccTransGetAccountAmount (fixture->txn, fixture->acc1), amt1));
g_assert (gnc_numeric_eq (xaccTransGetAccountAmount (fixture->txn, fixture->acc2), amt2));
}
/* xaccTransGetRateForCommodity
gboolean
xaccTransGetRateForCommodity(const Transaction *trans,
const gnc_commodity *split_com,
const Split *split, gnc_numeric *rate)
*/
static void
test_xaccTransGetRateForCommodity (Fixture *fixture, gconstpointer pData)
{
gnc_numeric rate = gnc_numeric_zero ();
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto split0 = xaccMallocSplit (book);
auto split1 = xaccTransFindSplitByAccount(fixture->txn, fixture->acc1);
g_assert (!xaccTransGetRateForCommodity (NULL, fixture->comm,
split0, &rate));
g_assert (!xaccTransGetRateForCommodity (fixture->txn, NULL,
split0, &rate));
g_assert (!xaccTransGetRateForCommodity (fixture->txn, fixture->comm,
NULL, &rate));
g_assert (xaccTransGetRateForCommodity (fixture->txn, fixture->curr,
split0, &rate));
g_assert (gnc_numeric_equal (rate, gnc_numeric_create (1, 1)));
rate = gnc_numeric_zero ();
g_assert (!xaccTransGetRateForCommodity (fixture->txn, fixture->comm,
split0, &rate));
g_assert (gnc_numeric_zero_p (rate));
g_assert (xaccTransGetRateForCommodity (fixture->txn, fixture->comm,
split1, &rate));
g_assert (gnc_numeric_equal (rate, gnc_numeric_create (1800, 240)));
}
/* xaccTransGetAccountConvRate
gnc_numeric
xaccTransGetAccountConvRate(const Transaction *txn, const Account *acc)// C: 5 in 4 Local: 0:0:0
*/
static void
test_xaccTransGetAccountConvRate (Fixture *fixture, gconstpointer pData)
{
auto msg1 = "[xaccTransGetAccountConvRate()] How can amount be nonzero and value be zero?";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL);
auto check = test_error_struct_new ("gnc.engine", loglevel, msg1);
auto split1 = xaccTransFindSplitByAccount(fixture->txn, fixture->acc1);
gnc_numeric rate;
fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
(GLogFunc)test_checked_handler);
g_assert (gnc_numeric_equal (xaccTransGetAccountConvRate (fixture->txn,
fixture->acc2),
gnc_numeric_create (1, 1)));
g_assert (gnc_numeric_equal (xaccTransGetAccountConvRate (fixture->txn,
fixture->acc1),
gnc_numeric_create (1800, 240)));
g_assert_cmpint (check->hits, ==, 0);
split1->value = gnc_numeric_zero();
rate = xaccTransGetAccountConvRate (fixture->txn, fixture->acc1);
g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_OVERFLOW);
g_assert_cmpint (check->hits, ==, 1);
}
/* xaccTransGetAccountBalance
gnc_numeric
xaccTransGetAccountBalance (const Transaction *trans,// C: 1 Local: 0:0:0
*/
static void
test_xaccTransGetAccountBalance (Fixture *fixture, gconstpointer pData)
{
#ifdef USE_CLANG_FUNC_SIG
#define _func "gnc_numeric xaccTransGetAccountBalance(const Transaction *, const Account *)"
#else
#define _func "xaccTransGetAccountBalance"
#endif
auto msg1 = _func ": assertion 'account && trans' failed";
#undef _func
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
auto check = test_error_struct_new ("gnc.engine", loglevel, msg1);
auto split1 = xaccTransFindSplitByAccount(fixture->txn, fixture->acc1);
gnc_numeric rate;
fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
(GLogFunc)test_checked_handler);
rate = xaccTransGetAccountBalance (NULL, fixture->acc1);
g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_ARG);
g_assert_cmpint (check->hits, ==, 1);
rate = xaccTransGetAccountBalance (fixture->txn, NULL);
g_assert_cmpint (gnc_numeric_check (rate), ==, GNC_ERROR_ARG);
g_assert_cmpint (check->hits, ==, 2);
rate = xaccTransGetAccountBalance (fixture->txn, fixture->acc1);
g_assert (gnc_numeric_equal (rate, gnc_numeric_create (100000, 1000)));
g_assert_cmpint (check->hits, ==, 2);
rate = xaccTransGetAccountBalance (fixture->txn, fixture->acc2);
g_assert (gnc_numeric_equal (rate, gnc_numeric_create (-3200, 240)));
g_assert_cmpint (check->hits, ==, 2);
}
/* xaccTransGetCurrency
gnc_commodity *
xaccTransGetCurrency (const Transaction *trans)// C: 33 in 17 SCM: 34 in 26 Local: 2:0:0
Simple Getter. No need to test.
*/
/* xaccTransSetCurrency
void
xaccTransSetCurrency (Transaction *trans, gnc_commodity *curr)// C: 22 in 18 SCM: 3 in 3 Local: 1:0:0
*/
static void
test_xaccTransSetCurrency (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
gnc_commodity *curr = gnc_commodity_new (book, "Japanese Yen", "CURRENCY", "JPY", "¥", 1);
auto split1 = xaccTransFindSplitByAccount (fixture->txn, fixture->acc1);
gnc_numeric old_val = xaccSplitGetValue (split1);
/* Prevent commit in xaccTransSetCurrency() */
xaccTransBeginEdit(fixture->txn);
xaccTransSetCurrency (fixture->txn, curr);
g_assert (fixture->txn->common_currency == curr);
g_assert_cmpint (xaccSplitGetValue (split1).denom, ==,
gnc_commodity_get_fraction (curr));
g_assert_cmpint (xaccSplitGetValue (split1).num, ==,
old_val.num / old_val.denom);
}
/* xaccTransBeginEdit
void
xaccTransBeginEdit (Transaction *trans)// C: 72 in 28 SCM: 5 in 5 Local: 16:0:0
*/
static void
test_xaccTransBeginEdit ()
{
QofBook *book = qof_book_new ();
Transaction *txn = xaccMallocTransaction (book);
Transaction *dupe = NULL;
auto msg1 = "[xaccOpenLog] Attempt to open disabled transaction log";
auto msg2 = "[xaccTransWriteLog] Attempt to write disabled transaction log";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_INFO);
auto logdomain = "gnc.translog";
auto check1 = test_error_struct_new (logdomain, loglevel, msg1);
auto check2 = test_error_struct_new (logdomain, loglevel, msg2);
guint hdlr = g_log_set_handler (logdomain, loglevel,
(GLogFunc)test_list_handler, NULL);
test_add_error (check1);
test_add_error (check2);
g_assert_cmpint (0, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
g_assert (txn->orig == NULL);
xaccTransBeginEdit (txn);
g_assert_cmpint (1, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
dupe = txn->orig;
g_assert (txn->orig != NULL);
g_assert_cmpint (1, ==, check1->hits);
g_assert_cmpint (1, ==, check2->hits);
xaccTransBeginEdit (txn);
g_assert_cmpint (2, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
g_assert (txn->orig == dupe);
g_assert_cmpint (1, ==, check1->hits);
g_assert_cmpint (1, ==, check2->hits);
xaccTransRollbackEdit (txn);
xaccTransRollbackEdit (txn);
g_assert_cmpint (0, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
g_assert (txn->orig == NULL);
qof_book_mark_readonly (book);
xaccTransBeginEdit (txn);
dupe = txn->orig;
g_assert_cmpint (1, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
g_assert (txn->orig == dupe);
g_assert_cmpint (1, ==, check1->hits);
g_assert_cmpint (2, ==, check2->hits);
xaccTransRollbackEdit (txn);
g_assert_cmpint (0, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
g_assert (txn->orig == NULL);
qof_book_destroy (book);
xaccTransBeginEdit (txn);
g_assert_cmpint (1, ==, qof_instance_get_editlevel (QOF_INSTANCE (txn)));
g_assert (txn->orig == NULL);
g_assert_cmpint (1, ==, check1->hits);
g_assert_cmpint (2, ==, check2->hits);
g_log_remove_handler (logdomain, hdlr);
test_clear_error_list ();
test_error_struct_free (check1);
test_error_struct_free (check2);
/* qof_book_destroy has already removed enough of the innards that
trying to unref the txn and book crashes. */
}
/* xaccTransDestroy
void
xaccTransDestroy (Transaction *trans)// C: 26 in 15 SCM: 4 in 4 Local: 3:0:0
*/
static void
test_xaccTransDestroy (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
QofBook *book = qof_instance_get_book (QOF_INSTANCE (txn));
Transaction *dupe = xaccTransClone (txn);
xaccTransBeginEdit (txn);
g_assert (!qof_instance_get_destroying (QOF_INSTANCE (txn)));
g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
xaccTransDestroy (txn);
g_assert (qof_instance_get_destroying (QOF_INSTANCE (txn)));
g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
xaccTransRollbackEdit (txn);
qof_book_mark_readonly (book);
xaccTransBeginEdit (txn);
xaccTransDestroy (txn);
g_assert (qof_instance_get_destroying (QOF_INSTANCE (txn)));
g_assert (xaccTransEqual (txn, dupe, FALSE, TRUE, FALSE, TRUE));
xaccTransRollbackEdit (txn);
test_destroy (dupe);
}
/* destroy_gains
static void
destroy_gains (Transaction *trans)// Local: 1:0:0 -- from do_destroy
*/
static void
test_destroy_gains (GainsFixture *fixture, gconstpointer pData)
{
/* Don't try to test with a NULL transaction, this is an internal
* function that isn't protected.
*/
Fixture *base = &(fixture->base);
auto base_split = static_cast<Split*>(g_list_nth_data (base->txn->splits, 1));
xaccTransBeginEdit (fixture->gains_txn); /* Protect it from being actually destroyed */
base->func->destroy_gains (base->txn);
g_assert (qof_instance_get_destroying (QOF_INSTANCE (fixture->gains_txn)));
g_assert (base_split->gains_split == NULL);
xaccTransCommitEdit (fixture->gains_txn);
}
/* do_destroy
static void
do_destroy (Transaction *trans)// Local: 1:1:0 callback passed to qof_commit_edit_part2 in XaccTransCommitEdit
NB: This function has a weird three-step process for destroying and freeing the splits, which isn't really testable.
*/
static void
test_do_destroy (GainsFixture *fixture, gconstpointer pData)
{
Fixture *base = &(fixture->base);
auto base_split = static_cast<Split*>(g_list_nth_data (base->txn->splits, 1));
QofBook *book = qof_instance_get_book (base->txn);
TestSignal sig = test_signal_new (QOF_INSTANCE (base->txn),
QOF_EVENT_DESTROY, NULL);
g_object_add_weak_pointer (G_OBJECT (base->txn->splits->data),
reinterpret_cast<void**>(&base_split));
g_object_ref (base->txn);
g_object_ref (fixture->gains_txn);
base->func->do_destroy (base->txn);
g_assert_cmpint (test_signal_return_hits (sig), ==, 1);
g_assert (base->txn->description == NULL);
g_assert_cmpint (GPOINTER_TO_INT(base->txn->num), ==, 1);
g_assert (qof_instance_get_destroying (QOF_INSTANCE (fixture->gains_txn)));
g_assert (base_split == NULL);
test_signal_free (sig);
}
/* xaccEnableDataScrubbing
* xaccDisableDataScrubbing
Trivial setters
*/
/* was_trans_emptied
static gboolean was_trans_emptied(Transaction *trans)// Local: 1:0:0 xaccTransCommitEdit
*/
static void
test_was_trans_emptied (Fixture *fixture, gconstpointer pData)
{
GList *list = fixture->txn->splits;
g_assert (!fixture->func->was_trans_emptied (fixture->txn));
fixture->txn->splits = NULL;
g_assert (fixture->func->was_trans_emptied (fixture->txn));
/* Restore the list so teardown can free the splits */
fixture->txn->splits = list;
}
/* trans_on_error
static void trans_on_error(Transaction *trans, QofBackendError errcode)// Local: 0:1:0 callback for qof_commit_edit_part2, xaccTransCommitEdit
*/
static QofBackendError errorvalue = ERR_BACKEND_NO_ERR;
static void
commit_error_cb (gpointer data, QofBackendError errcode)
{
errorvalue = errcode;
}
static void
test_trans_on_error (Fixture *fixture, gconstpointer pData)
{
QofBackendError errcode = ERR_BACKEND_MODIFIED;
auto msg =
"[trans_on_error()] Another user has modified this transaction\n"
"\tjust a moment ago. Please look at their changes,\n"
"\tand try again, if needed.\n";
auto logdomain = "gnc.engine";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL);
auto check = test_error_struct_new (logdomain, loglevel, msg);
fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
(GLogFunc)test_checked_handler);
gnc_engine_add_commit_error_callback ((EngineCommitErrorCallback)commit_error_cb, NULL);
xaccTransBeginEdit (fixture->txn);
g_assert_cmpint (qof_instance_get_editlevel (fixture->txn), ==, 1);
fixture->func->trans_on_error (fixture->txn, errcode);
g_assert_cmpint (check->hits, ==, 1);
g_assert_cmpint ((guint)errorvalue, ==, (guint)errcode);
g_assert_cmpint (qof_instance_get_editlevel (fixture->txn), ==, 0);
errorvalue = ERR_BACKEND_NO_ERR;
}
/* trans_cleanup_commit
static void trans_cleanup_commit(Transaction *trans)// Local: 0:1:0 callback for qof_commit_edit_part2, xaccTransCommitEdit
*/
static void
test_trans_cleanup_commit (Fixture *fixture, gconstpointer pData)
{
QofBook *book = qof_instance_get_book (QOF_INSTANCE (fixture->txn));
auto destr_split = xaccMallocSplit (book);
auto bogus_split = xaccMallocSplit (book);
auto split0 = static_cast<Split*>(fixture->txn->splits->data);
Account *acct0 = split0->acc;
Transaction *orig = NULL;
auto sig_d_remove = test_signal_new (QOF_INSTANCE (destr_split),
QOF_EVENT_REMOVE, NULL);
auto sig_b_remove = test_signal_new (QOF_INSTANCE (bogus_split),
QOF_EVENT_REMOVE, NULL);
auto sig_d_destroy = test_signal_new (QOF_INSTANCE (destr_split),
QOF_EVENT_DESTROY, NULL);
auto sig_b_modify = test_signal_new (QOF_INSTANCE (bogus_split),
QOF_EVENT_MODIFY, NULL);
auto sig_t_modify = test_signal_new (QOF_INSTANCE (fixture->txn),
QOF_EVENT_MODIFY, NULL);
auto sig_a_changed = test_signal_new (QOF_INSTANCE (acct0),
GNC_EVENT_ITEM_CHANGED, NULL);
xaccTransBeginEdit (fixture->txn);
orig = fixture->txn->orig;
g_object_ref (orig);
/* Check the txn-isn't-the-parent path */
fixture->txn->splits = g_list_prepend (fixture->txn->splits, destr_split);
fixture->txn->splits = g_list_prepend (fixture->txn->splits, bogus_split);
qof_instance_set_dirty (QOF_INSTANCE (destr_split));
qof_instance_set_dirty (QOF_INSTANCE (bogus_split));
qof_instance_set_destroying (QOF_INSTANCE (destr_split), TRUE);
/*Reverse the splits list so we can check later that it got sorted */
fixture->txn->splits = g_list_reverse (fixture->txn->splits);
g_assert (fixture->txn->splits->data != split0);
fixture->func->trans_cleanup_commit (fixture->txn);
g_assert_cmpint (test_signal_return_hits (sig_d_remove), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_b_remove), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_d_destroy), ==, 0);
g_assert_cmpint (test_signal_return_hits (sig_b_modify), ==, 0);
g_assert_cmpint (test_signal_return_hits (sig_t_modify), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_a_changed), ==, 1);
g_assert_cmpint (g_list_index (fixture->txn->splits, destr_split), ==, -1);
g_assert_cmpint (g_list_index (fixture->txn->splits, bogus_split), ==, -1);
g_assert (fixture->txn->orig == NULL);
g_assert (fixture->txn->splits->data == split0);
g_assert (qof_instance_get_destroying (destr_split));
/* Note that the function itself aborts if qof_instance_editlevel != 0 */
/* load things back up and test the txn-is-the-parent path */
qof_instance_increase_editlevel (fixture->txn);
destr_split->parent = fixture->txn;
bogus_split->parent = fixture->txn;
fixture->txn->splits = g_list_prepend (fixture->txn->splits, destr_split);
fixture->txn->splits = g_list_prepend (fixture->txn->splits, bogus_split);
fixture->txn->orig = orig;
orig->num = fixture->txn->num;
g_object_ref (orig);
fixture->func->trans_cleanup_commit (fixture->txn);
g_assert_cmpint (test_signal_return_hits (sig_d_remove), ==, 2);
g_assert_cmpint (test_signal_return_hits (sig_b_remove), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_d_destroy), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_b_modify), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_t_modify), ==, 2);
g_assert_cmpint (test_signal_return_hits (sig_a_changed), ==, 2);
g_assert_cmpint (g_list_index (fixture->txn->splits, destr_split), ==, -1);
g_assert_cmpint (g_list_index (fixture->txn->splits, bogus_split), ==, 0);
g_assert_cmpint (GPOINTER_TO_INT(orig->num), ==, 1);
test_destroy (orig);
}
/* xaccTransCommitEdit
void
xaccTransCommitEdit (Transaction *trans)// C: 88 in 28 SCM: 5 in 5 Local: 16:0:0
Setup has to run transCommitEdit, so we have to do our own setup for this function.
*/
static void
test_xaccTransCommitEdit (void)
{
QofBook *book = qof_book_new ();
auto split1 = xaccMallocSplit (book);
auto split2 = xaccMallocSplit (book);
Transaction *txn = xaccMallocTransaction (book);
Account *acc1 = xaccMallocAccount (book);
Account *acc2 = xaccMallocAccount (book);
gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand",
"CURRENCY", "GNR", "", 240);
gnc_commodity *comm = gnc_commodity_new (book, "Wildebeest Fund",
"FUND", "WBFXX", "", 1000);
Timespec posted = gnc_dmy2timespec (21, 4, 2012);
auto sig_1_modify = test_signal_new (QOF_INSTANCE (split1),
QOF_EVENT_MODIFY, NULL);
auto sig_2_modify = test_signal_new (QOF_INSTANCE (split2),
QOF_EVENT_MODIFY, NULL);
auto sig_txn_destroy = test_signal_new (QOF_INSTANCE (txn),
QOF_EVENT_DESTROY, NULL);
xaccAccountSetCommodity (acc1, comm);
xaccAccountSetCommodity (acc2, curr);
txn->date_posted.tv_sec = posted.tv_sec;
txn->date_posted.tv_nsec = posted.tv_nsec;
split1->memo = static_cast<char*>(CACHE_INSERT ("foo"));
split1->action = static_cast<char*>(CACHE_INSERT ("bar"));
split1->amount = gnc_numeric_create (100000, 1000);
split1->value = gnc_numeric_create (3200, 240);
/* Note, deliberately imblanced to force xaccTransScrubImbalance
* to create a balance split, thus showing that it got called.
*/
split2->amount = gnc_numeric_create (-3000, 240);
split2->value = gnc_numeric_create (-3000, 240);
split1->acc = acc1;
split2->acc = acc2;
txn->num = static_cast<char*>(CACHE_INSERT ("123"));
txn->description = static_cast<char*>(CACHE_INSERT ("Waldo Pepper"));
xaccTransBeginEdit (txn);
{
xaccTransSetCurrency (txn, curr);
xaccSplitSetParent (split1, txn);
xaccSplitSetParent (split2, txn);
}
/* Setup's done, now test: */
xaccTransCommitEdit (txn);
g_assert_cmpint (txn->date_entered.tv_sec, !=, 0);
/* Signals make sure that trans_cleanup_commit got called */
g_assert_cmpint (test_signal_return_hits (sig_1_modify), ==, 1);
g_assert_cmpint (test_signal_return_hits (sig_2_modify), ==, 1);
g_assert_cmpint (g_list_length (txn->splits), ==, 3);
xaccTransBeginEdit (txn);
g_list_free (txn->splits);
txn->splits = NULL;
xaccTransCommitEdit (txn);
g_assert_cmpint (test_signal_return_hits (sig_txn_destroy), ==, 1);
test_signal_free (sig_1_modify);
test_signal_free (sig_2_modify);
test_signal_free (sig_txn_destroy);
test_destroy (split1);
test_destroy (split2);
test_destroy (acc1);
test_destroy (acc2);
test_destroy (curr);
test_destroy (comm);
qof_book_destroy (book);
}
/* xaccTransRollbackEdit
void
xaccTransRollbackEdit (Transaction *trans)// C: 2 in 2 Local: 1:0:0
*/
static void
test_xaccTransRollbackEdit (Fixture *fixture, gconstpointer pData)
{
Transaction *txn = fixture->txn;
Transaction *orig = NULL;
QofBook *book = qof_instance_get_book (txn);
Timespec new_post = timespec_now ();
Timespec new_entered = timespecCanonicalDayTime (timespec_now ());
Timespec orig_post = txn->date_posted;
Timespec orig_entered = txn->date_entered;
KvpFrame *base_frame = NULL;
auto sig_account = test_signal_new (QOF_INSTANCE (fixture->acc1),
GNC_EVENT_ITEM_CHANGED, NULL);
auto mbe = static_cast<TransMockBackend*>(qof_book_get_backend (book));
auto split_00 = static_cast<Split*>(txn->splits->data);
auto split_01 = static_cast<Split*>(txn->splits->next->data);
auto split_02 = xaccMallocSplit (book);
xaccTransBeginEdit (txn);
qof_instance_set_destroying (txn, TRUE);
orig = txn->orig;
base_frame = orig->inst.kvp_data; /* DupeTransaction copies the kvp_frame */
g_object_ref (orig); /* Keep rollback from actually freeing it */
txn->num = static_cast<char*>(CACHE_INSERT("321"));
txn->description = static_cast<char*>(CACHE_INSERT("salt peanuts"));
txn->common_currency = NULL;
txn->inst.kvp_data = NULL;
txn->date_entered = new_entered;
txn->date_posted = new_post;
txn->splits->data = split_01;
txn->splits->next->data = split_00;
qof_instance_set_dirty (QOF_INSTANCE (split_01));
xaccSplitSetParent (split_02, txn);
g_object_ref (split_02);
auto split_10 = xaccDupeSplit(static_cast<Split*>(orig->splits->data));
g_object_ref (split_10);
auto split_11 = xaccDupeSplit(static_cast<Split*>(orig->splits->next->data));
g_object_ref (split_11);
qof_instance_increase_editlevel (QOF_INSTANCE (txn)); /* So it's 2 */
xaccTransRollbackEdit (txn);
g_assert (txn->orig == orig);
qof_instance_reset_editlevel (QOF_INSTANCE (txn)); /* Now it's 0 */
xaccTransRollbackEdit (txn);
g_assert (txn->orig == orig);
qof_instance_increase_editlevel (QOF_INSTANCE (txn)); /* And back to 1 */
xaccTransRollbackEdit (txn);
g_assert (txn->orig == NULL);
g_assert_cmpstr (txn->num, ==, "123");
g_assert_cmpint (GPOINTER_TO_INT(orig->num), ==, 1);
g_assert_cmpstr (txn->description, ==, "Waldo Pepper");
g_assert (txn->inst.kvp_data == base_frame);
g_assert (txn->common_currency == fixture->curr);
g_assert (timespec_equal (&(txn->date_posted), &orig_post));
g_assert (timespec_equal (&(txn->date_entered), &orig_entered));
g_assert_cmpuint (test_signal_return_hits (sig_account), ==, 1);
g_assert_cmpuint (g_list_length (txn->splits), ==, 2);
g_assert_cmpint (GPOINTER_TO_INT(split_02->memo), ==, 1);
g_assert (xaccSplitEqual (static_cast<Split*>(txn->splits->data), split_10,
FALSE, FALSE, FALSE));
g_assert (xaccSplitEqual (static_cast<Split*>(txn->splits->next->data),
split_10, FALSE, FALSE, FALSE));
g_assert_cmpstr (mbe->m_last_call.c_str(), ==, "rollback");
g_assert_cmpuint (qof_instance_get_editlevel (QOF_INSTANCE (txn)), ==, 0);
g_assert (qof_instance_get_destroying (txn) == FALSE);
test_signal_free (sig_account);
g_object_unref (split_10);
g_object_unref (split_11);
g_object_unref (split_02);
g_object_unref (orig);
}
/* A second xaccTransRollbackEdit test to check the backend error handling */
static void
test_xaccTransRollbackEdit_BackendErrors (Fixture *fixture, gconstpointer pData)
{
auto mbe = static_cast<TransMockBackend*>(qof_book_get_backend (qof_instance_get_book (fixture->txn)));
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
auto msg = "[xaccTransRollbackEdit()] Rollback Failed. Ouch!";
auto check = test_error_struct_new ("gnc.engine", loglevel, msg);
fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
(GLogFunc)test_checked_handler);
g_object_ref (fixture->txn);
xaccTransBeginEdit (fixture->txn);
mbe->inject_error(ERR_BACKEND_MODIFIED);
xaccTransRollbackEdit (fixture->txn);
g_assert_cmpint (check->hits, ==, 1);
g_assert_cmpstr (mbe->m_last_call.c_str(), ==, "rollback");
mbe->m_last_call.clear();
xaccTransBeginEdit (fixture->txn);
mbe->inject_error (ERR_BACKEND_MOD_DESTROY);
xaccTransRollbackEdit (fixture->txn);
g_assert_cmpint (GPOINTER_TO_INT(fixture->txn->num), ==, 1);
g_assert_cmpstr (mbe->m_last_call.c_str(), ==, "rollback");
}
/* xaccTransIsOpen C: 23 in 7 SCM: 1 Local: 0:0:0
* xaccTransOrder C: 2 in 2 SCM: 12 in 12 Local: 0:1:0
* Simple convenience functions. No test required.
*/
/* xaccTransOrder_num_action
int
xaccTransOrder_num_action (const Transaction *ta, const char *actna,
const Transaction *tb, const char *actnb)// C: 1 Local: 1:0:0
*/
static void
test_xaccTransOrder_num_action (Fixture *fixture, gconstpointer pData)
{
Transaction *txnA = fixture->txn;
Transaction *txnB = fixture->func->dupe_trans (txnA);
g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, NULL, NULL), ==, -1);
g_assert_cmpint (xaccTransOrder_num_action (NULL, NULL, txnA, NULL), ==, 1);
g_assert_cmpint (xaccTransOrder_num_action (NULL, NULL, NULL, NULL), ==, 0);
g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==,
qof_instance_guid_compare (txnA, txnB));
txnB->description = static_cast<char*>(CACHE_INSERT ("Salt Peanuts"));
g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), >=, 1);
txnB->date_entered.tv_sec += 1;
g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, -1);
txnB->num = static_cast<char*>(CACHE_INSERT ("101"));
g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, 1);
txnB->num = static_cast<char*>(CACHE_INSERT ("one-oh-one"));
g_assert_cmpint (xaccTransOrder_num_action (txnA, NULL, txnB, NULL), ==, 1);
g_assert_cmpint (xaccTransOrder_num_action (txnA, "24", txnB, "42"), ==, -1);
txnB->date_posted.tv_sec -= 1;
g_assert_cmpint (xaccTransOrder_num_action (txnA, "24", txnB, "42"), ==, 1);
fixture->func->xaccFreeTransaction (txnB);
}
/* xaccTransSetDateInternal Local: 7:0:0
* set_gains_date_dirty Local: 4:0:0
* xaccTransSetDatePostedSecs C: 17 in 13 Local: 0:0:0
* xaccTransSetDatePostedGDate C: 1 Local: 1:0:0
* xaccTransSetDateEnteredSecs C: 10 in 9 Local: 0:0:0
* xaccTransSetDatePostedTS C: 9 in 8 Local: 2:0:0
* xaccTransSetDateEnteredTS C: 3 in 3 Local: 1:0:0
* xaccTransSetDate C: 43 in 23 SCM: 2 in 2 Local: 0:0:0
* xaccTransSetDateDueTS C: 2 in 2 Local: 0:0:0
* xaccTransSetTxnType C: 4 in 3 Local: 0:0:0
* xaccTransClearReadOnly C: 4 in 2 Local: 1:0:0
* xaccTransSetReadOnly C: 2 in 2 Local: 1:0:0
* qofTransSetNum Local: 0:1:0
* xaccTransSetNum C: 13 in 12 SCM: 3 in 3 Local: 2:0:0
* qofTransSetDescription Local: 0:0:0
* xaccTransSetDescription C: 20 in 18 SCM: 5 in 3 Local: 2:0:0
* qofTransSetNotes Local: 0:0:0
* xaccTransSetNotes C: 5 in 5 SCM: 3 in 3 Local: 1:0:0
* xaccTransSetIsClosingTxn C: 1 Local: 0:0:0
* xaccTransGetSplit C: 57 in 24 SCM: 30 in 21 Local: 0:0:0
* xaccTransGetSplitIndex C: 7 in 2 Local: 0:0:0
* xaccTransGetSplitList C: 23 in 15 SCM: 19 in 15 Local: 2:1:0
* xaccTransCountSplits C: 17 in 9 SCM: 2 in 2 Local: 0:0:0
* xaccTransGetNum C: 15 in 12 SCM: 13 in 13 Local: 0:1:0
* xaccTransGetDescription C: 43 in 23 SCM: 9 in 9 Local: 0:2:0
* xaccTransGetNotes C: 8 in 6 SCM: 7 in 7 Local: 0:1:0
* xaccTransGetIsClosingTxn SCM: 1 Local: 0:1:0
* xaccTransGetDate C: 42 in 19 Local: 0:0:0
* xaccTransGetDatePostedTS C: 6 in 5 Local: 1:0:0
* xaccTransGetDateEnteredTS C: 1 Local: 0:0:0
* xaccTransRetDatePostedTS C: 10 in 6 Local: 1:1:0
* xaccTransGetDatePostedGDate C: 1 Local: 1:0:0
* xaccTransRetDateEnteredTS C: 1 Local: 0:1:0
* xaccTransGetDateDueTS C: 1 Local: 1:0:0
* xaccTransRetDateDueTS C: 1 SCM: 2 in 2 Local: 0:1:0
* xaccTransGetTxnType C: 3 in 2 SCM: 12 in 6 Local: 0:1:0*/
static void
test_xaccTransGetTxnType (Fixture *fixture, gconstpointer pData)
{
const char i = 'I';
const char p = 'P';
auto txn = fixture->txn;
xaccTransSetTxnType(txn, i);
g_assert_cmpint (i, ==, xaccTransGetTxnType(txn));
xaccTransSetTxnType(txn, p);
g_assert_cmpint (p, ==, xaccTransGetTxnType(txn));
}
/* xaccTransGetReadOnly C: 7 in 5 Local: 1:0:0
* xaccTransIsReadonlyByPostedDate C: 2 in 2 Local: 0:0:0
* xaccTransHasReconciledSplitsByAccount Local: 1:0:0
* xaccTransHasReconciledSplits C: 4 in 3 Local: 0:0:0
* xaccTransHasSplitsInStateByAccount Local: 1:0:0
* xaccTransHasSplitsInState C: 4 in 1 Local: 0:0:0
* counter_thunk Local: 0:1:0
* gnc_book_count_transactions C: 3 in 2 Local: 0:0:0
* xaccTransGetVoidStatus C: 3 in 2 SCM: 1 Local: 0:1:0
* An absurdly long list of trivial accessors which don't need to be tested.
*/
/* xaccTransVoid
void
xaccTransVoid(Transaction *trans, const char *reason)// C: 1 SCM: 2 in 2 Local: 0:0:0
* xaccTransUnvoid
void
xaccTransUnvoid (Transaction *trans)// C: 1 Local: 0:0:0
*/
static void
test_xaccTransVoid (Fixture *fixture, gconstpointer pData)
{
/* Actual function variables start here. */
auto frame = fixture->txn->inst.kvp_data;
auto void_reason = "Voided for Unit Test";
auto txn_notes = g_strdup (frame->get_slot(trans_notes_str)->get<const char*>());
Timespec now = timespec_now ();
char iso8601_str[ISO_DATELENGTH + 1] = "";
GList *split = NULL;
xaccTransVoid (fixture->txn, void_reason);
g_assert_cmpstr (frame->get_slot(trans_notes_str)->get<const char*>(), ==,
"Voided transaction");
g_assert_cmpstr (frame->get_slot(void_former_notes_str)->get<const char*>(),
==, txn_notes);
g_assert_cmpstr (frame->get_slot(void_reason_str)->get<const char*>(), ==,
void_reason);
gnc_timespec_to_iso8601_buff (now, iso8601_str);
g_assert_cmpstr (frame->get_slot(void_time_str)->get<const char*>(), ==,
iso8601_str);
g_assert_cmpstr (frame->get_slot(TRANS_READ_ONLY_REASON)->get<const char*>(),
==, "Transaction Voided");
for (split = fixture->txn->splits; split; split=g_list_next (split))
{
g_assert (gnc_numeric_zero_p (((Split*)(split->data))->value));
g_assert (gnc_numeric_zero_p (((Split*)(split->data))->amount));
}
xaccTransUnvoid (fixture->txn);
g_assert_cmpstr (frame->get_slot(trans_notes_str)->get<const char*>(), ==,
txn_notes);
g_assert (frame->get_slot(void_former_notes_str) == NULL);
g_assert (frame->get_slot(void_reason_str) == NULL);
g_assert (frame->get_slot(void_time_str) == NULL);
g_assert (frame->get_slot(TRANS_READ_ONLY_REASON) == NULL);
for (split = fixture->txn->splits; split; split=g_list_next (split))
{
g_assert (!gnc_numeric_zero_p (((Split*)(split->data))->value));
g_assert (!gnc_numeric_zero_p (((Split*)(split->data))->amount));
}
g_free (txn_notes);
}
/* xaccTransReverse
Transaction *
xaccTransReverse (Transaction *orig)// C: 2 in 2 Local: 0:0:0
*/
static void
test_xaccTransReverse (Fixture *fixture, gconstpointer pData)
{
Transaction *rev = xaccTransReverse (fixture->txn);
auto frame = fixture->txn->inst.kvp_data;
GList *orig_splits = NULL, *rev_splits = NULL;
g_assert (guid_equal (frame->get_slot(TRANS_REVERSED_BY)->get<GncGUID*>(),
xaccTransGetGUID (rev)));
g_assert (!qof_instance_is_dirty (QOF_INSTANCE (rev))); //Cleared by commit
g_assert_cmpint (g_list_length (fixture->txn->splits), ==,
g_list_length (rev->splits));
for (orig_splits = fixture->txn->splits,
rev_splits = g_list_reverse (rev->splits);
orig_splits && rev_splits;
orig_splits = g_list_next (orig_splits),
rev_splits = g_list_next (rev_splits))
{
auto orig_split = static_cast<Split*>(orig_splits->data);
auto rev_split = static_cast<Split*>(rev_splits->data);
g_assert (gnc_numeric_equal (orig_split->amount,
gnc_numeric_neg (rev_split->amount)));
g_assert (gnc_numeric_equal (orig_split->value,
gnc_numeric_neg (rev_split->value)));
g_assert_cmpint (xaccSplitGetReconcile (rev_split), ==, NREC);
}
fixture->func->xaccFreeTransaction (rev);
}
/* xaccTransGetReversedBy C: 2 in 2 Local: 0:0:0
* Trivial getter.
*/
/* xaccTransScrubSplits C: 1 Local: 0:0:0
* Trival pass-through.
*/
/* xaccTransScrubGainsDate
static void
xaccTransScrubGainsDate (Transaction *trans)// Local: 1:0:0
*/
static void
test_xaccTransScrubGainsDate_no_dirty (GainsFixture *fixture,
gconstpointer pData)
{
auto base_split = static_cast<Split *>(g_list_nth_data (fixture->base.txn->splits, 1));
auto gains_split = base_split->gains_split;
base_split->gains = GAINS_STATUS_GAINS;
gains_split->gains = GAINS_STATUS_GAINS;
fixture->base.func->xaccTransScrubGainsDate (fixture->base.txn);
g_assert (!timespec_equal (&(fixture->base.txn->date_posted),
&(fixture->gains_txn->date_posted)));
g_assert_cmphex (base_split->gains & GAINS_STATUS_DATE_DIRTY, ==, 0);
g_assert_cmphex (base_split->gains_split->gains & GAINS_STATUS_DATE_DIRTY,
==, 0);
}
static void
test_xaccTransScrubGainsDate_base_dirty (GainsFixture *fixture,
gconstpointer pData)
{
auto base_split = static_cast<Split *>(g_list_nth_data (fixture->base.txn->splits, 1));
auto gains_split = base_split->gains_split;
base_split->gains = GAINS_STATUS_GAINS | GAINS_STATUS_DATE_DIRTY;
gains_split->gains = GAINS_STATUS_GAINS;
fixture->base.func->xaccTransScrubGainsDate (fixture->base.txn);
g_assert (timespec_equal (&(fixture->base.txn->date_posted),
&(fixture->gains_txn->date_posted)));
g_assert_cmphex (base_split->gains & GAINS_STATUS_DATE_DIRTY, ==, 0);
g_assert_cmphex (base_split->gains_split->gains & GAINS_STATUS_DATE_DIRTY,
==, 0);
}
static void
test_xaccTransScrubGainsDate_gains_dirty (GainsFixture *fixture,
gconstpointer pData)
{
auto base_split = static_cast<Split*>(g_list_nth_data (fixture->base.txn->splits, 1));
auto gains_split = base_split->gains_split;
base_split->gains = GAINS_STATUS_GAINS;
gains_split->gains = GAINS_STATUS_GAINS | GAINS_STATUS_DATE_DIRTY;
fixture->base.func->xaccTransScrubGainsDate (fixture->base.txn);
g_assert (timespec_equal (&(fixture->base.txn->date_posted),
&(fixture->gains_txn->date_posted)));
g_assert_cmphex (base_split->gains & GAINS_STATUS_DATE_DIRTY, ==, 0);
g_assert_cmphex (base_split->gains_split->gains & GAINS_STATUS_DATE_DIRTY,
==, 0);
}
/* xaccTransScrubGains Local: 1:0:0
* Non-trivial, but it passes through selected splits to functions in
* cap-gains.c and Scrub3.c that are beyond the scope of this test
* program.
*/
/* xaccTransFindSplitByAccount C: 7 in 5 Local: 0:0:0
* destroy_tx_on_book_close Local: 0:1:0
* gnc_transaction_book_end Local: 0:1:0
* trans_is_balanced_p Local: 0:1:0
* Trivial pass-through.
*/
void
test_suite_transaction (void)
{
GNC_TEST_ADD (suitename, "check open", Fixture, NULL, setup, test_check_open, teardown);
GNC_TEST_ADD (suitename, "xaccTransStillHasSplit", Fixture, NULL, setup, test_xaccTransStillHasSplit, teardown);
GNC_TEST_ADD (suitename, "mark trans", Fixture, NULL, setup, test_mark_trans, teardown);
GNC_TEST_ADD (suitename, "gen event trans", Fixture, NULL, setup, test_gen_event_trans, teardown);
GNC_TEST_ADD_FUNC (suitename, "gnc transaction init", test_gnc_transaction_init);
GNC_TEST_ADD_FUNC (suitename, "gnc transaction dispose", test_gnc_transaction_dispose);
GNC_TEST_ADD_FUNC (suitename, "gnc transaction finalize", test_gnc_transaction_finalize);
GNC_TEST_ADD (suitename, "gnc transaction set/get property", Fixture, NULL, setup, test_gnc_transaction_set_get_property, teardown);
GNC_TEST_ADD (suitename, "xaccMallocTransaction", Fixture, NULL, setup, test_xaccMallocTransaction, teardown);
GNC_TEST_ADD (suitename, "xaccTransSortSplits", Fixture, NULL, setup, test_xaccTransSortSplits, teardown);
GNC_TEST_ADD (suitename, "dupe_trans", Fixture, NULL, setup, test_dupe_trans, teardown);
GNC_TEST_ADD (suitename, "xaccTransClone", Fixture, NULL, setup, test_xaccTransClone, teardown);
GNC_TEST_ADD (suitename, "xaccTransCopyFromClipBoard", Fixture, NULL, setup, test_xaccTransCopyFromClipBoard, teardown);
GNC_TEST_ADD (suitename, "xaccTransCopyFromClipBoard No-Start", Fixture, NULL, setup, test_xaccTransCopyFromClipBoard_no_start, teardown);
GNC_TEST_ADD (suitename, "xaccFreeTransaction", Fixture, NULL, setup, test_xaccFreeTransaction, teardown);
// GNC_TEST_ADD (suitename, "compare split guids", Fixture, NULL, setup, test_compare_split_guids, teardown);
GNC_TEST_ADD (suitename, "xaccTransEqual", Fixture, NULL, setup, test_xaccTransEqual, teardown);
GNC_TEST_ADD (suitename, "xaccTransLookup", Fixture, NULL, setup, test_xaccTransLookup, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetImbalanceValue", Fixture, NULL, setup, test_xaccTransGetImbalanceValue, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetImbalance", Fixture, NULL, setup, test_xaccTransGetImbalance, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetImbalance Trading Accounts", Fixture, NULL, setup, test_xaccTransGetImbalance_trading, teardown);
GNC_TEST_ADD (suitename, "xaccTransIsBalanced", Fixture, NULL, setup, test_xaccTransIsBalanced, teardown);
GNC_TEST_ADD (suitename, "xaccTransIsBalanced Trading Accounts", Fixture, NULL, setup, test_xaccTransIsBalanced_trading, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetAccountValue", Fixture, NULL, setup, test_xaccTransGetAccountValue, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetRateForCommodity", Fixture, NULL, setup, test_xaccTransGetRateForCommodity, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetAccountAmount", Fixture, NULL, setup, test_xaccTransGetAccountAmount, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetAccountConvRate", Fixture, NULL, setup, test_xaccTransGetAccountConvRate, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetAccountBalance", Fixture, NULL, setup, test_xaccTransGetAccountBalance, teardown);
GNC_TEST_ADD (suitename, "xaccTransSetCurrency", Fixture, NULL, setup, test_xaccTransSetCurrency, teardown);
GNC_TEST_ADD_FUNC (suitename, "xaccTransBeginEdit", test_xaccTransBeginEdit);
GNC_TEST_ADD (suitename, "xaccTransDestroy", Fixture, NULL, setup, test_xaccTransDestroy, teardown);
GNC_TEST_ADD (suitename, "destroy gains", GainsFixture, NULL, setup_with_gains, test_destroy_gains, teardown_with_gains);
GNC_TEST_ADD (suitename, "do destroy", GainsFixture, NULL, setup_with_gains, test_do_destroy, teardown_with_gains);
GNC_TEST_ADD (suitename, "was trans emptied", Fixture, NULL, setup, test_was_trans_emptied, teardown);
GNC_TEST_ADD (suitename, "trans on error", Fixture, NULL, setup, test_trans_on_error, teardown);
GNC_TEST_ADD (suitename, "trans cleanup commit", Fixture, NULL, setup, test_trans_cleanup_commit, teardown);
GNC_TEST_ADD_FUNC (suitename, "xaccTransCommitEdit", test_xaccTransCommitEdit);
GNC_TEST_ADD (suitename, "xaccTransRollbackEdit", Fixture, NULL, setup, test_xaccTransRollbackEdit, teardown);
GNC_TEST_ADD (suitename, "xaccTransRollbackEdit - Backend Errors", Fixture, NULL, setup, test_xaccTransRollbackEdit_BackendErrors, teardown);
GNC_TEST_ADD (suitename, "xaccTransOrder_num_action", Fixture, NULL, setup, test_xaccTransOrder_num_action, teardown);
GNC_TEST_ADD (suitename, "xaccTransGetTxnType", Fixture, NULL, setup, test_xaccTransGetTxnType, teardown);
GNC_TEST_ADD (suitename, "xaccTransVoid", Fixture, NULL, setup, test_xaccTransVoid, teardown);
GNC_TEST_ADD (suitename, "xaccTransReverse", Fixture, NULL, setup, test_xaccTransReverse, teardown);
GNC_TEST_ADD (suitename, "xaccTransScrubGainsDate_no_dirty", GainsFixture, NULL, setup_with_gains, test_xaccTransScrubGainsDate_no_dirty, teardown_with_gains);
GNC_TEST_ADD (suitename, "xaccTransScrubGainsDate_base_dirty", GainsFixture, NULL, setup_with_gains, test_xaccTransScrubGainsDate_base_dirty, teardown_with_gains);
GNC_TEST_ADD (suitename, "xaccTransScrubGainsDate_gains_dirty", GainsFixture, NULL, setup_with_gains, test_xaccTransScrubGainsDate_gains_dirty, teardown_with_gains);
}