Merge Christian Gruber's 'test_import_backend' into master.

This commit is contained in:
John Ralls 2020-05-20 17:08:54 -07:00
commit f2a13ecac7
16 changed files with 1303 additions and 0 deletions

View File

@ -37,3 +37,51 @@ gnc_add_test(test-import-account-matcher gtest-import-account-matcher.cpp
set_dist_list(test_generic_import_DIST CMakeLists.txt
test-import-parse.c test-import-pending-matches.cpp
gtest-import-account-matcher.cpp)
set(gtest_import_backend_INCLUDE_DIRS
${CMAKE_BINARY_DIR}/common # for config.h
${CMAKE_SOURCE_DIR}/common
${CMAKE_SOURCE_DIR}/gnucash/import-export
${CMAKE_SOURCE_DIR}/libgnucash/app-utils
${CMAKE_SOURCE_DIR}/libgnucash/app-utils/mocks
${CMAKE_SOURCE_DIR}/libgnucash/core-utils
${CMAKE_SOURCE_DIR}/libgnucash/engine
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks
${GTEST_INCLUDE_DIR}
${GMOCK_INCLUDE_DIR}
)
set(gtest_import_backend_LIBS
PkgConfig::GTK3
${Boost_LIBRARIES}
${GMODULE_LDFLAGS}
${GTHREAD_LDFLAGS}
${ICU4C_I18N_LDFLAGS}
gmock
gtest
)
set(gtest_import_backend_SOURCES
gtest-import-backend.cpp
${CMAKE_SOURCE_DIR}/gnucash/import-export/import-backend.c
${CMAKE_SOURCE_DIR}/gnucash/import-export/import-settings.c
${CMAKE_SOURCE_DIR}/gnucash/import-export/import-utilities.c
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks/gmock-qofinstance.cpp
${CMAKE_SOURCE_DIR}/libgnucash/app-utils/mocks/gmock-gnc-prefs.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks/gmock-qofbook.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks/gmock-Account.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks/gmock-Transaction.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks/gmock-Split.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/mocks/gmock-qofquery.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/gnc-numeric.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/gnc-rational.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/gnc-int128.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/gnc-date.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/gnc-datetime.cpp
${CMAKE_SOURCE_DIR}/libgnucash/engine/gnc-timezone.cpp
${CMAKE_SOURCE_DIR}/libgnucash/core-utils/gnc-locale-utils.cpp
)
gnc_add_test(test-import-backend "${gtest_import_backend_SOURCES}"
gtest_import_backend_INCLUDE_DIRS gtest_import_backend_LIBS)

View File

@ -0,0 +1,273 @@
#include <gtk/gtk.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <config.h>
#include <gnc-datetime.hpp>
extern "C"
{
#include <import-backend.h>
#include <engine-helpers.h>
#include <gnc-ui-util.h>
}
#include "gmock-gnc-prefs.h"
#include "gmock-qofbook.h"
#include "gmock-Account.h"
#include "gmock-Transaction.h"
#include "gmock-Split.h"
/* Global test environment */
class TestEnvironment : public testing::Environment
{
public:
void SetUp()
{
m_book = new QofMockBook;
};
void TearDown()
{
m_book->free();
};
QofMockBook* m_book;
};
testing::Environment* const env = testing::AddGlobalTestEnvironment(new TestEnvironment);
/* mock functions, which can not be mocked by mock classes */
gint
safe_strcasecmp (const gchar * da, const gchar * db)
{
// use simplified case-sensitive string comparison as mock up
return g_strcmp0(da, db);
}
const char *
qof_log_prettify (const char *name)
{
// do nothing
return name;
}
// this is a slightly modified version of the function from engine-helpers.c
const char *
gnc_get_num_action (const Transaction *trans, const Split *split)
{
gboolean num_action = qof_book_use_split_action_for_num_field(gnc_get_current_book());
if (trans && !split)
return xaccTransGetNum(trans);
if (split && !trans)
return xaccSplitGetAction(split);
if (trans && split)
{
if (num_action)
return xaccSplitGetAction(split);
else
return xaccTransGetNum(trans);
}
else return NULL;
}
QofBook *
gnc_get_current_book (void)
{
return ((TestEnvironment*)env)->m_book;
}
/* GMock MATCHERS */
// GMock MATCHER to check for duplicates in containers
MATCHER(HasDuplicates, std::string("has ") + std::string(negation ? "no " : "") + std::string("duplicated elements"))
{
bool ret = false;
for (auto e : arg)
{
if (std::count(arg.begin(), arg.end(), e) > 1)
{
ret = true;
break;
}
}
return ret;
}
// Test fixture for tests without bayesian matching
class ImportBackendTest : public testing::Test
{
protected:
void SetUp()
{
m_prefs = MockPrefsBackend::getInstance();
ASSERT_NE(m_prefs, nullptr);
m_import_acc = new MockAccount();
m_dest_acc = new MockAccount();
m_trans = new MockTransaction();
m_split = new MockSplit();
using namespace testing;
// define behaviour of m_import_acc
ON_CALL(*m_import_acc, getBook())
.WillByDefault(Return(((TestEnvironment*)env)->m_book));
}
void TearDown()
{
m_import_acc->free();
m_dest_acc->free();
m_trans->free();
m_split->free();
}
MockPrefsBackend* m_prefs;
MockAccount* m_import_acc;
MockAccount* m_dest_acc;
MockTransaction* m_trans;
MockSplit* m_split;
};
/* Tests using fixture ImportBackendTest */
//! Test for function gnc_import_TransInfo_new()
TEST_F(ImportBackendTest, CreateTransInfo)
{
GncMockImportMatchMap imap(m_import_acc);
gchar* online_id;
using namespace testing;
//qof_instance_get (QOF_INSTANCE (split), "online-id", &online_id, NULL);
// Define first split
ON_CALL(*m_trans, getSplit(0))
.WillByDefault(Return(m_split));
// define description of the transaction
ON_CALL(*m_trans, getDescription())
.WillByDefault(Return("This is the description"));
// function gnc_import_TransInfo_new() should try to find account using the description from the transaction
EXPECT_CALL(imap, findAccount(_, StrEq("This is the description")))
.WillOnce(Return(m_dest_acc));
// call function to be tested
GNCImportTransInfo *trans_info = gnc_import_TransInfo_new(m_trans, &imap);
// check 'trans_info'
EXPECT_EQ(gnc_import_TransInfo_get_fsplit(trans_info), m_split);
EXPECT_EQ(gnc_import_TransInfo_get_destacc(trans_info), m_dest_acc);
// transaction is not open anymore
ON_CALL(*m_trans, isOpen())
.WillByDefault(Return(false));
// delete transaction info
gnc_import_TransInfo_delete(trans_info);
};
// Test fixture for tests with bayesian matching
class ImportBackendBayesTest : public ImportBackendTest
{
protected:
void SetUp()
{
ImportBackendTest::SetUp();
using namespace testing;
// set bayesian import matching in preferences
ON_CALL(*m_prefs, getBool(StrEq(GNC_PREFS_GROUP_IMPORT), StrEq(GNC_PREF_USE_BAYES)))
.WillByDefault(Return(true));
}
void TearDown()
{
ImportBackendTest::TearDown();
};
};
/* Tests using fixture ImportBackendBayesTest */
//! Test for function gnc_import_TransInfo_new()
TEST_F(ImportBackendBayesTest, CreateTransInfo)
{
using namespace testing;
GncMockImportMatchMap imap(m_import_acc);
time64 date(GncDateTime(GncDate(2020, 3, 18)));
struct tm *tm_struct;
char local_day_of_week[16];
// get local day of week
tm_struct = gnc_gmtime(&date);
qof_strftime(local_day_of_week, sizeof(local_day_of_week), "%A", tm_struct);
gnc_tm_free(tm_struct);
// Define first split
ON_CALL(*m_trans, getSplit(0))
.WillByDefault(Return(m_split));
// Transaction has no further splits
ON_CALL(*m_trans, getSplit(Gt(0)))
.WillByDefault(Return(nullptr));
// Define description and memo of first split
// This transaction is used for testing tokenization of its content.
// Therefore the description text and the memo should contain
// * consecutive separators
// * separators at the beginning and end of string
// * duplicated tokens within and between description text end memo
// The token separator is space.
ON_CALL(*m_trans, getDescription())
.WillByDefault(Return(" test tokens within description tokens "));
ON_CALL(*m_split, getMemo())
.WillByDefault(Return(" test the memo test "));
// Define transaction date
ON_CALL(*m_trans, getDate())
.WillByDefault(Return(date));
// check tokens created from transaction
EXPECT_CALL(imap, findAccountBayes(AllOf(
Each(Not(IsEmpty())), // tokens must not be empty strings
Each(Not(HasSubstr(" "))), // tokens must not contain separator
Not(HasDuplicates()), // tokens must be unique
Contains(StrEq(local_day_of_week)), // tokens must contain local day of week
Contains(StrEq("description")), // spot sample
Contains(StrEq("memo")) // spot sample
)))
.WillOnce(Return(m_dest_acc));
// call function to be tested
GNCImportTransInfo *trans_info = gnc_import_TransInfo_new(m_trans, &imap);
// check 'trans_info'
EXPECT_EQ(gnc_import_TransInfo_get_fsplit(trans_info), m_split);
EXPECT_EQ(gnc_import_TransInfo_get_destacc(trans_info), m_dest_acc);
// transaction is not open anymore
ON_CALL(*m_trans, isOpen())
.WillByDefault(Return(false));
// delete transaction info
gnc_import_TransInfo_delete(trans_info);
};

View File

@ -0,0 +1,47 @@
#include <config.h>
#include "gmock-gnc-prefs.h"
PrefsBackend* prefsbackend = NULL;
gboolean
gnc_prefs_get_bool (const gchar *group, const gchar *pref_name)
{
return ((MockPrefsBackend*)prefsbackend)->getBool(group, pref_name);
}
gint
gnc_prefs_get_int (const gchar *group, const gchar *pref_name)
{
return ((MockPrefsBackend*)prefsbackend)->getInt(group, pref_name);
}
gint64
gnc_prefs_get_int64 (const gchar *group, const gchar *pref_name)
{
return ((MockPrefsBackend*)prefsbackend)->getInt64(group, pref_name);
}
gdouble
gnc_prefs_get_float (const gchar *group, const gchar *pref_name)
{
return ((MockPrefsBackend*)prefsbackend)->getFloat(group, pref_name);
}
gchar *
gnc_prefs_get_string (const gchar *group, const gchar *pref_name)
{
return ((MockPrefsBackend*)prefsbackend)->getString(group, pref_name);
}
gint
gnc_prefs_get_enum (const gchar *group, const gchar *pref_name)
{
return ((MockPrefsBackend*)prefsbackend)->getEnum(group, pref_name);
}
void
gnc_prefs_get_coords (const gchar *group, const gchar *pref_name, gdouble *x, gdouble *y)
{
((MockPrefsBackend*)prefsbackend)->getCoords(group, pref_name, x, y);
}

View File

@ -0,0 +1,47 @@
#ifndef GMOCK_GNC_PREFS_H
#define GMOCK_GNC_PREFS_H
#include <gmock/gmock.h>
extern "C"
{
#include <gnc-prefs.h>
#include <gnc-prefs-p.h>
}
// mock up for PrefsBackend (singleton class)
class MockPrefsBackend : PrefsBackend
{
public:
MockPrefsBackend(MockPrefsBackend const&) = delete;
MockPrefsBackend& operator=(MockPrefsBackend const&) = delete;
static MockPrefsBackend* getInstance()
{
static MockPrefsBackend prefs; // preferences object
// register preferences object
if (prefsbackend == NULL)
prefsbackend = (PrefsBackend*)&prefs;
// check that preferences object is correctly registered
EXPECT_EQ((MockPrefsBackend*)prefsbackend, &prefs);
return &prefs;
}
MOCK_METHOD2(getBool, gboolean(const gchar *, const gchar *));
MOCK_METHOD2(getInt, gint(const gchar *, const gchar *));
MOCK_METHOD2(getInt64, gint64(const gchar *, const gchar *));
MOCK_METHOD2(getFloat, gdouble(const gchar *, const gchar *));
MOCK_METHOD2(getString, gchar*(const gchar *, const gchar *));
MOCK_METHOD2(getEnum, gint(const gchar *, const gchar *));
MOCK_METHOD4(getCoords, void(const gchar *, const gchar *, gdouble *, gdouble *));
private:
MockPrefsBackend() {}
~MockPrefsBackend() {}
};
#endif

View File

@ -0,0 +1,114 @@
#include <config.h>
#include "gmock-Account.h"
struct _MockAccountClass
{
QofInstanceClass parent_class;
};
typedef struct _MockAccountClass MockAccountClass;
G_DEFINE_TYPE(MockAccount, gnc_mock_account, QOF_TYPE_INSTANCE);
static void
gnc_mock_account_init (MockAccount *inst)
{
// function is unused, initialization is done in the MockAccount's constructor
}
static void
gnc_mock_account_class_init(MockAccountClass *klass)
{
// function is unused, class functions are defined in C++ code
}
void
xaccAccountBeginEdit (Account *account)
{
g_return_if_fail(GNC_IS_MOCK_ACCOUNT(account));
((MockAccount*)account)->beginEdit();
}
void
xaccAccountCommitEdit (Account *account)
{
g_return_if_fail(GNC_IS_MOCK_ACCOUNT(account));
((MockAccount*)account)->commitEdit();
}
QofBook *
gnc_account_get_book(const Account *account)
{
g_return_val_if_fail(GNC_IS_MOCK_ACCOUNT(account), NULL);
return ((MockAccount*)account)->getBook();
}
gint
xaccAccountForEachTransaction(const Account *acc, TransactionCallback proc,
void *data)
{
g_return_val_if_fail(GNC_IS_MOCK_ACCOUNT(acc), 0);
return ((MockAccount*)acc)->forEachTransaction(proc, data);
}
GncImportMatchMap *
gnc_account_imap_create_imap (Account *acc)
{
g_return_val_if_fail(GNC_IS_MOCK_ACCOUNT(acc), NULL);
return ((MockAccount*)acc)->imapCreateImap();
}
Account*
gnc_account_imap_find_account (
GncImportMatchMap *imap,
const char* category,
const char *key)
{
return ((GncMockImportMatchMap*)imap)->findAccount(category, key);
}
void
gnc_account_imap_add_account (
GncImportMatchMap *imap,
const char *category,
const char *key,
Account *acc)
{
// not used at the moment
((GncMockImportMatchMap*)imap)->addAccount(category, key, acc);
}
Account*
gnc_account_imap_find_account_bayes (
GncImportMatchMap *imap,
GList *tokens)
{
// \todo use std::list instead of std::vector, since GList is a double-linked list like std::list
std::vector<std::string> tokenVec;
for (auto token = tokens; token; token = token->next)
{
tokenVec.push_back(static_cast <char const *> (token->data));
}
return ((GncMockImportMatchMap*)imap)->findAccountBayes(tokenVec);
}
void
gnc_account_imap_add_account_bayes (
GncImportMatchMap *imap,
GList *tokens,
Account *acc)
{
// \todo use std::list instead of std::vector, since GList is a double-linked list like std::list
std::vector<std::string> tokenVec;
for (auto token = tokens; token; token = token->next)
{
tokenVec.push_back(static_cast <char const *> (token->data));
}
((GncMockImportMatchMap*)imap)->addAccountBayes(tokenVec, acc);
}

View File

@ -0,0 +1,69 @@
#ifndef GMOCK_ACCOUNT_H
#define GMOCK_ACCOUNT_H
#include <gmock/gmock.h>
#include <Account.h>
#include <AccountP.h>
#include "gmock-qofbook.h"
#include "gmock-gobject.h"
GType gnc_mock_account_get_type(void);
#define GNC_TYPE_MOCK_ACCOUNT (gnc_mock_account_get_type ())
#define GNC_IS_MOCK_ACCOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNC_TYPE_MOCK_ACCOUNT))
// mock up for Account
class MockAccount : public Account
{
public:
MockAccount() {}
void* operator new(size_t size)
{
return mock_g_object_new (GNC_TYPE_MOCK_ACCOUNT, NULL, size);
}
// define separate free() function since destructor is protected
void free()
{
delete this;
}
void operator delete(void* acc, size_t size)
{
mock_g_object_unref(acc, size);
}
MOCK_METHOD0(beginEdit, void());
MOCK_METHOD0(commitEdit, void());
MOCK_METHOD0(getBook, QofMockBook*());
MOCK_METHOD2(forEachTransaction, gint(TransactionCallback, void*));
MOCK_METHOD0(imapCreateImap, GncImportMatchMap*());
protected:
// Protect destructor to avoid MockAccount objects to be created on stack. MockAccount
// objects can only be dynamically created, since they are derived from GObject.
~MockAccount() {}
};
class GncMockImportMatchMap : public GncImportMatchMap
{
public:
GncMockImportMatchMap(MockAccount* account)
{
g_return_if_fail(GNC_IS_MOCK_ACCOUNT(account));
acc = account;
book = account->getBook();
};
MOCK_METHOD2(findAccount, Account *(const char*, const char*));
MOCK_METHOD3(addAccount, void(const char*, const char*, Account*));
MOCK_METHOD1(findAccountBayes, Account *(std::vector<std::string>));
MOCK_METHOD2(addAccountBayes, void(std::vector<std::string>, Account*));
};
#endif

View File

@ -0,0 +1,142 @@
#include <config.h>
#include "gmock-Split.h"
#include "gmock-qofbook.h"
#include "gmock-Account.h"
#include "gmock-Transaction.h"
struct _MockSplitClass
{
QofInstanceClass parent_class;
};
typedef struct _MockSplitClass MockSplitClass;
G_DEFINE_TYPE(MockSplit, gnc_mock_split, QOF_TYPE_INSTANCE);
static void
gnc_mock_split_init (MockSplit *inst)
{
// function is unused since it's overwritten by MockSplit's constructor anyway
}
static void
gnc_mock_split_class_init (MockSplitClass *klass)
{
// function is unused, class functions are defined in C++ code
}
Split *
xaccMallocSplit (QofBook *book)
{
g_return_val_if_fail(QOF_IS_MOCK_BOOK(book), NULL);
return ((QofMockBook*)book)->mallocSplit();
}
QofBook *
xaccSplitGetBook (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), NULL);
return ((MockSplit*)split)->getBook();
}
Account *
xaccSplitGetAccount (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), NULL);
return ((MockSplit*)split)->getAccount();
}
void
xaccSplitSetAccount (Split *split, Account *acc)
{
g_return_if_fail(GNC_IS_MOCK_SPLIT(split));
g_return_if_fail(GNC_IS_MOCK_ACCOUNT(acc));
((MockSplit*)split)->setAccount(acc);
}
gnc_numeric
xaccSplitGetAmount (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), gnc_numeric_zero());
return ((MockSplit*)split)->getAmount();
}
void
xaccSplitSetAmount (Split *split, gnc_numeric amt)
{
g_return_if_fail(GNC_IS_MOCK_SPLIT(split));
((MockSplit*)split)->setAmount(amt);
}
gnc_numeric
xaccSplitGetValue (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), gnc_numeric_zero());
return ((MockSplit*)split)->getValue();
}
void
xaccSplitSetValue (Split *split, gnc_numeric val)
{
g_return_if_fail(GNC_IS_MOCK_SPLIT(split));
((MockSplit*)split)->setValue(val);
}
const char *
xaccSplitGetMemo (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), NULL);
return ((MockSplit*)split)->getMemo();
}
char
xaccSplitGetReconcile (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), VREC);
return ((MockSplit*)split)->getReconcile();
}
void
xaccSplitSetReconcile (Split *split, char recn)
{
g_return_if_fail(GNC_IS_MOCK_SPLIT(split));
((MockSplit*)split)->setReconcile(recn);
}
void
xaccSplitSetDateReconciledSecs (Split *split, time64 secs)
{
g_return_if_fail(GNC_IS_MOCK_SPLIT(split));
((MockSplit*)split)->setDateReconciledSecs(secs);
}
const char *
xaccSplitGetAction (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), NULL);
return ((MockSplit*)split)->getAction();
}
Split *
xaccSplitGetOtherSplit (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), NULL);
return ((MockSplit*)split)->getOtherSplit();
}
Transaction *
xaccSplitGetParent (const Split *split)
{
g_return_val_if_fail(GNC_IS_MOCK_SPLIT(split), NULL);
return ((MockSplit*)split)->getParent();
}
void
xaccSplitSetParent(Split *split, Transaction *trans)
{
g_return_if_fail(GNC_IS_MOCK_SPLIT(split));
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockSplit*)split)->setParent(trans);
}

View File

@ -0,0 +1,85 @@
#ifndef GMOCK_SPLIT_H
#define GMOCK_SPLIT_H
#include <gmock/gmock.h>
#include <Split.h>
#include <SplitP.h>
#include "gmock-qofbook.h"
#include "gmock-gobject.h"
GType gnc_mock_split_get_type(void);
#define GNC_TYPE_MOCK_SPLIT (gnc_mock_split_get_type ())
#define GNC_IS_MOCK_SPLIT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNC_TYPE_MOCK_SPLIT))
// mock up for Split
class MockSplit : public Split
{
public:
MockSplit()
{
acc = nullptr;
orig_acc = nullptr;
parent = nullptr;
orig_parent = nullptr;
lot = nullptr;
action = nullptr;
memo = nullptr;
reconciled = VREC;
amount = gnc_numeric_zero();
value = gnc_numeric_zero();
date_reconciled = 0;
balance = gnc_numeric_zero();
cleared_balance = gnc_numeric_zero();
reconciled_balance = gnc_numeric_zero();
noclosing_balance = gnc_numeric_zero();
gains = GAINS_STATUS_UNKNOWN;
gains_split = nullptr;
}
void* operator new(size_t size)
{
return mock_g_object_new (GNC_TYPE_MOCK_SPLIT, NULL, size);
}
// define separate free() function since destructor is protected
void free()
{
delete this;
}
void operator delete(void* split, size_t size)
{
mock_g_object_unref(split, size);
}
MOCK_METHOD0(init, void());
MOCK_METHOD0(getBook, QofBook *());
MOCK_METHOD0(getAccount, Account *());
MOCK_METHOD1(setAccount, void(Account*));
MOCK_METHOD0(getAmount, gnc_numeric());
MOCK_METHOD1(setAmount, void(gnc_numeric));
MOCK_METHOD0(getValue, gnc_numeric());
MOCK_METHOD1(setValue, void(gnc_numeric));
MOCK_METHOD0(getMemo, const char *());
MOCK_METHOD0(getReconcile, char());
MOCK_METHOD1(setReconcile, void(char));
MOCK_METHOD1(setDateReconciledSecs, void(time64));
MOCK_METHOD0(getAction, const char *());
MOCK_METHOD0(getOtherSplit, Split *());
MOCK_METHOD0(getParent, Transaction *());
MOCK_METHOD1(setParent, void(Transaction*));
protected:
// Protect destructor to avoid MockSplit objects to be created on stack. MockSplit
// objects can only be dynamically created, since they are derived from GObject.
~MockSplit() {}
};
#endif

View File

@ -0,0 +1,125 @@
#include <config.h>
#include "gmock-Transaction.h"
#include "gmock-Account.h"
struct _MockTransactionClass
{
QofInstanceClass parent_class;
};
typedef struct _MockTransactionClass MockTransactionClass;
G_DEFINE_TYPE(MockTransaction, gnc_mock_transaction, QOF_TYPE_INSTANCE);
static void
gnc_mock_transaction_init (MockTransaction *inst)
{
// function is unused, initialization is done in the MockTransaction's constructor
}
static void
gnc_mock_transaction_class_init(MockTransactionClass *klass)
{
// function is unused, class functions are defined in C++ code
}
void
xaccTransBeginEdit (Transaction *trans)
{
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockTransaction*)trans)->beginEdit();
}
void
xaccTransCommitEdit (Transaction *trans)
{
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockTransaction*)trans)->commitEdit();
}
Split *
xaccTransGetSplit (const Transaction *trans, int i)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), NULL);
return ((MockTransaction*)trans)->getSplit(i);
}
Split *
xaccTransFindSplitByAccount(const Transaction *trans, const Account *acc)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), NULL);
g_return_val_if_fail(GNC_IS_MOCK_ACCOUNT(acc), NULL);
return ((MockTransaction*)trans)->findSplitByAccount(acc);
}
time64
xaccTransGetDate (const Transaction *trans)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), 0);
return ((MockTransaction*)trans)->getDate();
}
void
xaccTransSetDatePostedSecsNormalized (Transaction *trans, time64 time)
{
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockTransaction*)trans)->setDatePostedSecsNormalized(time);
}
const char *
xaccTransGetDescription (const Transaction *trans)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), NULL);
return ((MockTransaction*)trans)->getDescription();
}
void
xaccTransSetDescription (Transaction *trans, const char *desc)
{
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockTransaction*)trans)->setDescription(desc);
}
const char *
xaccTransGetNotes (const Transaction *trans)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), NULL);
return ((MockTransaction*)trans)->getNotes();
}
void
xaccTransSetNotes (Transaction *trans, const char *notes)
{
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockTransaction*)trans)->setDescription(notes);
}
gnc_numeric
xaccTransGetImbalanceValue (const Transaction * trans)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), gnc_numeric_zero());
return ((MockTransaction*)trans)->getImbalanceValue();
}
const char *
xaccTransGetNum (const Transaction *trans)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), NULL);
return ((MockTransaction*)trans)->getNum();
}
gboolean
xaccTransIsOpen (const Transaction *trans)
{
g_return_val_if_fail(GNC_IS_MOCK_TRANSACTION(trans), FALSE);
return ((MockTransaction*)trans)->isOpen();
}
void
xaccTransDestroy (Transaction *trans)
{
g_return_if_fail(GNC_IS_MOCK_TRANSACTION(trans));
((MockTransaction*)trans)->destroy();
}

View File

@ -0,0 +1,73 @@
#ifndef GMOCK_TRANSACTION_H
#define GMOCK_TRANSACTION_H
#include <gmock/gmock.h>
#include <Transaction.h>
#include <TransactionP.h>
#include "gmock-qofbook.h"
#include "gmock-gobject.h"
GType gnc_mock_transaction_get_type(void);
#define GNC_TYPE_MOCK_TRANSACTION (gnc_mock_transaction_get_type ())
#define GNC_IS_MOCK_TRANSACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GNC_TYPE_MOCK_TRANSACTION))
// mock up for Transaction
class MockTransaction : public Transaction
{
public:
MockTransaction()
{
num = nullptr;
description = nullptr;
common_currency = nullptr;
splits = nullptr;
date_entered = 0;
date_posted = 0;
marker = 0;
orig = nullptr;
readonly_reason = nullptr;
reason_cache_valid = FALSE;
isClosingTxn_cached = -1;
}
void* operator new(size_t size)
{
return mock_g_object_new (GNC_TYPE_MOCK_TRANSACTION, NULL, size);
}
// define separate free() function since destructor is protected
void free()
{
delete this;
}
void operator delete(void* trans, size_t size)
{
mock_g_object_unref(trans, size);
}
MOCK_METHOD0(beginEdit, void());
MOCK_METHOD0(commitEdit, void());
MOCK_METHOD1(getSplit, Split *(int));
MOCK_METHOD1(findSplitByAccount, Split *(const Account*));
MOCK_METHOD0(getDate, time64());
MOCK_METHOD1(setDatePostedSecsNormalized, void(time64));
MOCK_METHOD0(getDescription, const char *());
MOCK_METHOD1(setDescription, void(const char*));
MOCK_METHOD0(getNotes, const char *());
MOCK_METHOD1(setNotes, void(const char*));
MOCK_METHOD0(getImbalanceValue, gnc_numeric());
MOCK_METHOD0(getNum, const char *());
MOCK_METHOD0(isOpen, gboolean());
MOCK_METHOD0(destroy, void());
protected:
// Protect destructor to avoid MockTransaction objects to be created on stack. MockTransaction
// objects can only be dynamically created, since they are derived from GObject.
~MockTransaction() {}
};
#endif

View File

@ -0,0 +1,27 @@
#ifndef GMOCK_GOBJECT_H
#define GMOCK_GOBJECT_H
#include <glib.h>
static gpointer
mock_g_object_new (GType object_type, const gchar *first_property_name, size_t size)
{
GTypeQuery query;
g_type_query(object_type, &query);
g_assert(size == query.instance_size);
return g_object_new (object_type, first_property_name);
}
static void
mock_g_object_unref (gpointer object, size_t size)
{
GType object_type = G_OBJECT_TYPE(object);
GTypeQuery query;
g_type_query(object_type, &query);
g_assert(size == query.instance_size);
g_object_unref(object);
}
#endif

View File

@ -0,0 +1,29 @@
#include "gmock-qofbook.h"
struct _QofMockBookClass
{
QofInstanceClass parent_class;
};
typedef struct _QofMockBookClass QofMockBookClass;
G_DEFINE_TYPE(QofMockBook, qof_mock_book, QOF_TYPE_INSTANCE);
static void
qof_mock_book_init (QofMockBook *inst)
{
// function is unused, initialization is done in the QofMockBook's constructor
}
static void
qof_mock_book_class_init(QofMockBookClass *klass)
{
// function is unused, class functions are defined in C++ code
}
gboolean
qof_book_use_split_action_for_num_field (const QofBook *book)
{
g_return_val_if_fail(QOF_IS_MOCK_BOOK(book), FALSE);
return ((QofMockBook*)book)->useSplitActionForNumField();
}

View File

@ -0,0 +1,62 @@
#ifndef GMOCK_QOFBOOK_H
#define GMOCK_QOFBOOK_H
#include <gmock/gmock.h>
#include <qofbook.h>
#include <qofbook-p.h>
#include "gmock-gobject.h"
#include "gmock-Split.h"
GType qof_mock_book_get_type(void);
#define QOF_TYPE_MOCK_BOOK (qof_mock_book_get_type ())
#define QOF_IS_MOCK_BOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), QOF_TYPE_MOCK_BOOK))
// mock up for QofBook
class QofMockBook : public QofBook
{
public:
QofMockBook()
{
hash_of_collections = nullptr;
data_tables = nullptr;
data_table_finalizers = nullptr;
book_open = 'n';
read_only = TRUE;
session_dirty = FALSE;
version = 0;
cached_num_field_source_isvalid = FALSE;
cached_num_days_autoreadonly_isvalid = FALSE;
}
void* operator new(size_t size)
{
return mock_g_object_new (QOF_TYPE_MOCK_BOOK, NULL, size);
}
// define separate free() function since destructor is protected
void free()
{
delete this;
}
void operator delete(void* book, size_t size)
{
mock_g_object_unref(book, size);
}
MOCK_METHOD0(mallocSplit, Split *());
MOCK_METHOD0(useSplitActionForNumField, gboolean());
protected:
// Protect destructor to avoid MockQofBook objects to be created on stack. MockQofBook
// objects can only be dynamically created, since they are derived from GObject.
~QofMockBook() {}
};
#endif

View File

@ -0,0 +1,48 @@
#include <glib.h>
extern "C"
{
#include <qofinstance.h>
}
#include <qofinstance-p.h>
G_DEFINE_TYPE(QofInstance, qof_instance, G_TYPE_OBJECT);
static void
qof_instance_init (QofInstance *inst)
{
// function is unused, initialization is done in the constructor of the derived mock class
}
static void
qof_instance_class_init(QofInstanceClass *klass)
{
// function is unused, class functions are defined in C++ code
}
// This is a reimplementation of the function from qofinstance.cpp
void
qof_instance_get (const QofInstance *inst, const gchar *first_prop, ...)
{
va_list ap;
g_return_if_fail (QOF_IS_INSTANCE (inst));
va_start (ap, first_prop);
g_object_get_valist (G_OBJECT (inst), first_prop, ap);
va_end (ap);
}
// This is a reimplementation of the function from qofinstance.cpp
// with calling qof_instance_set_dirty()
void
qof_instance_set (QofInstance *inst, const gchar *first_prop, ...)
{
va_list ap;
g_return_if_fail (QOF_IS_INSTANCE (inst));
va_start (ap, first_prop);
g_object_set_valist (G_OBJECT (inst), first_prop, ap);
va_end (ap);
}

View File

@ -0,0 +1,68 @@
#include <config.h>
#include "gmock-qofquery.h"
#include "gmock-qofbook.h"
QofQuery *
qof_query_create_for (QofIdTypeConst obj_type)
{
return (QofQuery*)qof_query_factory.create();
/*
// \todo create typed query objects
QofQuery *ret = NULL;
if (g_strcmp0(obj_type, GNC_ID_SPLIT) == 0)
ret = (QofQuery*)qof_query_factory.createForSplit();
// else
// FAIL();
return ret;
*/
}
void
qof_query_set_book (QofQuery *query, QofBook *book)
{
g_return_if_fail(QOF_IS_MOCK_BOOK(book));
((QofMockQuery*)query)->setBook(book);
}
GList *
qof_query_run (QofQuery *query)
{
GList *matching_objects = NULL;
// \todo use typed mock objects
auto matchingObjects = ((QofMockQuery*)query)->run();
for (auto object : matchingObjects)
{
matching_objects = g_list_append(matching_objects, static_cast<gpointer>(object));
}
return matching_objects;
}
void
xaccQueryAddDateMatchTT (
QofQuery *query,
gboolean use_start,
time64 stt,
gboolean use_end,
time64 ett,
QofQueryOp op)
{
((QofMockQuery*)query)->addDateMatchTT(use_start, stt, use_end, ett, op);
}
void
xaccQueryAddSingleAccountMatch(QofQuery *query, Account *acc, QofQueryOp op)
{
((QofMockQuery*)query)->addSingleAccountMatch(acc, op);
}
void
qof_query_destroy (QofQuery *query)
{
((QofMockQuery*)query)->destroy();
}

View File

@ -0,0 +1,46 @@
#ifndef GMOCK_QOFQUERY_H
#define GMOCK_QOFQUERY_H
#include <gmock/gmock.h>
#include <qofquery.h>
#include <qofquery-p.h>
extern "C"
{
#include <Query.h>
}
// mock up for QofQuery
// hint: class QofMockQuery can not be derived from QofQuery, since struct _QofQuery is not public
class QofMockQuery
{
public:
QofMockQuery() {};
MOCK_METHOD1(setBook, void(QofBook*));
MOCK_METHOD0(destroy, void());
MOCK_METHOD5(addDateMatchTT, void(gboolean, time64, gboolean, time64, QofQueryOp));
MOCK_METHOD2(addSingleAccountMatch, void(Account*, QofQueryOp));
MOCK_METHOD0(run, std::vector<void*>());
};
/*
// typed mock up for QofQuery
template <typename T>
class MockQofQueryWithType : MockQofQuery
{
public:
// \todo: write constructor
MOCK_METHOD0_T(run, std::list<T*>());
};
*/
class QofQueryFactory
{
public:
// MOCK_METHOD0(createForSplit, MockQofQueryWithType<Split>*());
MOCK_METHOD0(create, QofMockQuery*());
} qof_query_factory;
#endif