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