diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in index db8f47230..52029b861 100644 --- a/docs/reference/glib/glib-sections.txt.in +++ b/docs/reference/glib/glib-sections.txt.in @@ -3363,6 +3363,7 @@ g_test_assert_expected_messages GTestTrapFlags GTestSubprocessFlags g_test_trap_subprocess +g_test_trap_subprocess_with_envp g_test_trap_has_passed g_test_trap_reached_timeout g_test_trap_assert_passed diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 9d5b1cfbb..704f5ce0e 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -3850,6 +3850,32 @@ G_GNUC_END_IGNORE_DEPRECATIONS * @test_flags: Flags to modify subprocess behaviour. * * Respawns the test program to run only @test_path in a subprocess. + * + * This is equivalent to calling g_test_trap_subprocess_with_envp() with `envp` + * set to %NULL. See the documentation for that function for full details. + * + * Since: 2.38 + */ +void +g_test_trap_subprocess (const char *test_path, + guint64 usec_timeout, + GTestSubprocessFlags test_flags) +{ + g_test_trap_subprocess_with_envp (test_path, NULL, usec_timeout, test_flags); +} + +/** + * g_test_trap_subprocess_with_envp: + * @test_path: (nullable): Test to run in a subprocess + * @envp: (array zero-terminated=1) (nullable) (element-type filename): Environment + * to run the test in, or %NULL to inherit the parent’s environment. This must + * be in the GLib filename encoding. + * @usec_timeout: Timeout for the subprocess test in micro seconds. + * @test_flags: Flags to modify subprocess behaviour. + * + * Respawns the test program to run only @test_path in a subprocess with the + * given @envp environment. + * * This can be used for a test case that might not return, or that * might abort. * @@ -3863,6 +3889,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS * tests with names of this form will automatically be skipped in the * parent process. * + * If @envp is %NULL, the parent process’ environment will be inherited. + * * If @usec_timeout is non-0, the test subprocess is aborted and * considered failing if its run time exceeds it. * @@ -3905,23 +3933,44 @@ G_GNUC_END_IGNORE_DEPRECATIONS * g_test_trap_assert_stderr ("*ERROR*too large*"); * } * + * static void + * test_different_username (void) + * { + * if (g_test_subprocess ()) + * { + * // Code under test goes here + * g_message ("Username is now simulated as %s", g_getenv ("USER")); + * return; + * } + * + * // Reruns this same test in a subprocess + * g_autoptr(GStrv) envp = g_get_environ (); + * envp = g_environ_setenv (g_steal_pointer (&envp), "USER", "charlie", TRUE); + * g_test_trap_subprocess_with_envp (NULL, envp, 0, G_TEST_SUBPROCESS_DEFAULT); + * g_test_trap_assert_passed (); + * g_test_trap_assert_stdout ("Username is now simulated as charlie"); + * } + * * int * main (int argc, char **argv) * { * g_test_init (&argc, &argv, NULL); * - * g_test_add_func ("/myobject/create_large_object", + * g_test_add_func ("/myobject/create-large-object", * test_create_large_object); + * g_test_add_func ("/myobject/different-username", + * test_different_username); * return g_test_run (); * } * ]| * - * Since: 2.38 + * Since: 2.80 */ void -g_test_trap_subprocess (const char *test_path, - guint64 usec_timeout, - GTestSubprocessFlags test_flags) +g_test_trap_subprocess_with_envp (const char *test_path, + const char * const *envp, + guint64 usec_timeout, + GTestSubprocessFlags test_flags) { GError *error = NULL; GPtrArray *argv; @@ -3980,7 +4029,7 @@ g_test_trap_subprocess (const char *test_path, if (!g_spawn_async_with_pipes (test_initial_cwd, (char **)argv->pdata, - NULL, flags, + (char **) envp, flags, NULL, NULL, &pid, NULL, &stdout_fd, &stderr_fd, &error)) diff --git a/glib/gtestutils.h b/glib/gtestutils.h index 30ede2588..69ca9c9b7 100644 --- a/glib/gtestutils.h +++ b/glib/gtestutils.h @@ -515,6 +515,11 @@ GLIB_AVAILABLE_IN_2_38 void g_test_trap_subprocess (const char *test_path, guint64 usec_timeout, GTestSubprocessFlags test_flags); +GLIB_AVAILABLE_IN_2_80 +void g_test_trap_subprocess_with_envp (const char *test_path, + const char * const *envp, + guint64 usec_timeout, + GTestSubprocessFlags test_flags); GLIB_AVAILABLE_IN_ALL gboolean g_test_trap_has_passed (void); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index acbc1be22..83aaad9bb 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -404,6 +404,25 @@ test_subprocess_timeout (void) g_assert_true (g_test_trap_reached_timeout ()); } +static void +test_subprocess_envp (void) +{ + char **envp = NULL; + + if (g_test_subprocess ()) + { + g_assert_cmpstr (g_getenv ("TEST_SUBPROCESS_VARIABLE"), ==, "definitely set"); + return; + } + + envp = g_get_environ (); + envp = g_environ_setenv (g_steal_pointer (&envp), "TEST_SUBPROCESS_VARIABLE", "definitely set", TRUE); + g_test_trap_subprocess_with_envp (NULL, (const gchar * const *) envp, + 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_strfreev (envp); +} + /* run a test with fixture setup and teardown */ typedef struct { guint seed; @@ -2909,6 +2928,7 @@ main (int argc, g_test_add_func ("/trap_subprocess/no-such-test", test_subprocess_no_such_test); if (g_test_slow ()) g_test_add_func ("/trap_subprocess/timeout", test_subprocess_timeout); + g_test_add_func ("/trap_subprocess/envp", test_subprocess_envp); g_test_add_func ("/trap_subprocess/patterns", test_subprocess_patterns); diff --git a/glib/tests/utils.c b/glib/tests/utils.c index 3abef9312..e71d9a6ef 100644 --- a/glib/tests/utils.c +++ b/glib/tests/utils.c @@ -211,8 +211,27 @@ test_prgname_thread_safety (void) static void test_tmpdir (void) { + char **envp = NULL; + g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=627969"); - g_assert_cmpstr (g_get_tmp_dir (), !=, ""); + g_test_summary ("Test that g_get_tmp_dir() returns a correct default if TMPDIR is set to the empty string"); + + if (g_test_subprocess ()) + { + g_assert_cmpstr (g_get_tmp_dir (), !=, ""); + return; + } + + envp = g_get_environ (); + + envp = g_environ_setenv (g_steal_pointer (&envp), "TMPDIR", "", TRUE); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "TMP"); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "TEMP"); + + g_test_trap_subprocess_with_envp (NULL, (const gchar * const *) envp, + 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_strfreev (envp); } #if defined(__GNUC__) && (__GNUC__ >= 4) @@ -1309,11 +1328,6 @@ main (int argc, { argv0 = argv[0]; - /* for tmpdir test, need to do this early before g_get_any_init */ - g_setenv ("TMPDIR", "", TRUE); - g_unsetenv ("TMP"); - g_unsetenv ("TEMP"); - /* g_test_init() only calls g_set_prgname() if g_get_prgname() * returns %NULL, but g_get_prgname() on Windows never returns NULL. * So we need to do this by hand to make test_appname() work on