From 575a9da718e8c84da052f50f1435914a94197696 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Tue, 28 May 2013 13:22:59 -0400 Subject: [PATCH] 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 | 129 ++++++++++++++++++++++---- glib/gtestutils.h | 6 ++ 3 files changed, 120 insertions(+), 17 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 298fdefa5..d9b8dca3d 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 4841178f5..80f693113 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 ()); - 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 (); + va_start (ap, first_path); + result = g_test_build_filename_va (file_type, first_path, ap); + va_end (ap); - pathv[1] = first_path; + 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) + return test_disted_files_dir; + else if (file_type == G_TEST_BUILT) + return test_built_files_dir; + + 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 47ee4508a..0b1ba78de 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)