mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
For clarity. In so doing found the backend behavior a bit inconsistent so it's modified to do what the enum values indicate. In the course of changing the various calls I found some implementation errors in the back end and corrected them.
2048 lines
85 KiB
C++
2048 lines
85 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 *
|
|
* https://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*, SessionOpenMode) 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;
|
|
time64 entered = gnc_dmy2time64 (20, 4, 2012);
|
|
time64 posted = gnc_dmy2time64 (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 = posted;
|
|
txn->date_entered = entered;
|
|
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(g_strdup ("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, ==, 0);
|
|
g_assert_cmpint (txn->date_posted, ==, 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;
|
|
time64 now = gnc_time(NULL);
|
|
Time64 *t_entered, *t_posted;
|
|
g_assert_cmpstr (txn->num, ==, "");
|
|
g_assert_cmpstr (txn->description, ==, "");
|
|
g_assert (txn->common_currency == NULL);
|
|
g_assert_cmpint (txn->date_entered, ==, 0);
|
|
g_assert_cmpint (txn->date_posted, ==, 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 (txn->date_entered == now);
|
|
g_assert (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_cmpint (t_entered->t, ==, now);
|
|
g_assert_cmpint (t_posted->t, ==, now);
|
|
xaccTransRollbackEdit (txn);
|
|
test_destroy (txn);
|
|
test_destroy (curr);
|
|
qof_book_destroy (book);
|
|
}
|
|
/* 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)
|
|
{
|
|
time64 posted = gnc_dmy2time64 (12, 7, 2011);
|
|
time64 entered = gnc_dmy2time64 (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(g_strdup ("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 (newtxn->date_posted == posted);
|
|
g_assert (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)
|
|
{
|
|
time64 posted = gnc_dmy2time64 (12, 7, 2011);
|
|
time64 entered = gnc_dmy2time64 (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 (newtxn->date_posted == posted);
|
|
g_assert (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);
|
|
time64 now = gnc_time (nullptr);
|
|
time64 never = 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 (to_txn->date_entered == now);
|
|
g_assert (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);
|
|
time64 now = gnc_time (nullptr);
|
|
time64 never = 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 (to_txn->date_entered == now);
|
|
g_assert (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, ==, 0);
|
|
g_assert_cmpint (txn->date_posted, ==, 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_time64_to_iso8601_buff (clone->date_posted, posted);
|
|
gnc_time64_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 = txn0->date_entered;
|
|
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 = txn0->date_posted;
|
|
clone->date_entered = txn0->date_posted;
|
|
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 = txn0->date_entered;
|
|
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;
|
|
split10->noclosing_balance = split00->noclosing_balance;
|
|
split11->noclosing_balance = split01->noclosing_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);
|
|
|
|
g_log_remove_handler (logdomain, hdlr);
|
|
test_clear_error_list ();
|
|
test_error_struct_free (check1);
|
|
test_error_struct_free (check2);
|
|
xaccTransDestroy (txn);
|
|
qof_book_destroy (book);
|
|
}
|
|
/* 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);
|
|
|
|
time64 posted = gnc_dmy2time64 (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 = posted;
|
|
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, !=, 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);
|
|
time64 new_post = gnc_time (nullptr);
|
|
time64 new_entered = time64CanonicalDayTime (new_post);
|
|
time64 orig_post = txn->date_posted;
|
|
time64 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 (txn->date_posted == orig_post);
|
|
g_assert (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 += 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 -= 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
|
|
* xaccTransSetDate C: 43 in 23 SCM: 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*>());
|
|
time64 now = gnc_time(NULL);
|
|
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_time64_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 (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 (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 (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);
|
|
|
|
}
|