r21668 - gnucash/trunk/src/test-core - [Testing] Provide list error handler, rename some functions
John Ralls
jralls at code.gnucash.org
Sun Dec 4 19:06:28 EST 2011
Author: jralls
Date: 2011-12-04 19:06:28 -0500 (Sun, 04 Dec 2011)
New Revision: 21668
Trac: http://svn.gnucash.org/trac/changeset/21668
Modified:
gnucash/trunk/src/test-core/test-stuff.c
gnucash/trunk/src/test-core/test-stuff.h
Log:
[Testing] Provide list error handler, rename some functions
Add an GTestFatalFunc which can examine a list of error conditions and suppress those messages and prevent their exiting while passing through any unexpected errors.
Rename test_silent_logger to test_null_handler and change it to a GTestFatalFunc (it can still be used as a GLogFunc).
Rename test_handle_faults to test_checked_handler and improve its flow and message display. It no longer asserts on a bad match.
Modified: gnucash/trunk/src/test-core/test-stuff.c
===================================================================
--- gnucash/trunk/src/test-core/test-stuff.c 2011-12-05 00:06:18 UTC (rev 21667)
+++ gnucash/trunk/src/test-core/test-stuff.c 2011-12-05 00:06:28 UTC (rev 21668)
@@ -358,37 +358,95 @@
return str_list[num];
}
-void
-test_silent_logger( const char *log_domain, GLogLevelFlags log_level,
+gboolean
+test_null_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data )
{
//Silent, remember?
- return;
+ 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_handle_faults( const char *log_domain, GLogLevelFlags log_level,
- const gchar *msg, gpointer user_data )
+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)
+
+ 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)))
{
- g_printf("Received Log Message %s\n", 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;
}
-/* If it's a lower loglevel than we expected, report it and move on */
- if (tdata->log_level && log_level < tdata->log_level)
- {
- g_printf ("Received Log Message %s\n", msg);
- return FALSE;
- }
- if (tdata->log_domain != NULL)
- g_assert_cmpstr (tdata->log_domain, ==, log_domain);
- if (tdata->log_level)
- g_assert_cmpuint (tdata->log_level, ==, log_level);
- if (tdata->log_level)
- g_assert_cmpstr (tdata->msg, ==, msg);
return FALSE;
+
}
void
Modified: gnucash/trunk/src/test-core/test-stuff.h
===================================================================
--- gnucash/trunk/src/test-core/test-stuff.h 2011-12-05 00:06:18 UTC (rev 21667)
+++ gnucash/trunk/src/test-core/test-stuff.h 2011-12-05 00:06:28 UTC (rev 21668)
@@ -79,11 +79,21 @@
}
/**
- * Test Support
+ * Suppressing Expected Errors
*
- * Struct and functions for unit test support:
- * Intercept and report GLib error messages to test functions.
- * Ensure that mock functions are called, and with the right data pointer
+ * 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.
*
*/
@@ -95,23 +105,42 @@
} TestErrorStruct;
/**
- * Pass this to g_test_log_set_fatal_handler(), setting user_data to
- * a pointer to TestErrorStruct to intercept and handle expected
- * error and warning messages. It will g_assert if an error is
- * received which doesn't match the log_level, log_domain, and
- * message in the struct (if they're set), or return FALSE to prevent
- * the message from aborting. Be sure to g_free() the
- * TestErrorData:msg after you're done testing it.
+ * 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_handle_faults( const char *log_domain, GLogLevelFlags log_level,
+gboolean test_checked_handler (const char *log_domain, GLogLevelFlags log_level,
const gchar *msg, gpointer user_data);
/**
- * When you know you're going to get a useless log message, pass this
- * to g_log_set_default_handler to shut it up.
+ * Just returns FALSE or suppresses the message regardless of what the
+ * error is. Use this only as a last resort.
*/
-void test_silent_logger( const char *log_domain, GLogLevelFlags log_level,
- const gchar *msg, gpointer user_data );
+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
*/
@@ -237,4 +266,10 @@
void test_signal_assert_hits (TestSignal sig, guint hits);
void test_signal_free (TestSignal sig);
+/* 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 */
More information about the gnucash-changes
mailing list