mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-24 09:50:54 -06:00
66c5e398ae
g_assert() can be compiled out, so should not be used for tests
g_assert_true was removed
to fis https://bugs.gnucash.org/show_bug.cgi?id=792008 because
g_assert_true was introduced in glib-2.38 and at the time GnuCash required
only glib-2.26. GnuCash has required glib >= 2.40 since 8acbc41c6
so
g_assert_true can be restored.
369 lines
14 KiB
C
369 lines
14 KiB
C
/********************************************************************
|
|
* 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>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/** @file unittest-support.h
|
|
* @brief Macros and logging-capture functions to ease writing GLib-testing
|
|
* based unit tests.
|
|
*/
|
|
|
|
/** @name Unit Test Macros
|
|
* These macros facilitate combining a suite name and a test name to make a path
|
|
* when registering a test function with the corresponding g_test_add and
|
|
* g_test_add_func. Create a const char* suitename somewhere in the file and
|
|
* pass it as the first parameter, and the test name as the second. The
|
|
* remaining parameters are the same as in the underlying function.
|
|
*/
|
|
|
|
/**
|
|
* Wraps gnc_test_add() for test functions needing a fixture.
|
|
*/
|
|
|
|
#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 );\
|
|
}
|
|
|
|
/**
|
|
* Wraps gnc_test_add_func() for test functions which don't require a fixture.
|
|
*/
|
|
|
|
#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 );\
|
|
}
|
|
/** @} */
|
|
/** @name 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.
|
|
*
|
|
* To simplify the process a bit and make sure that everything gets
|
|
* cleaned up at the end of each test, add a GSList for handlers to
|
|
* your Fixture and set it to NULL in setup(), then call
|
|
* g_slist_free_full() on it with test_free_log_handler as the
|
|
* function. Create new TestErrorStruct instances with
|
|
* test_error_struct_new, and pass that along with your handler of
|
|
* choice to test_log_set_handler or test_log_set_fatal_handler. This
|
|
* is much simpler, as teardown will clean everything up for you and
|
|
* you need call only those functions. As an added bonus, the hit
|
|
* count won't be doubled as it is if you do everything by hand.
|
|
*
|
|
* NB: If you have more than one fatal error in a test function be
|
|
* sure to use the test_list_handler: You can have only one fatal
|
|
* handler.
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* 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;
|
|
char *log_domain;
|
|
char *msg;
|
|
guint hits;
|
|
} TestErrorStruct;
|
|
|
|
/**
|
|
* Convenience function to create an error struct. If you use this
|
|
* with test_set_log_handler it will get cleaned up at tesrdown,
|
|
* otherwise call test_error_free() at the end of your test function.
|
|
*
|
|
* NB: If you need to change the message, be sure to free the old one
|
|
* and to allocate the new one on the stack.
|
|
*
|
|
* @param log_domain: The string representing the domain of the log message
|
|
* @param log_level: The GLogLevelFlags for the message
|
|
* @param msg: The exact error message that the logger will emit
|
|
* @return: A TestErrorStruct *
|
|
*/
|
|
TestErrorStruct* test_error_struct_new (const char *log_domain,
|
|
const GLogLevelFlags log_level,
|
|
const char *msg);
|
|
|
|
/**
|
|
* Free a TestErrorStruct created with test_error_struct_new
|
|
* @param error: The TestErrorStruct to be freed
|
|
*/
|
|
void test_error_struct_free (TestErrorStruct *);
|
|
|
|
/**
|
|
* Holds a handler instance with its TestErrorStruct, handler id, and whether
|
|
* it's a list handler. A test fixture can be set up to hold a GSList of these
|
|
* so that they can be automatically unregistered and freed during teardown.
|
|
*/
|
|
typedef struct
|
|
{
|
|
TestErrorStruct *error;
|
|
gint handler;
|
|
gboolean list_handler;
|
|
} TestLogHandler;
|
|
|
|
|
|
/**
|
|
* Set a log handler and add it to a GList for removal at teardown
|
|
*
|
|
* Don't pass a NULL TestErrorStruct! It's needed to set the
|
|
* parameters for g_log_set_handler. Use a TestErrorStruct created
|
|
* with test_error_struct_new() or you'll have errors with freeing it
|
|
* in teardown.
|
|
*
|
|
* @param handler_list: A GSList of LogHandlers
|
|
* @param error: A TestErrorStruct with the necessary data
|
|
* @param handler: The Handler to set the data with
|
|
* @return: The new GSList pointer.
|
|
*/
|
|
GSList *test_log_set_handler (GSList *list, TestErrorStruct *error,
|
|
GLogFunc handler);
|
|
|
|
/**
|
|
* Set a log handler and add it to a GList for removal at teardown;
|
|
* also set the fatal handler so that the test program doesn't abort
|
|
* for fatal log messages. If a test function has more than one fatal
|
|
* message, be sure to use the test_list_handler!
|
|
*
|
|
* Don't pass a NULL TestErrorStruct! It's needed to set the
|
|
* parameters for g_log_set_handler. Use a TestErrorStruct created
|
|
* with test_error_struct_new() or you'll have errors with freeing it
|
|
* in teardown.
|
|
*
|
|
* @param handler_list: A GSList of LogHandlers
|
|
* @param error: A TestErrorStruct with the necessary data
|
|
* @param handler: The Handler to set the data with
|
|
* @return: The new GSList pointer.
|
|
*/
|
|
GSList *test_log_set_fatal_handler (GSList *list, TestErrorStruct *error,
|
|
GLogFunc handler);
|
|
|
|
/**
|
|
* Clears all the log handlers. Pass this to g_slist_free() in teardown.
|
|
*/
|
|
void test_free_log_handler (gpointer item);
|
|
|
|
/**
|
|
* Check that the user_data error message is a substring of the
|
|
* actual error otherwise assert. 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_substring_handler (const char *log_domain, GLogLevelFlags log_level,
|
|
const gchar *msg, gpointer user_data);
|
|
/**
|
|
* 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. Rather than checking for an exact match, this function
|
|
* checks using a substring match. If the list is empty or nothing
|
|
* matches, passes control on to test_checked_substring_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_substring_handler (const char *log_domain, GLogLevelFlags log_level,
|
|
const gchar *msg, gpointer user_data);
|
|
|
|
/**
|
|
* 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 );
|
|
|
|
/** @}
|
|
*/
|
|
/** @name Test Signals
|
|
* Test the emission of signals from objects. Signals are used to coordinate the
|
|
* behavior of the GUI with events in other parts of the program. @{
|
|
*/
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* Create a test signal.
|
|
* @param entity: The QofInstance emitting the signal
|
|
* @param eventType: The type of the signal
|
|
* @param event_data: Any data required by the signal or NULL if none is.
|
|
* @return A newly created TestSignal. Use test_signal_free to release it.
|
|
*/
|
|
|
|
TestSignal test_signal_new (QofInstance *entity, QofEventId eventType,
|
|
gpointer event_data);
|
|
/**
|
|
* gets the number of times the TestSignal has been called.
|
|
*/
|
|
guint test_signal_return_hits (TestSignal sig);
|
|
|
|
/**
|
|
* 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)
|
|
|
|
/**
|
|
* Free a test signal.
|
|
*/
|
|
void test_signal_free (TestSignal sig);
|
|
|
|
/** @}
|
|
*/
|
|
|
|
/** @name Testing for object disposal
|
|
* Sometimes we need to make sure that certain objects that we've created aren't leaking. These functions can help.
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Unrefs obj and returns true if its finalize method was called.
|
|
*/
|
|
|
|
gboolean test_object_checked_destroy (GObject *obj);
|
|
|
|
/**
|
|
* 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 pointer 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_true (obj != NULL && G_IS_OBJECT (obj)); \
|
|
g_assert_true (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);
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /*UNITTEST_SUPPORT_H*/
|