Merge branch 'test-trap-subprocess-envp' into 'main'

gtestutils: Add g_test_trap_subprocess_with_envp() for testing envs

See merge request GNOME/glib!3721
This commit is contained in:
Philip Withnall 2023-11-28 11:49:11 +00:00
commit 8f6f382940
5 changed files with 101 additions and 12 deletions

View File

@ -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

View File

@ -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 parents 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))

View File

@ -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);

View File

@ -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);

View File

@ -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