[Testing] Separate unit test functions from make check functions.

I'd originally put the functions supporting log detection, qof event handling, and mock-counting in test-stuff along with the functions that support the older "make check" integration tests. There are now more unit test support functions than there are of the older functions, so it's time for them to move out on their own.

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22132 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
John Ralls committed 2012-04-03 21:35:19 +00:00
1 parent dd5e532cdf
commit 6d32b6f693
43 files changed
+572 -500

No files matched your search

+1
View File
@@ -8,6 +8,7 @@
#include "gnc-exp-parser.h"
#include "gnc-numeric.h"
#include "test-stuff.h"
#include <unittest-support.h>
static GList *tests = NULL;
@@ -7,6 +7,7 @@
#include "gnc-numeric.h"
#include "test-engine-stuff.h"
#include "test-stuff.h"
#include <unittest-support.h>
static void
test_num_print_info (gnc_numeric n, GNCPrintAmountInfo print_info, int line)
+1
View File
@@ -29,6 +29,7 @@
#include "test-engine-stuff.h"
#include "test-stuff.h"
#include "test-dbi-stuff.h"
#include <unittest-support.h>
#include "TransLog.h"
#include "Account.h"
@@ -30,6 +30,7 @@
#include "test-stuff.h"
#include "test-dbi-stuff.h"
#include "test-dbi-business-stuff.h"
#include <unittest-support.h>
#include "Account.h"
#include "Split.h"
+1
View File
@@ -31,6 +31,7 @@
#include "test-engine-stuff.h"
#include "test-stuff.h"
#include "test-dbi-stuff.h"
#include <unittest-support.h>
#include "Account.h"
#include "Split.h"
+2 -2
View File
@@ -23,9 +23,9 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include <unittest-support.h>
/* Add specific headers for this class */
#include "gnc-backend-sql.h"
#include "../gnc-backend-sql.h"
static const gchar *suitename = "/backend/sql/gnc-backend-sql";
void test_suite_gnc_backend_sql (void);
+9 -8
View File
@@ -37,15 +37,16 @@
#include <glib-object.h>
#include <glib/gstdio.h>
#include "cashobjects.h"
#include "TransLog.h"
#include "gnc-engine.h"
#include "gnc-backend-xml.h"
#include "io-gncxml-v2.h"
#include <cashobjects.h>
#include <TransLog.h>
#include <gnc-engine.h>
#include "../gnc-backend-xml.h"
#include "../io-gncxml-v2.h"
#include "test-stuff.h"
#include "test-engine-stuff.h"
#include "test-file-stuff.h"
#include <test-stuff.h>
#include <unittest-support.h>
#include <test-engine-stuff.h>
#include <test-file-stuff.h>
#define GNC_LIB_NAME "gncmod-backend-xml"
+10 -9
View File
@@ -29,16 +29,17 @@
#include <stdlib.h>
#include <unistd.h>
#include "gnc-xml-helper.h"
#include "gnc-xml.h"
#include "gnc-engine.h"
#include "cashobjects.h"
#include "sixtp-parsers.h"
#include "sixtp-dom-parsers.h"
#include "../gnc-xml-helper.h"
#include "../gnc-xml.h"
#include <gnc-engine.h>
#include <cashobjects.h>
#include "../sixtp-parsers.h"
#include "../sixtp-dom-parsers.h"
#include "test-stuff.h"
#include "test-engine-stuff.h"
#include "test-file-stuff.h"
#include <test-stuff.h>
#include <test-engine-stuff.h>
#include <test-file-stuff.h>
#include <unittest-support.h>
#include "Account.h"
#include "Scrub.h"
+15 -14
View File
@@ -33,23 +33,24 @@
#include <dirent.h>
#include <sys/stat.h>
#include "gnc-xml-helper.h"
#include "gnc-xml.h"
#include "gnc-engine.h"
#include "cashobjects.h"
#include "sixtp-parsers.h"
#include "../gnc-xml-helper.h"
#include "../gnc-xml.h"
#include <gnc-engine.h>
#include <cashobjects.h>
#include "../sixtp-parsers.h"
#include "sixtp-dom-parsers.h"
#include "TransLog.h"
#include "io-gncxml-gen.h"
#include "../sixtp-dom-parsers.h"
#include <TransLog.h>
#include "../io-gncxml-gen.h"
#include "test-stuff.h"
#include "test-engine-stuff.h"
#include "test-file-stuff.h"
#include <test-stuff.h>
#include <test-engine-stuff.h>
#include <test-file-stuff.h>
#include <unittest-support.h>
#include "AccountP.h"
#include "Transaction.h"
#include "TransactionP.h"
#include <AccountP.h>
#include <Transaction.h>
#include <TransactionP.h>
static QofBook *book;
+4 -3
View File
@@ -24,9 +24,10 @@
#include "config.h"
#include <glib.h>
#include <stdio.h>
#include "qof.h"
#include "cashobjects.h"
#include "test-stuff.h"
#include <qof.h>
#include <test-stuff.h>
#include <unittest-support.h>
#include "../cashobjects.h"
#define TEST_MODULE_NAME "TestModuleName"
#define TEST_CORE "TestCoreType"
+3 -3
View File
@@ -1,5 +1,5 @@
/********************************************************************
* utest-Account.c: GLib g_test test suite for Account.c. *
* utest-Account.c: GLib g_test test suite for Account.c. *
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
* *
* This program is free software; you can redistribute it and/or *
@@ -22,8 +22,8 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include "gnc-event.h"
#include <unittest-support.h>
#include <gnc-event.h>
/* Add specific headers for this class */
#include "../Account.h"
#include "../AccountP.h"
+3 -3
View File
@@ -1,6 +1,6 @@
/********************************************************************
* test_qofbook.c: GLib g_test test suite for qofbook. *
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
* Copyright 2012 Christian Stimming <christian@cstimming.de> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
@@ -22,8 +22,8 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "qof.h"
#include "test-stuff.h"
#include <qof.h>
#include <unittest-support.h>
#include "../gncInvoice.h"
static const gchar *suitename = "/engine/gncInvoice";
+1 -1
View File
@@ -24,7 +24,7 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include <unittest-support.h>
/* Add specific headers for this class */
#include <Split.h>
#include <SplitP.h>
+1 -1
View File
@@ -4,7 +4,7 @@
#include <libguile.h>
#include "gnc-module.h"
#include <test-stuff.h>
#include <unittest-support.h>
static void
guile_main(void *closure, int argc, char ** argv)
+1 -1
View File
@@ -8,7 +8,7 @@
#include <stdio.h>
#include <gmodule.h>
#include <libguile.h>
#include <test-stuff.h>
#include <unittest-support.h>
#include "gnc-module.h"
+1 -1
View File
@@ -1,5 +1,5 @@
#! /bin/sh
guile -c "(use-modules (gnucash test-stuff))
guile -c "(use-modules (gnucash unittest-support))
(define log-domain \"gnc.module\")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-WARNING))
+1 -1
View File
@@ -2,7 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <libguile.h>
#include <test-stuff.h>
#include <unittest-support.h>
#include "gnc-module.h"
+1 -1
View File
@@ -2,7 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <libguile.h>
#include <test-stuff.h>
#include <unittest-support.h>
#include "gnc-module.h"
+1 -1
View File
@@ -3,7 +3,7 @@ exec guile -s $0 "$@"
!#
;; test-load-deps.scm : load gnc-mod-baz, which depends on gnc-mod-foo
(use-modules (gnucash test-stuff))
(use-modules (gnucash unittest-support))
(define log-domain "gnc.module")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-WARNING))
+1 -1
View File
@@ -2,7 +2,7 @@
exec guile -s $0 "$@"
!#
(use-modules (gnucash test-stuff))
(use-modules (gnucash unittest-support))
(define log-domain "gnc.module")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-WARNING))
+1 -1
View File
@@ -2,7 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <libguile.h>
#include <test-stuff.h>
#include <unittest-support.h>
#include "gnc-module.h"
+1 -1
View File
@@ -3,7 +3,7 @@ echo " test-scm-init: testing Scheme-only module system init. ";
exec guile -s $0 "$@"
!#
(use-modules (gnucash test-stuff))
(use-modules (gnucash unittest-support))
(define log-domain "gnc.module")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-WARNING))
+1 -1
View File
@@ -1,5 +1,5 @@
#! /bin/sh
guile -c "(use-modules (gnucash test-stuff))
guile -c "(use-modules (gnucash unittest-support))
(define log-domain \"gnc.module\")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-WARNING))
+1 -1
View File
@@ -1,7 +1,7 @@
#! /bin/sh
exec guile -s $0 "$@"
!#
(use-modules (gnucash test-stuff))
(use-modules (gnucash unittest-support))
(define log-domain "gnc.module")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-WARNING))
+2 -2
View File
@@ -16,7 +16,7 @@ test_qof_SOURCES = \
test-kvp_frame.c \
test-qofobject.c \
test-qofsession.c \
${top_srcdir}/src/test-core/test-stuff.c
${top_srcdir}/src/test-core/unittest-support.c
test_qof_HEADERS = \
$(top_srcdir)/${MODULEPATH}/qofbook.h \
@@ -24,7 +24,7 @@ test_qof_HEADERS = \
$(top_srcdir)/${MODULEPATH}/kvp_frame.h \
$(top_srcdir)/${MODULEPATH}/qofobject.h \
$(top_srcdir)/${MODULEPATH}/qofsession.h \
$(top_srcdir)/src/test-core/test-stuff.h
$(top_srcdir)/src/test-core/unittest-support.h
TEST_PROGS += test-qof
+1 -1
View File
@@ -24,10 +24,10 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include <unittest-support.h>
#include "qof.h"
#include "qofbook-p.h"
#include "qofbookslots.h"
#include "test-stuff.h"
static const gchar *suitename = "/qof/gnc-date";
void test_suite_gnc_date ( void );
+1 -1
View File
@@ -22,7 +22,7 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include "unittest-support.h"
#include "qof.h"
static const gchar *suitename = "/qof/kvp_frame";
+4 -4
View File
@@ -22,10 +22,10 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "qof.h"
#include "qofbook-p.h"
#include "qofbookslots.h"
#include "test-stuff.h"
#include <unittest-support.h>
#include "../qof.h"
#include "../qofbook-p.h"
#include "../qofbookslots.h"
static const gchar *suitename = "/qof/qofbook";
void test_suite_qofbook ( void );
+4 -4
View File
@@ -19,11 +19,11 @@
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
\********************************************************************/
#include "config.h"
#include <config.h>
#include <glib.h>
#include "qof.h"
#include "test-stuff.h"
#include "qofbackend-p.h"
#include <unittest-support.h>
#include "../qof.h"
#include "../qofbackend-p.h"
static const gchar *suitename = "/qof/qofinstance";
void test_suite_qofinstance ( void );
+3 -3
View File
@@ -22,9 +22,9 @@
#include "config.h"
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include "qof.h"
#include "qofobject-p.h"
#include <unittest-support.h>
#include "../qof.h"
#include "../qofobject-p.h"
static const gchar *suitename = "/qof/qofobject";
void test_suite_qofobject ( void );
+5 -5
View File
@@ -22,11 +22,11 @@
#include "config.h"
#include <glib.h>
#include "test-stuff.h"
#include "qof.h"
#include "qofbackend-p.h"
#include "qofsession-p.h"
#include "qofclass-p.h"
#include <unittest-support.h>
#include "../qof.h"
#include "../qofbackend-p.h"
#include "../qofsession-p.h"
#include "../qofclass-p.h"
static const gchar *suitename = "/qof/qofsession";
void test_suite_qofsession ( void );
+3 -3
View File
@@ -29,9 +29,9 @@
#include "gncmm/Book.hpp"
extern "C" {
#include "qofbook-p.h"
#include "qofbookslots.h"
#include "test-stuff.h"
#include <qofbook-p.h>
#include <qofbookslots.h>
#include <unittest-support.h>
}
static const gchar *suitename = "/optional/gtkmm";
@@ -1,7 +1,7 @@
from unittest import main
from gnucash import Book, Account, Split, Transaction
from test_stuff import *
from unittest_support import *
from test_book import BookSession
@@ -1,7 +1,7 @@
from unittest import main
from gnucash import Transaction, Book, Account, Split
from test_stuff import *
from unittest_support import *
from test_book import BookSession
+1 -1
View File
@@ -4,7 +4,7 @@ exec guile -s "$0"
(setenv "GNC_UNINSTALLED" "1")
(display " testing stylesheet module load ... ")
(use-modules (gnucash test-stuff))
(use-modules (gnucash unittest-support))
(define log-domain "gnc.report.core")
(define check (new-TestErrorStruct))
(define log-level (G-LOG-LEVEL-CRITICAL))
+24 -18
View File
@@ -1,15 +1,19 @@
noinst_LTLIBRARIES = libtest-core.la
SWIG_FILES = test-stuff.i
SWIG_FILES = \
unittest-support.i
libtest_core_la_SOURCES = \
test-stuff.c
test-stuff.c \
unittest-support.c
libtest_core_la_LIBADD = \
${top_builddir}/src/libqof/qof/libgnc-qof.la \
${GLIB_LIBS}
noinst_HEADERS=test-stuff.h
noinst_HEADERS = \
test-stuff.h \
unittest-support.h
libtest_core_la_CPPFLAGS = \
-I${top_srcdir}/src \
@@ -20,20 +24,20 @@ libtest_core_la_LDFLAGS = \
-rpath ${exec-prefix}/lib
if BUILDING_FROM_SVN
swig-test-stuff-guile.c: test-stuff.i $(top_srcdir)/src/base-typemaps.i
swig-unittest-support-guile.c: unittest-support.i $(top_srcdir)/src/base-typemaps.i
$(SWIG) -guile $(SWIG_ARGS) -Linkage module \
-I${top_srcdir}/src \
${AM_CPPFLAGS} -o $@ $<
swig-test-stuff-python.c: test-stuff.i $(top_srcdir)/src/base-typemaps.i
swig-unittest-support-python.c: unittest-support.i $(top_srcdir)/src/base-typemaps.i
$(SWIG) -python -Wall -Werror $(SWIG_ARGS) \
-I${top_srcdir}/src \
${AM_CPPFLAGS} -o $@ $<
test-stuff.py: swig-test-stuff-python.c ${SWIG_FILES}
unittest-support.py: swig-unittest-support-python.c ${SWIG_FILES}
endif
noinst_LTLIBRARIES += libtest-core-guile.la
libtest_core_guile_la_SOURCES = swig-test-stuff-guile.c
libtest_core_guile_la_SOURCES = swig-unittest-support-guile.c
libtest_core_guile_la_LIBADD = \
${GUILE_LIBS} \
${GLIB_LIBS} \
@@ -48,25 +52,25 @@ libtest_core_guile_la_LDFLAGS = \
if WITH_PYTHON
noinst_LTLIBRARIES += _test_stuff.la
noinst_LTLIBRARIES += _unittest_support.la
_test_stuff_la_SOURCES = \
swig-test-stuff-python.c
_test_stuff_la_CFLAGS = \
_unittest_support_la_SOURCES = \
swig-unittest-support-python.c
_unittest_support_la_CFLAGS = \
${libtest_core_la_CPPFLAGS} \
${PYTHON_CPPFLAGS}
_test_stuff_la_LDFLAGS = \
_unittest_support_la_LDFLAGS = \
${PYTHON_LDFLAGS} \
-module \
-rpath ${exec-prefix}/lib
_test_stuff_la_LIBADD = \
_unittest_support_la_LIBADD = \
${PYTHON_LIBS} \
${PYTHON_EXTRA_LIBS} \
libtest-core.la
endif
SCM_FILES = test-stuff.scm
SCM_FILES = unittest-support.scm
gncmoddir = ${GNC_SHAREDIR}/guile-modules/gnucash
gncmod_DATA = $(SCM_FILES)
@@ -93,8 +97,10 @@ CLEANFILES = .scm-links
EXTRA_DIST = \
$(SCM_FILES) \
swig-test-stuff-python.c \
swig-test-stuff-guile.c \
test-stuff.i
swig-unittest-support-python.c \
swig-unittest-support-guile.c \
unittest-support.i
MAINTAINERCLEANFILES = swig-test-stuff-guile.c swig-test-stuff-python.c
MAINTAINERCLEANFILES = \
swig-unittest-support-guile.c \
swig-unittest-support-python.c
-215
View File
@@ -21,14 +21,6 @@
#include <glib/gprintf.h>
#include "test-stuff.h"
typedef struct
{
gpointer data;
gboolean called;
gchar *msg;
} TestStruct;
static TestStruct tdata;
void vsuccess_args(
const char *test_title,
@@ -357,210 +349,3 @@ get_random_string_in_array(const char* str_list[])
num = get_random_int_in_range(0, num - 1);
return str_list[num];
}
gboolean
test_null_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
//Silent, remember?
return FALSE;
}
static gchar*
test_log_level (GLogLevelFlags flags)
{
const gchar *message[] = {"RECURSIVE", "FATAL", "ERROR", "CRITICAL",
"WARNING", "MESSAGE", "INFO", "DEBUG"
};
guint i = 0, last = 0, max_bit = 7;
gchar *msg = NULL;
for (i; i <= max_bit; i++)
if (flags & 1 << i)
{
gchar *tmp_msg = msg;
gchar *sep = (last < 2 ? " " : "|");
last = i;
msg = (tmp_msg ? g_strjoin (sep, tmp_msg, message[i], NULL)
: g_strdup (message[i]));
if (tmp_msg)
g_free (tmp_msg);
}
if (msg == NULL)
msg = g_strdup ("");
return msg;
}
static GList *message_queue = NULL;
void
test_add_error (TestErrorStruct *error)
{
message_queue = g_list_append (message_queue, error);
}
void
test_clear_error_list (void)
{
g_list_free (message_queue);
message_queue = NULL;
}
gboolean
test_list_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
GList *list = g_list_first (message_queue);
const guint fatal = G_LOG_FLAG_FATAL;
while (list)
{
TestErrorStruct *error = (TestErrorStruct*)list->data;
if (!g_strcmp0 (log_domain, error->log_domain)
&& ((log_level | fatal) == (error->log_level | fatal))
&& !g_strcmp0 (msg, error->msg))
return FALSE;
list = g_list_next (list);
}
/* No list or no matches, fall through */
return test_checked_handler (log_domain, log_level, msg, user_data);
}
gboolean
test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
TestErrorStruct *tdata = (TestErrorStruct*)user_data;
if ((tdata == NULL)
|| (tdata->log_domain != NULL
&& g_strcmp0 (tdata->log_domain, log_domain))
|| (tdata->log_level && tdata->log_level != log_level)
|| (tdata->msg && g_strcmp0 (tdata->msg, msg)))
{
gchar *level = test_log_level (log_level);
g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
g_free (level);
g_assert (log_level ^ G_LOG_FLAG_FATAL);
return FALSE;
}
return FALSE;
}
gboolean
test_log_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
gchar *level = test_log_level (log_level);
g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
g_free (level);
g_assert (log_level ^ G_LOG_FLAG_FATAL);
return FALSE;
}
void
test_set_called( const gboolean val )
{
tdata.called = val;
}
gboolean
test_reset_called( void )
{
const gboolean called = tdata.called;
tdata.called = FALSE;
return called;
}
void
test_set_data( const gpointer val )
{
tdata.data = val;
}
gpointer
test_reset_data( void )
{
const gpointer data = tdata.data;
tdata.data = NULL;
return data;
}
void
test_free( gpointer data )
{
if (!data) return;
g_free(data);
}
typedef struct
{
QofInstance *entity;
QofEventId event_type;
gpointer event_data;
gint hdlr;
guint hits;
} _TestSignal;
static void
mock_signal_handler (QofInstance *entity, QofEventId event_type,
gpointer handler_data, gpointer event_data)
{
_TestSignal *signal = (_TestSignal*)handler_data;
if ((signal->entity == entity || signal->entity == NULL)
&& signal->event_type == event_type)
{
if (signal->event_data)
g_assert (signal->event_data == event_data);
signal->hits += 1;
}
}
TestSignal
test_signal_new (QofInstance *entity, QofEventId event_type,
gpointer event_data)
{
_TestSignal *sig = g_slice_new (_TestSignal);
sig->entity = entity;
sig->event_type = event_type;
sig->event_data = event_data;
sig->hits = 0;
sig->hdlr = qof_event_register_handler (mock_signal_handler, (gpointer)sig);
return (TestSignal)sig;
}
void
test_signal_free (TestSignal sigp)
{
_TestSignal *sig = (_TestSignal *)sigp;
qof_event_unregister_handler (sig->hdlr);
g_slice_free (_TestSignal, sig);
}
guint
test_signal_return_hits (TestSignal sigp)
{
_TestSignal *sig = (_TestSignal *)sigp;
return sig->hits;
}
static void
notify_destroy (gpointer pdata, GObject *obj)
{
gboolean *data = (gboolean*)pdata;
if (! (*data)) *data = TRUE;
}
gboolean
test_object_checked_destroy (GObject *obj)
{
gboolean is_destroyed = FALSE;
if (!obj || ! G_IS_OBJECT (obj)) return FALSE;
g_object_weak_ref (obj, notify_destroy, &is_destroyed);
g_object_unref (obj);
return is_destroyed;
}
+1 -179
View File
@@ -4,7 +4,7 @@
*
* Modified by bstanley 20010323
* removed testing functionality which depends on the rest of gnucash -
* sepearated into gnc-test-stuff.h
* separated into gnc-test-stuff.h
*
*/
@@ -36,7 +36,6 @@ Otherwise, only failures are printed out.
#include <glib.h>
#include <stdlib.h>
#include <qof.h>
/**
* Use this to indicate the result of a test.
@@ -54,130 +53,6 @@ Otherwise, only failures are printed out.
#define do_test_args( result, title, format ) do_test_call( result, title, __FILE__, __LINE__, format, ... );
*/
/**
* Use this macro to format informative test path output when using g_test_add.
* Suite stands for tests' pack, while path for individual test name.
*/
#define GNC_TEST_ADD( suite, path, fixture, data, setup, test, teardown )\
{\
gchar *testpath = g_strdup_printf( "%s/%s", suite, path );\
g_test_add( testpath, fixture, data, setup, test, teardown );\
g_free( testpath );\
}
/**
* Use this macro to format informative test path output when using g_test_add_func.
* Suite stands for tests' pack, while path for individual test name.
*/
#define GNC_TEST_ADD_FUNC( suite, path, test )\
{\
gchar *testpath = g_strdup_printf( "%s/%s", suite, path );\
g_test_add_func( testpath, test );\
g_free( testpath );\
}
/**
* Suppressing Expected Errors
*
* Functions for suppressing expected errors during tests. Pass
*
* Note that you need to call both g_log_set_handler *and*
* g_test_log_set_fatal_handler to both avoid the assertion and
* suppress the error message. The callbacks work in either role, just
* cast them appropriately for the use.
*/
/**
* Struct to pass as user_data for the handlers. Setting a parameter
* to NULL or 0 will match any value in the error, so if you have the
* same message and log level being issued in two domains you can
* match both of them by setting log_domain = NULL.
*
*/
typedef struct
{
GLogLevelFlags log_level;
gchar *log_domain;
gchar *msg;
} TestErrorStruct;
/**
* Check the user_data against the actual error and assert on any
* differences. Displays the error (and asserts if G_LOG_FLAG_FATAL
* is TRUE) if NULL is passed as user_data, but a NULL or 0 value
* member matches anything.
*/
gboolean test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data);
/**
* Just print the log message. Since GLib has a habit of eating its
* log messages, it's sometimes useful to call
* g_test_log_set_fatal_handler() with this to make sure that
* g_return_if_fail() error messages make it to the surface.
*/
gboolean test_log_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data);
/**
* Just returns FALSE or suppresses the message regardless of what the
* error is. Use this only as a last resort.
*/
gboolean test_null_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data );
/**
* Maintains an internal list of TestErrorStructs which are each
* checked by the list handler. If an error matches any entry on the
* list, test_list_handler will return FALSE, blocking the error from
* halting the program.
*
* Call test_add_error for each TestErrorStruct to check against and
* test_clear_error_list when you no longer expect the errors.
*/
void test_add_error (TestErrorStruct *error);
void test_clear_error_list (void);
/**
* Checks received errors against the list created by
* test_add_error. If the list is empty or nothing matches, passes
* control on to test_checked_handler, giving the opportunity for an
* additional check that's not in the list (set user_data to NULL if
* you want test_checked_handler to immediately print the error).
*/
gboolean test_list_handler (const char *log_domain,
GLogLevelFlags log_level,
const gchar *msg, gpointer user_data );
/**
* Call this from a mock object to indicate that the mock has in fact
* been called
*/
void test_set_called( const gboolean val );
/**
* Destructively tests (meaning that it resets called to FALSE) and
* returns the value of called.
*/
gboolean test_reset_called( void );
/**
* Set the test data pointer with the what you expect your mock to be
* called with.
*/
void test_set_data( gpointer data );
/**
* Destructively retrieves the test data pointer. Call from your mock
* to ensure that it received the expected data.
*/
gpointer test_reset_data( void );
/**
* A handy function to use to free memory from lists of simple
* pointers. Call g_list_free_full(list, (GDestroyNotify)*test_free).
*/
void test_free( gpointer data );
/* Privately used to indicate a test result. You may use these if you
* wish, but it's easier to use the do_test macro above.
@@ -253,58 +128,5 @@ gint64 get_random_gint64(void);
double get_random_double(void);
const char* get_random_string_in_array(const char* str_list[]);
/* TestSignal is an opaque struct used to mock handling signals
* emitted by functions-under-test. It registers a handler and counts
* how many times it is called with the right instance and type. The
* struct is allocated using g_slice_new, and it registers a
* qof_event_handler; test_signal_free cleans up at the end of the
* test function (or sooner, if you want to reuse a TestSignal). If
* event_data isn't NULL, the mock signal handler will test that it
* matches the event_data passed with the signal and assert if it
* isn't the same object (pointer comparison). If the actual event
* data is a local variable, it won't be accessible, so the event_data
* passed to test_signal_new should be NULL to avoid the test.
*/
typedef gpointer TestSignal;
TestSignal test_signal_new (QofInstance *entity, QofEventId eventType,
gpointer event_data);
/* test_signal_return_hits gets the number of times the TestSignal has
* been called.
*/
guint test_signal_return_hits (TestSignal sig);
/* test_signal_assert_hits is a convenience macro which wraps
* test_signal_return_hits with and equality assertion.
*/
#define test_signal_assert_hits(sig, hits) \
g_assert_cmpint (test_signal_return_hits (sig), ==, hits)
void test_signal_free (TestSignal sig);
/* test_object_checked_destroy unrefs obj and returns true if its finalize
* method was called.
*/
gboolean test_object_checked_destroy (GObject *obj);
/**
* test_destroy() ensures that a GObject is still alive at the time
* it's called and that it is finalized. The first assertion will
* trigger if you pass it a ponter which isn't a GObject -- which
* could be the case if the object has already been finalized. Then it
* calls test_object_checked_destroy() on it, asserting if the
* finalize method wasn't called (which indicates a leak).
*/
#define test_destroy(obj) \
g_assert (obj != NULL && G_IS_OBJECT (obj)); \
g_assert (test_object_checked_destroy (G_OBJECT (obj)))
/* For Scheme testing access:
void gnc_log_init_filename_special (gchar *filename);
void gnc_log_shutdown (void);
void gnc_log_set_handler (guint logdomain, gchar *logdomain, GLogFunc * func, gpointer data);
*/
#endif /* TEST_STUFF_H */
+242
View File
@@ -0,0 +1,242 @@
/********************************************************************
* unittest-support.c: Support structures for GLib Unit Testing *
* Copyright 2011-12 John Ralls <jralls@ceridwen.us> *
* Copyright 2011 Muslim Chochlov <muslim.chochlov@gmail.com> *
* *
* 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 <config.h>
#include <glib/gprintf.h>
#include "unittest-support.h"
typedef struct
{
gpointer data;
gboolean called;
gchar *msg;
} TestStruct;
static TestStruct tdata;
gboolean
test_null_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
//Silent, remember?
return FALSE;
}
static gchar*
test_log_level (GLogLevelFlags flags)
{
const gchar *message[] = {"RECURSIVE", "FATAL", "ERROR", "CRITICAL",
"WARNING", "MESSAGE", "INFO", "DEBUG"
};
guint i = 0, last = 0, max_bit = 7;
gchar *msg = NULL;
for (i; i <= max_bit; i++)
if (flags & 1 << i)
{
gchar *tmp_msg = msg;
gchar *sep = (last < 2 ? " " : "|");
last = i;
msg = (tmp_msg ? g_strjoin (sep, tmp_msg, message[i], NULL)
: g_strdup (message[i]));
if (tmp_msg)
g_free (tmp_msg);
}
if (msg == NULL)
msg = g_strdup ("");
return msg;
}
static GList *message_queue = NULL;
void
test_add_error (TestErrorStruct *error)
{
message_queue = g_list_append (message_queue, error);
}
void
test_clear_error_list (void)
{
g_list_free (message_queue);
message_queue = NULL;
}
gboolean
test_list_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
GList *list = g_list_first (message_queue);
const guint fatal = G_LOG_FLAG_FATAL;
while (list)
{
TestErrorStruct *error = (TestErrorStruct*)list->data;
if (!g_strcmp0 (log_domain, error->log_domain)
&& ((log_level | fatal) == (error->log_level | fatal))
&& !g_strcmp0 (msg, error->msg))
return FALSE;
list = g_list_next (list);
}
/* No list or no matches, fall through */
return test_checked_handler (log_domain, log_level, msg, user_data);
}
gboolean
test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
TestErrorStruct *tdata = (TestErrorStruct*)user_data;
if ((tdata == NULL)
|| (tdata->log_domain != NULL
&& g_strcmp0 (tdata->log_domain, log_domain))
|| (tdata->log_level && tdata->log_level != log_level)
|| (tdata->msg && g_strcmp0 (tdata->msg, msg)))
{
gchar *level = test_log_level (log_level);
g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
g_free (level);
g_assert (log_level ^ G_LOG_FLAG_FATAL);
return FALSE;
}
return FALSE;
}
gboolean
test_log_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
gchar *level = test_log_level (log_level);
g_printf ( "<%s> (%s) %s\n", level, log_domain, msg);
g_free (level);
g_assert (log_level ^ G_LOG_FLAG_FATAL);
return FALSE;
}
void
test_set_called( const gboolean val )
{
tdata.called = val;
}
gboolean
test_reset_called( void )
{
const gboolean called = tdata.called;
tdata.called = FALSE;
return called;
}
void
test_set_data( const gpointer val )
{
tdata.data = val;
}
gpointer
test_reset_data( void )
{
const gpointer data = tdata.data;
tdata.data = NULL;
return data;
}
void
test_free( gpointer data )
{
if (!data) return;
g_free(data);
}
typedef struct
{
QofInstance *entity;
QofEventId event_type;
gpointer event_data;
gint hdlr;
guint hits;
} _TestSignal;
static void
mock_signal_handler (QofInstance *entity, QofEventId event_type,
gpointer handler_data, gpointer event_data)
{
_TestSignal *signal = (_TestSignal*)handler_data;
if ((signal->entity == entity || signal->entity == NULL)
&& signal->event_type == event_type)
{
if (signal->event_data)
g_assert (signal->event_data == event_data);
signal->hits += 1;
}
}
TestSignal
test_signal_new (QofInstance *entity, QofEventId event_type,
gpointer event_data)
{
_TestSignal *sig = g_slice_new (_TestSignal);
sig->entity = entity;
sig->event_type = event_type;
sig->event_data = event_data;
sig->hits = 0;
sig->hdlr = qof_event_register_handler (mock_signal_handler, (gpointer)sig);
return (TestSignal)sig;
}
void
test_signal_free (TestSignal sigp)
{
_TestSignal *sig = (_TestSignal *)sigp;
qof_event_unregister_handler (sig->hdlr);
g_slice_free (_TestSignal, sig);
}
guint
test_signal_return_hits (TestSignal sigp)
{
_TestSignal *sig = (_TestSignal *)sigp;
return sig->hits;
}
static void
notify_destroy (gpointer pdata, GObject *obj)
{
gboolean *data = (gboolean*)pdata;
if (! (*data)) *data = TRUE;
}
gboolean
test_object_checked_destroy (GObject *obj)
{
gboolean is_destroyed = FALSE;
if (!obj || ! G_IS_OBJECT (obj)) return FALSE;
g_object_weak_ref (obj, notify_destroy, &is_destroyed);
g_object_unref (obj);
return is_destroyed;
}
+208
View File
@@ -0,0 +1,208 @@
/********************************************************************
* unittest-support.h: Support structures for GLib Unit Testing *
* Copyright 2011-12 John Ralls <jralls@ceridwen.us> *
* Copyright 2011 Muslim Chochlov <muslim.chochlov@gmail.com> *
* *
* 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 *
********************************************************************/
#ifndef UNITTEST_SUPPORT_H
#define UNITTEST_SUPPORT_H
#include <glib.h>
#include <qof.h>
/**
* Use this macro to format informative test path output when using g_test_add.
* Suite stands for tests' pack, while path for individual test name.
*/
#define GNC_TEST_ADD( suite, path, fixture, data, setup, test, teardown )\
{\
gchar *testpath = g_strdup_printf( "%s/%s", suite, path );\
g_test_add( testpath, fixture, data, setup, test, teardown );\
g_free( testpath );\
}
/**
* Use this macro to format informative test path output when using g_test_add_func.
* Suite stands for tests' pack, while path for individual test name.
*/
#define GNC_TEST_ADD_FUNC( suite, path, test )\
{\
gchar *testpath = g_strdup_printf( "%s/%s", suite, path );\
g_test_add_func( testpath, test );\
g_free( testpath );\
}
/**
* Suppressing Expected Errors
*
* Functions for suppressing expected errors during tests. Pass
*
* Note that you need to call both g_log_set_handler *and*
* g_test_log_set_fatal_handler to both avoid the assertion and
* suppress the error message. The callbacks work in either role, just
* cast them appropriately for the use.
*/
/**
* Struct to pass as user_data for the handlers. Setting a parameter
* to NULL or 0 will match any value in the error, so if you have the
* same message and log level being issued in two domains you can
* match both of them by setting log_domain = NULL.
*
*/
typedef struct
{
GLogLevelFlags log_level;
gchar *log_domain;
gchar *msg;
} TestErrorStruct;
/**
* Check the user_data against the actual error and assert on any
* differences. Displays the error (and asserts if G_LOG_FLAG_FATAL
* is TRUE) if NULL is passed as user_data, but a NULL or 0 value
* member matches anything.
*/
gboolean test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data);
/**
* Just print the log message. Since GLib has a habit of eating its
* log messages, it's sometimes useful to call
* g_test_log_set_fatal_handler() with this to make sure that
* g_return_if_fail() error messages make it to the surface.
*/
gboolean test_log_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data);
/**
* Just returns FALSE or suppresses the message regardless of what the
* error is. Use this only as a last resort.
*/
gboolean test_null_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data );
/**
* Maintains an internal list of TestErrorStructs which are each
* checked by the list handler. If an error matches any entry on the
* list, test_list_handler will return FALSE, blocking the error from
* halting the program.
*
* Call test_add_error for each TestErrorStruct to check against and
* test_clear_error_list when you no longer expect the errors.
*/
void test_add_error (TestErrorStruct *error);
void test_clear_error_list (void);
/**
* Checks received errors against the list created by
* test_add_error. If the list is empty or nothing matches, passes
* control on to test_checked_handler, giving the opportunity for an
* additional check that's not in the list (set user_data to NULL if
* you want test_checked_handler to immediately print the error).
*/
gboolean test_list_handler (const char *log_domain,
GLogLevelFlags log_level,
const gchar *msg, gpointer user_data );
/**
* Call this from a mock object to indicate that the mock has in fact
* been called
*/
void test_set_called( const gboolean val );
/**
* Destructively tests (meaning that it resets called to FALSE) and
* returns the value of called.
*/
gboolean test_reset_called( void );
/**
* Set the test data pointer with the what you expect your mock to be
* called with.
*/
void test_set_data( gpointer data );
/**
* Destructively retrieves the test data pointer. Call from your mock
* to ensure that it received the expected data.
*/
gpointer test_reset_data( void );
/**
* A handy function to use to free memory from lists of simple
* pointers. Call g_list_free_full(list, (GDestroyNotify)*test_free).
*/
void test_free( gpointer data );
/* TestSignal is an opaque struct used to mock handling signals
* emitted by functions-under-test. It registers a handler and counts
* how many times it is called with the right instance and type. The
* struct is allocated using g_slice_new, and it registers a
* qof_event_handler; test_signal_free cleans up at the end of the
* test function (or sooner, if you want to reuse a TestSignal). If
* event_data isn't NULL, the mock signal handler will test that it
* matches the event_data passed with the signal and assert if it
* isn't the same object (pointer comparison). If the actual event
* data is a local variable, it won't be accessible, so the event_data
* passed to test_signal_new should be NULL to avoid the test.
*/
typedef gpointer TestSignal;
TestSignal test_signal_new (QofInstance *entity, QofEventId eventType,
gpointer event_data);
/* test_signal_return_hits gets the number of times the TestSignal has
* been called.
*/
guint test_signal_return_hits (TestSignal sig);
/* test_signal_assert_hits is a convenience macro which wraps
* test_signal_return_hits with and equality assertion.
*/
#define test_signal_assert_hits(sig, hits) \
g_assert_cmpint (test_signal_return_hits (sig), ==, hits)
void test_signal_free (TestSignal sig);
/* test_object_checked_destroy unrefs obj and returns true if its finalize
* method was called.
*/
gboolean test_object_checked_destroy (GObject *obj);
/**
* test_destroy() ensures that a GObject is still alive at the time
* it's called and that it is finalized. The first assertion will
* trigger if you pass it a ponter which isn't a GObject -- which
* could be the case if the object has already been finalized. Then it
* calls test_object_checked_destroy() on it, asserting if the
* finalize method wasn't called (which indicates a leak).
*/
#define test_destroy(obj) \
g_assert (obj != NULL && G_IS_OBJECT (obj)); \
g_assert (test_object_checked_destroy (G_OBJECT (obj)))
/* For Scheme testing access:
void gnc_log_init_filename_special (gchar *filename);
void gnc_log_shutdown (void);
void gnc_log_set_handler (guint logdomain, gchar *logdomain, GLogFunc * func, gpointer data);
*/
#endif /*UNITTEST_SUPPORT_H*/
@@ -1,12 +1,12 @@
%module test_stuff
%module unittest_support
%{
#include "config.h"
#include "test-stuff.h"
#include "unittest-support.h"
%}
#if defined(SWIGGUILE)
%{
SCM scm_init_test_stuff_module (void);
SCM scm_init_unittest_support_module (void);
%}
#endif
@@ -1,6 +1,6 @@
(define-module (gnucash test-stuff))
(load-extension "libtest-core-guile" "scm_init_test_stuff_module")
(use-modules (test_stuff))
(define-module (gnucash unittest-support))
(load-extension "libtest-core-guile" "scm_init_unittest_support_module")
(use-modules (unittest_support))
(re-export TestErrorStruct-log-level-set)
(re-export TestErrorStruct-log-level-get)
+2 -2
View File
@@ -235,10 +235,10 @@ sub print_preamble {
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA $gnuemail *
********************************************************************/
#include "config.h"
#include <config.h>
#include <string.h>
#include <glib.h>
#include "test-stuff.h"
#include <unittest-support.h>
/* Add specific headers for this class */
static const gchar *suitename = "$indir";