gtestutils: add g_test_trap_subprocess()

g_test_trap_fork() doesn't work on Windows and is potentially flaky on
unix anyway given the fork-but-don't-exec. Replace it with
g_test_trap_subprocess(), which re-spawns the same program with
arguments telling it to run a specific (otherwise-ignored) test case.

Make the existing g_test_trap_fork() unit tests be unix-only (they
never passed on Windows anyway), and add a parallel set of
g_test_trap_subprocess() tests.

Also fix the logic of gtestutils's "-p" argument (which is used by the
subprocess tests); previously if you had tests "/foo/bar" and
"/foo/bar/baz", and ran the test program with "-p /foo/bar/baz", it
would run "/foo/bar" too. Fix that and add tests.

https://bugzilla.gnome.org/show_bug.cgi?id=679683
This commit is contained in:
Dan Winship 2012-11-24 15:58:27 -05:00
parent 38859e8e29
commit 960f5500e2
5 changed files with 712 additions and 246 deletions

View File

@ -2907,6 +2907,7 @@ g_test_perf
g_test_verbose
g_test_undefined
g_test_quiet
g_test_subprocess
g_test_run
GTestFunc
g_test_add_func
@ -2934,7 +2935,7 @@ g_test_expect_message
g_test_assert_expected_messages
GTestTrapFlags
g_test_trap_fork
g_test_trap_subprocess
g_test_trap_has_passed
g_test_trap_reached_timeout
g_test_trap_assert_passed
@ -2943,6 +2944,7 @@ g_test_trap_assert_stdout
g_test_trap_assert_stdout_unmatched
g_test_trap_assert_stderr
g_test_trap_assert_stderr_unmatched
g_test_trap_fork
g_test_rand_bit
g_test_rand_int

View File

@ -1097,7 +1097,7 @@ g_assert_warning (const char *log_domain,
*
* Note that you cannot use this to test g_error() messages, since
* g_error() intentionally never returns even if the program doesn't
* abort; use g_test_trap_fork() in this case.
* abort; use g_test_trap_subprocess() in this case.
*
* Since: 2.34
*/

File diff suppressed because it is too large Load Diff

View File

@ -104,6 +104,9 @@ void g_test_init (int *argc,
#define g_test_verbose() (g_test_config_vars->test_verbose)
#define g_test_quiet() (g_test_config_vars->test_quiet)
#define g_test_undefined() (g_test_config_vars->test_undefined)
GLIB_AVAILABLE_IN_2_38
gboolean g_test_subprocess (void);
/* run all tests under toplevel suite (path: /) */
GLIB_AVAILABLE_IN_ALL
int g_test_run (void);
@ -164,7 +167,6 @@ void g_test_queue_destroy (GDestroyNotify destroy_func,
gpointer destroy_data);
#define g_test_queue_unref(gobject) g_test_queue_destroy (g_object_unref, gobject)
/* test traps are guards used around forked tests */
typedef enum {
G_TEST_TRAP_SILENCE_STDOUT = 1 << 7,
G_TEST_TRAP_SILENCE_STDERR = 1 << 8,
@ -173,6 +175,18 @@ typedef enum {
GLIB_AVAILABLE_IN_ALL
gboolean g_test_trap_fork (guint64 usec_timeout,
GTestTrapFlags test_trap_flags);
typedef enum {
G_TEST_SUBPROCESS_INHERIT_STDIN = 1 << 0,
G_TEST_SUBPROCESS_INHERIT_STDOUT = 1 << 1,
G_TEST_SUBPROCESS_INHERIT_STDERR = 1 << 2,
} GTestSubprocessFlags;
GLIB_AVAILABLE_IN_2_38
void g_test_trap_subprocess (const char *test_path,
guint64 usec_timeout,
GTestSubprocessFlags test_flags);
GLIB_AVAILABLE_IN_ALL
gboolean g_test_trap_has_passed (void);
GLIB_AVAILABLE_IN_ALL

View File

@ -118,6 +118,70 @@ test_fork_timeout (void)
g_assert (g_test_trap_reached_timeout());
}
static void
test_subprocess_fail_child (void)
{
g_assert_not_reached ();
}
static void
test_subprocess_fail (void)
{
g_test_trap_subprocess ("/trap_subprocess/fail/subprocess", 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*ERROR*test_subprocess_fail_child*should not be reached*");
}
static void
test_subprocess_no_such_test_child (void)
{
g_test_trap_subprocess ("/trap_subprocess/this-test-does-not-exist", 0, 0);
g_assert_not_reached ();
}
static void
test_subprocess_no_such_test (void)
{
g_test_trap_subprocess ("/trap_subprocess/no-such-test/subprocess", 0, 0);
g_test_trap_assert_failed ();
g_test_trap_assert_stderr ("*test does not exist*");
g_test_trap_assert_stderr_unmatched ("*should not be reached*");
}
static void
test_subprocess_patterns_child (void)
{
g_print ("some stdout text: somagic17\n");
g_printerr ("some stderr text: semagic43\n");
exit (0);
}
static void
test_subprocess_patterns (void)
{
g_test_trap_subprocess ("/trap_subprocess/patterns/subprocess", 0, 0);
g_test_trap_assert_passed ();
g_test_trap_assert_stdout ("*somagic17*");
g_test_trap_assert_stderr ("*semagic43*");
}
static void
test_subprocess_timeout_child (void)
{
/* loop and sleep forever */
while (TRUE)
g_usleep (1000 * 1000);
}
static void
test_subprocess_timeout (void)
{
/* allow child to run for only a fraction of a second */
g_test_trap_subprocess ("/trap_subprocess/timeout/subprocess", 0.11 * 1000000, 0);
g_test_trap_assert_failed ();
g_assert (g_test_trap_reached_timeout ());
}
/* run a test with fixture setup and teardown */
typedef struct {
guint seed;
@ -321,6 +385,100 @@ test_expected_messages (void)
g_test_trap_assert_stderr ("*Did not see expected message CRITICAL*nope*");
}
static void
test_dash_p_hidden (void)
{
if (!g_test_subprocess ())
g_assert_not_reached ();
g_print ("Test /misc/dash-p/subprocess/hidden ran\n");
}
static void
test_dash_p_hidden_sub (void)
{
if (!g_test_subprocess ())
g_assert_not_reached ();
g_print ("Test /misc/dash-p/subprocess/hidden/sub ran\n");
}
/* The rest of the dash_p tests will get run by the toplevel test
* process, but they shouldn't do anything there.
*/
static void
test_dash_p_child (void)
{
if (!g_test_subprocess ())
return;
g_print ("Test /misc/dash-p/child ran\n");
}
static void
test_dash_p_child_sub (void)
{
if (!g_test_subprocess ())
return;
g_print ("Test /misc/dash-p/child/sub ran\n");
}
static void
test_dash_p_child_sub2 (void)
{
if (!g_test_subprocess ())
return;
g_print ("Test /misc/dash-p/child/sub2 ran\n");
}
static void
test_dash_p_child_sub_child (void)
{
if (!g_test_subprocess ())
return;
g_print ("Test /misc/dash-p/child/subprocess ran\n");
}
static void
test_dash_p (void)
{
g_test_trap_subprocess ("/misc/dash-p/subprocess/hidden", 0, 0);
g_test_trap_assert_passed ();
g_test_trap_assert_stdout ("*Test /misc/dash-p/subprocess/hidden ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden/sub ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden/sub2 ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden/sub/subprocess ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/child*");
g_test_trap_subprocess ("/misc/dash-p/subprocess/hidden/sub", 0, 0);
g_test_trap_assert_passed ();
g_test_trap_assert_stdout ("*Test /misc/dash-p/subprocess/hidden/sub ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden/sub2 ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden/subprocess ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/child*");
g_test_trap_subprocess ("/misc/dash-p/child", 0, 0);
g_test_trap_assert_passed ();
g_test_trap_assert_stdout ("*Test /misc/dash-p/child ran*");
g_test_trap_assert_stdout ("*Test /misc/dash-p/child/sub ran*");
g_test_trap_assert_stdout ("*Test /misc/dash-p/child/sub2 ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/child/subprocess ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden*");
g_test_trap_subprocess ("/misc/dash-p/child/sub", 0, 0);
g_test_trap_assert_passed ();
g_test_trap_assert_stdout ("*Test /misc/dash-p/child/sub ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/child ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/child/sub2 ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/child/subprocess ran*");
g_test_trap_assert_stdout_unmatched ("*Test /misc/dash-p/subprocess/hidden*");
}
int
main (int argc,
char *argv[])
@ -335,12 +493,37 @@ main (int argc,
g_test_add ("/misc/primetoul", Fixturetest, (void*) 0xc0cac01a, fixturetest_setup, fixturetest_test, fixturetest_teardown);
if (g_test_perf())
g_test_add_func ("/misc/timer", test_timer);
#ifdef G_OS_UNIX
g_test_add_func ("/forking/fail assertion", test_fork_fail);
g_test_add_func ("/forking/patterns", test_fork_patterns);
if (g_test_slow())
g_test_add_func ("/forking/timeout", test_fork_timeout);
#endif
g_test_add_func ("/trap_subprocess/fail", test_subprocess_fail);
g_test_add_func ("/trap_subprocess/fail/subprocess", test_subprocess_fail_child);
g_test_add_func ("/trap_subprocess/no-such-test", test_subprocess_no_such_test);
g_test_add_func ("/trap_subprocess/no-such-test/subprocess", test_subprocess_no_such_test_child);
if (g_test_slow ())
{
g_test_add_func ("/trap_subprocess/timeout", test_subprocess_timeout);
g_test_add_func ("/trap_subprocess/timeout/subprocess", test_subprocess_timeout_child);
}
g_test_add_func ("/trap_subprocess/patterns", test_subprocess_patterns);
g_test_add_func ("/trap_subprocess/patterns/subprocess", test_subprocess_patterns_child);
g_test_add_func ("/misc/fatal-log-handler", test_fatal_log_handler);
g_test_add_func ("/misc/expected-messages", test_expected_messages);
g_test_add_func ("/misc/dash-p", test_dash_p);
g_test_add_func ("/misc/dash-p/child", test_dash_p_child);
g_test_add_func ("/misc/dash-p/child/sub", test_dash_p_child_sub);
g_test_add_func ("/misc/dash-p/child/sub/subprocess", test_dash_p_child_sub_child);
g_test_add_func ("/misc/dash-p/child/sub/subprocess/child", test_dash_p_child_sub_child);
g_test_add_func ("/misc/dash-p/child/sub2", test_dash_p_child_sub2);
g_test_add_func ("/misc/dash-p/subprocess/hidden", test_dash_p_hidden);
g_test_add_func ("/misc/dash-p/subprocess/hidden/sub", test_dash_p_hidden_sub);
return g_test_run();
}