+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_DIST)
+ 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. distributed)
+ * @first_path: the first segment of the pathname
+ * @...: %NULL-terminated additional path segments
+ *
+ * Creates the pathname to a data file that is required for a test.
+ *
+ * This function is conceptually similar to g_build_filename() except
+ * that the first argument has been replaced with a #GTestFileType
+ * argument.
+ *
+ * The data file should either have been distributed with the module
+ * containing the test (%G_TEST_DIST) or built as part of the build
+ * system of that module (%G_TEST_BUILT).
+ *
+ * In order for this function to work in srcdir != builddir situations,
+ * the G_TEST_SRCDIR and G_TEST_BUILDDIR environment variables need to
+ * have been defined. As of 2.38, this is done by the glib.mk
+ * included in GLib. Please ensure that your copy is up to date before
+ * using this function.
+ *
+ * In case neither variable is set, this function will fall back to
+ * using the dirname portion of argv[0], possibly removing ".libs".
+ * This allows for casual running of tests directly from the commandline
+ * in the srcdir == builddir case and should also support running of
+ * installed tests, assuming the data files have been installed in the
+ * same relative path as the test binary.
+ *
+ * Returns: the path of the file, to be freed using g_free()
+ *
+ * Since: 2.38
+ **/
+/**
+ * GTestFileType:
+ * @G_TEST_DIST: a file that was included in the distribution tarball
+ * @G_TEST_BUILT: a file that was built on the compiling machine
+ *
+ * The type of file to return the filename for, when used with
+ * g_test_build_filename().
+ *
+ * These two options correspond rather directly to the 'dist' and
+ * 'built' terminology that automake uses and are explicitly used to
+ * distinguish between the 'srcdir' and 'builddir' being separate. All
+ * files in your project should either be dist (in the
+ * `DIST_EXTRA` or `dist_schema_DATA`
+ * sense, in which case they will always be in the srcdir) or built (in
+ * the `BUILT_SOURCES` sense, in which case they will
+ * always be in the builddir).
+ *
+ * Note: as a general rule of automake, files that are generated only as
+ * part of the build-from-git process (but then are distributed with the
+ * tarball) always go in srcdir (even if doing a srcdir != builddir
+ * build from git) and are considered as distributed files.
+ *
+ * Since: 2.38
+ **/
+gchar *
+g_test_build_filename (GTestFileType file_type,
+ const gchar *first_path,
+ ...)
+{
+ 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. distributed)
+ *
+ * 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_DIST)
+ 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. distributed)
+ * @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 functions");
+
+ va_start (ap, first_path);
+ result = g_test_build_filename_va (file_type, first_path, ap);
+ va_end (ap);
+
+ 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 result;
+}
+