/********************************************************************
 * utest-Split.c: GLib g_test test suite for Split.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                   *
 ********************************************************************/
#include <glib.h>

#include <config.h>
#include <string.h>
#include <unittest-support.h>
/* Add specific headers for this class */
#include <Split.h>
#include <SplitP.hpp>
#include <Account.h>
#include <Transaction.h>
#include <TransactionP.hpp>
#include <gnc-lot.h>
#include <gnc-event.h>

#if defined(__clang__)
#define USE_CLANG_FUNC_SIG 1
#endif

static const gchar *suitename = "/engine/Split";
extern "C" void test_suite_split ( void );

#include <qofinstance-p.h>
#include <kvp-frame.hpp>

typedef struct
{
    Split *split;
    SplitTestFunctions *func;
    gnc_commodity *curr;
    gnc_commodity *comm;
    GSList *hdlrs;
} Fixture;

static void
setup (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = qof_book_new ();
    Transaction *txn = xaccMallocTransaction (book);
    Account *acc = xaccMallocAccount (book);
    GNCLot *lot = gnc_lot_new (book);
    gnc_numeric value = gnc_numeric_create (123, 240);
    gnc_numeric amount = gnc_numeric_create (321, 1000);
    time64 time = gnc_time(NULL);
    Split *gains_split = xaccMallocSplit (book);
    fixture->curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY", "GNR", "", 240);
    fixture->comm = gnc_commodity_new (book, "Wildebeest Fund", "FUND", "WBFXX", "", 1000);

    fixture->func = _utest_split_fill_functions ();
    fixture->split = xaccMallocSplit (book);
    xaccAccountSetCommodity (acc, fixture->comm);
    xaccTransBeginEdit (txn);
    xaccTransSetCurrency (txn, fixture->curr);
    xaccSplitSetParent (fixture->split, txn);
    xaccTransCommitEdit (txn);
    xaccAccountInsertLot (acc, lot);
    fixture->split->action = CACHE_INSERT ("foo");
    fixture->split->memo = CACHE_INSERT ("bar");
    fixture->split->acc = acc;
    fixture->split->lot = lot;
    fixture->split->parent = txn;
    fixture->split->amount = amount;
    fixture->split->value = value;
    fixture->split->date_reconciled = time;
    fixture->split->reconciled = YREC;
    fixture->split->gains = GAINS_STATUS_VALU_DIRTY;
    fixture->split->gains_split = gains_split;

    fixture->split->balance = amount;
    fixture->split->cleared_balance = amount;
    fixture->split->reconciled_balance = amount;
    qof_instance_mark_clean (QOF_INSTANCE (fixture->split));
    qof_instance_mark_clean (QOF_INSTANCE (acc));
    qof_instance_mark_clean (QOF_INSTANCE (txn));
    fixture->hdlrs = NULL;
}

static void
teardown (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Account *acc = xaccSplitGetAccount (fixture->split);
    Transaction *txn = xaccSplitGetParent (fixture->split);
    GNCLot *lot = xaccSplitGetLot (fixture->split);
    test_destroy (fixture->split->gains_split);
    test_destroy (lot);
    test_destroy (txn);
    test_destroy (acc);
    test_destroy (fixture->split);
    test_destroy (fixture->curr);
    test_destroy (fixture->comm);
    qof_book_destroy (book);
    g_free (fixture->func);
    g_slist_free_full (fixture->hdlrs, test_free_log_handler);
    test_clear_error_list();
}

/* gnc_split_init
static void
gnc_split_init(Split* split)*/
static void
test_gnc_split_init ()
{
    Split *split = static_cast<Split*>(g_object_new (GNC_TYPE_SPLIT, NULL));
    g_assert_true (split->acc == NULL);
    g_assert_true (split->orig_acc == NULL);
    g_assert_true (split->parent == NULL);
    g_assert_true (split->lot == NULL);
    g_assert_cmpstr (split->action, ==, "");
    g_assert_cmpstr (split->memo, ==, "");
    g_assert_cmpint (split->reconciled, ==, NREC);
    g_assert_true (gnc_numeric_zero_p (split->amount));
    g_assert_true (gnc_numeric_zero_p (split->value));
    g_assert_true (gnc_numeric_zero_p (split->balance));
    g_assert_true (gnc_numeric_zero_p (split->cleared_balance));
    g_assert_true (gnc_numeric_zero_p (split->reconciled_balance));
    g_assert_cmpint (split->gains, ==, GAINS_STATUS_UNKNOWN);
    g_assert_true (split->gains_split == NULL);
    /* Make sure that the parent's init has been run */
    g_assert_true (split->inst.kvp_data != NULL);

    g_object_unref (split);
}
/* gnc_split_dispose
static void
gnc_split_dispose(GObject *splitp)*/
static void
test_gnc_split_dispose ()
{
    /* gnc_split_dispose doesn't do anything besides chain up to its
     * parent, so we twiddle the parent QofInstance to populate its
     * collection object (which is released by its dispose) then run
     * dispose on Split and make sure that the collection object is indeed
     * released.
     *
     * TODO: Split keeps references to two Account objects, two
     * Transaction objects, a Split object, and a GNCLot object. All of
     * these should be unreffed in gnc_split_dispose.
     */
    Split *split = static_cast<Split*>(g_object_new (GNC_TYPE_SPLIT, NULL));
    QofInstance *instance = QOF_INSTANCE (split);
    QofBook *book = qof_book_new ();

    qof_instance_init_data (instance, GNC_ID_SPLIT, book);

    g_assert_cmpstr (instance->e_type, ==, GNC_ID_SPLIT);

    g_object_run_dispose (G_OBJECT (split));

    g_assert_true (instance->e_type == NULL);

    g_object_unref (split);
    qof_book_destroy (book);
}
/* gnc_split_finalize
static void
gnc_split_finalize(GObject* splitp)
Can't actually test this, it's a class function.
*/
/* gnc_split_get__property
static void
gnc_split_get_property(GObject         *object,*/
/* gnc_split_set_property
static void
gnc_split_set_property(GObject         *object,*/
static void
test_gnc_split_set_get_property ()
{
    /* TODO: Several of the parameters set by gnc_split_init are not
     * properties, and two members of struct split_s (orig_parent and
     * reconciled) are neither initialized in gnc_split_init nor
     * properties.
     */
    QofBook *book = qof_book_new ();
    gnc_commodity *curr = gnc_commodity_new (book, "Gnu Rand", "CURRENCY", "GNR", "", 100);
    Transaction *txn = xaccMallocTransaction (book), *rtxn = NULL;
    Account *acc = xaccMallocAccount (book), *racc = NULL;
    GNCLot *lot = gnc_lot_new (book), *rlot = NULL;
    Split *split = xaccMallocSplit (book);
    time64 time = gnc_time(nullptr);
    Time64 t = {time}, *rtime;
    char *r_action, *r_memo;
    gnc_numeric value = gnc_numeric_create (123, 100);
    gnc_numeric amount = gnc_numeric_create (321, 100);
    gnc_numeric *r_value, *r_amount;

    xaccAccountSetCommodity (acc, curr);
    xaccTransBeginEdit (txn);
    xaccTransSetCurrency (txn, curr);
    gnc_lot_set_account (lot, acc);
    qof_commit_edit (QOF_INSTANCE (txn));

    g_object_set (G_OBJECT (split),
                  "action", "foo",
                  "memo", "bar",
                  "value", &value,
                  "amount", &amount,
                  "reconcile-date", &t,
                  "account", acc,
                  "lot", lot,
                  "transaction", txn,
                  NULL);

    g_object_get (G_OBJECT (split),
                  "action", &r_action,
                  "memo", &r_memo,
                  "value", &r_value,
                  "amount", &r_amount,
                  "reconcile-date", &rtime,
                  "transaction", &rtxn,
                  "account", &racc,
                  "lot", &rlot,
                  NULL);

    g_assert_cmpstr (r_action, ==, "foo");
    g_assert_cmpstr (r_memo, ==, "bar");
    g_assert_true (gnc_numeric_equal (*r_value, value));
    /* Setting the transaction causes the amount to be scrubbed into the value */
    g_assert_true (gnc_numeric_equal (*r_amount, value));
    g_assert_cmpint (rtime->t, ==, time);
    g_assert_true (txn == rtxn);
    g_assert_true (acc == racc);
    g_assert_true (lot == rlot);

    /* The official destroy functions all step on each other. We'll take a
     * few leaks to save trouble; it will all work fine once the
     * refactoring is taken care of.
     */
    g_free (r_value);
    g_free (r_amount);
    g_object_unref (txn);
    g_object_unref (acc);
    g_object_unref (lot);
    gnc_commodity_destroy (curr);
    g_object_unref (split);
    qof_book_destroy (book);
}

/* xaccInitSplit
static void
xaccInitSplit(Split * split, QofBook *book)// Local: 1:0:0
An utterly useless function that just chains up to QofInstance.
*/

// Not Used
/* xaccSplitReinit
void
xaccSplitReinit(Split * split)//
*/
/* xaccMallocSplit
Split *
xaccMallocSplit(QofBook *book)// C: 46 in 23 SCM: 3 in 2
*/
static void
test_xaccMallocSplit (Fixture *fixture, gconstpointer pData)
{
    /* We use this in the setup, so we can just verify that it works. */
    g_assert_true (fixture->split != NULL);
}
/* xaccDupeSplit
Split *
xaccDupeSplit (const Split *s)// C: 1
*/
static void
test_xaccDupeSplit (Fixture *fixture, gconstpointer pData)
{
    Split *f_split = fixture->split;
    Split *split = xaccDupeSplit (f_split);

    g_assert_true (split != fixture->split);
    g_assert_true (qof_instance_get_guid (split) != qof_instance_get_guid (f_split));
    g_assert_true (guid_equal (qof_instance_get_guid (split), qof_instance_get_guid (f_split)));
    g_assert_true (qof_instance_get_book (split) == qof_instance_get_book (f_split));
    g_assert_true (split->parent == f_split->parent);
    g_assert_true (split->acc == f_split->acc);
    g_assert_true (split->orig_acc == f_split->orig_acc);
    g_assert_true (split->lot == f_split->lot);
    g_assert_cmpstr (split->memo, ==, f_split->memo);
    g_assert_cmpstr (split->action, ==, f_split->action);
    g_assert_true (compare (split->inst.kvp_data, f_split->inst.kvp_data) == 0);
    g_assert_cmpint (split->reconciled, ==, f_split->reconciled);
    g_assert_cmpint (split->date_reconciled, ==, f_split->date_reconciled);
    g_assert_true (gnc_numeric_equal (split->value, f_split->value));
    g_assert_true (gnc_numeric_equal (split->amount, f_split->amount));
    /* xaccDupeSplit intentionally doesn't copy the balances */
    g_assert_true (gnc_numeric_zero_p (split->balance));
    g_assert_true (gnc_numeric_zero_p (split->cleared_balance));
    g_assert_true (gnc_numeric_zero_p (split->reconciled_balance));
    /* FIXME: gains and gains_split are not copied */
    g_assert_cmpint (split->gains, !=, f_split->gains);
    g_assert_true (split->gains_split != f_split->gains_split);

}
/* xaccSplitCloneNoKvp
Split *
xaccSplitCloneNoKvp (const Split *s)// C: 1
*/
static void
test_xaccSplitCloneNoKvp (Fixture *fixture, gconstpointer pData)
{
    Split *f_split = fixture->split;
    Split *split = xaccSplitCloneNoKvp (f_split);

    g_assert_true (split != fixture->split);
    g_assert_true (qof_instance_get_guid (split) != qof_instance_get_guid (f_split));
    g_assert_cmpint (guid_compare (qof_instance_get_guid (split), qof_instance_get_guid (f_split)), !=, 0);
    g_assert_true (qof_instance_get_book (split) == qof_instance_get_book (f_split));
    g_assert_true (split->parent == NULL);
    g_assert_true (split->acc == f_split->acc);
    /* Clone doesn't copy the orig_acc */
    g_assert_true (split->orig_acc == NULL);
    g_assert_true (split->lot == f_split->lot);
    g_assert_cmpstr (split->memo, ==, f_split->memo);
    g_assert_cmpstr (split->action, ==, f_split->action);
    g_assert_true (split->inst.kvp_data->empty());
    g_assert_cmpint (split->reconciled, ==, f_split->reconciled);
    g_assert_cmpint (split->date_reconciled, == , f_split->date_reconciled);
    g_assert_true (gnc_numeric_equal (split->value, f_split->value));
    g_assert_true (gnc_numeric_equal (split->amount, f_split->amount));
    g_assert_true (gnc_numeric_equal (split->balance, f_split->balance));
    g_assert_true (gnc_numeric_equal (split->cleared_balance, f_split->cleared_balance));
    g_assert_true (gnc_numeric_equal (split->reconciled_balance, f_split->reconciled_balance));
    g_assert_cmpint (split->gains, ==, GAINS_STATUS_UNKNOWN);
    g_assert_true (split->gains_split == NULL);
}
// Not Used
/* xaccSplitDump
void
xaccSplitDump (const Split *split, const char *tag)//
*/
/* xaccFreeSplit
void
xaccFreeSplit (Split *split)// C: 3 in 1
Not testable and wrong besides.
*/
/* mark_split
void mark_split (Split *s)// C: 2 in 2 SCM: 10 in 1 Local: 8:0:0
OK, weird. Doesn't mark the split, marks the account sort-dirty and balance-dirty parameters.
*/
static void
test_mark_split (Fixture *fixture, gconstpointer pData)
{
    gboolean sort_dirty, balance_dirty;
    g_object_get (fixture->split->acc,
                  "sort-dirty", &sort_dirty,
                  "balance-dirty", &balance_dirty,
                  NULL);
    g_assert_cmpint (sort_dirty, ==, FALSE);
    g_assert_cmpint (balance_dirty, ==, FALSE);

    mark_split (fixture->split);

    g_object_get (fixture->split->acc,
                  "sort-dirty", &sort_dirty,
                  "balance-dirty", &balance_dirty,
                  NULL);
    g_assert_cmpint (sort_dirty, ==, TRUE);
    g_assert_cmpint (balance_dirty, ==, TRUE);
}
// Not Used
/* xaccSplitEqualCheckBal
static gboolean
xaccSplitEqualCheckBal (const char *tag, gnc_numeric a, gnc_numeric b)//
*/
static void
test_xaccSplitEqualCheckBal (Fixture *fixture, gconstpointer pData)
{
    gchar *msg = "[xaccSplitEqualCheckBal] test balances differ: 123/100 vs 456/100";
    GLogLevelFlags loglevel = G_LOG_LEVEL_INFO;
    guint hdlr;
    TestErrorStruct check = { loglevel, "gnc.engine", msg, 0 };

    gnc_numeric foo = gnc_numeric_create (123, 100);
    gnc_numeric bar = gnc_numeric_create (456, 100);

    hdlr = g_log_set_handler ("gnc.engine", loglevel,
                              (GLogFunc)test_checked_handler, &check);

    g_assert_cmpint (fixture->func->xaccSplitEqualCheckBal ("test ", foo, foo), ==, TRUE);
    g_assert_cmpint (fixture->func->xaccSplitEqualCheckBal ("test ", foo, bar), ==, FALSE);
    g_assert_cmpint (check.hits, ==, 1);
    g_log_remove_handler ("gnc.engine", hdlr);

}
/* xaccSplitEqual
gboolean
xaccSplitEqual(const Split *sa, const Split *sb,// C: 2 in 2 SCM: 1
*/

static void
test_xaccSplitEqual (Fixture *fixture, gconstpointer pData)
{
    Split *split1 = xaccSplitCloneNoKvp (fixture->split);
    Split *split2 = xaccDupeSplit (fixture->split);
    gchar *msg01 = "[xaccSplitEqual] one is nullptr";
    gchar *msg02 = "[xaccSplitEqual] GUIDs differ";
    gchar *msg03;
    gchar *msg04 = "[xaccSplitEqual] actions differ: foo vs bar";
    G_GNUC_UNUSED gchar *msg05 = "[xaccSplitEqual] kvp frames: differ foo vs bar";
    G_GNUC_UNUSED gchar *msg06 = "[xaccSplitEqual] reconcile flags differ: foo vs bar";
    G_GNUC_UNUSED gchar *msg07 = "[xaccSplitEqual] reconciled date differs";
    G_GNUC_UNUSED gchar *msg08 = "[xaccSplitEqual] amounts differ: foo vs bar";
    gchar *msg10 = "[xaccSplitEqual] transactions differ";
    gchar *msg11 = "[xaccTransEqual] one is nullptr";
    gchar *msg12 = "[xaccSplitEqualCheckBal] balances differ: 321/1000 vs 0/1";
    gchar *msg13 = "[xaccSplitEqualCheckBal] cleared balances differ: 321/1000 vs 0/1";
    gchar *msg14 = "[xaccSplitEqualCheckBal] reconciled balances differ: 321/1000 vs 0/1";
    gchar *logdomain = "gnc.engine";
    GLogLevelFlags loglevel = G_LOG_LEVEL_INFO;
    TestErrorStruct checkA = { loglevel, logdomain, msg01, 0 };
    TestErrorStruct checkB = { loglevel, logdomain, msg10, 0 };
    TestErrorStruct checkC = { loglevel, logdomain, msg11, 0 };
    TestErrorStruct checkD = { loglevel, logdomain, msg14, 0 };
    guint hdlr;

    test_add_error (&checkA);
    test_add_error (&checkB);
    test_add_error (&checkC);
    test_add_error (&checkD);

    hdlr  = g_log_set_handler (logdomain, loglevel,
                               (GLogFunc)test_list_handler, &checkA);
    /* Note that check_splits is just passed through to xaccTransEqual, so we don't vary it here. */
    /* Test that a NULL comparison fails */
    g_assert_true (xaccSplitEqual (fixture->split, NULL, TRUE, TRUE, TRUE) == FALSE);
    g_assert_true (xaccSplitEqual (NULL, split1, TRUE, TRUE, TRUE) == FALSE);
    g_assert_cmpint (checkA.hits, ==, 2);
    g_assert_cmpint (checkB.hits, ==, 0);
    g_assert_cmpint (checkC.hits, ==, 0);
    g_assert_cmpint (checkD.hits, ==, 0);
    checkA.msg = msg02;
    /* Clone creates splits with different GUIDs: Make sure that it fails comparison */
    g_assert_true (xaccSplitEqual (fixture->split, split1, TRUE, TRUE, TRUE) == FALSE);
    /* Test that the parent comparison fails */
    g_assert_true (xaccSplitEqual (fixture->split, split1, FALSE, TRUE, TRUE) == FALSE);
    /* Now set split1's parent so that it passes -- we're also checking that the GUID check is disabled when we pass FALSE to check_guids */
    g_assert_cmpint (checkA.hits, ==, 3);
    g_assert_cmpint (checkB.hits, ==, 1);
    g_assert_cmpint (checkC.hits, ==, 1);
    g_assert_cmpint (checkD.hits, ==, 0);
    split1->parent = fixture->split->parent;
    g_assert_true (xaccSplitEqual (fixture->split, split1, FALSE, TRUE, TRUE) == TRUE);
    /* Now set the GUIDs equal and see that the comparison passes */
    qof_instance_increase_editlevel (split1->parent);
    g_object_set (G_OBJECT (split1),
                  "guid", qof_instance_get_guid (QOF_INSTANCE(fixture->split)),
                  NULL);
    qof_instance_increase_editlevel (split1->parent);
    g_assert_true (xaccSplitEqual (fixture->split, split1, TRUE, TRUE, TRUE) == TRUE);
    g_assert_cmpint (checkA.hits, ==, 3);
    g_assert_cmpint (checkB.hits, ==, 1);
    g_assert_cmpint (checkC.hits, ==, 1);
    g_assert_cmpint (checkD.hits, ==, 0);
    /* Change the memo and action and test that each in turn causes the comparison to fail */
    split1->memo = "baz";
    msg03 = g_strdup_printf ("[xaccSplitEqual] memos differ: (%p)%s vs (%p)%s",
                             fixture->split->memo, fixture->split->memo,
                             split1->memo, split1->memo);
    checkA.msg = msg03;
    g_assert_true (xaccSplitEqual (fixture->split, split1, TRUE, TRUE, TRUE) == FALSE);
    g_assert_cmpint (checkA.hits, ==, 4);
    g_assert_cmpint (checkB.hits, ==, 1);
    g_assert_cmpint (checkC.hits, ==, 1);
    g_assert_cmpint (checkD.hits, ==, 0);
    split1->memo = fixture->split->memo;
    split1->action = "bar";
    checkA.msg = msg04;
    g_assert_true (xaccSplitEqual (fixture->split, split1, TRUE, TRUE, TRUE) == FALSE);
    g_log_remove_handler (logdomain, hdlr);
    hdlr  = g_log_set_handler (logdomain, loglevel,
                               (GLogFunc)test_list_handler, &checkA);
    g_assert_true (xaccSplitEqual (fixture->split, split1, TRUE, TRUE, TRUE) == FALSE);
    g_assert_cmpint (checkA.hits, ==, 6);
    g_assert_cmpint (checkB.hits, ==, 1);
    g_assert_cmpint (checkC.hits, ==, 1);
    g_assert_cmpint (checkD.hits, ==, 0);
    /* Split2 doesn't have balances copied from fixture->split, so the balance test fails */
    checkB.msg = msg12;
    checkC.msg = msg13;
    g_assert_true (xaccSplitEqual (fixture->split, split2, TRUE, TRUE, TRUE) == FALSE);
    g_assert_cmpint (checkA.hits, ==, 6);
    g_assert_cmpint (checkB.hits, ==, 2);
    g_assert_cmpint (checkC.hits, ==, 1);
    g_assert_cmpint (checkD.hits, ==, 0);

    split2->balance = fixture->split->balance;
    g_assert_true (xaccSplitEqual (fixture->split, split2, TRUE, TRUE, TRUE) == FALSE);
    g_assert_cmpint (checkA.hits, ==, 6);
    g_assert_cmpint (checkB.hits, ==, 2);
    g_assert_cmpint (checkC.hits, ==, 2);
    g_assert_cmpint (checkD.hits, ==, 0);

    split2->cleared_balance = fixture->split->cleared_balance;
    g_assert_true (xaccSplitEqual (fixture->split, split2, TRUE, TRUE, TRUE) == FALSE);
    g_assert_cmpint (checkA.hits, ==, 6);
    g_assert_cmpint (checkB.hits, ==, 2);
    g_assert_cmpint (checkC.hits, ==, 2);
    g_assert_cmpint (checkD.hits, ==, 1);

    test_clear_error_list ();
    g_assert_true (xaccSplitEqual (fixture->split, split2, TRUE, FALSE, TRUE) == TRUE);
    g_object_unref (split1);
    g_object_unref (split2);
    test_clear_error_list ();
    g_log_remove_handler (logdomain, hdlr);

    g_free (msg03);
}
/* xaccSplitGetAccount
 * xaccSplitSetAccount
 * commit_err
static void commit_err (QofInstance *inst, QofBackendError errcode)
Used as a callback in xaccSplitCommitEdit; it will get tested there via intercepting the warning and testing the signal.
*/
/* xaccSplitCommitEdit
void
xaccSplitCommitEdit(Split *s)// C: 2 in 1
Note that there is no xaccSplitBeginEdit.
Note: Unfortunately most of the internals of this function can't be monitored without a mock Account object.
*/
typedef struct
{
    guint hits;
    QofBackendError lasterr;
} TestErr;

static void
test_error_callback (gpointer pdata, QofBackendError errcode)
{
    TestErr *data = static_cast<TestErr*>(pdata);
    ++(data->hits);
    data->lasterr = errcode;
}
static void
test_xaccSplitCommitEdit (Fixture *fixture, gconstpointer pData)
{
    gboolean sort_dirty, balance_dirty;
    gchar *msg1 = "[xaccSplitCommitEdit()] Account lost track of moved or deleted split.";
    gchar *msg2 = "[xaccSplitCommitEdit()] Account grabbed split prematurely.";
    gchar *logdomain = "gnc.engine";
    GLogLevelFlags loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
    guint hdlr;
    TestErrorStruct checkA = { loglevel, logdomain, msg1, 0 };
    TestErrorStruct checkB = { loglevel, logdomain, msg2, 0 };
    TestSignal sig1, sig2;
    TestErr error = { 0, ERR_BACKEND_NO_ERR };
    Account *oacc = xaccMallocAccount (xaccSplitGetBook (fixture->split));
    Transaction *opar = xaccMallocTransaction (xaccSplitGetBook (fixture->split));
    test_add_error (&checkA);
    test_add_error (&checkB);
    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_list_handler, &checkA);
    hdlr = g_log_set_handler (logdomain, loglevel,
                              (GLogFunc)test_list_handler, &checkA);

    fixture->split->orig_acc = oacc;
    fixture->split->orig_parent = opar;

    gnc_engine_add_commit_error_callback ((EngineCommitErrorCallback)test_error_callback, &error);
    sig1 = test_signal_new (QOF_INSTANCE (fixture->split->orig_parent), QOF_EVENT_MODIFY, NULL);
    sig2 = test_signal_new (QOF_INSTANCE (fixture->split->lot), QOF_EVENT_MODIFY, NULL);

    qof_instance_set_dirty (QOF_INSTANCE (fixture->split));

    xaccSplitCommitEdit (fixture->split);

    g_object_get (fixture->split->acc,
                  "sort-dirty", &sort_dirty,
                  "balance-dirty", &balance_dirty,
                  NULL);
    g_assert_cmpint (sort_dirty, ==, TRUE);
    g_assert_cmpint (balance_dirty, ==, FALSE);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split->parent)));
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    test_signal_assert_hits (sig1, 1);
    test_signal_assert_hits (sig2, 3);
    g_assert_cmpint (error.hits, ==, 0);
    g_assert_cmpint (error.lasterr, ==, ERR_BACKEND_NO_ERR);
    g_assert_true (fixture->split->orig_acc == fixture->split->acc);
    g_assert_true (fixture->split->orig_parent == fixture->split->parent);
    g_assert_cmpint (checkA.hits, ==, 4);
    g_assert_cmpint (checkB.hits, ==, 2);

    qof_instance_mark_clean (QOF_INSTANCE (fixture->split->parent));
    qof_instance_increase_editlevel (fixture->split->acc);
    g_object_set (fixture->split->acc,
                  "sort-dirty", FALSE,
                  "balance-dirty", FALSE,
                  NULL);
    qof_instance_decrease_editlevel (fixture->split->acc);

    qof_instance_set_dirty (QOF_INSTANCE (fixture->split));
    xaccSplitCommitEdit (fixture->split);
    g_object_get (fixture->split->acc,
                  "sort-dirty", &sort_dirty,
                  "balance-dirty", &balance_dirty,
                  NULL);
    g_assert_cmpint (sort_dirty, ==, TRUE);
    g_assert_cmpint (balance_dirty, ==, FALSE);
    g_assert_true (!qof_instance_is_dirty (QOF_INSTANCE (fixture->split->parent)));
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    test_signal_assert_hits (sig1, 1);
    test_signal_assert_hits (sig2, 4);
    g_assert_cmpint (checkA.hits, ==, 4);
    g_assert_cmpint (checkB.hits, ==, 2);
    g_assert_cmpint (error.hits, ==, 0);
    g_assert_cmpint (error.lasterr, ==, ERR_BACKEND_NO_ERR);
    g_assert_true (fixture->split->orig_acc == fixture->split->acc);
    g_assert_true (fixture->split->orig_parent == fixture->split->parent);


    g_log_remove_handler (logdomain, hdlr);
    test_signal_free (sig1);
    test_signal_free (sig2);
    test_destroy (oacc);
    test_destroy (opar);
}
/* xaccSplitRollbackEdit
void
xaccSplitRollbackEdit(Split *s)// C: 2 in 1
*/
static void
test_xaccSplitRollbackEdit (Fixture *fixture, gconstpointer pData)
{
    TestSignal sig1, sig2, sig3;
    Transaction *txn1 = fixture->split->parent;
    Transaction *txn2 = xaccMallocTransaction (xaccSplitGetBook (fixture->split));
    Split *split2 = xaccMallocSplit (xaccSplitGetBook (fixture->split));
    Account *acc = fixture->split->acc;

    /* Set a second split on txn1 so that txn1 isn't destroyed when we
     * remove fixture->split from it.
     */
    xaccTransBeginEdit (txn1);
    xaccSplitSetParent (split2, txn1);
    xaccTransCommitEdit (txn1);

    sig1 = test_signal_new (QOF_INSTANCE (txn1),
                            GNC_EVENT_ITEM_REMOVED, NULL);
    sig2 = test_signal_new (QOF_INSTANCE (txn2),
                            GNC_EVENT_ITEM_ADDED, NULL);
    sig3 = test_signal_new (QOF_INSTANCE (txn1),
                            GNC_EVENT_ITEM_ADDED, NULL);
    fixture->split->orig_acc = NULL;
    g_assert_true (fixture->split->acc != fixture->split->orig_acc);
    fixture->split->orig_parent = NULL;

    xaccSplitRollbackEdit (fixture->split);
    test_signal_assert_hits (sig1, 1);
    test_signal_assert_hits (sig2, 0);
    test_signal_assert_hits (sig3, 0);
    g_assert_true (fixture->split->acc == NULL);
    g_assert_true (fixture->split->parent == NULL);
    g_assert_true (fixture->split->orig_parent == NULL);

    fixture->split->acc = acc;
    fixture->split->orig_acc = acc;
    fixture->split->orig_parent = txn1;
    fixture->split->parent = txn2;
    qof_instance_set_destroying (fixture->split, TRUE);

    xaccSplitRollbackEdit (fixture->split);
    g_assert_true (fixture->split->acc == acc);
    g_assert_true (fixture->split->parent == txn1);
    g_assert_true (fixture->split->orig_parent == txn1);
    test_signal_assert_hits (sig1, 1);
    test_signal_assert_hits (sig2, 1);
    test_signal_assert_hits (sig3, 1);
    g_assert_true (fixture->split->parent == fixture->split->orig_parent);
    g_assert_true (fixture->split->parent == txn1);

    test_signal_free (sig1);
    test_signal_free (sig2);
    test_signal_free (sig3);
}
/* xaccSplitLookup
Split *
xaccSplitLookup (const GncGUID *guid, QofBook *book)// C: 24 in 9
*/
static void
test_xaccSplitLookup (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    const GncGUID *guid = xaccSplitGetGUID (fixture->split);
    Split *split = xaccSplitLookup (NULL, book);
    g_assert_true (split == NULL);
    split = xaccSplitLookup (guid, NULL);
    g_assert_true (split == NULL);
    split = xaccSplitLookup (guid, book);
    g_assert_true (split == fixture->split);
}
/* xaccSplitDetermineGainStatus
void
xaccSplitDetermineGainStatus (Split *split)// C: 7 in 2
*/
static void
test_xaccSplitDetermineGainStatus (Fixture *fixture, gconstpointer pData)
{
    guint gains = fixture->split->gains;
    Split *g_split = fixture->split->gains_split;
    const GncGUID *g_guid = xaccSplitGetGUID (g_split);
    g_assert_cmpint (gains, !=, GAINS_STATUS_UNKNOWN);
    xaccSplitDetermineGainStatus (fixture->split);
    g_assert_cmpint (fixture->split->gains, ==, gains);
    g_assert_true (fixture->split->gains_split == g_split);

    g_assert_true (g_split != NULL);
    fixture->split->gains = GAINS_STATUS_UNKNOWN;
    xaccSplitDetermineGainStatus (fixture->split);
    g_assert_cmpint (fixture->split->gains, ==, GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY);
    g_assert_true (fixture->split->gains_split == g_split);

    fixture->split->gains = GAINS_STATUS_UNKNOWN;
    fixture->split->gains_split = NULL;
    g_assert_true (fixture->split->inst.kvp_data->get_slot({"gains_source"}) == NULL);
    xaccSplitDetermineGainStatus (fixture->split);
    g_assert_true (fixture->split->gains_split == NULL);
    g_assert_cmpint (fixture->split->gains, ==, GAINS_STATUS_A_VDIRTY | GAINS_STATUS_DATE_DIRTY);

    fixture->split->inst.kvp_data->set({"gains-source"}, new KvpValue(guid_copy(g_guid)));
    g_assert_true (fixture->split->gains_split == NULL);
    fixture->split->gains = GAINS_STATUS_UNKNOWN;
    xaccSplitDetermineGainStatus (fixture->split);
    g_assert_true (fixture->split->gains_split == g_split);
    g_assert_cmpint (fixture->split->gains, ==, GAINS_STATUS_GAINS);
}
/* get_currency_denom
static inline int
get_currency_denom(const Split * s)// Local: 6:0:0
*/
static void
test_get_currency_denom (Fixture *fixture, gconstpointer pData)
{
    Transaction *txn = fixture->split->parent;
    const gint denom = gnc_commodity_get_fraction (fixture->curr);
    g_assert_cmpint (fixture->func->get_currency_denom (NULL), ==, 0);
    fixture->split->parent = NULL;
    g_assert_cmpint (fixture->func->get_currency_denom (fixture->split), ==, GNC_DENOM_AUTO);
    fixture->split->parent = txn;
    txn->common_currency = NULL;
    g_assert_cmpint (fixture->func->get_currency_denom (fixture->split), ==, GNC_DENOM_AUTO);
    txn->common_currency = fixture->curr;
    g_assert_cmpint (fixture->func->get_currency_denom (fixture->split), ==, denom);
}
/* get_commodity_denom
static inline int
get_commodity_denom(const Split * s)// Local: 5:0:0
*/
static void
test_get_commodity_denom (Fixture *fixture, gconstpointer pData)
{
    Account *acc = fixture->split->acc;
    const gint denom = gnc_commodity_get_fraction (fixture->comm);
    g_assert_cmpint (fixture->func->get_commodity_denom (NULL), ==, 0);
    fixture->split->acc = NULL;
    g_assert_cmpint (fixture->func->get_commodity_denom (fixture->split), ==, GNC_DENOM_AUTO);
    fixture->split->acc = acc;
    g_assert_cmpint (fixture->func->get_commodity_denom (fixture->split), ==, denom);
}
/* xaccSplitSetSharePriceAndAmount
void
xaccSplitSetSharePriceAndAmount (Split *s, gnc_numeric price, gnc_numeric amt)// C: 1
*/
static void
test_xaccSplitSetSharePriceAndAmount (Fixture *fixture, gconstpointer pData)
{
    gnc_numeric price = {678, 100};
    gnc_numeric amt = {10000, 1000};

    xaccSplitSetSharePriceAndAmount (fixture->split, price, amt);
    g_assert_cmpint (fixture->split->value.num, ==, 16272);
    g_assert_cmpint (fixture->split->amount.num, ==, 10000);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    price.denom = 1000;

    xaccSplitSetSharePriceAndAmount (fixture->split, price, amt);
    g_assert_cmpint (fixture->split->value.num, ==, 1627);
    g_assert_cmpint (fixture->split->amount.num, ==, 10000);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
}
/* Used as a QofObject setter. Does the same as xaccSplitSetSharePrice
 * without the beginEdit/commitEdit and marking dirty.
 */
/* qofSplitSetSharePrice
static void
qofSplitSetSharePrice (Split *split, gnc_numeric price)//
*/
/* xaccSplitSetSharePrice
void
xaccSplitSetSharePrice (Split *s, gnc_numeric price)// C: 2 in 1
*/
static void
test_xaccSplitSetSharePrice (Fixture *fixture, gconstpointer pData)
{
    gnc_numeric price = {678, 100};

    xaccSplitSetSharePrice (fixture->split, price);
    g_assert_cmpint (fixture->split->value.num, ==, 522);
    g_assert_cmpint (fixture->split->amount.num, ==, 321);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
}
/* Used as a QofObject setter. Does the same as xaccSplitSetAmount
 * without the beginEdit/commitEdit and marking dirty.
 */
/* qofSplitSetAmount
static void
qofSplitSetAmount (Split *split, gnc_numeric amt)//
*/
/* xaccSplitSetAmount
void
xaccSplitSetAmount (Split *s, gnc_numeric amt)// C: 37 in 19 SCM: 18 in 2 Local: 4:0:0
*/
static void
test_xaccSplitSetAmount (Fixture *fixture, gconstpointer pData)
{
    gnc_numeric amt = {10000, 1000};

    xaccSplitSetAmount (fixture->split, amt);
    g_assert_cmpint (fixture->split->value.num, ==, 123);
    g_assert_cmpint (fixture->split->amount.num, ==, 10000);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
}
/* Used as a QofObject setter. Does the same as xaccSplitSetValue
 * without the beginEdit/commitEdit and marking dirty.
 */
/* qofSplitSetValue
static void
qofSplitSetValue (Split *split, gnc_numeric amt)//
*/
/* xaccSplitSetValue
void
xaccSplitSetValue (Split *s, gnc_numeric amt)// C: 43 in 18 SCM: 18 in 2 Local: 4:0:0
*/
static void
test_xaccSplitSetValue (Fixture *fixture, gconstpointer pData)
{
    gnc_numeric value = {678, 100};

    xaccSplitSetValue (fixture->split, value);
    g_assert_cmpint (fixture->split->value.num, ==, 1627);
    g_assert_cmpint (fixture->split->amount.num, ==, 321);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
}
/* xaccSplitGetBalance // C: 8 in 3 SCM: 4 in 3
 * xaccSplitGetClearedBalance // Not Used
 * xaccSplitGetReconciledBalance // Not Used
 Simple getters. No test.
*/
/* xaccSplitSetBaseValue
void
xaccSplitSetBaseValue (Split *s, gnc_numeric value,// C: 19 in 7
*/
static void
test_xaccSplitSetBaseValue (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    gnc_commodity *gnaira = gnc_commodity_new (book, "Gnaira", "CURRENCY", "GNA", "", 100);
    Account *acc = fixture->split->acc;
    gchar *msg1 = "[xaccSplitSetBaseValue()] split must have a parent account";
    gchar *fmt = "[xaccSplitSetBaseValue()] inappropriate base currency %s "
                 "given split currency=%s and commodity=%s\n";
    gchar *logdomain = "gnc.engine";
    GLogLevelFlags loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
    TestErrorStruct check = { loglevel, logdomain, msg1, 0 };
    gnc_numeric value = { 360, 240 };
    gnc_numeric old_val = fixture->split->value;
    gnc_numeric old_amt = fixture->split->amount;

    GLogFunc oldlogger = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler,
                                  &check);
    /* No parent account */
    fixture->split->acc = NULL;
    xaccSplitSetBaseValue (fixture->split, value, fixture->comm);
    g_assert_true (!qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    xaccTransRollbackEdit (fixture->split->parent);
    g_assert_cmpint (check.hits, ==, 1);
    /* Base currency ==  currency, != commodity */
    fixture->split->acc = acc;
    xaccSplitSetBaseValue (fixture->split, value, fixture->curr);
    g_assert_cmpint (fixture->split->value.num, ==, 360);
    g_assert_cmpint (fixture->split->value.denom, ==, 240);
    g_assert_cmpint (fixture->split->amount.num, ==, 321);
    g_assert_cmpint (fixture->split->amount.denom, ==, 1000);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    g_assert_cmpint (check.hits, ==, 1);

    /* Base currency == currency, == commodity */
    qof_instance_mark_clean (QOF_INSTANCE (fixture->split));
    fixture->split->value = old_val;
    fixture->split->amount = old_amt;
    xaccAccountSetCommodity(fixture->split->acc, fixture->curr);
    xaccSplitSetBaseValue (fixture->split, value, fixture->curr);
//    g_assert_true (gnc_numeric_equal (fixture->split->amount, old_amt));
    g_assert_cmpint (fixture->split->value.num, ==, 360);
    g_assert_cmpint (fixture->split->value.denom, ==, 240);
    g_assert_cmpint (fixture->split->amount.num, ==, 360);
    g_assert_cmpint (fixture->split->amount.denom, ==, 240);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    g_assert_cmpint (check.hits, ==, 1);
    /* Base currency != currency, == commodity */
    qof_instance_mark_clean (QOF_INSTANCE (fixture->split));
    fixture->split->value = old_val;
    fixture->split->amount = old_amt;
    xaccAccountSetCommodity(fixture->split->acc, fixture->comm);
    xaccSplitSetBaseValue (fixture->split, value, fixture->comm);
    g_assert_true (gnc_numeric_equal (fixture->split->value, old_val));
    g_assert_cmpint (fixture->split->amount.num, ==, 1500);
    g_assert_cmpint (fixture->split->amount.denom, ==, 1000);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    g_assert_cmpint (check.hits, ==, 1);

    /* Base currency != currency, != commodity */
    check.msg = g_strdup_printf (fmt, gnc_commodity_get_printname (gnaira),
                                 gnc_commodity_get_printname (fixture->curr),
                                 gnc_commodity_get_printname (fixture->comm));

    qof_instance_mark_clean (QOF_INSTANCE (fixture->split));
    fixture->split->amount = old_amt;
    fixture->split->amount = old_val;
    fixture->split->orig_parent = fixture->split->parent;
    xaccAccountSetCommodity(fixture->split->acc, fixture->comm);
    xaccSplitSetBaseValue (fixture->split, value, gnaira);
    g_assert_true (!qof_instance_is_dirty (QOF_INSTANCE (fixture->split)));
    g_assert_cmpint (check.hits, ==, 2);

    g_free (check.msg);
    g_log_set_default_handler (oldlogger, NULL);
    test_destroy (gnaira);
}
// Not Used
/* xaccSplitGetBaseValue
gnc_numeric
xaccSplitGetBaseValue (const Split *s, const gnc_commodity * base_currency)//
*/
/* xaccSplitConvertAmount
gnc_numeric
xaccSplitConvertAmount (const Split *split, const Account * account)// C: 1
*/
static void
test_xaccSplitConvertAmount (void)
{
    QofBook *book = qof_book_new ();
    gnc_commodity *gnaira = gnc_commodity_new (book, "Gnaira", "CURRENCY",
                            "GNA", "", 240);
    gnc_commodity *gncxx = gnc_commodity_new (book, "Wildebeest Fund", "FUND",
                           "GNCXX", "", 1000);
    gnc_commodity *gnm = gnc_commodity_new (book, "Gnome, Inc.", "NYSE",
                                            "GNM", "", 1000);
    gchar guidstr[GUID_ENCODING_LENGTH+1];

    Account *acc = xaccMallocAccount (book);
    Account *o_acc = xaccMallocAccount (book);
    Account *ya_acc = xaccMallocAccount (book);
    Transaction *txn = xaccMallocTransaction (book);
    Split *split = xaccMallocSplit (book);
    Split *o_split = xaccMallocSplit (book);

    gnc_numeric gnaira_amt = gnc_numeric_create (53214, 240);
    gnc_numeric gncxx_amt = gnc_numeric_create (300000, 1000);
    gnc_numeric result;

    gchar *logdomain = "gnc.engine";
    GLogLevelFlags loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
    TestErrorStruct check = { loglevel, logdomain, NULL, 0 };
    GLogFunc oldlogger = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);

    guid_to_string_buff(xaccSplitGetGUID(o_split), guidstr);
    check.msg = g_strdup_printf ("[xaccSplitConvertAmount()] The split's (%s) amount can't be converted from GNCXX into GNM.", guidstr);
    xaccAccountSetCommodity (acc, gnaira);
    xaccAccountSetCommodity (o_acc, gnaira);
    xaccAccountSetCommodity (ya_acc, gnm);
    xaccTransBeginEdit (txn);
    xaccTransSetCurrency (txn, gnaira);
    xaccSplitSetParent (split, txn);
    xaccSplitSetAccount (split, acc);
    xaccSplitSetParent (o_split, txn);
    xaccSplitSetAccount (o_split, o_acc);
    split->amount = gnaira_amt;
    split->value = gnaira_amt;
    o_split->amount = gnc_numeric_neg (gnaira_amt);
    o_split->value = gnc_numeric_neg (gnaira_amt);

    /* accounts are equal, return the amount */
    xaccTransCommitEdit (txn);
    result = xaccSplitConvertAmount (split, acc);
    g_assert_true (gnc_numeric_equal (result, gnaira_amt));

    /* commodities are equal, return the amount */
    result = xaccSplitConvertAmount (split, o_acc);
    g_assert_true (gnc_numeric_equal (result, gnaira_amt));

    /* commodities are different, but transaction is balanced: Returns the
     * value of o_split
     */
    o_split->amount = gncxx_amt;
    xaccAccountSetCommodity (o_acc, gncxx);
    result = xaccSplitConvertAmount (split, o_acc);
    g_assert_cmpint (result.num, ==, -300000);
    g_assert_cmpint (result.denom, ==, 1000);

    /* commodities are different, transaction is balanced, account isn't
     * the balancing account. Raises error and returns 0,0
     */
    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler,
                                  &check);
    result = xaccSplitConvertAmount (split, ya_acc);
    g_assert_true (gnc_numeric_zero_p (result));
    g_assert_cmpint (check.hits, ==, 1);

    /* Transaction isn't balanced, split has 0 value, returns that */
    split->value = gnc_numeric_zero ();
    result = xaccSplitConvertAmount (split, o_acc);
    g_assert_true (gnc_numeric_zero_p (result));
    g_assert_cmpint (check.hits, ==, 1);

    /* Transaction isn't balanced, compute a conversion */
    split->value = gnc_numeric_create (71330, 240);
    result = xaccSplitConvertAmount (split, o_acc);
    g_assert_cmpint (result.num, ==, -402131);
    g_assert_cmpint (result.denom, ==, 1000);
    g_assert_cmpint (check.hits, ==, 1);

    test_destroy (split);
    test_destroy (acc);
    test_destroy (o_split);
    test_destroy (o_acc);
    test_destroy (ya_acc);
    test_destroy (gnaira);
    test_destroy (gncxx);
    test_destroy (gnm);
    g_log_set_default_handler (oldlogger, NULL);
    g_free (check.msg);
}
/* xaccSplitDestroy
gboolean
xaccSplitDestroy (Split *split)// C: 17 in 9 SCM: 1
*/
static void
notify_destroy (gpointer pdata, GObject *obj)
{
    gboolean *data = (gboolean*)pdata;
    if (! (*data)) *data = TRUE;
}

static void
test_xaccSplitDestroy ()
{
    QofBook *book = qof_book_new ();
    gnc_commodity *gnaira = gnc_commodity_new (book, "Gnaira", "CURRENCY",
                            "GNA", "", 240);
    Account *acc = xaccMallocAccount (book);
    Transaction *txn = xaccMallocTransaction (book);
    Split *split1 = xaccMallocSplit (book);
    Split *split2 = xaccMallocSplit (book);
    gboolean is_destroyed = FALSE;

    xaccAccountSetCommodity (acc, gnaira);
    xaccSplitSetAccount (split1, acc);
    xaccSplitSetAccount (split2, acc);
    xaccTransBeginEdit (txn);
    xaccTransSetCurrency (txn, gnaira);
    xaccSplitSetParent (split1, txn);
    xaccSplitSetParent (split2, txn);
    xaccTransCommitEdit (txn);
    g_object_weak_ref (G_OBJECT (split1), notify_destroy, &is_destroyed);

    xaccSplitDestroy (split1);

    g_assert_cmpint (is_destroyed, ==, TRUE);

    test_destroy (split2);
    test_destroy (txn);
    test_destroy (acc);
    test_destroy (gnaira);
    qof_book_destroy (book);
}
/* xaccSplitOrder
gint
xaccSplitOrder (const Split *sa, const Split *sb)// C: 5 in 3
*/
static void
test_xaccSplitOrder (Fixture *fixture, gconstpointer pData)
{
    Split *split = fixture->split;
    QofBook *book = xaccSplitGetBook (split);
    Split *o_split = xaccMallocSplit (book);
    Transaction *o_txn = xaccMallocTransaction (book);
    Transaction *txn = split->parent;

    g_assert_cmpint (xaccSplitOrder (split, split), ==, 0);
    g_assert_cmpint (xaccSplitOrder (NULL, split), ==, -1);
    g_assert_cmpint (xaccSplitOrder (split, NULL), ==, 1);
    /* This is testing the call to xaccTransOrder: split has a parent and
     * o_split doesn't, so xaccTransOrder returns -1.
     */
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    /* This is testing the call to xaccTransOrder_num_action: split and o_split have
     * parents with the same date_posted so will sort on tran-num or
     * split-action based on book option.
     */
    o_split->parent = o_txn;
    split->parent->date_posted = gnc_time (NULL);
    o_split->parent->date_posted = split->parent->date_posted;

    /* The book_use_split_action_for_num_field book option hasn't been set so it
     * should sort on tran-num, so xaccTransOrder_num_action returns -1.
     */
    split->parent->num = "123";
    split->action = "5";
    o_split->parent->num = "124";
    o_split->action = "6";
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    /* Reverse, so xaccTransOrder_num_action returns +1.
     */
    split->parent->num = "124";
    o_split->parent->num = "123";
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, +1);

    /* Now set the book_use_split_action_for_num_field book option so it will
     * sort on split-action, so xaccTransOrder_num_action returns -1, initially.
     */

    /* create correct slot path */
    g_test_message( "Testing with use-split-action-for-num set to true - t" );
    qof_book_begin_edit (book);
    qof_instance_set (QOF_INSTANCE (book),
		      "split-action-num-field", "t",
		      NULL);
    qof_book_commit_edit (book);
    g_assert_true(qof_book_use_split_action_for_num_field(xaccSplitGetBook(split)) == TRUE);

    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    split->action = "7";
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, +1);

    /* Revert settings for the rest of the test */
    o_split->action = NULL;
    split->action = "foo";
    o_split->parent = NULL;
    qof_book_begin_edit (book);
    qof_instance_set (QOF_INSTANCE (book),
		      "split-action-num-field", "f",
		      NULL);
    qof_book_commit_edit (book);
    g_assert_true(qof_book_use_split_action_for_num_field(xaccSplitGetBook(split)) == FALSE);
    split->parent = NULL;
    /* This should return > 0 because o_split has no memo string */
    g_assert_cmpint (xaccSplitOrder (split, o_split), >, 0);
    o_split->memo = "baz";
    g_assert_cmpint (xaccSplitOrder (split, o_split), <, 0);
    /* This should return > 0 because o_split has no action string */
    o_split->memo = split->memo;
    g_assert_cmpint (xaccSplitOrder (split, o_split), >, 0);
    o_split->action = "waldo";
    g_assert_cmpint (xaccSplitOrder (split, o_split), <, 0);

    o_split->action = split->action;
    o_split->reconciled = NREC;
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, 1);
    split->reconciled = CREC;
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    split->reconciled = o_split->reconciled = YREC;
    o_split->amount = gnc_numeric_create (300, 1000);
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, 1);
    o_split->amount = gnc_numeric_create (400, 1000);
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    o_split->amount = split->amount;
    o_split->value = gnc_numeric_create (100, 240);
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, 1);
    o_split->value = gnc_numeric_create (200, 240);
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    o_split->value = split->value;
    /* Make sure that it doesn't crash if o_split->date_reconciled == NULL */
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, 1);
    o_split->date_reconciled = gnc_time(NULL);
    o_split->date_reconciled -= 50;
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, 1);
    o_split->date_reconciled += 100;
    g_assert_cmpint (xaccSplitOrder (split, o_split), ==, -1);

    o_split->date_reconciled = split->date_reconciled;
    o_split->date_reconciled = split->date_reconciled;

    g_assert_cmpint (xaccSplitOrder (split, o_split), ==,
                     qof_instance_guid_compare (split, o_split));

    /* so that it won't assert during teardown */
    split->parent = txn;
    test_destroy (o_split);
    test_destroy (o_txn);
}
/* xaccSplitOrderDateOnly
gint
xaccSplitOrderDateOnly (const Split *sa, const Split *sb)// C: 2 in 1
*/
static void
test_xaccSplitOrderDateOnly (Fixture *fixture, gconstpointer pData)
{
    /* Doesn't do what you'd first think: It orders based on the
     * transaction date posted.
     */
    Split *split = fixture->split;
    Split *o_split = xaccMallocSplit (xaccSplitGetBook (split));
    Transaction *txn = split->parent;
    Transaction *o_txn = xaccMallocTransaction (xaccSplitGetBook (split));

    g_assert_cmpint (xaccSplitOrderDateOnly (split, split), ==, 0);
    g_assert_cmpint (xaccSplitOrderDateOnly (NULL, split), ==, -1);
    g_assert_cmpint (xaccSplitOrderDateOnly (split, NULL), ==, 1);
    /* This is testing the call to xaccTransOrder: split has a parent and
     * o_split doesn't, so xaccTransOrder returns -1.
     */
    o_split->parent = NULL;
    g_assert_cmpint (xaccSplitOrderDateOnly (split, o_split), ==, -1);
    split->parent = NULL;
    g_assert_cmpint (xaccSplitOrderDateOnly (split, o_split), ==, 0);
    o_split->parent = o_txn;
    g_assert_cmpint (xaccSplitOrderDateOnly (split, o_split), ==, 1);
    split->parent = txn;

    txn->date_posted = gnc_time (nullptr);
    o_txn->date_posted = gnc_time (nullptr);
    o_txn->date_posted -= 50;
    g_assert_cmpint (xaccSplitOrderDateOnly (split, o_split), ==, 1);
    o_txn->date_posted += 100;
    g_assert_cmpint (xaccSplitOrderDateOnly (split, o_split), ==, -1);
    o_txn->date_posted -= 50;
    g_assert_cmpint (xaccSplitOrderDateOnly (split, o_split), ==, -1);

    test_destroy (o_split);
    test_destroy (o_txn);
}
/* get_corr_account_split
static gboolean
get_corr_account_split(const Split *sa, const Split **retval)// Local: 3:0:0
*/
static void
test_get_corr_account_split (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Transaction *txn = fixture->split->parent;
    Split *split1 = xaccMallocSplit (book);
    Split *split2 = xaccMallocSplit (book);
    Split *split3 = xaccMallocSplit (book);
    Split *split4 = xaccMallocSplit (book);
    Split *split5 = xaccMallocSplit (book);
    const Split *result = NULL;
    const gnc_numeric factor = gnc_numeric_create (2, 1);
    Account *acc1 = xaccMallocAccount (book);
    Account *acc2 = xaccMallocAccount (book);
    Account *acc3 = xaccMallocAccount (book);
    Account *acc4 = xaccMallocAccount (book);
    Account *acc5 = xaccMallocAccount (book);
#ifdef USE_CLANG_FUNC_SIG
#define _func "gboolean get_corr_account_split(const Split *, const Split **)"
#else
#define _func "gboolean get_corr_account_split(const Split*, const Split**)"
#endif
    gchar *msg = _func ": assertion 'sa' failed";
#undef _func
    GLogLevelFlags loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
    TestErrorStruct *check = test_error_struct_new ("gnc.engine",
                             loglevel, msg);
    fixture->hdlrs = test_log_set_fatal_handler (fixture->hdlrs, check,
                     (GLogFunc)test_checked_handler);

    xaccAccountSetCommodity (acc1, fixture->curr);
    xaccAccountSetCommodity (acc2, fixture->curr);
    xaccAccountSetCommodity (acc3, fixture->curr);
    xaccAccountSetCommodity (acc4, fixture->curr);
    xaccAccountSetCommodity (acc5, fixture->curr);

    split1->acc = acc1;
    split2->acc = acc2;
    split3->acc = acc3;
    split4->acc = acc4;
    split5->acc = acc5;

    split1->value = gnc_numeric_create (456, 240);
    split2->value = gnc_numeric_neg (fixture->split->value);
    split3->value = gnc_numeric_neg (split1->value);
    split4->value = gnc_numeric_neg (gnc_numeric_mul (fixture->split->value,
                                                      factor,
                                                      GNC_DENOM_AUTO,
                                                      GNC_HOW_RND_NEVER));
    split5->value = fixture->split->value;

    g_assert_true (!fixture->func->get_corr_account_split(fixture->split, &result));
    g_assert_true (result == NULL);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split2, txn);
    xaccTransCommitEdit (txn);

    g_assert_true (fixture->func->get_corr_account_split(fixture->split, &result));
    g_assert_true (result == split2);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split1, txn);
    xaccSplitSetParent (split3, txn);
    xaccTransCommitEdit (txn);

    g_assert_true (!fixture->func->get_corr_account_split(fixture->split, &result));
    g_assert_true (result == NULL);

    /* Test for bug 752035 */
    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split1, NULL);
    xaccSplitSetParent (split2, NULL);
    xaccSplitSetParent (split3, NULL);
    xaccSplitSetParent (split4, txn);
    xaccSplitSetParent (split5, txn);
    xaccTransCommitEdit (txn);

    g_assert_true (!fixture->func->get_corr_account_split(fixture->split, &result));
    g_assert_true (result == NULL);
    g_assert_cmpint (check->hits, ==, 0);

    g_assert_true (!fixture->func->get_corr_account_split(NULL, &result));
    g_assert_true (result == NULL);
    g_assert_cmpint (check->hits, ==, 1);

    test_destroy (split1);
    test_destroy (split2);
    test_destroy (split3);
    test_destroy (acc1);
    test_destroy (acc2);
    test_destroy (acc3);
}
// Not Used
/* xaccSplitGetCorrAccountName
const char *
xaccSplitGetCorrAccountName(const Split *sa)//
*/
/* xaccSplitGetCorrAccountFullName
char *
xaccSplitGetCorrAccountFullName(const Split *sa)// SCM: 1  Local: 2:0:0
*/
static void
test_xaccSplitGetCorrAccountFullName (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Transaction *txn = fixture->split->parent;
    Split *split1 = xaccMallocSplit (book);
    Account *acc0 = xaccMallocAccount (book);
    Account *acc1 = xaccMallocAccount (book);
    Account *acc2 = xaccMallocAccount (book);

    gchar *name1 = "waldo", *name2 = "pepper", *result;
    gchar *err = "-- Split Transaction --";

    xaccAccountSetCommodity (acc2, fixture->curr);
    gnc_account_append_child (acc1, acc2);
    gnc_account_append_child (acc0, acc1);
    split1->acc = acc2;
    split1->value = gnc_numeric_neg (fixture->split->value);
    xaccAccountSetName (acc1, name1);
    xaccAccountSetName (acc2, name2);

    result = xaccSplitGetCorrAccountFullName (fixture->split);
    g_assert_cmpstr (result, ==, err);
    g_free (result);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split1, txn);
    xaccTransCommitEdit (txn);

    result = xaccSplitGetCorrAccountFullName (fixture->split);
    g_assert_cmpstr (result, ==, gnc_account_get_full_name (acc2));
    g_free (result);

    test_destroy (split1);
    test_destroy (acc2);
    test_destroy (acc1);
    test_destroy (acc0);

}
// Make Static
/* xaccSplitGetCorrAccountCode
const char *
xaccSplitGetCorrAccountCode(const Split *sa)// Local: 2:0:0
*/
static void
test_xaccSplitGetCorrAccountCode (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Transaction *txn = fixture->split->parent;
    Split *split1 = xaccMallocSplit (book);
    Account *acc1 = xaccMallocAccount (book);

    gchar *code = "foo";
    gchar *err = "Split";

    xaccAccountSetCommodity (acc1, fixture->curr);
    split1->acc = acc1;
    split1->value = gnc_numeric_neg (fixture->split->value);
    xaccAccountSetCode (acc1, code);

    g_assert_cmpstr (xaccSplitGetCorrAccountCode (fixture->split), ==, err);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split1, txn);
    xaccTransCommitEdit (txn);

    g_assert_cmpstr (xaccSplitGetCorrAccountCode (fixture->split), ==, code);

    test_destroy (split1);
    test_destroy (acc1);
}
/* xaccSplitCompareAccountFullNames
int
xaccSplitCompareAccountFullNames(const Split *sa, const Split *sb)// SCM: 1
*/
static void
test_xaccSplitCompareAccountFullNames (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Transaction *txn = fixture->split->parent;
    Split *split = fixture->split;
    Split *split1 = xaccMallocSplit (book);
    Account *acc0 = xaccMallocAccount (book);
    Account *acc1 = xaccMallocAccount (book);
    Account *acc2 = xaccMallocAccount (book);

    gchar *name1 = "waldo", *name2 = "pepper";

    xaccAccountSetCommodity (acc2, fixture->curr);
    gnc_account_append_child (acc1, acc2);
    gnc_account_append_child (acc0, acc1);
    gnc_account_append_child (acc1, fixture->split->acc);
    split1->acc = acc2;
    split1->value = gnc_numeric_neg (fixture->split->value);
    xaccAccountSetName (acc1, name1);
    xaccAccountSetName (acc2, name2);

    g_assert_cmpint (xaccSplitCompareAccountFullNames (NULL, NULL), ==, 0);
    g_assert_cmpint (xaccSplitCompareAccountFullNames (split, NULL), ==, 1);
    g_assert_cmpint (xaccSplitCompareAccountFullNames (NULL, split), ==, -1);
    g_assert_cmpint (xaccSplitCompareAccountFullNames (split, split1), <, 0);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split1, txn);
    xaccTransCommitEdit (txn);

    test_destroy (split1);
    test_destroy (acc2);
    test_destroy (acc1);
    test_destroy (acc0);
}
/* xaccSplitCompareAccountCodes
int
xaccSplitCompareAccountCodes(const Split *sa, const Split *sb)// SCM: 1
*/
static void
test_xaccSplitCompareAccountCodes (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Account *acc = fixture->split->acc;
    Account *acc1 = xaccMallocAccount (book);
    Split *split = fixture->split;
    Split *split1 = xaccMallocSplit (book);

    gnc_commodity *gnaira = gnc_commodity_new (book, "Gnaira", "CURRENCY",
                            "GNA", "", 240);
    xaccAccountSetCommodity (fixture->split->acc, gnaira);
    xaccAccountSetCommodity (acc1, gnaira);
    split1->acc = acc1;
    split1->value = gnc_numeric_neg (fixture->split->value);
    xaccAccountSetCode (acc1, "bar");
    xaccAccountSetCode (acc, "foo");

    g_assert_cmpint (xaccSplitCompareAccountCodes (NULL, NULL), ==, 0);
    g_assert_cmpint (xaccSplitCompareAccountCodes (split, NULL), ==, 1);
    g_assert_cmpint (xaccSplitCompareAccountCodes (NULL, split), ==, -1);
    g_assert_cmpint (xaccSplitCompareAccountCodes (split, split1), >, 0);

    test_destroy (split1);
    test_destroy (acc1);
    test_destroy (gnaira);
}
/* xaccSplitCompareOtherAccountFullNames
int
xaccSplitCompareOtherAccountFullNames(const Split *sa, const Split *sb)// SCM: 1
*/
static void
test_xaccSplitCompareOtherAccountFullNames (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Transaction *txn = fixture->split->parent;
    Transaction *txn1 = xaccMallocTransaction (book);
    Split *split = fixture->split;
    Split *split1 = xaccMallocSplit (book);
    Split *split2 = xaccMallocSplit (book);
    Split *split3 = xaccMallocSplit (book);
    Account *acc = fixture->split->acc;
    Account *acc0 = xaccMallocAccount (book);
    Account *acc1 = xaccMallocAccount (book);
    Account *acc2 = xaccMallocAccount (book);

    gchar *name1 = "waldo", *name2 = "pepper";

    xaccAccountSetCommodity (acc2, fixture->curr);
    xaccAccountSetCommodity (acc1, fixture->curr);
    gnc_account_append_child (acc1, acc2);
    gnc_account_append_child (acc0, acc1);
    gnc_account_append_child (acc1, fixture->split->acc);
    xaccAccountSetName (acc1, name1);
    xaccAccountSetName (acc2, name2);
    split2->acc = acc1;
    split3->acc = acc;
    split1->value = gnc_numeric_create (456, 240);
    split2->value = gnc_numeric_neg (fixture->split->value);
    split3->value = gnc_numeric_neg (split1->value);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split2, txn);
    xaccTransCommitEdit (txn);

    xaccTransBeginEdit (txn1);
    xaccTransSetCurrency (txn1, fixture->curr);
    xaccSplitSetParent (split1, txn1);
    xaccSplitSetParent (split3, txn1);
    xaccTransCommitEdit (txn1);

    g_assert_cmpint (xaccSplitCompareOtherAccountFullNames (NULL, NULL), ==, 0);
    g_assert_cmpint (xaccSplitCompareOtherAccountFullNames (split, NULL), ==, 1);
    g_assert_cmpint (xaccSplitCompareOtherAccountFullNames (NULL, split), ==, -1);
    g_assert_cmpint (xaccSplitCompareOtherAccountFullNames (split, split1), <, 0);

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split1, txn);
    xaccTransCommitEdit (txn);

    test_destroy (split1);
    test_destroy (split2);
    test_destroy (split3);
    test_destroy (txn1);
    test_destroy (acc2);
    test_destroy (acc1);
    test_destroy (acc0);
}
/* xaccSplitCompareOtherAccountCodes
int
xaccSplitCompareOtherAccountCodes(const Split *sa, const Split *sb)// SCM: 1
*/
static void
test_xaccSplitCompareOtherAccountCodes (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Account *acc = fixture->split->acc;
    Account *acc1 = xaccMallocAccount (book);
    Transaction *txn = fixture->split->parent;
    Transaction *txn1 = xaccMallocTransaction (book);
    Split *split = fixture->split;
    Split *split1 = xaccMallocSplit (book);
    Split *split2 = xaccMallocSplit (book);
    Split *split3 = xaccMallocSplit (book);

    xaccAccountSetCommodity (acc1, fixture->curr);
    split2->acc = acc1;
    split3->acc = acc;
    split1->value = gnc_numeric_create (456, 240);
    split2->value = gnc_numeric_neg (fixture->split->value);
    split3->value = gnc_numeric_neg (split1->value);
    xaccAccountSetCode (acc1, "bar");
    xaccAccountSetCode (acc, "foo");

    xaccTransBeginEdit (txn);
    xaccSplitSetParent (split2, txn);
    xaccTransCommitEdit (txn);

    xaccTransBeginEdit (txn1);
    xaccTransSetCurrency (txn1, fixture->curr);
    xaccSplitSetParent (split1, txn1);
    xaccSplitSetParent (split3, txn1);
    xaccTransCommitEdit (txn1);

    g_assert_cmpint (xaccSplitCompareOtherAccountCodes (NULL, NULL), ==, 0);
    g_assert_cmpint (xaccSplitCompareOtherAccountCodes (split, NULL), ==, 1);
    g_assert_cmpint (xaccSplitCompareOtherAccountCodes (NULL, split), ==, -1);
    g_assert_cmpint (xaccSplitCompareOtherAccountCodes (split, split1), <, 0);

    test_destroy (split1);
    test_destroy (split2);
    test_destroy (split3);
    test_destroy (txn1);
    test_destroy (acc1);
}

/* xaccSplitSetParent
void
xaccSplitSetParent(Split *s, Transaction *t)// C: 10 in 7 SCM: 6 in 2 Local: 3:0:0
*/
static void
test_xaccSplitSetParent (Fixture *fixture, gconstpointer pData)
{
    QofBook *book = xaccSplitGetBook (fixture->split);
    Transaction *txn = fixture->split->parent;
    Transaction *txn1 = xaccMallocTransaction (book);
    Transaction *txn2 = xaccMallocTransaction (book);
    Split *split = fixture->split;
    TestSignal sig1, sig2;
    gchar *logdomain = "gnc.engine";
    GLogLevelFlags loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
    /* FIXME: This error doesn't actually stop execution, so we need to test for it happening. */
    gchar *msg = "[xaccSplitSetParent()] You may not add the split to more"
                 " than one transaction during the BeginEdit/CommitEdit block.";
    TestErrorStruct check = { loglevel, logdomain, msg, 0 };
    GLogFunc oldlogger = g_log_set_default_handler ((GLogFunc)test_null_handler,
                         &check);
    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler, &check);
    sig1 = test_signal_new (QOF_INSTANCE (txn2), GNC_EVENT_ITEM_ADDED, NULL);
    sig2 = test_signal_new (QOF_INSTANCE (txn), GNC_EVENT_ITEM_REMOVED, NULL);

    xaccTransBeginEdit (txn2);
    xaccTransSetCurrency (txn2, fixture->curr);
    split->orig_parent = txn1;
    xaccSplitSetParent (split, txn2);
    g_assert_true (split->parent == txn2);
    g_assert_true (split->orig_parent == txn1);
    test_signal_assert_hits (sig1, 1);
    test_signal_assert_hits (sig2, 1);
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (split)));
    g_assert_cmpint (check.hits, ==, 1);

    test_signal_free (sig1);
    test_signal_free (sig2);
    g_log_set_default_handler (oldlogger, NULL);
    /* txn already destroyed by xaccTransCommitEdit() */
}
/* xaccSplitGetSharePrice
gnc_numeric
xaccSplitGetSharePrice (const Split * split)// C: 3 in 3 SCM: 4 in 3
*/
static void
test_xaccSplitGetSharePrice (Fixture *fixture, gconstpointer pData)
{
    gnc_numeric result, quotient;
    gnc_numeric expected = gnc_numeric_create (0, 1);
    Split *split = fixture->split;
    /* Warning: this is a define in Split.c */
    char *logdomain = "gnc.engine";
    GLogLevelFlags loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
    TestErrorStruct check = { loglevel, logdomain, NULL, 0 };
    guint hdlr = g_log_set_handler (logdomain, loglevel,
                                    (GLogFunc)test_checked_handler, &check);
    GLogFunc oldhandler = g_log_set_default_handler ((GLogFunc)test_null_handler, &check);
    g_test_log_set_fatal_handler ((GTestLogFatalFunc)test_checked_handler,
                                  &check);

    result = xaccSplitGetSharePrice (NULL);
    g_assert_true (gnc_numeric_equal (result, expected));

    expected = gnc_numeric_div (split->value, split->amount,
                                GNC_DENOM_AUTO,
                                GNC_HOW_RND_ROUND_HALF_UP);

    result = xaccSplitGetSharePrice (split);
    g_assert_true (gnc_numeric_equal (result, expected));
    g_assert_cmpint (check.hits, ==, 0);

    expected = gnc_numeric_create (0, 1);
    split->amount = gnc_numeric_zero ();
    result = xaccSplitGetSharePrice (split);
    g_assert_true (gnc_numeric_equal (result, expected));
    g_assert_cmpint (check.hits, ==, 0);

    split->value = gnc_numeric_zero ();
    expected = gnc_numeric_create (0, 1);
    result = xaccSplitGetSharePrice (split);
    g_assert_true (gnc_numeric_equal (result, expected));
    g_assert_cmpint (check.hits, ==, 0);

    /* Now invent some value/amount pairs which cause numeric errors to test the limits */
/* This one was supposed to overflow, but it doesn't any more.
    split->amount = gnc_numeric_create (987654321, 10);
    split->value = gnc_numeric_create (3, 789304166);
    quotient = gnc_numeric_div (split->value, split->amount,
                                GNC_DENOM_AUTO,
                                GNC_HOW_RND_ROUND_HALF_UP);
    check.msg = g_strdup_printf ("[xaccSplitGetSharePrice()] "
                                 "Computing share price failed (%d): [ %"
                                 G_GINT64_FORMAT " / %" G_GINT64_FORMAT
                                 " ] / [ %" G_GINT64_FORMAT " / %"
                                 G_GINT64_FORMAT " ]",
                                 gnc_numeric_check(quotient), split->value.num,
                                 split->value.denom, split->amount.num,
                                 split->amount.denom);
    expected = gnc_numeric_create (0, 1);
    result = xaccSplitGetSharePrice (split);
    g_assert_true (gnc_numeric_equal (result, expected));
    g_assert_cmpint (check.hits, ==, 2);
    g_free (check.msg);
    */
    split->amount = gnc_numeric_create (987654321, 10);
    split->value = gnc_numeric_create (3, 0);
    quotient = gnc_numeric_div (split->value, split->amount,
                                GNC_DENOM_AUTO,
                                GNC_HOW_RND_ROUND_HALF_UP);
    check.msg = g_strdup_printf ("[xaccSplitGetSharePrice()] "
                                 "Computing share price failed (%d): [ %"
                                 G_GINT64_FORMAT " / %" G_GINT64_FORMAT
                                 " ] / [ %" G_GINT64_FORMAT " / %"
                                 G_GINT64_FORMAT " ]",
                                 gnc_numeric_check(quotient), split->value.num,
                                 split->value.denom, split->amount.num,
                                 split->amount.denom);
    expected = gnc_numeric_create (0, 1);
    result = xaccSplitGetSharePrice (split);
    g_assert_true (gnc_numeric_equal (result, expected));
    g_assert_cmpint (check.hits, ==, 2);
    g_free (check.msg);

    split->amount = gnc_numeric_create (9, 0);
    split->value = gnc_numeric_create (3, 789304166);
    quotient = gnc_numeric_div (split->value, split->amount,
                                GNC_DENOM_AUTO,
                                GNC_HOW_RND_ROUND_HALF_UP);
    check.msg = g_strdup_printf ("[xaccSplitGetSharePrice()] "
                                 "Computing share price failed (%d): [ %"
                                 G_GINT64_FORMAT " / %" G_GINT64_FORMAT
                                 " ] / [ %" G_GINT64_FORMAT " / %"
                                 G_GINT64_FORMAT " ]",
                                 gnc_numeric_check(quotient), split->value.num,
                                 split->value.denom, split->amount.num,
                                 split->amount.denom);
    expected = gnc_numeric_create (0, 1);
    result = xaccSplitGetSharePrice (split);
    g_assert_true (gnc_numeric_equal (result, expected));
    g_assert_cmpint (check.hits, ==, 4);
    g_free (check.msg);

    g_log_remove_handler (logdomain, hdlr);
    g_log_set_default_handler (oldhandler, NULL);

}
/* xaccSplitGetType // C: 4 in 2
 * xaccSplitMakeStockSplit // C: 1
 */
static void
test_xaccSplitMakeStockSplit (Fixture *fixture, gconstpointer pData)
{
    Split *split = fixture->split;
    g_assert_cmpstr (xaccSplitGetType (split), ==, "normal");

    xaccSplitMakeStockSplit (split);
    g_assert_cmpstr (xaccSplitGetType (split), ==, "stock-split");
    g_assert_true (qof_instance_is_dirty (QOF_INSTANCE (split)));
}
/* xaccSplitGetOtherSplit
Split *
xaccSplitGetOtherSplit (const Split *split)// C: 13 in 7 SCM: 10 in 4 Local: 1:0:0
*/
static void
test_xaccSplitGetOtherSplit (Fixture *fixture, gconstpointer pData)
{
    Split *split = fixture->split;
    Transaction *txn = split->parent;
    QofBook *book = xaccSplitGetBook (split);
    Split *split1 = xaccMallocSplit (book);
    Split *split2 = xaccMallocSplit (book);
    Account *acc2 = xaccMallocAccount (book);
    KvpValue *kvpnow = new KvpValue (gnc_time (NULL));

    g_assert_true (xaccSplitGetOtherSplit (NULL) == NULL);
    g_assert_true (xaccSplitGetOtherSplit (split1) == NULL);

    g_assert_true (xaccTransUseTradingAccounts (txn) == FALSE);
    g_assert_true (split->inst.kvp_data->get_slot({"lot-split"}) == NULL);
    g_assert_cmpint (xaccTransCountSplits (txn), !=, 2);
    g_assert_true (xaccSplitGetOtherSplit (split) == NULL);

    split1->value = gnc_numeric_neg (split->value);
    xaccSplitSetParent (split1, txn);
    g_assert_true (xaccSplitGetOtherSplit (split) == split1);

    xaccSplitSetParent (split2, txn);
    g_assert_true (xaccSplitGetOtherSplit (split) == NULL);

    split->inst.kvp_data->set({"lot-split"}, kvpnow);
    g_assert_true (split->inst.kvp_data->get_slot({"lot-split"}));
    g_assert_true (xaccSplitGetOtherSplit (split) == NULL);

    split1->inst.kvp_data->set({"lot-split"}, kvpnow);
    g_assert_true (split1->inst.kvp_data->get_slot({"lot-split"}));
    g_assert_true (xaccSplitGetOtherSplit (split) == split2);

    split->inst.kvp_data->set({"lot-split"}, NULL);
    g_assert_true (split->inst.kvp_data->get_slot({"lot-split"}) == NULL);
    split1->inst.kvp_data->set({"lot-split"}, NULL);
    g_assert_true (split1->inst.kvp_data->get_slot({"lot-split"}) == NULL);
    qof_book_begin_edit (book);
    qof_instance_set (QOF_INSTANCE (book),
		      "trading-accts", "t",
		      NULL);
    qof_book_commit_edit (book);
    g_assert_true (xaccTransUseTradingAccounts (txn));
    g_assert_true (xaccSplitGetOtherSplit (split) == NULL);
    split2->acc = acc2;
    xaccAccountSetType (acc2, ACCT_TYPE_TRADING);
    g_assert_true (xaccSplitGetOtherSplit (split) == split1);

    test_destroy (split1);
    test_destroy (split2);
    test_destroy (acc2);
}
/* xaccSplitVoidFormerAmount // SCM: 1  Local: 1:0:0
 * xaccSplitVoidFormerValue // Local: 1:0:0
 * xaccSplitVoid // C: 1 SCM: 1
 * xaccSplitUnvoid // C: 1
*/
static void
test_xaccSplitVoid (Fixture *fixture, gconstpointer pData)
{
    gnc_numeric value = fixture->split->value;
    gnc_numeric amount = fixture->split->amount;
    g_assert_true (gnc_numeric_zero_p (xaccSplitVoidFormerAmount (fixture->split)));
    g_assert_true (gnc_numeric_zero_p (xaccSplitVoidFormerValue (fixture->split)));
    xaccSplitVoid (fixture->split);
    g_assert_true (gnc_numeric_zero_p (fixture->split->value));
    g_assert_true (gnc_numeric_zero_p (fixture->split->amount));
    g_assert_true (gnc_numeric_equal (xaccSplitVoidFormerAmount (fixture->split),
                                 amount));
    g_assert_true (gnc_numeric_equal (xaccSplitVoidFormerValue (fixture->split),
                                 value));
    g_assert_cmpint (fixture->split->reconciled, ==, VREC);
    xaccSplitUnvoid (fixture->split);
    g_assert_true (gnc_numeric_equal (fixture->split->value, value));
    g_assert_true (gnc_numeric_equal (fixture->split->amount, amount));
    g_assert_true (gnc_numeric_zero_p (xaccSplitVoidFormerAmount (fixture->split)));
    g_assert_true (gnc_numeric_zero_p (xaccSplitVoidFormerValue (fixture->split)));
    g_assert_cmpint (fixture->split->reconciled, ==, NREC);
}

/* The rest of these are simple setters and getters unworthy of testing:
 * qofSplitSetMemo // Not Used
 * xaccSplitSetMemo // C: 26 in 13 SCM: 2 in 2 Local: 1:0:0
 * qofSplitSetAction // Not Used
 * xaccSplitSetAction // C: 16 in 10 SCM: 1  Local: 1:0:0
 * qofSplitSetReconcile // Not Used
 * xaccSplitSetReconcile // C: 14 in 11 SCM: 7 in 1 Local: 2:0:0
 * xaccSplitSetDateReconciledSecs // C: 4 in 2
 * xaccSplitSetDateReconciledTS // C: 5 in 5  Local: 1:0:0
 * xaccSplitGetDateReconciledTS // C: 1
 * xaccSplitRetDateReconciledTS // C: 2 in 2
 * xaccSplitGetParent // C: 111 in 30 SCM: 67 in 17 Local: 1:0:0
 * xaccSplitGetLot // C: 7 in 6 SCM: 3 in 3
 * xaccSplitSetLot // C: 2 in 1  Local: 1:0:0
 * xaccSplitGetMemo // C: 26 in 15 SCM: 8 in 7
 * xaccSplitGetAction // C: 6 in 6 SCM: 3 in 3
 * xaccSplitGetReconcile // C: 18 in 11 SCM: 1
 * xaccSplitGetAmount // C: 64 in 20 SCM: 25 in 12 Local: 13:0:0
 * xaccSplitGetValue // C: 52 in 17 SCM: 33 in 14 Local: 11:0:0
 * xaccSplitGetBook // Not Used
 * split_account_guid_getter // Not Used
 * DxaccSplitGetShareAmount // Not Used
 * no_op // Not Used
 * qofSplitSetParentTrans // Not Used
 * qofSplitSetAccount // Not Used
 */
/* This is the QofObject initialization function:
 * xaccSplitRegister // C: 1  Local: 1:0:0
 */


void
test_suite_split (void)
{

    GNC_TEST_ADD_FUNC (suitename, "gnc split init", test_gnc_split_init);
    GNC_TEST_ADD_FUNC (suitename, "gnc split dispose", test_gnc_split_dispose);
    GNC_TEST_ADD_FUNC (suitename, "gnc split set & get property", test_gnc_split_set_get_property);
    GNC_TEST_ADD (suitename, "xaccMallocSplit", Fixture, NULL, setup, test_xaccMallocSplit, teardown);
    GNC_TEST_ADD (suitename, "xaccDupeSplit", Fixture, NULL, setup, test_xaccDupeSplit, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitCloneNoKvp", Fixture, NULL, setup, test_xaccSplitCloneNoKvp, teardown);
    GNC_TEST_ADD (suitename, "mark split", Fixture, NULL, setup, test_mark_split, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitEqualCheckBal", Fixture, NULL, setup, test_xaccSplitEqualCheckBal, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitEqual", Fixture, NULL, setup, test_xaccSplitEqual, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitCommitEdit", Fixture, NULL, setup, test_xaccSplitCommitEdit, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitRollbackEdit", Fixture, NULL, setup, test_xaccSplitRollbackEdit, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitLookup", Fixture, NULL, setup, test_xaccSplitLookup, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitDetermineGainStatus", Fixture, NULL, setup, test_xaccSplitDetermineGainStatus, teardown);
    GNC_TEST_ADD (suitename, "get currency denom", Fixture, NULL, setup, test_get_currency_denom, teardown);
    GNC_TEST_ADD (suitename, "get commodity denom", Fixture, NULL, setup, test_get_commodity_denom, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitSetSharePriceAndAmount", Fixture, NULL, setup, test_xaccSplitSetSharePriceAndAmount, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitSetSharePrice", Fixture, NULL, setup, test_xaccSplitSetSharePrice, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitSetAmount", Fixture, NULL, setup, test_xaccSplitSetAmount, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitSetValue", Fixture, NULL, setup, test_xaccSplitSetValue, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitSetBaseValue", Fixture, NULL, setup, test_xaccSplitSetBaseValue, teardown);
    GNC_TEST_ADD_FUNC (suitename, "xaccSplitConvertAmount", test_xaccSplitConvertAmount);
    GNC_TEST_ADD_FUNC (suitename, "xaccSplitDestroy", test_xaccSplitDestroy);
    GNC_TEST_ADD (suitename, "xaccSplitOrder", Fixture, NULL, setup, test_xaccSplitOrder, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitOrderDateOnly", Fixture, NULL, setup, test_xaccSplitOrderDateOnly, teardown);
    GNC_TEST_ADD (suitename, "get corr account split", Fixture, NULL, setup, test_get_corr_account_split, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitGetCorrAccountFullName", Fixture, NULL, setup, test_xaccSplitGetCorrAccountFullName, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitGetCorrAccountCode", Fixture, NULL, setup, test_xaccSplitGetCorrAccountCode, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitCompareAccountFullNames", Fixture, NULL, setup, test_xaccSplitCompareAccountFullNames, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitCompareAccountCodes", Fixture, NULL, setup, test_xaccSplitCompareAccountCodes, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitCompareOtherAccountFullNames", Fixture, NULL, setup, test_xaccSplitCompareOtherAccountFullNames, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitCompareOtherAccountCodes", Fixture, NULL, setup, test_xaccSplitCompareOtherAccountCodes, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitSetParent", Fixture, NULL, setup, test_xaccSplitSetParent, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitGetSharePrice", Fixture, NULL, setup, test_xaccSplitGetSharePrice, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitMakeStockSplit", Fixture, NULL, setup, test_xaccSplitMakeStockSplit, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitGetOtherSplit", Fixture, NULL, setup, test_xaccSplitGetOtherSplit, teardown);
    GNC_TEST_ADD (suitename, "xaccSplitVoid", Fixture, NULL, setup, test_xaccSplitVoid, teardown);

}
