gnucash/libgnucash/engine/test/test-qofinstance.cpp
John Ralls 8f96882ead Remove tests checking members of deleted objects.
GLib's scribbling of freed memory is enabled on Arch so attempting to
read the deleted members of inst and book crash instead of reaturning
invalid results. These weren't really useful tests anyway.
2018-01-16 17:24:29 -08:00

1026 lines
38 KiB
C++

/********************************************************************
* test_qofinstance.c: GLib g_test test suite for qofinstance. *
* Copyright 2011 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, 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 <guid.hpp>
extern "C"
{
#include <config.h>
#include <glib.h>
#include <unittest-support.h>
#include "../qof.h"
}
#include "../qof-backend.hpp"
#include "../kvp-frame.hpp"
static const gchar *suitename = "/qof/qofinstance";
extern "C" void test_suite_qofinstance ( void );
static gchar* error_message;
static gboolean is_called;
static struct
{
QofInstance *m_inst = nullptr;
QofBackend *m_be = nullptr;
bool m_commit_called = false;
bool m_commit_with_err_called = false;
bool m_on_error_called = false;
bool m_on_free_called = false;
bool m_on_done_called = false;
QofBackendError m_err = ERR_BACKEND_NO_ERR;
} commit_test;
class QofInstMockBackend : public QofBackend
{
public:
QofInstMockBackend() : m_qof_error{ERR_BACKEND_NO_ERR} {
commit_test.m_be = this;
}
void session_begin(QofSession* sess, const char* book_name,
bool ignore_lock, bool create, bool force) override {}
void session_end() override {}
void load(QofBook*, QofBackendLoadType) override {}
void sync(QofBook* book) override {}
void safe_sync(QofBook* book) override {}
void begin(QofInstance* inst) override {
g_assert(inst);
g_assert(QOF_IS_INSTANCE(inst));
commit_test.m_inst = inst;
}
void set_error(QofBackendError err) {
QofBackend::set_error(err);
commit_test.m_err = err;
}
void commit(QofInstance* inst) override {
g_assert( inst );
g_assert( QOF_IS_INSTANCE( inst ) );
g_assert( commit_test.m_inst == inst );
g_assert( commit_test.m_be == this );
commit_test.m_commit_called = true;
set_error(m_qof_error);
}
void rollback(QofInstance* inst) override {}
void inject_error(QofBackendError err) {
m_qof_error = err;
}
private:
QofBackendError m_qof_error;
};
typedef struct
{
QofInstance *inst;
} Fixture;
static void
on_error(QofInstance* inst, QofBackendError err) {
g_assert( inst );
g_assert( QOF_IS_INSTANCE( inst ) );
g_assert( commit_test.m_err == err );
commit_test.m_on_error_called = true;
}
static void
on_done(QofInstance* inst) {
g_assert( inst );
g_assert( QOF_IS_INSTANCE( inst ) );
g_assert( commit_test.m_inst == inst );
commit_test.m_on_done_called = true;
}
static void
on_free(QofInstance* inst) {
g_assert( inst );
g_assert( QOF_IS_INSTANCE( inst ) );
g_assert(commit_test.m_inst == inst );
commit_test.m_on_free_called = true;
}
/* use g_free on error_message after this function been called */
static gboolean
fatal_handler ( const char * log_domain,
GLogLevelFlags log_level,
const gchar *msg,
gpointer user_data)
{
error_message = (gchar *) g_strdup( msg );
return FALSE;
}
static void
setup( Fixture *fixture, gconstpointer pData )
{
fixture->inst = static_cast<QofInstance*>(g_object_new(QOF_TYPE_INSTANCE, NULL));
}
static void
teardown( Fixture *fixture, gconstpointer pData )
{
g_object_unref(fixture->inst);
}
static void
test_instance_set_get_book( Fixture *fixture, gconstpointer pData )
{
QofBook *book;
/* set up */
book = qof_book_new();
g_assert( QOF_IS_INSTANCE( fixture->inst ) );
g_test_message( "Setting and getting book" );
qof_instance_set_book( fixture->inst, book );
g_assert( book == qof_instance_get_book( fixture->inst ) );
g_test_message( "Getting book when instance is null" );
g_assert( qof_instance_get_book( NULL ) == NULL );
/* Clean up */
qof_book_destroy( book );
}
static void
test_instance_set_get_guid( Fixture *fixture, gconstpointer pData )
{
GncGUID *gncGuid;
/* on null instance deprecated getter returns empty guid
* while instance_get_guid returns null
*/
g_assert( !qof_instance_get_guid( NULL ) );
g_assert( qof_entity_get_guid( NULL ) == guid_null() );
/* set up */
gncGuid = guid_new();
g_assert( QOF_IS_INSTANCE( fixture->inst ) );
g_assert( gncGuid );
/* guid already exists after instance init */
g_test_message( "Setting new guid" );
g_assert( qof_instance_get_guid( fixture->inst ) );
g_assert( !guid_equal( gncGuid, qof_instance_get_guid( fixture->inst ) ) );
qof_instance_set_guid( fixture->inst, gncGuid );
g_assert( guid_equal( gncGuid, qof_instance_get_guid( fixture->inst ) ) );
g_assert( guid_equal( gncGuid, qof_entity_get_guid( fixture->inst ) ) );
/* Clean up */
guid_free( gncGuid );
}
static void
test_instance_new_destroy( void )
{
/* qofinstance var */
QofInstance *inst;
QofInstanceClass *klass;
/* test var */
Timespec *timespec_priv;
const char *msg1 = "qof_instance_get_collection: assertion 'QOF_IS_INSTANCE(ptr)' failed";
const char *msg2 = "qof_instance_get_editlevel: assertion 'QOF_IS_INSTANCE(ptr)' failed";
const char *msg3 = "qof_instance_get_destroying: assertion 'QOF_IS_INSTANCE(ptr)' failed";
const char *msg4 = "qof_instance_get_dirty_flag: assertion 'QOF_IS_INSTANCE(ptr)' failed";
const char *log_domain = "qof";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
auto check = test_error_struct_new(log_domain, loglevel, msg1);
g_test_message( "Testing qofinstance object initialization" );
inst = static_cast<QofInstance*>(g_object_new(QOF_TYPE_INSTANCE, NULL));
g_assert( QOF_IS_INSTANCE( inst ) );
/* test class fields */
klass = QOF_INSTANCE_GET_CLASS( inst );
g_assert( QOF_IS_INSTANCE_CLASS( klass ) );
g_assert( klass->get_display_name == NULL );
g_assert( klass->refers_to_object == NULL );
g_assert( klass->get_typed_referring_object_list == NULL );
/* testing initial values */
g_assert( qof_instance_get_guid( inst ) );
g_assert( !qof_instance_get_collection( inst ) );
g_assert( qof_instance_get_book( inst ) == NULL );
g_assert( inst->kvp_data );
g_object_get( inst, "last-update", &timespec_priv, NULL);
g_assert_cmpint( timespec_priv->tv_sec, == , 0 );
g_assert_cmpint( timespec_priv->tv_nsec, == , -1 );
g_assert_cmpint( qof_instance_get_editlevel( inst ), == , 0 );
g_assert( !qof_instance_get_destroying( inst ) );
g_assert( !qof_instance_get_dirty_flag( inst ) );
g_assert( qof_instance_get_infant( inst ) );
g_assert_cmpint( qof_instance_get_version( inst ), == , 0 );
g_assert_cmpint( qof_instance_get_version_check( inst ), == , 0 );
g_assert_cmpint( qof_instance_get_idata( inst ), == , 0 );
g_test_message( "Testing object destruction" );
g_object_unref( inst );
g_free( error_message );
test_error_struct_free(check);
}
static void
test_instance_init_data( void )
{
QofInstance *inst;
QofIdType test_type = "test type";
QofBook *book;
QofCollection *col;
const GncGUID *gncguid;
char guid_id_before[GUID_ENCODING_LENGTH + 1];
char guid_id_after[GUID_ENCODING_LENGTH + 1];
/* set up */
inst = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( QOF_IS_INSTANCE( inst ) );
book = qof_book_new();
g_assert( QOF_IS_BOOK( book ) );
/* set fatal handler */
g_test_log_set_fatal_handler ( ( GTestLogFatalFunc )fatal_handler, NULL );
g_test_message( "Running test with correct initial data" );
gncguid = qof_instance_get_guid( inst );
g_assert( gncguid );
guid_to_string_buff( gncguid, guid_id_before );
g_assert( qof_instance_get_book( inst ) == NULL );
g_assert( qof_instance_get_collection( inst ) == NULL );
/* run init */
qof_instance_init_data( inst, test_type, book );
g_assert( qof_instance_get_book( inst ) == book );
guid_to_string_buff( gncguid, guid_id_after );
g_assert_cmpstr( guid_id_before, != , guid_id_after );
g_assert( qof_instance_get_collection( inst ) != NULL );
col = qof_book_get_collection( book, test_type );
g_assert( col );
g_assert( col == qof_instance_get_collection( inst ) );
g_assert_cmpstr( inst->e_type, == , test_type );
g_assert( qof_collection_lookup_entity( qof_instance_get_collection( inst ), gncguid ) == inst );
/* clean up */
g_object_unref( inst );
qof_book_destroy( book );
}
static void
test_instance_get_set_slots( Fixture *fixture, gconstpointer pData )
{
KvpFrame *kvp_frame, *kvp_frame2;
/* set up */
g_assert( fixture->inst );
kvp_frame = qof_instance_get_slots( fixture->inst );
g_assert( kvp_frame );
g_test_message( "Test when kvp frame is the same" );
qof_instance_set_slots( fixture->inst, kvp_frame );
g_assert( kvp_frame == qof_instance_get_slots( fixture->inst ) );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_test_message( "Test when kvp frame is not the same" );
kvp_frame2 = new KvpFrame;
g_assert( kvp_frame != kvp_frame2 );
qof_instance_set_slots( fixture->inst, kvp_frame2 );
g_assert( kvp_frame2 == qof_instance_get_slots( fixture->inst ) );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_test_message( "Test when kvp frame is null" );
qof_instance_set_slots( fixture->inst, NULL );
g_assert( NULL == qof_instance_get_slots( fixture->inst ) );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
}
static void
test_instance_version_cmp( void )
{
QofInstance *left, *right;
int result;
Timespec timespec_left, timespec_right;
/* set up*/
left = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
right = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_test_message( "Test both null" );
result = qof_instance_version_cmp( NULL, NULL );
g_assert_cmpint( result, == , 0 );
g_test_message( "Test left null" );
result = qof_instance_version_cmp( NULL, right );
g_assert_cmpint( result, == , -1 );
g_test_message( "Test right null" );
result = qof_instance_version_cmp( left, NULL );
g_assert_cmpint( result, == , 1 );
g_test_message( "Test left tv_sec lesser than right" );
timespec_left.tv_sec = 0;
timespec_right.tv_sec = 1;
qof_instance_set_last_update( left, timespec_left );
qof_instance_set_last_update( right, timespec_right );
result = qof_instance_version_cmp( left, right );
g_assert_cmpint( result, == , -1 );
g_test_message( "Test right tv_sec lesser than left" );
timespec_left.tv_sec = 1;
timespec_right.tv_sec = 0;
qof_instance_set_last_update( left, timespec_left );
qof_instance_set_last_update( right, timespec_right );
result = qof_instance_version_cmp( left, right );
g_assert_cmpint( result, == , 1 );
g_test_message( "Test left tv_nsec lesser than right" );
timespec_left.tv_sec = 1;
timespec_left.tv_nsec = 0;
timespec_right.tv_sec = 1;
timespec_right.tv_nsec = 1;
qof_instance_set_last_update( left, timespec_left );
qof_instance_set_last_update( right, timespec_right );
result = qof_instance_version_cmp( left, right );
g_assert_cmpint( result, == , -1 );
g_test_message( "Test right tv_sec lesser than left" );
timespec_left.tv_sec = 1;
timespec_left.tv_nsec = 1;
timespec_right.tv_sec = 1;
timespec_right.tv_nsec = 0;
qof_instance_set_last_update( left, timespec_left );
qof_instance_set_last_update( right, timespec_right );
result = qof_instance_version_cmp( left, right );
g_assert_cmpint( result, == , 1 );
g_test_message( "Test both equal" );
timespec_left.tv_sec = 1;
timespec_left.tv_nsec = 1;
timespec_right.tv_sec = 1;
timespec_right.tv_nsec = 1;
qof_instance_set_last_update( left, timespec_left );
qof_instance_set_last_update( right, timespec_right );
result = qof_instance_version_cmp( left, right );
g_assert_cmpint( result, == , 0 );
/* clear */
g_object_unref( left );
g_object_unref( right );
}
static void
test_instance_get_set_dirty( Fixture *fixture, gconstpointer pData )
{
QofIdType type = "test type";
QofCollection *col;
/* setup */
col = qof_collection_new ( type );
qof_instance_set_collection( fixture->inst, col );
g_assert( qof_instance_get_collection( fixture->inst ) );
g_test_message( "Test get_dirty on empty instance returns false" );
g_assert( qof_instance_get_dirty( NULL ) == FALSE );
g_test_message( "Test dirty" );
g_assert( !qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( !qof_collection_is_dirty( col ) );
g_assert( !qof_instance_get_dirty( fixture->inst ) );
qof_instance_set_dirty( fixture->inst );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( !qof_collection_is_dirty( col ) );
g_assert( qof_instance_get_dirty( fixture->inst ) );
/* clean up */
qof_instance_set_collection( fixture->inst, NULL );
qof_collection_destroy( col );
}
/* mock display name function */
static gchar*
mock_get_display_name(const QofInstance* inst)
{
gchar *display_name;
g_assert( inst );
g_assert( QOF_INSTANCE_GET_CLASS( inst )->get_display_name == mock_get_display_name );
is_called = TRUE;
display_name = g_strdup_printf("Mock display name %p", inst );
return display_name;
}
static void
test_instance_display_name( Fixture *fixture, gconstpointer pData )
{
QofIdType type = "test type";
QofCollection *col;
gchar *display_name, *default_display_name, *mock_display_name;
/* setup */
g_assert( fixture->inst );
is_called = FALSE;
col = qof_collection_new ( type );
g_assert( col );
qof_instance_set_collection( fixture->inst, col );
g_assert( qof_instance_get_collection( fixture->inst ) );
default_display_name = g_strdup_printf( "Object %s %p", type, fixture->inst );
mock_display_name = g_strdup_printf( "Mock display name %p", fixture->inst );
g_test_message( "Test instance when display name not set" );
g_assert( QOF_INSTANCE_GET_CLASS( fixture->inst )->get_display_name == NULL );
display_name = qof_instance_get_display_name( fixture->inst );
g_assert( !is_called );
g_assert_cmpstr( display_name, == , default_display_name );
g_free( display_name );
g_test_message( "Test instance when display name is set" );
QOF_INSTANCE_GET_CLASS( fixture->inst )->get_display_name = mock_get_display_name;
display_name = qof_instance_get_display_name( fixture->inst );
g_assert( is_called );
g_assert_cmpstr( display_name, == , mock_display_name );
g_free( display_name );
/* clean up */
g_free( default_display_name );
g_free( mock_display_name );
qof_instance_set_collection( fixture->inst, NULL );
qof_collection_destroy( col );
}
static void
mock_backend_begin( QofBackend *be, QofInstance *inst )
{
g_assert( be );
g_assert( inst );
g_assert_cmpstr( inst->e_type, == , "test type" );
is_called = TRUE;
}
static void
test_instance_begin_edit( Fixture *fixture, gconstpointer pData )
{
QofBook *book;
gboolean result;
/* setup */
auto be = new QofInstMockBackend;
g_assert( be );
book = qof_book_new();
g_assert( book );
g_assert( QOF_IS_BOOK( book ) );
qof_book_set_backend( book, be );
g_assert( fixture->inst );
fixture->inst->e_type = "test type";
g_assert( qof_instance_get_dirty_flag( fixture->inst ) == FALSE );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 0 );
g_test_message( "Test when instance is null" );
result = qof_begin_edit( NULL );
g_assert( result == FALSE );
g_test_message( "Test when instance's editlevel is >= 1" );
qof_instance_increase_editlevel( fixture->inst );
result = qof_begin_edit( fixture->inst );
g_assert( result == FALSE );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 2 );
g_test_message( "Test when instance's editlevel is <= 0 and backend not set" );
qof_instance_reset_editlevel( fixture->inst );
result = qof_begin_edit( fixture->inst );
g_assert( result == TRUE );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 1 );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) == TRUE );
g_test_message( "Test when instance's editlevel is <= 0 and backend is set" );
result = FALSE;
qof_instance_reset_editlevel( fixture->inst );
qof_instance_set_dirty_flag( fixture->inst, FALSE );
qof_instance_set_book( fixture->inst, book );
result = qof_begin_edit( fixture->inst );
g_assert( result == TRUE );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 1 );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) == FALSE );
/* clean up */
qof_book_set_backend( book, NULL );
qof_book_destroy( book );
delete be;
}
static void
test_instance_commit_edit( Fixture *fixture, gconstpointer pData )
{
gboolean result;
const gchar *msg = "[qof_commit_edit()] unbalanced call - resetting (was -2)";
const gchar *log_domain = "qof.engine";
auto loglevel = static_cast<GLogLevelFlags>(G_LOG_LEVEL_CRITICAL | G_LOG_FLAG_FATAL);
auto check = test_error_struct_new(log_domain, loglevel, msg);
g_test_message( "Test when instance set to null" );
result = qof_commit_edit( NULL );
g_assert( !result );
g_test_message( "Test when instance's editlevel >= 2" );
qof_instance_increase_editlevel( fixture->inst );
qof_instance_increase_editlevel( fixture->inst );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 2 );
result = qof_commit_edit( fixture->inst );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 1 );
g_assert( !result );
g_test_message( "Test when instance's editlevel = 1" );
result = qof_commit_edit( fixture->inst );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 0 );
g_assert( result );
g_test_message( "Test when instance's editlevel < 0" );
g_test_log_set_fatal_handler ( ( GTestLogFatalFunc )fatal_handler, NULL );
auto hdlr = g_log_set_handler (log_domain, loglevel,
(GLogFunc)test_checked_handler, check);
qof_instance_decrease_editlevel( fixture->inst );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , -1 );
result = qof_commit_edit( fixture->inst );
g_assert_cmpint( qof_instance_get_editlevel( fixture->inst ), == , 0 );
g_assert_cmpstr( error_message, == , "[qof_commit_edit()] unbalanced call - resetting (was -2)" );
g_free( error_message );
g_log_remove_handler (log_domain, hdlr);
test_error_struct_free(check);
}
/* backend commit test start */
static void
test_instance_commit_edit_part2( Fixture *fixture, gconstpointer pData )
{
QofBook *book;
gboolean result;
/* setup */
auto be = new QofInstMockBackend;
g_assert( be );
book = qof_book_new();
g_assert( book );
g_assert( QOF_IS_BOOK( book ) );
qof_book_set_backend( book, be );
/* init */
result = FALSE;
commit_test.m_commit_called = false;
commit_test.m_commit_with_err_called = false;
commit_test.m_on_error_called = false;
commit_test.m_on_free_called = false;
commit_test.m_on_done_called = false;
commit_test.m_inst = fixture->inst;
commit_test.m_be = be;
qof_instance_set_dirty_flag( fixture->inst, TRUE );
g_test_message( "Test when instance's backend not set, callbacks not set" );
g_assert( qof_instance_get_infant( fixture->inst ) );
g_assert( !qof_instance_get_destroying( fixture->inst ) );
result = qof_commit_edit_part2( fixture->inst, NULL, NULL, NULL );
g_assert( result );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( !qof_instance_get_infant( fixture->inst ) );
g_assert( !commit_test.m_commit_called );
g_assert( !commit_test.m_commit_with_err_called );
g_assert( !commit_test.m_on_error_called );
g_assert( !commit_test.m_on_free_called );
g_assert( !commit_test.m_on_done_called );
g_test_message( "Test when instance's backend not set, do_free is false" );
qof_instance_set_destroying( fixture->inst, TRUE );
result = qof_commit_edit_part2( fixture->inst, on_error, on_done, on_free );
g_assert( result );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( !commit_test.m_commit_called );
g_assert( !commit_test.m_commit_with_err_called );
g_assert( !commit_test.m_on_error_called );
g_assert( commit_test.m_on_free_called );
g_assert( !commit_test.m_on_done_called );
g_test_message( "Test when instance's backend not set, do_free is false" );
qof_instance_set_destroying( fixture->inst, FALSE );
commit_test.m_on_free_called = false;
result = qof_commit_edit_part2( fixture->inst, on_error, on_done, on_free );
g_assert( result );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( !commit_test.m_commit_called );
g_assert( !commit_test.m_commit_with_err_called );
g_assert( !commit_test.m_on_error_called );
g_assert( !commit_test.m_on_free_called );
g_assert( commit_test.m_on_done_called );
g_test_message( "Test when instance's backend is set, all cb set, no error produced" );
qof_instance_set_book( fixture->inst, book );
qof_instance_set_destroying( fixture->inst, FALSE );
commit_test.m_on_done_called = false;
result = qof_commit_edit_part2( fixture->inst, on_error, on_done, on_free );
g_assert( result );
g_assert( !qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( commit_test.m_commit_called );
g_assert( !commit_test.m_commit_with_err_called );
g_assert( !commit_test.m_on_error_called );
g_assert( !commit_test.m_on_free_called );
g_assert( commit_test.m_on_done_called );
g_test_message( "Test when instance's backend is set, all cb set, error produced" );
commit_test.m_commit_called = false;
commit_test.m_on_done_called = false;
be->inject_error(ERR_BACKEND_NO_HANDLER);
qof_instance_set_dirty_flag( fixture->inst, TRUE );
qof_instance_set_destroying( fixture->inst, TRUE );
result = qof_commit_edit_part2( fixture->inst, on_error, on_done, on_free );
g_assert( !result );
g_assert( qof_instance_get_dirty_flag( fixture->inst ) );
g_assert( !qof_instance_get_destroying( fixture->inst ) );
g_assert( commit_test.m_commit_called );
g_assert( commit_test.m_on_error_called );
g_assert( !commit_test.m_on_free_called );
g_assert( !commit_test.m_on_done_called );
/* clean up */
qof_book_set_backend( book, NULL );
qof_book_destroy( book );
delete be;
}
/* backend commit test end */
/* object reference tests */
static struct
{
gpointer inst;
gpointer ref;
gboolean refers_to_object_called;
} refers_test_struct;
static gboolean
mock_refers_to_object( const QofInstance* inst, const QofInstance* ref )
{
g_assert( inst );
g_assert( ref );
g_assert( refers_test_struct.inst == inst );
g_assert( refers_test_struct.ref == ref );
refers_test_struct.refers_to_object_called = TRUE;
return TRUE;
}
static void
test_instance_refers_to_object( Fixture *fixture, gconstpointer pData )
{
QofInstance * ref;
ref = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( fixture->inst );
g_assert( ref );
g_assert( QOF_INSTANCE_GET_CLASS( fixture->inst )->refers_to_object == NULL );
refers_test_struct.refers_to_object_called = FALSE;
refers_test_struct.inst = fixture->inst;
refers_test_struct.ref = ref;
g_test_message( "Test when refers to object not set" );
g_assert( !qof_instance_refers_to_object( fixture->inst, ref ) );
g_assert( !refers_test_struct.refers_to_object_called );
g_test_message( "Test when refers to object set" );
QOF_INSTANCE_GET_CLASS( fixture->inst )->refers_to_object = mock_refers_to_object;
g_assert( qof_instance_refers_to_object( fixture->inst, ref ) );
g_assert( refers_test_struct.refers_to_object_called );
g_object_unref( ref );
}
static struct
{
GList *list;
gpointer ref;
guint call_count;
} refers_test_struct_from_col;
static gboolean
mock_refers_to_object_from_col( const QofInstance* inst, const QofInstance* ref )
{
g_assert( inst );
g_assert( ref );
g_assert( g_list_find( refers_test_struct_from_col.list, inst ) );
g_assert( refers_test_struct_from_col.ref == ref );
refers_test_struct_from_col.call_count++;
refers_test_struct.refers_to_object_called = TRUE;
return TRUE;
}
static void
test_instance_get_referring_object_list_from_collection( void )
{
QofIdType type = "test type";
QofBook *book;
GList *inst_list = NULL;
GList *result = NULL;
QofCollection *coll;
QofInstance *ref;
/* randomly init number of entities >=0 and < 10 */
gint32 list_length = g_test_rand_int_range( 0, 10 );
int i;
/* setup book and ref instance */
book = qof_book_new();
g_assert( book );
g_assert( QOF_IS_BOOK( book ) );
ref = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( ref );
g_assert( QOF_IS_INSTANCE( ref ) );
QOF_INSTANCE_GET_CLASS( ref )->refers_to_object = NULL;
refers_test_struct_from_col.call_count = 0;
/* init list of entities of one type,
* put them into book collection and
* save in the list
*/
for (i = 0; i < list_length; i++ )
{
auto inst = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( inst );
qof_instance_init_data( inst, type, book );
inst_list = g_list_append ( inst_list, inst );
g_assert_cmpint( g_list_length( inst_list ), == , (i + 1) );
}
g_assert_cmpint( list_length, == , g_list_length( inst_list ) );
g_test_message( "Test when refers to object not set" );
coll = qof_book_get_collection( book, type );
g_assert( coll );
result = qof_instance_get_referring_object_list_from_collection( coll, ref );
g_assert( !result );
g_assert_cmpint( refers_test_struct_from_col.call_count, == , 0 );
g_test_message( "Test when refers to object is set" );
QOF_INSTANCE_GET_CLASS( ref )->refers_to_object = mock_refers_to_object_from_col;
refers_test_struct_from_col.list = inst_list;
refers_test_struct_from_col.ref = ref;
result = qof_instance_get_referring_object_list_from_collection( coll, ref );
if ( list_length == 0 )
g_assert( !result );
else
g_assert( result );
g_assert_cmpint( g_list_length( inst_list ), == , g_list_length( result ) );
g_assert_cmpint( g_list_length( inst_list ), == , refers_test_struct_from_col.call_count );
/* clean up list and destroy book */
g_list_foreach( inst_list, (GFunc) g_object_unref, NULL );
g_list_free( inst_list );
g_list_free( result );
qof_book_destroy( book );
g_object_unref( ref );
}
static struct
{
gpointer inst;
gpointer ref;
gboolean get_typed_referring_object_list_called;
} get_typed_referring_object_list_struct;
static GList*
mock_get_typed_referring_object_list( const QofInstance* inst, const QofInstance* ref )
{
GList* result = NULL;
g_assert( inst );
g_assert( ref );
g_assert( get_typed_referring_object_list_struct.inst == inst );
g_assert( get_typed_referring_object_list_struct.ref == ref );
get_typed_referring_object_list_struct.get_typed_referring_object_list_called = TRUE;
return g_list_append( result, (gpointer) inst );
}
static void
test_instance_get_typed_referring_object_list( void )
{
QofInstance *inst;
QofInstance *ref;
QofBook *book;
GList* result = NULL;
/* setup */
inst = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
ref = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
book = qof_book_new();
g_assert( inst );
g_assert( ref );
g_assert( book );
QOF_INSTANCE_GET_CLASS( inst )->refers_to_object = NULL;
QOF_INSTANCE_GET_CLASS( inst )->get_typed_referring_object_list = NULL;
qof_instance_init_data( inst, "test type", book );
get_typed_referring_object_list_struct.get_typed_referring_object_list_called = FALSE;
/*
* cases when refers to object is set are not tested in current function
* as they are checked in the previous tests
*/
g_test_message( "Test when get typed referring object list is not set" );
result = qof_instance_get_typed_referring_object_list( inst, ref );
g_assert( !result );
g_assert( !get_typed_referring_object_list_struct.get_typed_referring_object_list_called );
g_list_free( result );
g_test_message( "Test when get typed referring object list is set" );
QOF_INSTANCE_GET_CLASS( inst )->get_typed_referring_object_list = mock_get_typed_referring_object_list;
get_typed_referring_object_list_struct.inst = inst;
get_typed_referring_object_list_struct.ref = ref;
result = qof_instance_get_typed_referring_object_list( inst, ref );
g_assert( result );
g_assert_cmpint( g_list_length( result ), == , 1 );
g_assert( get_typed_referring_object_list_struct.get_typed_referring_object_list_called );
g_list_free( result );
/* clean */
g_object_unref( inst );
g_object_unref( ref );
qof_book_destroy( book );
}
static struct
{
guint refers_to_object_call_count;
guint get_typed_referring_object_list_count;
} get_referring_object_list_struct;
static gboolean
mock_simple_refers_to_object( const QofInstance* inst, const QofInstance* ref )
{
g_assert( inst );
g_assert( ref );
if ( inst->e_type == ref->e_type )
{
get_referring_object_list_struct.refers_to_object_call_count++;
return TRUE;
}
return FALSE;
}
static GList*
mock_simple_get_typed_referring_object_list(const QofInstance* inst, const QofInstance* ref)
{
g_assert( inst );
g_assert( ref );
get_referring_object_list_struct.get_typed_referring_object_list_count++;
return qof_instance_get_referring_object_list_from_collection(qof_instance_get_collection(inst), ref);
}
static void
test_instance_get_referring_object_list( void )
{
/* walk through the book's each collection's each instance */
QofInstance *ref1;
QofInstance *ref2;
QofBook *book;
QofIdType type1 = "type1";
QofIdType type2 = "type2";
gint32 col1_length = g_test_rand_int_range( 0, 10 );
gint32 col2_length = g_test_rand_int_range( 0, 10 );
GList* inst_list1 = NULL;
GList* inst_list2 = NULL;
GList* result = NULL;
int i, j;
/* setup */
book = qof_book_new();
g_assert( book );
g_assert( QOF_IS_BOOK( book ) );
ref1 = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( ref1 );
ref2 = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( ref2 );
qof_instance_init_data( ref1, type1, book );
qof_instance_init_data( ref2, type2, book );
QOF_INSTANCE_GET_CLASS( ref1 )->refers_to_object = NULL;
QOF_INSTANCE_GET_CLASS( ref1 )->get_typed_referring_object_list = NULL;
g_assert_cmpint( qof_collection_count( qof_book_get_collection( book, type1 ) ), == , 1 );
g_assert_cmpint( qof_collection_count( qof_book_get_collection( book, type2 ) ), == , 1 );
get_referring_object_list_struct.refers_to_object_call_count = 0;
get_referring_object_list_struct.get_typed_referring_object_list_count = 0;
/*
* fill two collections with different types
* and random number of elements
*/
for (i = 0; i < col1_length; i++ )
{
auto inst = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( inst );
qof_instance_init_data( inst, type1, book );
inst_list1 = g_list_append ( inst_list1, inst );
g_assert_cmpint( g_list_length( inst_list1 ), == , (i + 1) );
}
g_assert_cmpint( qof_collection_count( qof_book_get_collection( book, type1 ) ), == , col1_length + 1 );
g_assert_cmpint( g_list_length( inst_list1 ), == , col1_length );
for (j = 0; j < col2_length; j++ )
{
auto inst = static_cast<QofInstance*>(g_object_new( QOF_TYPE_INSTANCE, NULL ));
g_assert( inst );
qof_instance_init_data( inst, type2, book );
inst_list2 = g_list_append ( inst_list2, inst );
g_assert_cmpint( g_list_length( inst_list2 ), == , (j + 1) );
}
g_assert_cmpint( qof_collection_count( qof_book_get_collection( book, type2 ) ), == , col2_length + 1 );
g_assert_cmpint( g_list_length( inst_list2 ), == , col2_length );
g_test_message( "Test object list returned for ref1 instance by default" );
result = qof_instance_get_referring_object_list( ref1 );
g_assert( !result );
g_assert_cmpint( get_referring_object_list_struct.refers_to_object_call_count, == , 0 );
g_test_message( "Test object list returned for ref2 instance by default" );
result = qof_instance_get_referring_object_list( ref2 );
g_assert( !result );
g_assert_cmpint( get_referring_object_list_struct.refers_to_object_call_count, == , 0 );
/*
* refers to object is made simple as it is tested enough
* it checks if instance types are equal
* that is for ref1 we should get all elements from collection with type1
* for ref2 we should get all elements from collection with type2
*/
g_test_message( "Test object list returned for ref1 instance when refers_to_object is set" );
QOF_INSTANCE_GET_CLASS( ref1 )->refers_to_object = mock_simple_refers_to_object;
result = qof_instance_get_referring_object_list( ref1 );
g_assert( result );
g_assert_cmpint( g_list_length( result ), == , col1_length + 1 );
g_assert_cmpint( get_referring_object_list_struct.refers_to_object_call_count, == , col1_length + 1 );
g_list_free( result );
g_test_message( "Test object list returned for ref2 instance when refers_to_object is set" );
get_referring_object_list_struct.refers_to_object_call_count = 0;
result = qof_instance_get_referring_object_list( ref2 );
g_assert( result );
g_assert_cmpint( g_list_length( result ), == , col2_length + 1 );
g_assert_cmpint( get_referring_object_list_struct.refers_to_object_call_count, == , col2_length + 1 );
g_list_free( result );
g_test_message( "Test object list returned for ref1 instance when refers_to_object is set and get typed set" );
QOF_INSTANCE_GET_CLASS( ref1 )->get_typed_referring_object_list = mock_simple_get_typed_referring_object_list;
get_referring_object_list_struct.refers_to_object_call_count = 0;
get_referring_object_list_struct.get_typed_referring_object_list_count = 0;
result = qof_instance_get_referring_object_list( ref1 );
g_assert( result );
g_assert_cmpint( g_list_length( result ), == , col1_length + 1 );
g_assert_cmpint( get_referring_object_list_struct.refers_to_object_call_count, == , col1_length + 1 );
g_assert_cmpint( get_referring_object_list_struct.get_typed_referring_object_list_count, == , 2 );
g_list_free( result );
g_test_message( "Test object list returned for ref2 instance when refers_to_object is set and get typed set" );
get_referring_object_list_struct.refers_to_object_call_count = 0;
get_referring_object_list_struct.get_typed_referring_object_list_count = 0;
result = qof_instance_get_referring_object_list( ref2 );
g_assert( result );
g_assert_cmpint( g_list_length( result ), == , col2_length + 1 );
g_assert_cmpint( get_referring_object_list_struct.refers_to_object_call_count, == , col2_length + 1 );
g_assert_cmpint( get_referring_object_list_struct.get_typed_referring_object_list_count, == , 2 );
g_list_free( result );
/* clean */
g_object_unref( ref1 );
g_object_unref( ref2 );
g_list_foreach( inst_list1, (GFunc) g_object_unref, NULL );
g_list_foreach( inst_list2, (GFunc) g_object_unref, NULL );
g_list_free( inst_list1 );
g_list_free( inst_list2 );
qof_book_destroy( book );
}
extern "C" void
test_suite_qofinstance ( void )
{
GNC_TEST_ADD( suitename, "set get book", Fixture, NULL, setup, test_instance_set_get_book, teardown );
GNC_TEST_ADD( suitename, "set get guid", Fixture, NULL, setup, test_instance_set_get_guid, teardown );
GNC_TEST_ADD_FUNC( suitename, "instance new and destroy", test_instance_new_destroy );
GNC_TEST_ADD_FUNC( suitename, "init data", test_instance_init_data );
GNC_TEST_ADD( suitename, "get set slots", Fixture, NULL, setup, test_instance_get_set_slots, teardown );
GNC_TEST_ADD_FUNC( suitename, "version compare", test_instance_version_cmp );
GNC_TEST_ADD( suitename, "get set dirty", Fixture, NULL, setup, test_instance_get_set_dirty, teardown );
GNC_TEST_ADD( suitename, "display name", Fixture, NULL, setup, test_instance_display_name, teardown );
GNC_TEST_ADD( suitename, "begin edit", Fixture, NULL, setup, test_instance_begin_edit, teardown );
GNC_TEST_ADD( suitename, "commit edit", Fixture, NULL, setup, test_instance_commit_edit, teardown );
GNC_TEST_ADD( suitename, "commit edit part 2", Fixture, NULL, setup, test_instance_commit_edit_part2, teardown );
GNC_TEST_ADD( suitename, "instance refers to object", Fixture, NULL, setup, test_instance_refers_to_object, teardown );
GNC_TEST_ADD_FUNC( suitename, "instance get referring object list from collection", test_instance_get_referring_object_list_from_collection );
GNC_TEST_ADD_FUNC( suitename, "instance get typed referring object list", test_instance_get_typed_referring_object_list);
GNC_TEST_ADD_FUNC( suitename, "instance get referring object list", test_instance_get_referring_object_list );
}