[glib] gtest: Add more path building API



commit 575a9da718e8c84da052f50f1435914a94197696
Author: Ryan Lortie <desrt desrt ca>
Date:   Tue May 28 13:22:59 2013 -0400

    gtest: Add more path building API
    
    Add a pair of functions for returning strings that don't need to be
    freed.  This is a bit of a hack but it will turn the 99% case of using
    these functions from:
    
      gchar *tmp;
      tmp = g_test_build_filename (...);
      fd = open (tmp, ...);
      g_free (tmp);
    
    to:
    
      fd = open (g_test_get_filename (...), ...);
    
    which is a pretty substantial win.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=549783

 docs/reference/glib/glib-sections.txt |    2 +
 glib/gtestutils.c                     |  125 +++++++++++++++++++++++++++++----
 glib/gtestutils.h                     |    6 ++
 3 files changed, 118 insertions(+), 15 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 298fdef..d9b8dca 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2918,6 +2918,8 @@ g_test_add
 
 GTestFileType
 g_test_build_filename
+g_test_get_filename
+g_test_get_dir
 
 g_test_fail
 g_test_message
diff --git a/glib/gtestutils.c b/glib/gtestutils.c
index 4841178..80f6931 100644
--- a/glib/gtestutils.c
+++ b/glib/gtestutils.c
@@ -544,6 +544,7 @@ static gboolean    test_run_list = FALSE;
 static gchar      *test_run_seedstr = NULL;
 static GRand      *test_run_rand = NULL;
 static gchar      *test_run_name = "";
+static GSList    **test_filename_free_list;
 static guint       test_run_forks = 0;
 static guint       test_run_count = 0;
 static guint       test_run_success = FALSE;
@@ -1815,8 +1816,12 @@ static gboolean
 test_case_run (GTestCase *tc)
 {
   gchar *old_name = test_run_name, *old_base = g_strdup (test_uri_base);
+  GSList **old_free_list, *filename_free_list = NULL;
   gboolean success = TRUE;
 
+  old_free_list = test_filename_free_list;
+  test_filename_free_list = &filename_free_list;
+
   test_run_name = g_strconcat (old_name, "/", tc->name, NULL);
   if (strstr (test_run_name, "/subprocess"))
     {
@@ -1885,6 +1890,8 @@ test_case_run (GTestCase *tc)
     }
 
  out:
+  g_slist_free_full (filename_free_list, g_free);
+  test_filename_free_list = old_free_list;
   g_free (test_run_name);
   test_run_name = old_name;
   g_free (test_uri_base);
@@ -2903,6 +2910,35 @@ g_test_log_msg_free (GTestLogMsg *tmsg)
   g_free (tmsg);
 }
 
+static gchar *
+g_test_build_filename_va (GTestFileType  file_type,
+                          const gchar   *first_path,
+                          va_list        ap)
+{
+  const gchar *pathv[16];
+  gint num_path_segments;
+
+  if (file_type == G_TEST_DISTED)
+    pathv[0] = test_disted_files_dir;
+  else if (file_type == G_TEST_BUILT)
+    pathv[0] = test_built_files_dir;
+  else
+    g_assert_not_reached ();
+
+  pathv[1] = first_path;
+
+  for (num_path_segments = 2; num_path_segments < G_N_ELEMENTS (pathv); num_path_segments++)
+    {
+      pathv[num_path_segments] = va_arg (ap, const char *);
+      if (pathv[num_path_segments] == NULL)
+        break;
+    }
+
+  g_assert_cmpint (num_path_segments, <, G_N_ELEMENTS (pathv));
+
+  return g_build_filenamev ((gchar **) pathv);
+}
+
 /**
  * g_test_build_filename:
  * @file_type: the type of file (built vs. disted)
@@ -2951,32 +2987,91 @@ g_test_build_filename (GTestFileType  file_type,
                        const gchar   *first_path,
                        ...)
 {
-  const gchar *pathv[16];
-  gint num_path_segments;
+  gchar *result;
   va_list ap;
 
   g_assert (g_test_initialized ());
 
+  va_start (ap, first_path);
+  result = g_test_build_filename_va (file_type, first_path, ap);
+  va_end (ap);
+
+  return result;
+}
+
+/**
+ * g_test_get_dir:
+ * @file_type: the type of file (built vs. disted)
+ *
+ * Gets the pathname of the directory containing test files of the type
+ * specified by @file_type.
+ *
+ * This is approximately the same as calling g_test_build_filename("."),
+ * but you don't need to free the return value.
+ *
+ * Returns: the path of the directory, owned by GLib
+ *
+ * Since: 2.38
+ **/
+const gchar *
+g_test_get_dir (GTestFileType file_type)
+{
+  g_assert (g_test_initialized ());
+
   if (file_type == G_TEST_DISTED)
-    pathv[0] = test_disted_files_dir;
+    return test_disted_files_dir;
   else if (file_type == G_TEST_BUILT)
-    pathv[0] = test_built_files_dir;
-  else
-    g_assert_not_reached ();
+    return test_built_files_dir;
 
-  pathv[1] = first_path;
+  g_assert_not_reached ();
+}
+
+/**
+ * g_test_get_filename:
+ * @file_type: the type of file (built vs. disted)
+ * @first_path: the first segment of the pathname
+ * ...: NULL terminated additional path segments
+ *
+ * Gets the pathname to a data file that is required for a test.
+ *
+ * This is the same as g_test_build_filename() with two differences.
+ * The first difference is that must only use this function from within
+ * a testcase function.  The second difference is that you need not free
+ * the return value -- it will be automatically freed when the testcase
+ * finishes running.
+ *
+ * It is safe to use this function from a thread inside of a testcase
+ * but you must ensure that all such uses occur before the main testcase
+ * function returns (ie: it is best to ensure that all threads have been
+ * joined).
+ *
+ * Returns: the path, automatically freed at the end of the testcase
+ *
+ * Since: 2.38
+ **/
+const gchar *
+g_test_get_filename (GTestFileType  file_type,
+                     const gchar   *first_path,
+                     ...)
+{
+  gchar *result;
+  GSList *node;
+  va_list ap;
+
+  g_assert (g_test_initialized ());
+  if (test_filename_free_list == NULL)
+    g_error ("g_test_get_filename() can only be used within testcase funcitons");
 
   va_start (ap, first_path);
-  for (num_path_segments = 2; num_path_segments < G_N_ELEMENTS (pathv); num_path_segments++)
-    {
-      pathv[num_path_segments] = va_arg (ap, const char *);
-      if (pathv[num_path_segments] == NULL)
-        break;
-    }
+  result = g_test_build_filename_va (file_type, first_path, ap);
+  va_end (ap);
 
-  g_assert_cmpint (num_path_segments, <, G_N_ELEMENTS (pathv));
+  node = g_slist_prepend (NULL, result);
+  do
+    node->next = *test_filename_free_list;
+  while (!g_atomic_pointer_compare_and_exchange (test_filename_free_list, node->next, node));
 
-  return g_build_filenamev ((gchar **) pathv);
+  return result;
 }
 
 /* --- macros docs START --- */
diff --git a/glib/gtestutils.h b/glib/gtestutils.h
index 47ee450..0b1ba78 100644
--- a/glib/gtestutils.h
+++ b/glib/gtestutils.h
@@ -382,6 +382,12 @@ GLIB_AVAILABLE_IN_2_38
 gchar * g_test_build_filename                    (GTestFileType   file_type,
                                                   const gchar    *first_path,
                                                   ...) G_GNUC_NULL_TERMINATED;
+GLIB_AVAILABLE_IN_2_38
+const gchar *g_test_get_dir                      (GTestFileType   file_type);
+GLIB_AVAILABLE_IN_2_38
+const gchar *g_test_get_filename                 (GTestFileType   file_type,
+                                                  const gchar    *first_path,
+                                                  ...) G_GNUC_NULL_TERMINATED;
 
 #define g_test_assert_expected_messages() g_test_assert_expected_messages_internal (G_LOG_DOMAIN, __FILE__, 
__LINE__, G_STRFUNC)
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]