From 58031feb17659a8d24ff4e2eeebe70f10fcce5da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 15 Dec 2022 21:40:35 +0100 Subject: [PATCH 01/29] meson: Use 'tap' test protocol by default Meson supports tap protocol results parsing, allowing us to track better the tests that are running (and the ones that are actually skipped) without manually parsing the test output. However this also implies that using the verbose mode for a test doesn't show its output by default (unless there are failures). --- gio/tests/meson.build | 2 ++ glib/tests/meson.build | 2 ++ gmodule/tests/meson.build | 1 + gobject/tests/meson.build | 9 ++++++++- gthread/tests/meson.build | 8 +++++++- meson.build | 4 ++++ 6 files changed, 24 insertions(+), 2 deletions(-) diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 13a1775ce..16478f69b 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -1035,6 +1035,7 @@ foreach test_name, extra_args : gio_tests endif test(test_name, exe, + protocol : extra_args.get('protocol', test_protocol), env : local_test_env, timeout : timeout, suite : suite, @@ -1059,6 +1060,7 @@ foreach test_name, extra_args : python_tests test( test_name, python, + protocol : extra_args.get('protocol', test_protocol), depends: depends, args: ['-B', files(test_name)], env: test_env, diff --git a/glib/tests/meson.build b/glib/tests/meson.build index e1b12e368..16ba33492 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -398,6 +398,7 @@ foreach test_name, extra_args : glib_tests endforeach test(test_name, exe, + protocol : extra_args.get('protocol', test_protocol), depends : depends, env : test_env, timeout : timeout, @@ -444,6 +445,7 @@ foreach test_name, extra_args : python_tests test( test_name, python, + protocol : extra_args.get('protocol', test_protocol), depends: depends, args: ['-B', files(test_name)], env: test_env, diff --git a/gmodule/tests/meson.build b/gmodule/tests/meson.build index a78887529..513ea4213 100644 --- a/gmodule/tests/meson.build +++ b/gmodule/tests/meson.build @@ -115,6 +115,7 @@ foreach test_name, extra_args : gmodule_tests test(test_name, exe, + protocol : extra_args.get('protocol', test_protocol), depends : depends, env : test_env, timeout : timeout, diff --git a/gobject/tests/meson.build b/gobject/tests/meson.build index a880dfb33..96a7b40d3 100644 --- a/gobject/tests/meson.build +++ b/gobject/tests/meson.build @@ -186,7 +186,13 @@ foreach test_name, extra_args : gobject_tests timeout = timeout * 10 endif - test(test_name, exe, env : test_env, timeout : timeout, suite : suite) + test(test_name, + exe, + protocol : extra_args.get('protocol', test_protocol), + env : test_env, + timeout : timeout, + suite : suite, + ) endforeach foreach test_name, extra_args : python_tests @@ -200,6 +206,7 @@ foreach test_name, extra_args : python_tests test( test_name, python, + protocol : extra_args.get('protocol', test_protocol), depends: depends, args: ['-B', files(test_name)], env: test_env, diff --git a/gthread/tests/meson.build b/gthread/tests/meson.build index 86da67413..53fb78e18 100644 --- a/gthread/tests/meson.build +++ b/gthread/tests/meson.build @@ -44,5 +44,11 @@ foreach test_name, extra_args : gthread_tests suite += 'failing' endif - test(test_name, exe, env : test_env, timeout : timeout, suite : suite) + test(test_name, + exe, + protocol : extra_args.get('protocol', test_protocol), + env : test_env, + timeout : timeout, + suite : suite, + ) endforeach diff --git a/meson.build b/meson.build index 8d3500ad7..74173e060 100644 --- a/meson.build +++ b/meson.build @@ -151,6 +151,10 @@ common_test_env = [ 'MALLOC_CHECK_=2', ] +# Note: this may cause the tests output not to be printed when running in +# verbose mode, see https://github.com/mesonbuild/meson/issues/11185 +# Can be changed it to 'exitcode' if required during development. +test_protocol = 'tap' test_timeout = 30 test_timeout_slow = 90 From 1594cf77eb60c92bf3b4e34c9398cc059b62756b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 15 Dec 2022 22:09:17 +0100 Subject: [PATCH 02/29] meson: Use exitcode protocol for some c++ and gobject definition tests In all these cases we don't really care about running the test file, while building and basic execution it is relevant. Also they don't support TAP at all. --- gio/tests/meson.build | 2 ++ gmodule/tests/meson.build | 2 ++ gobject/tests/meson.build | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 16478f69b..e0bcc7c72 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -144,6 +144,7 @@ gio_tests = { if have_cxx gio_tests += { 'cxx' : { + 'protocol': 'exitcode', 'source' : ['cxx.cpp'], 'suite': ['C++'], }, @@ -152,6 +153,7 @@ if have_cxx foreach std, arg: cxx_standards gio_tests += { 'cxx-@0@'.format(std) : { + 'protocol': 'exitcode', 'source' : ['cxx.cpp'], 'suite' : ['cpp'], 'cpp_args' : [arg], diff --git a/gmodule/tests/meson.build b/gmodule/tests/meson.build index 513ea4213..ec7eb68fd 100644 --- a/gmodule/tests/meson.build +++ b/gmodule/tests/meson.build @@ -5,6 +5,7 @@ gmodule_tests = { if have_cxx gmodule_tests += { 'cxx' : { + 'protocol': 'exitcode', 'source' : ['cxx.cpp'], 'suite' : ['cpp'], } @@ -13,6 +14,7 @@ if have_cxx foreach std, arg: cxx_standards gmodule_tests += { 'cxx-@0@'.format(std) : { + 'protocol': 'exitcode', 'source' : ['cxx.cpp'], 'suite' : ['cpp'], 'cpp_args' : [arg], diff --git a/gobject/tests/meson.build b/gobject/tests/meson.build index 96a7b40d3..9e807463b 100644 --- a/gobject/tests/meson.build +++ b/gobject/tests/meson.build @@ -41,7 +41,7 @@ gobject_tests = { 'defaultiface' : { 'source' : ['defaultiface.c', 'testmodule.c'], }, - 'deftype' : {}, + 'deftype' : { 'protocol': 'exitcode' }, 'deprecated-properties' : {}, 'dynamictype' : { 'source' : ['dynamictype.c', 'testmodule.c'], @@ -109,6 +109,7 @@ gobject_tests = { if have_cxx gobject_tests += { 'cxx' : { + 'protocol': 'exitcode', 'source' : ['cxx.cpp'], 'suite' : ['cpp'], }, @@ -117,6 +118,7 @@ if have_cxx foreach std, arg: cxx_standards gobject_tests += { 'cxx-@0@'.format(std) : { + 'protocol': 'exitcode', 'source' : ['cxx.cpp'], 'suite' : ['cpp'], 'cpp_args' : [arg], From 6efbc7c6246e2b075488d2395fa519ad5ae7b1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 15 Dec 2022 22:42:40 +0100 Subject: [PATCH 03/29] meson: Add 'core' suite to glib (only) tests As per meson default, the project name is a suite per se that is always added to a test, so running `meson test --suite=glib` is the same as not passing the `--suite` argument at all, and so making all the tests to run. To be able to only run the *glib* tests without using the `--no-suite` args, add a `core` suite that only targets the glib folder tests. --- glib/tests/meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/glib/tests/meson.build b/glib/tests/meson.build index 16ba33492..49c44be27 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -386,7 +386,7 @@ foreach test_name, extra_args : glib_tests ) depends = [extra_args.get('depends', [])] - suite = ['glib'] + extra_args.get('suite', []) + suite = ['glib', 'core'] + extra_args.get('suite', []) timeout = suite.contains('slow') ? test_timeout_slow : test_timeout if extra_args.get('can_fail', false) @@ -432,7 +432,7 @@ endif foreach test_name, extra_args : python_tests depends = [extra_args.get('depends', [])] - suite = ['glib', 'no-valgrind'] + suite = ['glib', 'core', 'no-valgrind'] if extra_args.get('can_fail', false) suite += 'failing' @@ -488,7 +488,7 @@ if not meson.is_cross_build() and host_system != 'windows' test('gtester-xmllint-check', xmllint, args : ['--noout', tmpsample_xml], env : test_env, - suite : ['glib'], + suite : ['glib', 'core'], ) endif endif From d4088e7f2a0f0d30050d3714516844136425c38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 16 Dec 2022 19:21:27 +0100 Subject: [PATCH 04/29] gio: Use 'cpp' suite for C++ tests That's what we use for all the tests, so be consistent. --- gio/tests/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gio/tests/meson.build b/gio/tests/meson.build index e0bcc7c72..de5b80d72 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -146,7 +146,7 @@ if have_cxx 'cxx' : { 'protocol': 'exitcode', 'source' : ['cxx.cpp'], - 'suite': ['C++'], + 'suite': ['cpp'], }, } From 254c71e7c6644304403d9b55f18a2e21fc7e7f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 16 Dec 2022 21:32:32 +0100 Subject: [PATCH 05/29] gtestutils: Set the TAP version 13 as first line of tests output This is not required, but meson may warn about in future versions, so it's safer to define it. However, we must be sure that we only expose it once and in the root binary if a test file launches another subprocess test file. To avoid this, we set an environment variable at test init, so that it can be inherited by children. It's not the best solution, but for sure the best-effort one without having to change gtest arguments and called binaries. Non mentioning a version was considered as assuming we were using TAP version 12, while no version earlier than 13 can be specified explicitly so let's use it. See: https://testanything.org/tap-specification.html And: https://testanything.org/tap-version-13-specification.html --- glib/gtestutils.c | 23 ++++++++++++++-- glib/tests/testing.c | 64 +++++++++++++++++++++++++++++++------------- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 22b48d9ef..7009e8e59 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -901,6 +901,7 @@ static const char *test_built_files_dir; /* points into test_argv0_dirnam static char *test_initial_cwd = NULL; static gboolean test_in_forked_child = FALSE; static gboolean test_in_subprocess = FALSE; +static gboolean test_is_subtest = FALSE; static GTestConfig mutable_test_config_vars = { FALSE, /* test_initialized */ TRUE, /* test_quick */ @@ -994,9 +995,16 @@ g_test_log (GTestLogType lbit, { case G_TEST_LOG_START_BINARY: if (test_tap_log) - g_print ("# random seed: %s\n", string2); + { + if (!test_in_forked_child && !test_is_subtest) + g_print ("TAP version 13\n"); + + g_print ("# random seed: %s\n", string2); + } else if (g_test_verbose ()) - g_print ("GTest: random seed: %s\n", string2); + { + g_print ("GTest: random seed: %s\n", string2); + } break; case G_TEST_LOG_START_SUITE: if (test_tap_log) @@ -1644,6 +1652,17 @@ void if (!g_get_prgname() && !no_g_set_prgname) g_set_prgname ((*argv)[0]); + if (g_getenv ("G_TEST_ROOT_PROCESS")) + { + test_is_subtest = TRUE; + } + else if (!g_setenv ("G_TEST_ROOT_PROCESS", test_argv0 ? test_argv0 : "root", TRUE)) + { + g_printerr ("%s: Failed to set environment variable ‘%s’\n", + test_argv0, "G_TEST_ROOT_PROCESS"); + exit (1); + } + /* Set up the temporary directory for isolating the test. We have to do this * early, as we want the return values from g_get_user_data_dir() (and * friends) to return subdirectories of the temporary directory throughout diff --git a/glib/tests/testing.c b/glib/tests/testing.c index 24e8d08e4..d9e8522b2 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -35,6 +35,8 @@ #include #include +#define TAP_VERSION G_STRINGIFY (13) + /* test assertion variants */ static void test_assertions_bad_cmpvariant_types (void) @@ -1089,6 +1091,7 @@ test_tap (void) GError *error = NULL; int status; gchar *output; + char **envp; testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); @@ -1099,7 +1102,12 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + /* Remove the G_TEST_ROOT_PROCESS env so it will be considered a standalone test */ + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "G_TEST_ROOT_PROCESS"); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1107,6 +1115,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nok 1 /pass\n")); g_free (output); g_ptr_array_unref (argv); @@ -1118,7 +1127,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1126,6 +1135,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nok 1 /skip # SKIP not enough tea\n")); g_free (output); g_ptr_array_unref (argv); @@ -1137,7 +1147,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1145,6 +1155,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nok 1 /skip-printf # SKIP not enough coffee\n")); g_free (output); g_ptr_array_unref (argv); @@ -1156,7 +1167,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1164,6 +1175,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nnot ok 1 /incomplete # TODO mind reading not implemented yet\n")); g_free (output); g_ptr_array_unref (argv); @@ -1175,7 +1187,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1183,6 +1195,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nnot ok 1 /incomplete-printf # TODO telekinesis not implemented yet\n")); g_free (output); g_ptr_array_unref (argv); @@ -1194,7 +1207,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1202,6 +1215,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nnot ok 1 /fail\n")); g_free (output); g_clear_error (&error); @@ -1214,7 +1228,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1222,6 +1236,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nnot ok 1 /fail-printf - this test intentionally left failing\n")); g_free (output); g_clear_error (&error); @@ -1234,7 +1249,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &status, &error); @@ -1252,7 +1267,7 @@ test_tap (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, NULL, NULL, &status, &error); @@ -1272,11 +1287,12 @@ test_tap (void) g_ptr_array_add (argv, "2"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP\n")); g_assert_nonnull (strstr (output, "\nok 2 /b # SKIP\n")); @@ -1304,11 +1320,12 @@ test_tap (void) g_ptr_array_add (argv, "0"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a\n")); g_assert_nonnull (strstr (output, "\nok 2 /b\n")); @@ -1336,11 +1353,12 @@ test_tap (void) g_ptr_array_add (argv, "11"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP\n")); g_assert_nonnull (strstr (output, "\nok 2 /b # SKIP\n")); @@ -1372,11 +1390,12 @@ test_tap (void) g_ptr_array_add (argv, "/b"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nok 1 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 2 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 3 /b\n")); @@ -1403,11 +1422,12 @@ test_tap (void) g_ptr_array_add (argv, "/b"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nok 1 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 2 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 3 /b\n")); @@ -1433,11 +1453,12 @@ test_tap (void) g_ptr_array_add (argv, "/b/b"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "\nok 1 /b/b\n")); g_assert_nonnull (strstr (output, "\nok 2 /b/b/a\n")); g_assert_nonnull (strstr (output, "\n1..2\n")); @@ -1461,13 +1482,14 @@ test_tap (void) g_ptr_array_add (argv, "/b"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); g_spawn_check_wait_status (status, &error); g_assert_nonnull (error); + g_assert_false (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "do not mix [-r | --run-prefix] with '-p'\n")); g_clear_error (&error); @@ -1489,11 +1511,12 @@ test_tap (void) g_ptr_array_add (argv, "/c/a"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP by request")); g_assert_nonnull (strstr (output, "\nok 2 /b # SKIP by request")); @@ -1527,11 +1550,12 @@ test_tap (void) g_ptr_array_add (argv, "/c/a"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); + g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP by request")); g_assert_nonnull (strstr (output, "\nok 2 /b\n")); @@ -1564,18 +1588,20 @@ test_tap (void) g_ptr_array_add (argv, "/c/a"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); g_assert_no_error (error); g_spawn_check_wait_status (status, &error); g_assert_nonnull (error); + g_assert_false (g_str_has_prefix (output, "TAP version " TAP_VERSION)); g_assert_nonnull (strstr (output, "do not mix [-x | --skip-prefix] with '-s'\n")); g_clear_error (&error); g_free (output); g_ptr_array_unref (argv); + g_strfreev (envp); } static void From 5c799ff01d87f5553b2ceed154fcb54e83e9b22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 18:33:38 +0100 Subject: [PATCH 06/29] gtestutils: Write tap test results atomically When running multiple tests in parallel using meson, the output could be mixed and if we write the TAP reports in multiple steps the output could be mangled together with other results. An example is: https://gitlab.gnome.org/3v1n0/glib/-/jobs/2507620 Where we have: ok 5 /cancellable/poll-fd# GLib-GIO-DEBUG: Collecting capable appnames: 0ms # Allocating hashtables:...... 0ms # Reading capable apps: 63ms # Reading URL associations:... 0ms # Reading extension assocs: 78ms # Reading exe-only apps:...... 47ms # Reading classes: 312ms # Reading UWP apps: 47ms # Postprocessing:..............16ms # TOTAL: 563ms # SKIP Platform not supported Leading to a clear TAP parsing error --- glib/gtestutils.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 7009e8e59..ed1f087d3 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1034,7 +1034,7 @@ g_test_log (GTestLogType lbit, fail = result == G_TEST_RUN_FAILURE; if (test_tap_log) { - const gchar *ok; + GString *tap_output; /* The TAP representation for an expected failure starts with * "not ok", even though it does not actually count as failing @@ -1043,19 +1043,20 @@ g_test_log (GTestLogType lbit, * for which GTestResult does not currently have a * representation. */ if (fail || result == G_TEST_RUN_INCOMPLETE) - ok = "not ok"; + tap_output = g_string_new ("not ok"); else - ok = "ok"; + tap_output = g_string_new ("ok"); - g_print ("%s %d %s", ok, test_run_count, string1); + g_string_append_printf (tap_output, " %d %s", test_run_count, string1); if (result == G_TEST_RUN_INCOMPLETE) - g_print (" # TODO %s\n", string2 ? string2 : ""); + g_string_append_printf (tap_output, " # TODO %s", string2 ? string2 : ""); else if (result == G_TEST_RUN_SKIPPED) - g_print (" # SKIP %s\n", string2 ? string2 : ""); + g_string_append_printf (tap_output, " # SKIP %s", string2 ? string2 : ""); else if (result == G_TEST_RUN_FAILURE && string2 != NULL) - g_print (" - %s\n", string2); - else - g_print ("\n"); + g_string_append_printf (tap_output, " - %s", string2); + + g_print ("%s\n", tap_output->str); + g_string_free (tap_output, TRUE); } else if (g_test_verbose ()) g_print ("GTest: result: %s\n", g_test_result_names[result]); From a943d42104d1c2d6d388adb1f8335f803727c2e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 18:51:47 +0100 Subject: [PATCH 07/29] gtestutils: Use TAP format for all the verbose output In some cases if verbose output was enabled we were using wrong output format in TAP mode, so let's fix these cases and run the 'testing' test case in --verbose mode to ensure we won't regress. --- glib/gtestutils.c | 14 ++++++++++++-- glib/tests/meson.build | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index ed1f087d3..b3d83b665 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -3023,7 +3023,12 @@ test_should_run (const char *test_path, return TRUE; if (g_test_verbose ()) - g_print ("GTest: skipping: %s\n", test_run_name); + { + if (test_tap_log) + g_print ("# skipping: %s\n", test_run_name); + else + g_print ("GTest: skipping: %s\n", test_run_name); + } return FALSE; } @@ -3867,7 +3872,12 @@ g_test_trap_subprocess (const char *test_path, } if (g_test_verbose ()) - g_print ("GTest: subprocess: %s\n", test_path); + { + if (test_tap_log) + g_print ("# subprocess: %s\n", test_path); + else + g_print ("GTest: subprocess: %s\n", test_path); + } test_trap_clear (); test_trap_last_subprocess = g_strdup (test_path); diff --git a/glib/tests/meson.build b/glib/tests/meson.build index 49c44be27..cb019b6f7 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -140,6 +140,7 @@ glib_tests = { 'string' : {}, 'strvbuilder' : {}, 'testing' : { + 'args': [ '--verbose' ], 'extra_programs' : ['testing-helper'], }, 'test-printf' : {}, @@ -398,6 +399,7 @@ foreach test_name, extra_args : glib_tests endforeach test(test_name, exe, + args: extra_args.get('args', []), protocol : extra_args.get('protocol', test_protocol), depends : depends, env : test_env, From f68c49102e1d78c0497f09453b2b189d2f57b736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 19:07:15 +0100 Subject: [PATCH 08/29] gtestutils: Write log to stderr atomically We used to send the test log to stderr in pieces, but this could be problematic when running multiple tests in parallel, so let's just prepare the string in pieces and write it all at once. --- glib/gtestutils.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index b3d83b665..40d420c3a 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -950,6 +950,7 @@ g_test_log_send (guint n_bytes, { GTestLogBuffer *lbuffer = g_test_log_buffer_new (); GTestLogMsg *msg; + GString *output; guint ui; g_test_log_buffer_push (lbuffer, n_bytes, buffer); msg = g_test_log_buffer_pop (lbuffer); @@ -957,22 +958,25 @@ g_test_log_send (guint n_bytes, g_warn_if_fail (lbuffer->data->len == 0); g_test_log_buffer_free (lbuffer); /* print message */ - g_printerr ("{*LOG(%s)", g_test_log_type_name (msg->log_type)); + output = g_string_new (NULL); + g_string_printf (output, "{*LOG(%s)", g_test_log_type_name (msg->log_type)); for (ui = 0; ui < msg->n_strings; ui++) - g_printerr (":{%s}", msg->strings[ui]); + g_string_append_printf (output, ":{%s}", msg->strings[ui]); if (msg->n_nums) { - g_printerr (":("); + g_string_append (output, ":("); for (ui = 0; ui < msg->n_nums; ui++) { if ((long double) (long) msg->nums[ui] == msg->nums[ui]) - g_printerr ("%s%ld", ui ? ";" : "", (long) msg->nums[ui]); + g_string_append_printf (output, "%s%ld", ui ? ";" : "", (long) msg->nums[ui]); else - g_printerr ("%s%.16g", ui ? ";" : "", (double) msg->nums[ui]); + g_string_append_printf (output, "%s%.16g", ui ? ";" : "", (double) msg->nums[ui]); } - g_printerr (")"); + g_string_append_c (output, ')'); } - g_printerr (":LOG*}\n"); + g_string_append (output, ":LOG*}"); + g_printerr ("%s\n", output->str); + g_string_free (output, TRUE); g_test_log_msg_free (msg); } } From 78a206f467dc3387a3116df587a1084a9d052bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 23:16:59 +0100 Subject: [PATCH 09/29] tests/testing, testing-helper: Add test to check g_test_message on TAP Ensure that g_test_message() output is conformant to TAP specifications. --- glib/tests/testing-helper.c | 12 ++++++++ glib/tests/testing.c | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index 3d435e588..647aabf4e 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -79,6 +79,14 @@ test_summary (void) "it in the TAP output later."); } +static void +test_message (void) +{ + g_test_message ("Tests that single line message works"); + g_test_message ("Tests that multi\nline\nmessage\nworks"); + g_test_message ("Tests that multi\nline\nmessage\nworks with trailing too\n"); +} + int main (int argc, char *argv[]) @@ -185,6 +193,10 @@ main (int argc, { g_test_add_func ("/summary", test_summary); } + else if (g_strcmp0 (argv1, "message") == 0) + { + g_test_add_func ("/message", test_message); + } else { g_assert_not_reached (); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index d9e8522b2..28f92cec1 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -1641,6 +1641,60 @@ test_tap_summary (void) g_ptr_array_unref (argv); } +static void +test_tap_message (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **output_lines; + + g_test_summary ("Test the output of g_test_message() from the TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "message"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + const char *expected_tap_header = "\n1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + output_lines = g_strsplit (interesting_lines, "\n", -1); + g_assert_cmpuint (g_strv_length (output_lines), >=, 10); + + guint i = 0; + g_assert_cmpstr (output_lines[i++], ==, "# Tests that single line message works"); + g_assert_cmpstr (output_lines[i++], ==, "# Tests that multi"); + g_assert_cmpstr (output_lines[i++], ==, "# line"); + g_assert_cmpstr (output_lines[i++], ==, "# message"); + g_assert_cmpstr (output_lines[i++], ==, "# works"); + g_assert_cmpstr (output_lines[i++], ==, "# Tests that multi"); + g_assert_cmpstr (output_lines[i++], ==, "# line"); + g_assert_cmpstr (output_lines[i++], ==, "# message"); + g_assert_cmpstr (output_lines[i++], ==, "# works with trailing too"); + g_assert_cmpstr (output_lines[i++], ==, "# "); + + g_free (output); + g_strfreev (output_lines); + g_ptr_array_unref (argv); +} + static void test_init_no_argv0 (void) { @@ -1771,6 +1825,7 @@ main (int argc, g_test_add_func ("/tap", test_tap); g_test_add_func ("/tap/summary", test_tap_summary); + g_test_add_func ("/tap/message", test_tap_message); g_test_add_func ("/init/no_argv0", test_init_no_argv0); From 250f3f06440f3527030d07cbbd66c2f5265acd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 23:20:08 +0100 Subject: [PATCH 10/29] gtestutils: Write g_test_message() output in a single operation Do not write it in multiple lines, to ensure it's going to be written all together, and nothing else could be written in the middle. Also optimize a bit the code. --- glib/gtestutils.c | 29 +++++++++++++++++++++++------ glib/tests/testing-helper.c | 4 ++-- glib/tests/testing.c | 6 ++++-- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 40d420c3a..84d4bca93 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1094,17 +1094,34 @@ g_test_log (GTestLogType lbit, case G_TEST_LOG_MESSAGE: if (test_tap_log) { - if (strstr (string1, "\n") == NULL) + if (strchr (string1, '\n') == NULL) g_print ("# %s\n", string1); else { - char **lines = g_strsplit (string1, "\n", -1); - gsize i; + GString *output = g_string_new (NULL); + const char *line = string1; - for (i = 0; lines[i] != NULL; i++) - g_print ("# %s\n", lines[i]); + do + { + const char *next = strchr (line, '\n'); + g_string_append (output, "# "); - g_strfreev (lines); + if (next) + { + g_string_append_len (output, line, next - line + 1); + line = next + 1; + } + else + { + g_string_append (output, line); + g_string_append_c (output, '\n'); + line = next; + } + } + while (line != NULL); + + g_print ("%s", output->str); + g_string_free (g_steal_pointer (&output), TRUE); } } else if (g_test_verbose ()) diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index 647aabf4e..4479bc7be 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -83,8 +83,8 @@ static void test_message (void) { g_test_message ("Tests that single line message works"); - g_test_message ("Tests that multi\nline\nmessage\nworks"); - g_test_message ("Tests that multi\nline\nmessage\nworks with trailing too\n"); + g_test_message ("Tests that multi\n\nline\nmessage\nworks"); + g_test_message ("\nTests that multi\nline\nmessage\nworks with leading and trailing too\n"); } int diff --git a/glib/tests/testing.c b/glib/tests/testing.c index 28f92cec1..c97f9db62 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -1676,18 +1676,20 @@ test_tap_message (void) interesting_lines += strlen (expected_tap_header); output_lines = g_strsplit (interesting_lines, "\n", -1); - g_assert_cmpuint (g_strv_length (output_lines), >=, 10); + g_assert_cmpuint (g_strv_length (output_lines), >=, 12); guint i = 0; g_assert_cmpstr (output_lines[i++], ==, "# Tests that single line message works"); g_assert_cmpstr (output_lines[i++], ==, "# Tests that multi"); + g_assert_cmpstr (output_lines[i++], ==, "# "); g_assert_cmpstr (output_lines[i++], ==, "# line"); g_assert_cmpstr (output_lines[i++], ==, "# message"); g_assert_cmpstr (output_lines[i++], ==, "# works"); + g_assert_cmpstr (output_lines[i++], ==, "# "); g_assert_cmpstr (output_lines[i++], ==, "# Tests that multi"); g_assert_cmpstr (output_lines[i++], ==, "# line"); g_assert_cmpstr (output_lines[i++], ==, "# message"); - g_assert_cmpstr (output_lines[i++], ==, "# works with trailing too"); + g_assert_cmpstr (output_lines[i++], ==, "# works with leading and trailing too"); g_assert_cmpstr (output_lines[i++], ==, "# "); g_free (output); From 28299eb4675e322f3299b59b6fe05986a4dc931d Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 16 Dec 2022 18:07:20 -0500 Subject: [PATCH 11/29] gtestutils: "Bail out!" TAP message cannot be multiline Extra lines must be prepended with `#` which g_test_message() does for us. Note that lines after "Bail out" are ignored, so we print stdout/stderr before. --- glib/gtestutils.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 84d4bca93..e2b2d4257 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -4122,8 +4122,10 @@ g_test_trap_assertions (const char *domain, logged_child_output = logged_child_output || log_child_output (process_id); - msg = g_strdup_printf ("stdout of child process (%s) %s: %s\nstdout was:\n%s", - process_id, match_error, stdout_pattern, test_trap_last_stdout); + g_test_message ("stdout was:\n%s", test_trap_last_stdout); + + msg = g_strdup_printf ("stdout of child process (%s) %s: %s", + process_id, match_error, stdout_pattern); g_assertion_message (domain, file, line, func, msg); g_free (msg); } @@ -4133,8 +4135,10 @@ g_test_trap_assertions (const char *domain, logged_child_output = logged_child_output || log_child_output (process_id); - msg = g_strdup_printf ("stderr of child process (%s) %s: %s\nstderr was:\n%s", - process_id, match_error, stderr_pattern, test_trap_last_stderr); + g_test_message ("stderr was:\n%s", test_trap_last_stderr); + + msg = g_strdup_printf ("stderr of child process (%s) %s: %s", + process_id, match_error, stderr_pattern); g_assertion_message (domain, file, line, func, msg); g_free (msg); } From 07ff0f7460ae4089ad8e5ff05685a8ca5ae153b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 17 Dec 2022 04:36:07 +0100 Subject: [PATCH 12/29] gtestutils: Print commented TAP output if running a subprocess If a gtest process is run as a child of another process, we should not print the TAP output in plain mode or we'll break the parent results. We can instead just comment their output so that it gets ignored by TAP parsers. --- glib/gtestutils.c | 20 +++++++++++++------- glib/tests/testing.c | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index e2b2d4257..b640d9293 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1000,7 +1000,7 @@ g_test_log (GTestLogType lbit, case G_TEST_LOG_START_BINARY: if (test_tap_log) { - if (!test_in_forked_child && !test_is_subtest) + if (!test_is_subtest && !test_in_subprocess && !test_in_forked_child) g_print ("TAP version 13\n"); g_print ("# random seed: %s\n", string2); @@ -1018,7 +1018,7 @@ g_test_log (GTestLogType lbit, if (string1[0] != 0) g_print ("# Start of %s tests\n", string1); else if (test_paths == NULL) - g_print ("1..%d\n", test_count); + g_print ("%s1..%d\n", test_is_subtest ? "# " : "", test_count); } break; case G_TEST_LOG_STOP_SUITE: @@ -1030,7 +1030,7 @@ g_test_log (GTestLogType lbit, if (string1[0] != 0) g_print ("# End of %s tests\n", string1); else if (test_paths != NULL) - g_print ("1..%d\n", test_run_count); + g_print ("%s1..%d\n", test_is_subtest ? "# " : "", test_run_count); } break; case G_TEST_LOG_STOP_CASE: @@ -1051,6 +1051,9 @@ g_test_log (GTestLogType lbit, else tap_output = g_string_new ("ok"); + if (test_is_subtest) + g_string_prepend (tap_output, "# "); + g_string_append_printf (tap_output, " %d %s", test_run_count, string1); if (result == G_TEST_RUN_INCOMPLETE) g_string_append_printf (tap_output, " # TODO %s", string2 ? string2 : ""); @@ -1060,7 +1063,7 @@ g_test_log (GTestLogType lbit, g_string_append_printf (tap_output, " - %s", string2); g_print ("%s\n", tap_output->str); - g_string_free (tap_output, TRUE); + g_string_free (g_steal_pointer (&tap_output), TRUE); } else if (g_test_verbose ()) g_print ("GTest: result: %s\n", g_test_result_names[result]); @@ -1069,7 +1072,7 @@ g_test_log (GTestLogType lbit, if (fail && test_mode_fatal) { if (test_tap_log) - g_print ("Bail out!\n"); + g_print ("%sBail out!\n", test_is_subtest ? "# " : ""); g_abort (); } if (result == G_TEST_RUN_SKIPPED || result == G_TEST_RUN_INCOMPLETE) @@ -1077,7 +1080,10 @@ g_test_log (GTestLogType lbit, break; case G_TEST_LOG_SKIP_CASE: if (test_tap_log) - g_print ("ok %d %s # SKIP\n", test_run_count, string1); + { + g_print ("%sok %d %s # SKIP\n", test_is_subtest ? "# " : "", + test_run_count, string1); + } break; case G_TEST_LOG_MIN_RESULT: if (test_tap_log) @@ -1129,7 +1135,7 @@ g_test_log (GTestLogType lbit, break; case G_TEST_LOG_ERROR: if (test_tap_log) - g_print ("Bail out! %s\n", string1); + g_print ("%sBail out! %s\n", test_is_subtest ? "# " : "", string1); else if (g_test_verbose ()) g_print ("(ERROR: %s)\n", string1); break; diff --git a/glib/tests/testing.c b/glib/tests/testing.c index c97f9db62..d46100296 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -1670,7 +1670,7 @@ test_tap_message (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); - const char *expected_tap_header = "\n1..1\n"; + const char *expected_tap_header = "\n# 1..1\n"; const char *interesting_lines = strstr (output, expected_tap_header); g_assert_nonnull (interesting_lines); interesting_lines += strlen (expected_tap_header); From a3f26bd50974d127022150c166bcce3fecb17219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 16 Jan 2023 20:23:22 +0100 Subject: [PATCH 13/29] testing: Add TAP test for Bail out! messages --- glib/tests/testing-helper.c | 15 +++++++ glib/tests/testing.c | 84 +++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index 4479bc7be..c4cbe0058 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -51,6 +51,12 @@ test_fail (void) g_test_fail (); } +static void +test_error (void) +{ + g_error ("This should error out\nBecause it's just wrong!"); +} + static void test_fail_printf (void) { @@ -157,6 +163,15 @@ main (int argc, { g_test_add_func ("/fail", test_fail); } + else if (g_strcmp0 (argv1, "error") == 0) + { + g_test_add_func ("/error", test_error); + } + else if (g_strcmp0 (argv1, "error-and-pass") == 0) + { + g_test_add_func ("/error", test_error); + g_test_add_func ("/pass", test_pass); + } else if (g_strcmp0 (argv1, "fail-printf") == 0) { g_test_add_func ("/fail-printf", test_fail_printf); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index d46100296..5854c3cf5 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -1697,6 +1697,88 @@ test_tap_message (void) g_ptr_array_unref (argv); } +static void +test_tap_error (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + + g_test_summary ("Test that g_error() generates Bail out TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "error"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_nonnull (error); + + const char *expected_tap_header = "\n# 1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out\n" + "Because it's just wrong!\n"); + + g_free (output); + g_ptr_array_unref (argv); + g_clear_error (&error); +} + +static void +test_tap_error_and_pass (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + + g_test_summary ("Test that g_error() generates Bail out TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "error-and-pass"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_nonnull (error); + + const char *expected_tap_header = "\n# 1..2\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out\n" + "Because it's just wrong!\n"); + + g_free (output); + g_ptr_array_unref (argv); + g_clear_error (&error); +} + static void test_init_no_argv0 (void) { @@ -1828,6 +1910,8 @@ main (int argc, g_test_add_func ("/tap", test_tap); g_test_add_func ("/tap/summary", test_tap_summary); g_test_add_func ("/tap/message", test_tap_message); + g_test_add_func ("/tap/error", test_tap_error); + g_test_add_func ("/tap/error-and-pass", test_tap_error_and_pass); g_test_add_func ("/init/no_argv0", test_init_no_argv0); From 9cfae239150ab0c6aea238cd84fb9cbbf5fafc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 16 Jan 2023 21:36:15 +0100 Subject: [PATCH 14/29] gtestutils: Do not allow newlines in Bail out! messages It would break TAP parsing, so let's just print all inline --- glib/gtestutils.c | 14 ++++++++++++-- glib/tests/testing-helper.c | 2 +- glib/tests/testing.c | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index b640d9293..c1d827ecf 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1135,9 +1135,19 @@ g_test_log (GTestLogType lbit, break; case G_TEST_LOG_ERROR: if (test_tap_log) - g_print ("%sBail out! %s\n", test_is_subtest ? "# " : "", string1); + { + char *message = g_strdup (string1); + char *line = message; + + while ((line = strchr (line, '\n'))) + *(line++) = ' '; + + g_print ("%sBail out! %s\n", test_is_subtest ? "# " : "", g_strstrip (message)); + } else if (g_test_verbose ()) - g_print ("(ERROR: %s)\n", string1); + { + g_print ("(ERROR: %s)\n", string1); + } break; default: ; } diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index c4cbe0058..4d26221ea 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -54,7 +54,7 @@ test_fail (void) static void test_error (void) { - g_error ("This should error out\nBecause it's just wrong!"); + g_error ("This should error out\nBecause it's just\nwrong!"); } static void diff --git a/glib/tests/testing.c b/glib/tests/testing.c index 5854c3cf5..885ac7541 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -1730,7 +1730,7 @@ test_tap_error (void) g_assert_nonnull (interesting_lines); interesting_lines += strlen (expected_tap_header); - g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out\n" + g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out " "Because it's just wrong!\n"); g_free (output); @@ -1771,7 +1771,7 @@ test_tap_error_and_pass (void) g_assert_nonnull (interesting_lines); interesting_lines += strlen (expected_tap_header); - g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out\n" + g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out " "Because it's just wrong!\n"); g_free (output); From 28b73434bed5042af0e539389ed0dfdaa4e5b0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 17 Dec 2022 05:33:57 +0100 Subject: [PATCH 15/29] gtestutils: Use TAP version 14 Subtests syntax to show subtests output Instead of just commenting all the output of sub-processes we can just use the TAP 14 syntax for subtests, by using 4-spaces to indent the subtests output. This may not work perfectly when there are sub-process that may write output mixed with the parent, but it should be enough to expose the hierarchy. --- glib/gtestutils.c | 44 ++- glib/tests/testing.c | 851 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 867 insertions(+), 28 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index c1d827ecf..7ab52a7f1 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -58,6 +58,7 @@ #include "glib-private.h" #include "gutilsprivate.h" +#define TAP_SUBTEST_PREFIX " " /* a 4-space indented line */ /** * SECTION:testing @@ -994,16 +995,23 @@ g_test_log (GTestLogType lbit, gchar *astrings[3] = { NULL, NULL, NULL }; guint8 *dbuffer; guint32 dbufferlen; + gboolean is_subtest; + const char *tap_prefix; + + is_subtest = test_is_subtest || test_in_forked_child || test_in_subprocess; + tap_prefix = test_tap_log && is_subtest ? TAP_SUBTEST_PREFIX : ""; switch (lbit) { case G_TEST_LOG_START_BINARY: if (test_tap_log) { - if (!test_is_subtest && !test_in_subprocess && !test_in_forked_child) - g_print ("TAP version 13\n"); + if (!is_subtest) + g_print ("TAP version 14\n"); + else + g_print ("# Subtest: %s\n", test_argv0); - g_print ("# random seed: %s\n", string2); + g_print ("%s# random seed: %s\n", tap_prefix, string2); } else if (g_test_verbose ()) { @@ -1016,9 +1024,9 @@ g_test_log (GTestLogType lbit, /* We only print the TAP "plan" (1..n) ahead of time if we did * not use the -p option to select specific tests to be run. */ if (string1[0] != 0) - g_print ("# Start of %s tests\n", string1); + g_print ("%s# Start of %s tests\n", tap_prefix, string1); else if (test_paths == NULL) - g_print ("%s1..%d\n", test_is_subtest ? "# " : "", test_count); + g_print ("%s1..%d\n", tap_prefix, test_count); } break; case G_TEST_LOG_STOP_SUITE: @@ -1028,9 +1036,9 @@ g_test_log (GTestLogType lbit, * we were using -p, we need to print how many tests we ran at * the end instead. */ if (string1[0] != 0) - g_print ("# End of %s tests\n", string1); + g_print ("%s# End of %s tests\n", tap_prefix, string1); else if (test_paths != NULL) - g_print ("%s1..%d\n", test_is_subtest ? "# " : "", test_run_count); + g_print ("%s1..%d\n", tap_prefix, test_run_count); } break; case G_TEST_LOG_STOP_CASE: @@ -1051,8 +1059,8 @@ g_test_log (GTestLogType lbit, else tap_output = g_string_new ("ok"); - if (test_is_subtest) - g_string_prepend (tap_output, "# "); + if (is_subtest) + g_string_prepend (tap_output, TAP_SUBTEST_PREFIX); g_string_append_printf (tap_output, " %d %s", test_run_count, string1); if (result == G_TEST_RUN_INCOMPLETE) @@ -1072,7 +1080,7 @@ g_test_log (GTestLogType lbit, if (fail && test_mode_fatal) { if (test_tap_log) - g_print ("%sBail out!\n", test_is_subtest ? "# " : ""); + g_print ("Bail out!\n"); g_abort (); } if (result == G_TEST_RUN_SKIPPED || result == G_TEST_RUN_INCOMPLETE) @@ -1081,19 +1089,19 @@ g_test_log (GTestLogType lbit, case G_TEST_LOG_SKIP_CASE: if (test_tap_log) { - g_print ("%sok %d %s # SKIP\n", test_is_subtest ? "# " : "", + g_print ("%sok %d %s # SKIP\n", tap_prefix, test_run_count, string1); } break; case G_TEST_LOG_MIN_RESULT: if (test_tap_log) - g_print ("# min perf: %s\n", string1); + g_print ("%s# min perf: %s\n", tap_prefix, string1); else if (g_test_verbose ()) g_print ("(MINPERF:%s)\n", string1); break; case G_TEST_LOG_MAX_RESULT: if (test_tap_log) - g_print ("# max perf: %s\n", string1); + g_print ("%s# max perf: %s\n", tap_prefix, string1); else if (g_test_verbose ()) g_print ("(MAXPERF:%s)\n", string1); break; @@ -1101,7 +1109,7 @@ g_test_log (GTestLogType lbit, if (test_tap_log) { if (strchr (string1, '\n') == NULL) - g_print ("# %s\n", string1); + g_print ("%s# %s\n", tap_prefix, string1); else { GString *output = g_string_new (NULL); @@ -1110,6 +1118,7 @@ g_test_log (GTestLogType lbit, do { const char *next = strchr (line, '\n'); + g_string_append (output, tap_prefix); g_string_append (output, "# "); if (next) @@ -1142,7 +1151,12 @@ g_test_log (GTestLogType lbit, while ((line = strchr (line, '\n'))) *(line++) = ' '; - g_print ("%sBail out! %s\n", test_is_subtest ? "# " : "", g_strstrip (message)); + if (is_subtest) + g_print ("%sBail out! %s\nBail out!\n", tap_prefix, message); + else + g_print ("Bail out! %s\n", message); + + g_free (message); } else if (g_test_verbose ()) { diff --git a/glib/tests/testing.c b/glib/tests/testing.c index 885ac7541..658521083 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -35,7 +35,8 @@ #include #include -#define TAP_VERSION G_STRINGIFY (13) +#define TAP_VERSION G_STRINGIFY (14) +#define TAP_SUBTEST_PREFIX " " /* test assertion variants */ static void @@ -1116,6 +1117,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nok 1 /pass\n")); g_free (output); g_ptr_array_unref (argv); @@ -1136,6 +1138,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nok 1 /skip # SKIP not enough tea\n")); g_free (output); g_ptr_array_unref (argv); @@ -1156,6 +1159,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nok 1 /skip-printf # SKIP not enough coffee\n")); g_free (output); g_ptr_array_unref (argv); @@ -1176,6 +1180,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nnot ok 1 /incomplete # TODO mind reading not implemented yet\n")); g_free (output); g_ptr_array_unref (argv); @@ -1196,6 +1201,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nnot ok 1 /incomplete-printf # TODO telekinesis not implemented yet\n")); g_free (output); g_ptr_array_unref (argv); @@ -1216,6 +1222,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nnot ok 1 /fail\n")); g_free (output); g_clear_error (&error); @@ -1237,6 +1244,7 @@ test_tap (void) g_spawn_check_wait_status (status, &error); g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nnot ok 1 /fail-printf - this test intentionally left failing\n")); g_free (output); g_clear_error (&error); @@ -1293,6 +1301,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP\n")); g_assert_nonnull (strstr (output, "\nok 2 /b # SKIP\n")); @@ -1326,6 +1335,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a\n")); g_assert_nonnull (strstr (output, "\nok 2 /b\n")); @@ -1359,6 +1369,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP\n")); g_assert_nonnull (strstr (output, "\nok 2 /b # SKIP\n")); @@ -1396,6 +1407,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nok 1 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 2 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 3 /b\n")); @@ -1428,6 +1440,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nok 1 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 2 /c/a\n")); g_assert_nonnull (strstr (output, "\nok 3 /b\n")); @@ -1459,6 +1472,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "\nok 1 /b/b\n")); g_assert_nonnull (strstr (output, "\nok 2 /b/b/a\n")); g_assert_nonnull (strstr (output, "\n1..2\n")); @@ -1517,6 +1531,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP by request")); g_assert_nonnull (strstr (output, "\nok 2 /b # SKIP by request")); @@ -1556,6 +1571,7 @@ test_tap (void) &error); g_assert_no_error (error); g_assert_true (g_str_has_prefix (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "# Subtest: ")); g_assert_nonnull (strstr (output, "1..10\n")); g_assert_nonnull (strstr (output, "\nok 1 /a # SKIP by request")); g_assert_nonnull (strstr (output, "\nok 2 /b\n")); @@ -1604,8 +1620,636 @@ test_tap (void) g_strfreev (envp); } +/* Test the TAP output when a test suite is run with --tap. */ +static void +test_tap_subtest (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char** envp = NULL; + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + g_test_message ("pass"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "pass"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + g_clear_pointer (&envp, g_strfreev); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /pass\n")); + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("skip"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /skip # SKIP not enough tea\n")); + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("skip with printf format"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-printf"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /skip-printf # SKIP not enough coffee\n")); + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("incomplete"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "incomplete"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null (strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "not ok 1 /incomplete # TODO mind reading not implemented yet\n")); + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("incomplete with printf format"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "incomplete-printf"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "not ok 1 /incomplete-printf # TODO telekinesis not implemented yet\n")); + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("fail"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "fail"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "not ok 1 /fail\n")); + g_free (output); + g_clear_error (&error); + g_ptr_array_unref (argv); + + g_test_message ("fail with message"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "fail-printf"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "not ok 1 /fail-printf - this test intentionally left failing\n")); + g_free (output); + g_clear_error (&error); + g_ptr_array_unref (argv); + + g_test_message ("all"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "all"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, NULL, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_error (error, G_SPAWN_EXIT_ERROR, 1); + g_clear_error (&error); + g_ptr_array_unref (argv); + + g_test_message ("all-non-failures"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "all-non-failures"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, NULL, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_ptr_array_unref (argv); + + g_test_message ("--GTestSkipCount"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "--GTestSkipCount"); + g_ptr_array_add (argv, "2"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, TAP_SUBTEST_PREFIX "1..10\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /b # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 6 /prefix/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 7 /prefix/b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 8 /prefix-long/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 9 /c/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 10 /d/a\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("--GTestSkipCount=0 is the same as omitting it"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "--GTestSkipCount"); + g_ptr_array_add (argv, "0"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, TAP_SUBTEST_PREFIX "1..10\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 6 /prefix/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 7 /prefix/b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 8 /prefix-long/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 9 /c/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 10 /d/a\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("--GTestSkipCount > number of tests skips all"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "--GTestSkipCount"); + g_ptr_array_add (argv, "11"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, TAP_SUBTEST_PREFIX "1..10\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /b # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b/a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/b # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b/a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 6 /prefix/a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 7 /prefix/b/b # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 8 /prefix-long/a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 9 /c/a # SKIP\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 10 /d/a # SKIP\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("-p"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "-p"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, "-p"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, "-p"); + g_ptr_array_add (argv, "/b"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /c/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /c/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "1..5\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("--run-prefix"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "-r"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, "-r"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, "--run-prefix"); + g_ptr_array_add (argv, "/b"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /c/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /c/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 6 /b/b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "1..6\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("--run-prefix 2"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "-r"); + g_ptr_array_add (argv, "/pre"); + g_ptr_array_add (argv, "--run-prefix"); + g_ptr_array_add (argv, "/b/b"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /b/b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "1..2\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("--run-prefix conflict"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "-r"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, "-p"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, "--run-prefix"); + g_ptr_array_add (argv, "/b"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_spawn_check_wait_status (status, &error); + g_assert_nonnull (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, "do not mix [-r | --run-prefix] with '-p'\n")); + g_clear_error (&error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("-s"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "-s"); + g_ptr_array_add (argv, "/a"); + g_ptr_array_add (argv, "-s"); + g_ptr_array_add (argv, "/b"); + g_ptr_array_add (argv, "-s"); + g_ptr_array_add (argv, "/pre"); + g_ptr_array_add (argv, "-s"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_null( strstr (output, "\n# Subtest: ")); + g_assert_nonnull (strstr (output, TAP_SUBTEST_PREFIX "1..10\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /a # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /b # SKIP by request")); + /* "-s /b" would skip a test named exactly /b, but not a test named + * /b/anything */ + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 6 /prefix/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 7 /prefix/b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 8 /prefix-long/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 9 /c/a # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 10 /d/a\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); + + g_test_message ("--skip-prefix"); + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "skip-options"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, "-x"); + g_ptr_array_add (argv, "/a"); + g_ptr_array_add (argv, "--skip-prefix"); + g_ptr_array_add (argv, "/pre"); + g_ptr_array_add (argv, "-x"); + g_ptr_array_add (argv, "/c/a"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "TAP version " TAP_VERSION)); + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + g_assert_nonnull (strstr (output, TAP_SUBTEST_PREFIX "1..10\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 1 /a # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 2 /b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 3 /b/a\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 4 /b/b\n")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 5 /b/b/a\n")); + /* "--skip-prefix /pre" will skip all test path which begins with /pre */ + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 6 /prefix/a # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 7 /prefix/b/b # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 8 /prefix-long/a # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 9 /c/a # SKIP by request")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX "ok 10 /d/a\n")); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_free (output); + g_ptr_array_unref (argv); +} + static void test_tap_summary (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **envp; + + g_test_summary ("Test the output of g_test_summary() from the TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "summary"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + /* Remove the G_TEST_ROOT_PROCESS env so it will be considered a standalone test */ + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "G_TEST_ROOT_PROCESS"); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + g_assert_null (strstr (output, "# Subtest: ")); + + /* Note: The test path in the output is not `/tap/summary` because it’s the + * test path from testing-helper, not from this function. */g_assert_null (strstr (output, "# Subtest: ")); + g_assert_nonnull (strstr (output, "\n# /summary summary: Tests that g_test_summary() " + "works with TAP, by outputting a known " + "summary message in testing-helper, and " + "checking for it in the TAP output later.\n")); + g_free (output); + g_ptr_array_unref (argv); + g_strfreev (envp); +} + +static void +test_tap_subtest_summary (void) { const char *testing_helper; GPtrArray *argv; @@ -1633,10 +2277,13 @@ test_tap_summary (void) g_assert_no_error (error); /* Note: The test path in the output is not `/tap/summary` because it’s the * test path from testing-helper, not from this function. */ - g_assert_nonnull (strstr (output, "\n# /summary summary: Tests that g_test_summary() " - "works with TAP, by outputting a known " - "summary message in testing-helper, and " - "checking for it in the TAP output later.\n")); + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + g_assert_nonnull (strstr (output, + "\n" TAP_SUBTEST_PREFIX + "# /summary summary: Tests that g_test_summary() " + "works with TAP, by outputting a known " + "summary message in testing-helper, and " + "checking for it in the TAP output later.\n")); g_free (output); g_ptr_array_unref (argv); } @@ -1650,6 +2297,7 @@ test_tap_message (void) int status; gchar *output; char **output_lines; + char **envp; g_test_summary ("Test the output of g_test_message() from the TAP output of a test."); @@ -1661,7 +2309,12 @@ test_tap_message (void) g_ptr_array_add (argv, "--tap"); g_ptr_array_add (argv, NULL); - g_spawn_sync (NULL, (char **) argv->pdata, NULL, + /* Remove the G_TEST_ROOT_PROCESS env so it will be considered a standalone test */ + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "G_TEST_ROOT_PROCESS"); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &output, NULL, &status, &error); @@ -1670,7 +2323,9 @@ test_tap_message (void) g_spawn_check_wait_status (status, &error); g_assert_no_error (error); - const char *expected_tap_header = "\n# 1..1\n"; + g_assert_null (strstr (output, "# Subtest: ")); + + const char *expected_tap_header = "\n1..1\n"; const char *interesting_lines = strstr (output, expected_tap_header); g_assert_nonnull (interesting_lines); interesting_lines += strlen (expected_tap_header); @@ -1692,6 +2347,65 @@ test_tap_message (void) g_assert_cmpstr (output_lines[i++], ==, "# works with leading and trailing too"); g_assert_cmpstr (output_lines[i++], ==, "# "); + g_free (output); + g_strfreev (output_lines); + g_strfreev (envp); + g_ptr_array_unref (argv); +} + +static void +test_tap_subtest_message (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **output_lines; + + g_test_summary ("Test the output of g_test_message() from the TAP output of a sub-test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "message"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + + const char *expected_tap_header = "\n" TAP_SUBTEST_PREFIX "1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + output_lines = g_strsplit (interesting_lines, "\n", -1); + g_assert_cmpuint (g_strv_length (output_lines), >=, 12); + + guint i = 0; + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# Tests that single line message works"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# Tests that multi"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# "); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# line"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# message"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# works"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# "); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# Tests that multi"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# line"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# message"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# works with leading and trailing too"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# "); + g_free (output); g_strfreev (output_lines); g_ptr_array_unref (argv); @@ -1699,6 +2413,56 @@ test_tap_message (void) static void test_tap_error (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **envp; + + g_test_summary ("Test that g_error() generates Bail out TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "error"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + /* Remove the G_TEST_ROOT_PROCESS env so it will be considered a standalone test */ + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "G_TEST_ROOT_PROCESS"); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_nonnull (error); + + g_assert_false (g_str_has_prefix (output, "# Subtest: ")); + + const char *expected_tap_header = "\n1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + g_assert_cmpstr (interesting_lines, ==, "Bail out! GLib-FATAL-ERROR: This should error out " + "Because it's just wrong!\n"); + + g_free (output); + g_strfreev (envp); + g_ptr_array_unref (argv); + g_clear_error (&error); +} + +static void +test_tap_subtest_error (void) { const char *testing_helper; GPtrArray *argv; @@ -1725,13 +2489,17 @@ test_tap_error (void) g_spawn_check_wait_status (status, &error); g_assert_nonnull (error); - const char *expected_tap_header = "\n# 1..1\n"; + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + + const char *expected_tap_header = "\n" TAP_SUBTEST_PREFIX "1..1\n"; const char *interesting_lines = strstr (output, expected_tap_header); g_assert_nonnull (interesting_lines); interesting_lines += strlen (expected_tap_header); - g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out " - "Because it's just wrong!\n"); + g_assert_cmpstr (interesting_lines, ==, + TAP_SUBTEST_PREFIX "Bail out! GLib-FATAL-ERROR: This should error out " + "Because it's just wrong!\n" + "Bail out!\n"); g_free (output); g_ptr_array_unref (argv); @@ -1740,6 +2508,54 @@ test_tap_error (void) static void test_tap_error_and_pass (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **envp; + + g_test_summary ("Test that g_error() generates Bail out TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + /* Remove the G_TEST_ROOT_PROCESS env so it will be considered a standalone test */ + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "G_TEST_ROOT_PROCESS"); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "error-and-pass"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_nonnull (error); + + const char *expected_tap_header = "\n1..2\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + g_assert_cmpstr (interesting_lines, ==, "Bail out! GLib-FATAL-ERROR: This should error out " + "Because it's just wrong!\n"); + + g_free (output); + g_strfreev (envp); + g_ptr_array_unref (argv); + g_clear_error (&error); +} + +static void +test_tap_subtest_error_and_pass (void) { const char *testing_helper; GPtrArray *argv; @@ -1766,13 +2582,17 @@ test_tap_error_and_pass (void) g_spawn_check_wait_status (status, &error); g_assert_nonnull (error); - const char *expected_tap_header = "\n# 1..2\n"; + g_assert_true (g_str_has_prefix (output, "# Subtest: ")); + + const char *expected_tap_header = "\n" TAP_SUBTEST_PREFIX "1..2\n"; const char *interesting_lines = strstr (output, expected_tap_header); g_assert_nonnull (interesting_lines); interesting_lines += strlen (expected_tap_header); - g_assert_cmpstr (interesting_lines, ==, "# Bail out! GLib-FATAL-ERROR: This should error out " - "Because it's just wrong!\n"); + g_assert_cmpstr (interesting_lines, ==, + TAP_SUBTEST_PREFIX "Bail out! GLib-FATAL-ERROR: This should error out " + "Because it's just wrong!\n" + "Bail out!\n"); g_free (output); g_ptr_array_unref (argv); @@ -1908,10 +2728,15 @@ main (int argc, g_test_add_func ("/misc/path/second", test_path_second); g_test_add_func ("/tap", test_tap); + g_test_add_func ("/tap/subtest", test_tap_subtest); g_test_add_func ("/tap/summary", test_tap_summary); + g_test_add_func ("/tap/subtest/summary", test_tap_subtest_summary); g_test_add_func ("/tap/message", test_tap_message); + g_test_add_func ("/tap/subtest/message", test_tap_subtest_message); g_test_add_func ("/tap/error", test_tap_error); + g_test_add_func ("/tap/subtest/error", test_tap_subtest_error); g_test_add_func ("/tap/error-and-pass", test_tap_error_and_pass); + g_test_add_func ("/tap/subtest/error-and-pass", test_tap_subtest_error_and_pass); g_test_add_func ("/init/no_argv0", test_init_no_argv0); From f893df4b7d52cce6c2abcd485a8cfc15320835b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 17 Dec 2022 06:30:09 +0100 Subject: [PATCH 16/29] gtestutils: Use TAP 13 comments syntax for subtests Sadly meson 60 doesn't support parsing TAP 14 subtests properly, so it would fail. So temporary go back to the previous logic in a simple way so that this commit can be reverted quickly when we can use a newer meson version. --- glib/gtestutils.c | 6 ++++-- glib/tests/testing.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 7ab52a7f1..4df2394f7 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -58,7 +58,9 @@ #include "glib-private.h" #include "gutilsprivate.h" -#define TAP_SUBTEST_PREFIX " " /* a 4-space indented line */ +/* FIXME: Remove '#' prefix when we'll depend on a meson version supporting TAP 14 + * See https://gitlab.gnome.org/GNOME/glib/-/issues/2885 */ +#define TAP_SUBTEST_PREFIX "# " /* a 4-space indented line */ /** * SECTION:testing @@ -1007,7 +1009,7 @@ g_test_log (GTestLogType lbit, if (test_tap_log) { if (!is_subtest) - g_print ("TAP version 14\n"); + g_print ("TAP version 13\n"); else g_print ("# Subtest: %s\n", test_argv0); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index 658521083..dbbde1733 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -35,8 +35,8 @@ #include #include -#define TAP_VERSION G_STRINGIFY (14) -#define TAP_SUBTEST_PREFIX " " +#define TAP_VERSION G_STRINGIFY (13) +#define TAP_SUBTEST_PREFIX "# " /* test assertion variants */ static void From c00135ec736eae942b97741f00f597546936976b Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 16 Dec 2022 17:28:34 -0500 Subject: [PATCH 17/29] gtestutils: Do not use default log handler when using TAP Only use g_test_log() because it will prepend `#` to log messages when using TAP protocol. Meson >=1.0 rightfully prints a warning when using TAP protocol and stdout contains non-comment unknown TAP command. --- glib/gtestutils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 4df2394f7..552ee336d 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -3295,9 +3295,10 @@ gtest_default_log_handler (const gchar *log_domain, msg = g_strjoinv ("", (gchar**) strv); g_test_log (fatal ? G_TEST_LOG_ERROR : G_TEST_LOG_MESSAGE, msg, NULL, 0, NULL); - g_log_default_handler (log_domain, log_level, message, unused_data); - g_free (msg); + + if (!test_tap_log) + g_log_default_handler (log_domain, log_level, message, unused_data); } void From 19c7d4f15ef12419e1b8837fa6873bac382e42a0 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Wed, 21 Dec 2022 10:31:33 -0500 Subject: [PATCH 18/29] tests: Use g_test_message() in gdatetime tests --- glib/tests/gdatetime.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c index 7874d258d..49390c900 100644 --- a/glib/tests/gdatetime.c +++ b/glib/tests/gdatetime.c @@ -403,7 +403,7 @@ test_GDateTime_new_from_timeval (void) dt = g_date_time_new_from_timeval_local (&tv); if (g_test_verbose ()) - g_printerr ("\nDT%04d-%02d-%02dT%02d:%02d:%02d%s\n", + g_test_message ("DT%04d-%02d-%02dT%02d:%02d:%02d%s", g_date_time_get_year (dt), g_date_time_get_month (dt), g_date_time_get_day_of_month (dt), @@ -501,7 +501,7 @@ test_GDateTime_new_from_timeval_utc (void) dt = g_date_time_new_from_timeval_utc (&tv); if (g_test_verbose ()) - g_printerr ("\nDT%04d-%02d-%02dT%02d:%02d:%02d%s\n", + g_test_message ("DT%04d-%02d-%02dT%02d:%02d:%02d%s", g_date_time_get_year (dt), g_date_time_get_month (dt), g_date_time_get_day_of_month (dt), @@ -2097,7 +2097,7 @@ test_all_dates (void) dt = g_date_time_new (timezone, year, month, day, 0, 0, 0); #if 0 - g_printerr ("%04d-%02d-%02d = %04d-W%02d-%d = %04d-%03d\n", + g_test_message ("%04d-%02d-%02d = %04d-W%02d-%d = %04d-%03d", year, month, day, week_year, week_num, weekday, year, day_of_year); @@ -2384,7 +2384,7 @@ check_and_set_locale (int category, setlocale (category, name); if (strstr (setlocale (category, NULL), name) == NULL) { - g_print ("Unavailable '%s' locale\n", name); + g_test_message ("Unavailable '%s' locale", name); g_test_skip ("required locale not available, skipping tests"); return FALSE; } From ed8810216aedf4bbfc3172a3d5df826e3976a2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 12 Jan 2023 18:19:43 +0100 Subject: [PATCH 19/29] gio/tests: Use default log writer to stderr for launched processes We don't want to bother TAP parser with subprocess messages when using verbose logging, so let's just use stderr by default. --- gio/tests/fake-document-portal.c | 2 ++ gio/tests/fake-service-name.c | 2 ++ gio/tests/gapplication.c | 2 ++ gio/tests/gdbus-testserver.c | 2 ++ 4 files changed, 8 insertions(+) diff --git a/gio/tests/fake-document-portal.c b/gio/tests/fake-document-portal.c index 0ef86b59a..585dee58b 100644 --- a/gio/tests/fake-document-portal.c +++ b/gio/tests/fake-document-portal.c @@ -125,6 +125,8 @@ main (gint argc, gchar *argv[]) GMainLoop *loop; guint id; + g_log_writer_default_set_use_stderr (TRUE); + loop = g_main_loop_new (NULL, FALSE); id = g_bus_own_name (G_BUS_TYPE_SESSION, diff --git a/gio/tests/fake-service-name.c b/gio/tests/fake-service-name.c index 6e317a7cc..0acabd9ec 100644 --- a/gio/tests/fake-service-name.c +++ b/gio/tests/fake-service-name.c @@ -98,6 +98,8 @@ main (gint argc, gchar *argv[]) { guint id; + g_log_writer_default_set_use_stderr (TRUE); + loop = g_main_loop_new (NULL, FALSE); introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); g_assert (introspection_data != NULL); diff --git a/gio/tests/gapplication.c b/gio/tests/gapplication.c index 4320352d1..a11f2b8bc 100644 --- a/gio/tests/gapplication.c +++ b/gio/tests/gapplication.c @@ -1686,6 +1686,8 @@ main (int argc, char **argv) { g_setenv ("LC_ALL", "C", TRUE); + g_log_writer_default_set_use_stderr (TRUE); + g_test_init (&argc, &argv, NULL); if (!g_test_subprocess ()) diff --git a/gio/tests/gdbus-testserver.c b/gio/tests/gdbus-testserver.c index ae8e47b18..3a16db378 100644 --- a/gio/tests/gdbus-testserver.c +++ b/gio/tests/gdbus-testserver.c @@ -843,6 +843,8 @@ main (int argc, char *argv[]) { guint owner_id; + g_log_writer_default_set_use_stderr (TRUE); + introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); g_hash_table_insert (properties, g_strdup ("y"), g_variant_ref_sink (g_variant_new_byte (1))); From b3fd737eaa9b0617a38faedfb57d9d63ac677e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 12 Jan 2023 22:20:14 +0100 Subject: [PATCH 20/29] gmessages: Share the same logic to pick the output for log level Use the very same logic in both the fallback handler and the default handler --- glib/gmessages.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/glib/gmessages.c b/glib/gmessages.c index 4fd7544ea..7612cb13b 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -525,6 +525,7 @@ static inline const char * format_string (const char *format, va_list args, char **out_allocated_string) G_GNUC_PRINTF (1, 0); +static inline FILE * log_level_to_file (GLogLevelFlags log_level); static void _g_log_abort (gboolean breakpoint) @@ -1206,8 +1207,6 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], GLogLevelFlags log_level, gboolean use_color) { - gboolean to_stdout = !gmessages_use_stderr; - /* we may not call _any_ GLib functions here */ strcpy (level_prefix, log_level_to_color (log_level, use_color)); @@ -1216,19 +1215,15 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], { case G_LOG_LEVEL_ERROR: strcat (level_prefix, "ERROR"); - to_stdout = FALSE; break; case G_LOG_LEVEL_CRITICAL: strcat (level_prefix, "CRITICAL"); - to_stdout = FALSE; break; case G_LOG_LEVEL_WARNING: strcat (level_prefix, "WARNING"); - to_stdout = FALSE; break; case G_LOG_LEVEL_MESSAGE: strcat (level_prefix, "Message"); - to_stdout = FALSE; break; case G_LOG_LEVEL_INFO: strcat (level_prefix, "INFO"); @@ -1258,7 +1253,7 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], if ((log_level & G_LOG_FLAG_FATAL) != 0 && !g_test_initialized ()) win32_keep_fatal_message = TRUE; #endif - return to_stdout ? stdout : stderr; + return log_level_to_file (log_level); } typedef struct { @@ -1487,7 +1482,7 @@ log_level_to_priority (GLogLevelFlags log_level) return "5"; } -static FILE * +static inline FILE * log_level_to_file (GLogLevelFlags log_level) { if (gmessages_use_stderr) From 49a115d6dbd4df6d1fa43b485a0233fee33fb3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 12 Jan 2023 18:48:30 +0100 Subject: [PATCH 21/29] tests/logging, testing: Add more tests for cases enforcing gmessages on stderr --- glib/tests/logging.c | 85 +++++++++++++++++++++++++++++++++++++++++++- glib/tests/testing.c | 20 +++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/glib/tests/logging.c b/glib/tests/logging.c index e58b405a2..964451422 100644 --- a/glib/tests/logging.c +++ b/glib/tests/logging.c @@ -61,16 +61,45 @@ test_default_handler_error (void) } static void -test_default_handler_critical (void) +test_default_handler_error_stderr (void) { + g_log_writer_default_set_use_stderr (FALSE); + g_log_set_default_handler (g_log_default_handler, NULL); + g_error ("message1"); + exit (0); +} + +static void +test_default_handler_critical_stderr (void) +{ + g_log_writer_default_set_use_stderr (TRUE); g_log_set_default_handler (g_log_default_handler, NULL); g_critical ("message2"); exit (0); } +static void +test_default_handler_critical (void) +{ + g_log_writer_default_set_use_stderr (FALSE); + g_log_set_default_handler (g_log_default_handler, NULL); + g_critical ("message2"); + exit (0); +} + +static void +test_default_handler_warning_stderr (void) +{ + g_log_writer_default_set_use_stderr (TRUE); + g_log_set_default_handler (g_log_default_handler, NULL); + g_warning ("message3"); + exit (0); +} + static void test_default_handler_warning (void) { + g_log_writer_default_set_use_stderr (FALSE); g_log_set_default_handler (g_log_default_handler, NULL); g_warning ("message3"); exit (0); @@ -79,6 +108,16 @@ test_default_handler_warning (void) static void test_default_handler_message (void) { + g_log_writer_default_set_use_stderr (FALSE); + g_log_set_default_handler (g_log_default_handler, NULL); + g_message ("message4"); + exit (0); +} + +static void +test_default_handler_message_stderr (void) +{ + g_log_writer_default_set_use_stderr (TRUE); g_log_set_default_handler (g_log_default_handler, NULL); g_message ("message4"); exit (0); @@ -87,6 +126,16 @@ test_default_handler_message (void) static void test_default_handler_info (void) { + g_log_writer_default_set_use_stderr (FALSE); + g_log_set_default_handler (g_log_default_handler, NULL); + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "message5"); + exit (0); +} + +static void +test_default_handler_info_stderr (void) +{ + g_log_writer_default_set_use_stderr (TRUE); g_log_set_default_handler (g_log_default_handler, NULL); g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "message5"); exit (0); @@ -95,6 +144,7 @@ test_default_handler_info (void) static void test_default_handler_bar_info (void) { + g_log_writer_default_set_use_stderr (FALSE); g_log_set_default_handler (g_log_default_handler, NULL); g_setenv ("G_MESSAGES_DEBUG", "foo bar baz", TRUE); @@ -106,6 +156,7 @@ test_default_handler_bar_info (void) static void test_default_handler_baz_debug (void) { + g_log_writer_default_set_use_stderr (FALSE); g_log_set_default_handler (g_log_default_handler, NULL); g_setenv ("G_MESSAGES_DEBUG", "foo bar baz", TRUE); @@ -117,6 +168,7 @@ test_default_handler_baz_debug (void) static void test_default_handler_debug (void) { + g_log_writer_default_set_use_stderr (FALSE); g_log_set_default_handler (g_log_default_handler, NULL); g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); @@ -192,6 +244,7 @@ test_default_handler_would_drop (void) static void test_default_handler_0x400 (void) { + g_log_writer_default_set_use_stderr (FALSE); g_log_set_default_handler (g_log_default_handler, NULL); g_log (G_LOG_DOMAIN, 1<<10, "message7"); exit (0); @@ -205,26 +258,51 @@ test_default_handler (void) g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*ERROR*message1*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/error-stderr", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*ERROR*message1*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/critical", 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*CRITICAL*message2*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/critical-stderr", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*CRITICAL*message2*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/warning", 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_failed (); g_test_trap_assert_stderr ("*WARNING*message3*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/warning-stderr", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*WARNING*message3*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/message", 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_passed (); g_test_trap_assert_stderr ("*Message*message4*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/message-stderr", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_assert_stderr ("*Message*message4*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/info", 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_passed (); g_test_trap_assert_stdout_unmatched ("*INFO*message5*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/info-stderr", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_assert_stderr_unmatched ("*INFO*message5*"); + g_test_trap_subprocess ("/logging/default-handler/subprocess/bar-info", 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_passed (); @@ -746,10 +824,15 @@ main (int argc, char *argv[]) g_test_add_func ("/logging/default-handler", test_default_handler); g_test_add_func ("/logging/default-handler/subprocess/error", test_default_handler_error); + g_test_add_func ("/logging/default-handler/subprocess/error-stderr", test_default_handler_error_stderr); g_test_add_func ("/logging/default-handler/subprocess/critical", test_default_handler_critical); + g_test_add_func ("/logging/default-handler/subprocess/critical-stderr", test_default_handler_critical_stderr); g_test_add_func ("/logging/default-handler/subprocess/warning", test_default_handler_warning); + g_test_add_func ("/logging/default-handler/subprocess/warning-stderr", test_default_handler_warning_stderr); g_test_add_func ("/logging/default-handler/subprocess/message", test_default_handler_message); + g_test_add_func ("/logging/default-handler/subprocess/message-stderr", test_default_handler_message_stderr); g_test_add_func ("/logging/default-handler/subprocess/info", test_default_handler_info); + g_test_add_func ("/logging/default-handler/subprocess/info-stderr", test_default_handler_info_stderr); g_test_add_func ("/logging/default-handler/subprocess/bar-info", test_default_handler_bar_info); g_test_add_func ("/logging/default-handler/subprocess/baz-debug", test_default_handler_baz_debug); g_test_add_func ("/logging/default-handler/subprocess/debug", test_default_handler_debug); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index dbbde1733..ed86f6e27 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -673,6 +673,23 @@ test_expected_messages (void) g_test_trap_assert_stderr ("*GLib:ERROR*Did not see expected message testing-CRITICAL*nope*"); } +static void +test_messages (void) +{ + g_test_trap_subprocess ("/misc/messages/subprocess/use-stderr", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_stderr ("*message is in stderr*"); + g_test_trap_assert_stderr ("*warning is in stderr*"); + g_test_trap_has_passed (); +} + +static void +test_messages_use_stderr (void) +{ + g_message ("message is in stderr"); + g_warning ("warning is in stderr"); +} + static void test_expected_messages_debug (void) { @@ -2702,6 +2719,9 @@ main (int argc, g_test_add_func ("/misc/expected-messages/expect-error", test_expected_messages_expect_error); g_test_add_func ("/misc/expected-messages/skip-debug", test_expected_messages_debug); + g_test_add_func ("/misc/messages", test_messages); + g_test_add_func ("/misc/messages/subprocess/use-stderr", test_messages_use_stderr); + 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); From 04e8c8c719923b246eed92ca367660a5e5d019c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 12 Jan 2023 18:49:12 +0100 Subject: [PATCH 22/29] gio/tests/gsettings: Write subprocess stdout as test message This won't confuse the meson TAP parser. --- gio/tests/gsettings.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index c7de624a2..d3fd4289d 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -3017,6 +3017,8 @@ main (int argc, char *argv[]) if (!g_test_subprocess ()) { GError *local_error = NULL; + char *subprocess_stdout = NULL; + /* A GVDB header is 6 guint32s, and requires a magic number in the first * two guint32s. A set of zero bytes of a greater length is considered * corrupt. */ @@ -3056,14 +3058,20 @@ main (int argc, char *argv[]) "--schema-file=org.gtk.test.enums.xml " "--schema-file=org.gtk.test.gschema.xml " "--override-file=org.gtk.test.gschema.override", - NULL, NULL, &result, NULL)); + &subprocess_stdout, NULL, &result, NULL)); + if (subprocess_stdout && *g_strstrip (subprocess_stdout) != '\0') + g_test_message ("%s", subprocess_stdout); + g_clear_pointer (&subprocess_stdout, g_free); g_assert_cmpint (result, ==, 0); g_remove ("schema-source/gschemas.compiled"); g_mkdir ("schema-source", 0777); g_assert_true (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=schema-source " "--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml", - NULL, NULL, &result, NULL)); + &subprocess_stdout, NULL, &result, NULL)); + if (subprocess_stdout && *g_strstrip (subprocess_stdout) != '\0') + g_test_message ("%s", subprocess_stdout); + g_clear_pointer (&subprocess_stdout, g_free); g_assert_cmpint (result, ==, 0); g_remove ("schema-source-corrupt/gschemas.compiled"); From 1daf05ecdac89b0e3b71ec6e579b2000b27aa617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 12 Jan 2023 18:53:55 +0100 Subject: [PATCH 23/29] gpoll: Print results to stderr This will make it compatible with TAP reporting. --- glib/tests/gpoll.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/glib/tests/gpoll.c b/glib/tests/gpoll.c index de296ca5f..ec3dd6999 100644 --- a/glib/tests/gpoll.c +++ b/glib/tests/gpoll.c @@ -204,11 +204,11 @@ print_buckets (gint buckets[], for (i = 0; i < count; i++) if (i < count - 1) - g_print ("%-4lld-%4lld|", i == 0 ? 0 : bucket_limits[i - 1], bucket_limits[i] - 1); + g_printerr ("%-4lld-%4lld|", i == 0 ? 0 : bucket_limits[i - 1], bucket_limits[i] - 1); else - g_print (" >= %-4lld|", bucket_limits[i - 1]); + g_printerr (" >= %-4lld|", bucket_limits[i - 1]); - g_print ("\n"); + g_printerr ("\n"); for (i = 0; i < count; i++) { @@ -225,17 +225,17 @@ print_buckets (gint buckets[], len = 4; padding = 9 - len; for (j = 0; j < padding / 2; j++) - g_print (" "); + g_printerr (" "); if (buckets[i] != 0) - g_print ("%*d", len, buckets[i]); + g_printerr ("%*d", len, buckets[i]); else - g_print (" "); + g_printerr (" "); for (j = padding / 2; j < padding; j++) - g_print (" "); - g_print (" "); + g_printerr (" "); + g_printerr (" "); } - g_print ("\n\n"); + g_printerr ("\n\n"); } static void @@ -281,7 +281,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("\nempty poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); + g_printerr ("\nempty poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); times_avg = 0; @@ -336,7 +336,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("1-socket + msg poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); + g_printerr ("1-socket + msg poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); times_avg = 0; @@ -384,7 +384,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("1-socket poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); + g_printerr ("1-socket poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); times_avg = 0; @@ -433,7 +433,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("half-socket poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); + g_printerr ("half-socket poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); times_avg = 0; @@ -491,7 +491,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("half-socket + msg poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); + g_printerr ("half-socket + msg poll time:\n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); times_avg = 0; @@ -540,7 +540,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("%d-socket poll time: \n%4lldns - %4lldns, average %4lldns\n", NUM_POLLEES, times_min, times_max, times_avg); + g_printerr ("%d-socket poll time: \n%4lldns - %4lldns, average %4lldns\n", NUM_POLLEES, times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); activatable = 0; @@ -599,7 +599,7 @@ test_gpoll (void) } times_avg /= NUM_POLLEES; - g_print ("variable socket number + msg poll time: \n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); + g_printerr ("variable socket number + msg poll time: \n%4lldns - %4lldns, average %4lldns\n", times_min, times_max, times_avg); print_buckets (buckets, bucket_limits, BUCKET_COUNT); cleanup_sockets (sockets, opp_sockets, NUM_POLLEES); From 871c4b46988420e161dd7b30d86b802fe96f4565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 12 Jan 2023 19:49:11 +0100 Subject: [PATCH 24/29] spawn-test-win32-gui: Write state to stderr Makes TAP happier --- glib/tests/spawn-test-win32-gui.c | 18 +++++++++--------- glib/tests/spawn-test.c | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/glib/tests/spawn-test-win32-gui.c b/glib/tests/spawn-test-win32-gui.c index 34945f524..46353c8f3 100644 --- a/glib/tests/spawn-test-win32-gui.c +++ b/glib/tests/spawn-test-win32-gui.c @@ -26,7 +26,7 @@ WinMain (struct HINSTANCE__ *hInstance, } else if (__argc <= 2) { - printf ("This is stdout\n"); + printf ("# This is stdout\n"); fflush (stdout); fprintf (stderr, "This is stderr\n"); @@ -41,36 +41,36 @@ WinMain (struct HINSTANCE__ *hInstance, if (infd < 0 || outfd < 0) { - printf ("spawn-test-win32-gui: illegal fds on command line %s", + fprintf (stderr, "spawn-test-win32-gui: illegal fds on command line %s\n", lpszCmdLine); exit (1); } n = strlen ("Hello there"); if (write (outfd, &n, sizeof (n)) == -1 || - write (outfd, "Hello there", n) == -1) + write (outfd, "Hello there\n", n) == -1) { int errsv = errno; - printf ("spawn-test-win32-gui: Write error: %s", strerror (errsv)); + fprintf (stderr, "spawn-test-win32-gui: Write error: %s\n", strerror (errsv)); exit (1); } if ((k = read (infd, &n, sizeof (n))) != sizeof (n)) { - printf ("spawn-test-win32-gui: Got only %d bytes, wanted %d", + fprintf (stderr, "spawn-test-win32-gui: Got only %d bytes, wanted %d\n", k, (int)sizeof (n)); exit (1); } - printf ("spawn-test-win32-gui: Parent says %d bytes to read", n); + fprintf (stderr, "spawn-test-win32-gui: Parent says %d bytes to read\n", n); if ((k = read (infd, buf, n)) != n) { int errsv = errno; if (k == -1) - printf ("spawn-test-win32-gui: Read error: %s", strerror (errsv)); + fprintf (stderr, "spawn-test-win32-gui: Read error: %s\n", strerror (errsv)); else - printf ("spawn-test-win32-gui: Got only %d bytes", k); + fprintf (stderr, "spawn-test-win32-gui: Got only %d bytes\n", k); exit (1); } @@ -79,7 +79,7 @@ WinMain (struct HINSTANCE__ *hInstance, write (outfd, "See ya", n) == -1) { int errsv = errno; - printf ("spawn-test-win32-gui: Write error: %s", strerror (errsv)); + fprintf (stderr, "spawn-test-win32-gui: Write error: %s\n", strerror (errsv)); exit (1); } } diff --git a/glib/tests/spawn-test.c b/glib/tests/spawn-test.c index c0b6829fe..7da666e3f 100644 --- a/glib/tests/spawn-test.c +++ b/glib/tests/spawn-test.c @@ -149,7 +149,7 @@ test_spawn_basics (void) g_assert_no_error (err); g_assert_true (result); - g_assert_cmpstr (output, ==, "This is stdout\r\n"); + g_assert_cmpstr (output, ==, "# This is stdout\r\n"); g_assert_cmpstr (erroutput, ==, "This is stderr\r\n"); g_free (output); From 5d91834d9bcc85cb84f55d9b6e2470ed81e1b2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 20:04:08 +0100 Subject: [PATCH 25/29] gtestutils: Do not generate the random seed if provided There's no point to generate a seed if we're going to overwrite it when --seed is used. --- glib/gtestutils.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 552ee336d..9a5ea2f22 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1696,13 +1696,17 @@ void } va_end (args); - /* setup random seed string */ - g_snprintf (seedstr, sizeof (seedstr), "R02S%08x%08x%08x%08x", g_random_int(), g_random_int(), g_random_int(), g_random_int()); - test_run_seedstr = seedstr; - /* parse args, sets up mode, changes seed, etc. */ parse_args (argc, argv); + if (test_run_seedstr == NULL) + { + /* setup random seed string */ + g_snprintf (seedstr, sizeof (seedstr), "R02S%08x%08x%08x%08x", + g_random_int(), g_random_int(), g_random_int(), g_random_int()); + test_run_seedstr = seedstr; + } + if (!g_get_prgname() && !no_g_set_prgname) g_set_prgname ((*argv)[0]); From 3d1736c8288cd01c4d7fe2b95ae12e120a29d494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 13 Jan 2023 21:39:14 +0100 Subject: [PATCH 26/29] gmessages: Make print handler functions to return default handlers g_set_print_handler() and g_set_printerr_handler() are supposed to return the old printer handlers, but in case the default is used NULL is returned instead. This makes hard to override the default handler to e.g. decorate the output with some minor content, without having to rewrite the low-level implementation. So, make the default printers to be functions and set them as the default ones. Also this avoids having to check each time what function to use at print time. --- glib/gmessages.c | 64 ++++++++++++++++++++++++++++++-------------- glib/tests/logging.c | 34 +++++++++++++++++++++-- 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/glib/gmessages.c b/glib/gmessages.c index 7612cb13b..aff1316f5 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -501,12 +501,14 @@ struct _GLogHandler GLogHandler *next; }; +static void g_default_print_func (const gchar *string); +static void g_default_printerr_func (const gchar *string); /* --- variables --- */ static GMutex g_messages_lock; static GLogDomain *g_log_domains = NULL; -static GPrintFunc glib_print_func = NULL; -static GPrintFunc glib_printerr_func = NULL; +static GPrintFunc glib_print_func = g_default_print_func; +static GPrintFunc glib_printerr_func = g_default_printerr_func; static GPrivate g_log_depth; static GPrivate g_log_structured_depth; static GLogFunc default_log_func = g_log_default_handler; @@ -3284,9 +3286,11 @@ g_log_default_handler (const gchar *log_domain, /** * g_set_print_handler: - * @func: the new print handler + * @func: (nullable): the new print handler or %NULL to + * reset to the default * - * Sets the print handler. + * Sets the print handler to @func, or resets it to the + * default GLib handler if %NULL. * * Any messages passed to g_print() will be output via * the new handler. The default handler simply outputs @@ -3294,7 +3298,14 @@ g_log_default_handler (const gchar *log_domain, * you can redirect the output, to a GTK+ widget or a * log file for example. * - * Returns: the old print handler + * Since 2.76 this functions always returns a valid + * #GPrintFunc, and never returns %NULL. If no custom + * print handler was set, it will return the GLib + * default print handler and that can be re-used to + * decorate its output and/or to write to stderr + * in all platforms. Before GLib 2.76, this was %NULL. + * + * Returns: (not nullable): the old print handler */ GPrintFunc g_set_print_handler (GPrintFunc func) @@ -3303,7 +3314,7 @@ g_set_print_handler (GPrintFunc func) g_mutex_lock (&g_messages_lock); old_print_func = glib_print_func; - glib_print_func = func; + glib_print_func = func ? func : g_default_print_func; g_mutex_unlock (&g_messages_lock); return old_print_func; @@ -3360,6 +3371,18 @@ format_string (const char *format, } } +static void +g_default_print_func (const gchar *string) +{ + print_string (stdout, string); +} + +static void +g_default_printerr_func (const gchar *string) +{ + print_string (stderr, string); +} + /** * g_print: * @format: the message format. See the printf() documentation @@ -3395,19 +3418,17 @@ g_print (const gchar *format, local_glib_print_func = glib_print_func; g_mutex_unlock (&g_messages_lock); - if (local_glib_print_func) - local_glib_print_func (string); - else - print_string (stdout, string); - + local_glib_print_func (string); g_free (free_me); } /** * g_set_printerr_handler: - * @func: the new error message handler + * @func: (nullable): he new error message handler or %NULL + * to reset to the default * - * Sets the handler for printing error messages. + * Sets the handler for printing error messages to @func, + * or resets it to the default GLib handler if %NULL. * * Any messages passed to g_printerr() will be output via * the new handler. The default handler simply outputs the @@ -3415,7 +3436,14 @@ g_print (const gchar *format, * redirect the output, to a GTK+ widget or a log file for * example. * - * Returns: the old error message handler + * Since 2.76 this functions always returns a valid + * #GPrintFunc, and never returns %NULL. If no custom error + * print handler was set, it will return the GLib default + * error print handler and that can be re-used to decorate + * its output and/or to write to stderr in all platforms. + * Before GLib 2.76, this was %NULL. + * + * Returns: (not nullable): the old error message handler */ GPrintFunc g_set_printerr_handler (GPrintFunc func) @@ -3424,7 +3452,7 @@ g_set_printerr_handler (GPrintFunc func) g_mutex_lock (&g_messages_lock); old_printerr_func = glib_printerr_func; - glib_printerr_func = func; + glib_printerr_func = func ? func : g_default_printerr_func; g_mutex_unlock (&g_messages_lock); return old_printerr_func; @@ -3463,11 +3491,7 @@ g_printerr (const gchar *format, local_glib_printerr_func = glib_printerr_func; g_mutex_unlock (&g_messages_lock); - if (local_glib_printerr_func) - local_glib_printerr_func (string); - else - print_string (stderr, string); - + local_glib_printerr_func (string); g_free (free_me); } diff --git a/glib/tests/logging.c b/glib/tests/logging.c index 964451422..201a8f99f 100644 --- a/glib/tests/logging.c +++ b/glib/tests/logging.c @@ -3,6 +3,12 @@ #define G_LOG_USE_STRUCTURED 1 #include +#ifdef G_OS_WIN32 +#define LINE_END "\r\n" +#else +#define LINE_END "\n" +#endif + /* Test g_warn macros */ static void test_warnings (void) @@ -362,13 +368,25 @@ test_print_handler (void) GPrintFunc old_print_handler; old_print_handler = g_set_print_handler (my_print_handler); - g_assert (old_print_handler == NULL); + g_assert_nonnull (old_print_handler); my_print_count = 0; g_print ("bu ba"); g_assert_cmpint (my_print_count, ==, 1); g_set_print_handler (NULL); + + if (g_test_subprocess ()) + { + old_print_handler ("default handler\n"); + g_print ("bu ba\n"); + return; + } + + g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_stdout ("*default handler" LINE_END "*"); + g_test_trap_assert_stdout ("*bu ba" LINE_END "*"); + g_test_trap_has_passed (); } static void @@ -377,13 +395,25 @@ test_printerr_handler (void) GPrintFunc old_printerr_handler; old_printerr_handler = g_set_printerr_handler (my_print_handler); - g_assert (old_printerr_handler == NULL); + g_assert_nonnull (old_printerr_handler); my_print_count = 0; g_printerr ("bu ba"); g_assert_cmpint (my_print_count, ==, 1); g_set_printerr_handler (NULL); + + if (g_test_subprocess ()) + { + old_printerr_handler ("default handler\n"); + g_printerr ("bu ba\n"); + return; + } + + g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_stderr ("*default handler" LINE_END "*"); + g_test_trap_assert_stderr ("*bu ba" LINE_END "*"); + g_test_trap_has_passed (); } static char *fail_str = "foo"; From 8b7b5f54575a88f3f99b66f39856a2981e9da4b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Sat, 14 Jan 2023 01:47:07 +0100 Subject: [PATCH 27/29] gtestutils: Define a custom g_print handler for TAP When using TAP output in gtest, all the printed strings should be commented not to break the spec, so enforce this at GTest level, by ensuring that all the lines written via g_print() will be in the commented form and will respect the subtest indentation. As per this we can remove some custom code in g_test_log() as now there are very few cases in which we need to use the default print handler which is now private when testing. --- glib/gtestutils.c | 184 +++++++++++++++++++++++++----------- glib/tests/logging.c | 10 +- glib/tests/testing-helper.c | 14 +++ glib/tests/testing.c | 103 ++++++++++++++++++++ 4 files changed, 250 insertions(+), 61 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 9a5ea2f22..486edf273 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -848,7 +848,10 @@ static void gtest_default_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data); - +static void g_test_tap_print (unsigned subtest_level, + gboolean commented, + const char *format, + ...) G_GNUC_PRINTF (3, 4); static const char * const g_test_result_names[] = { "OK", @@ -915,8 +918,90 @@ static GTestConfig mutable_test_config_vars = { }; const GTestConfig * const g_test_config_vars = &mutable_test_config_vars; static gboolean no_g_set_prgname = FALSE; +static GPrintFunc g_default_print_func = NULL; + /* --- functions --- */ +static inline gboolean +is_subtest (void) +{ + return test_is_subtest || test_in_forked_child || test_in_subprocess; +} + +static void +g_test_print_handler_full (const gchar *string, + gboolean use_tap_format, + gboolean is_tap_comment, + unsigned subtest_level) +{ + g_assert (string != NULL); + + if (G_LIKELY (use_tap_format) && strchr (string, '\n') != NULL) + { + static gboolean last_had_final_newline = TRUE; + GString *output = g_string_new_len (NULL, strlen (string) + 2); + const char *line = string; + + do + { + const char *next = strchr (line, '\n'); + + if (last_had_final_newline && (next || *line != '\0')) + { + for (unsigned l = 0; l < subtest_level; ++l) + g_string_append (output, TAP_SUBTEST_PREFIX); + + if G_LIKELY (is_tap_comment) + g_string_append (output, "# "); + } + + if (next) + { + next += 1; /* Include the newline */ + g_string_append_len (output, line, next - line); + } + else + { + g_string_append (output, line); + last_had_final_newline = (*line == '\0'); + } + + line = next; + } + while (line != NULL); + + g_default_print_func (output->str); + g_string_free (g_steal_pointer (&output), TRUE); + } + else + { + g_default_print_func (string); + } +} + +static void +g_test_print_handler (const gchar *string) +{ + g_test_print_handler_full (string, test_tap_log, TRUE, is_subtest () ? 1 : 0); +} + +static void +g_test_tap_print (unsigned subtest_level, + gboolean commented, + const char *format, + ...) +{ + va_list args; + char *string; + + va_start (args, format); + string = g_strdup_vprintf (format, args); + va_end (args); + + g_test_print_handler_full (string, TRUE, commented, subtest_level); + g_free (string); +} + const char* g_test_log_type_name (GTestLogType log_type) { @@ -997,23 +1082,33 @@ g_test_log (GTestLogType lbit, gchar *astrings[3] = { NULL, NULL, NULL }; guint8 *dbuffer; guint32 dbufferlen; - gboolean is_subtest; - const char *tap_prefix; + unsigned subtest_level; - is_subtest = test_is_subtest || test_in_forked_child || test_in_subprocess; - tap_prefix = test_tap_log && is_subtest ? TAP_SUBTEST_PREFIX : ""; + if (g_once_init_enter (&g_default_print_func)) + { + g_once_init_leave (&g_default_print_func, + g_set_print_handler (g_test_print_handler)); + g_assert_nonnull (g_default_print_func); + } + + subtest_level = is_subtest () ? 1 : 0; switch (lbit) { case G_TEST_LOG_START_BINARY: if (test_tap_log) { - if (!is_subtest) - g_print ("TAP version 13\n"); + if (!is_subtest ()) + { + g_test_tap_print (0, FALSE, "TAP version 13\n"); + } else - g_print ("# Subtest: %s\n", test_argv0); + { + g_test_tap_print (subtest_level > 0 ? subtest_level - 1 : 0, TRUE, + "Subtest: %s\n", test_argv0); + } - g_print ("%s# random seed: %s\n", tap_prefix, string2); + g_print ("random seed: %s\n", string2); } else if (g_test_verbose ()) { @@ -1026,9 +1121,9 @@ g_test_log (GTestLogType lbit, /* We only print the TAP "plan" (1..n) ahead of time if we did * not use the -p option to select specific tests to be run. */ if (string1[0] != 0) - g_print ("%s# Start of %s tests\n", tap_prefix, string1); + g_print ("Start of %s tests\n", string1); else if (test_paths == NULL) - g_print ("%s1..%d\n", tap_prefix, test_count); + g_test_tap_print (subtest_level, FALSE, "1..%d\n", test_count); } break; case G_TEST_LOG_STOP_SUITE: @@ -1038,9 +1133,9 @@ g_test_log (GTestLogType lbit, * we were using -p, we need to print how many tests we ran at * the end instead. */ if (string1[0] != 0) - g_print ("%s# End of %s tests\n", tap_prefix, string1); + g_print ("End of %s tests\n", string1); else if (test_paths != NULL) - g_print ("%s1..%d\n", tap_prefix, test_run_count); + g_test_tap_print (subtest_level, FALSE, "1..%d\n", test_run_count); } break; case G_TEST_LOG_STOP_CASE: @@ -1061,7 +1156,7 @@ g_test_log (GTestLogType lbit, else tap_output = g_string_new ("ok"); - if (is_subtest) + if (is_subtest ()) g_string_prepend (tap_output, TAP_SUBTEST_PREFIX); g_string_append_printf (tap_output, " %d %s", test_run_count, string1); @@ -1072,7 +1167,8 @@ g_test_log (GTestLogType lbit, else if (result == G_TEST_RUN_FAILURE && string2 != NULL) g_string_append_printf (tap_output, " - %s", string2); - g_print ("%s\n", tap_output->str); + g_string_append_c (tap_output, '\n'); + g_default_print_func (tap_output->str); g_string_free (g_steal_pointer (&tap_output), TRUE); } else if (g_test_verbose ()) @@ -1082,7 +1178,7 @@ g_test_log (GTestLogType lbit, if (fail && test_mode_fatal) { if (test_tap_log) - g_print ("Bail out!\n"); + g_test_tap_print (0, FALSE, "Bail out!\n"); g_abort (); } if (result == G_TEST_RUN_SKIPPED || result == G_TEST_RUN_INCOMPLETE) @@ -1091,56 +1187,25 @@ g_test_log (GTestLogType lbit, case G_TEST_LOG_SKIP_CASE: if (test_tap_log) { - g_print ("%sok %d %s # SKIP\n", tap_prefix, - test_run_count, string1); + g_test_tap_print (subtest_level, FALSE, "ok %d %s # SKIP\n", + test_run_count, string1); } break; case G_TEST_LOG_MIN_RESULT: if (test_tap_log) - g_print ("%s# min perf: %s\n", tap_prefix, string1); + g_print ("min perf: %s\n", string1); else if (g_test_verbose ()) g_print ("(MINPERF:%s)\n", string1); break; case G_TEST_LOG_MAX_RESULT: if (test_tap_log) - g_print ("%s# max perf: %s\n", tap_prefix, string1); + g_print ("max perf: %s\n", string1); else if (g_test_verbose ()) g_print ("(MAXPERF:%s)\n", string1); break; case G_TEST_LOG_MESSAGE: if (test_tap_log) - { - if (strchr (string1, '\n') == NULL) - g_print ("%s# %s\n", tap_prefix, string1); - else - { - GString *output = g_string_new (NULL); - const char *line = string1; - - do - { - const char *next = strchr (line, '\n'); - g_string_append (output, tap_prefix); - g_string_append (output, "# "); - - if (next) - { - g_string_append_len (output, line, next - line + 1); - line = next + 1; - } - else - { - g_string_append (output, line); - g_string_append_c (output, '\n'); - line = next; - } - } - while (line != NULL); - - g_print ("%s", output->str); - g_string_free (g_steal_pointer (&output), TRUE); - } - } + g_print ("%s\n", string1); else if (g_test_verbose ()) g_print ("(MSG: %s)\n", string1); break; @@ -1153,10 +1218,15 @@ g_test_log (GTestLogType lbit, while ((line = strchr (line, '\n'))) *(line++) = ' '; - if (is_subtest) - g_print ("%sBail out! %s\nBail out!\n", tap_prefix, message); + if (is_subtest ()) + { + g_test_tap_print (subtest_level, FALSE, "Bail out! %s\n", message); + g_test_tap_print (0, FALSE, "Bail out!\n"); + } else - g_print ("Bail out! %s\n", message); + { + g_test_tap_print (0, FALSE, "Bail out! %s\n", message); + } g_free (message); } @@ -3082,7 +3152,7 @@ test_should_run (const char *test_path, if (g_test_verbose ()) { if (test_tap_log) - g_print ("# skipping: %s\n", test_run_name); + g_print ("skipping: %s\n", test_run_name); else g_print ("GTest: skipping: %s\n", test_run_name); } @@ -3932,7 +4002,7 @@ g_test_trap_subprocess (const char *test_path, if (g_test_verbose ()) { if (test_tap_log) - g_print ("# subprocess: %s\n", test_path); + g_print ("subprocess: %s\n", test_path); else g_print ("GTest: subprocess: %s\n", test_path); } diff --git a/glib/tests/logging.c b/glib/tests/logging.c index 201a8f99f..ea9dcb825 100644 --- a/glib/tests/logging.c +++ b/glib/tests/logging.c @@ -374,18 +374,20 @@ test_print_handler (void) g_print ("bu ba"); g_assert_cmpint (my_print_count, ==, 1); - g_set_print_handler (NULL); - if (g_test_subprocess ()) { + g_set_print_handler (NULL); old_print_handler ("default handler\n"); g_print ("bu ba\n"); return; } + g_set_print_handler (old_print_handler); g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_stdout ("*default handler" LINE_END "*"); g_test_trap_assert_stdout ("*bu ba" LINE_END "*"); + g_test_trap_assert_stdout_unmatched ("*# default handler" LINE_END "*"); + g_test_trap_assert_stdout_unmatched ("*# bu ba" LINE_END "*"); g_test_trap_has_passed (); } @@ -401,15 +403,15 @@ test_printerr_handler (void) g_printerr ("bu ba"); g_assert_cmpint (my_print_count, ==, 1); - g_set_printerr_handler (NULL); - if (g_test_subprocess ()) { + g_set_printerr_handler (NULL); old_printerr_handler ("default handler\n"); g_printerr ("bu ba\n"); return; } + g_set_printerr_handler (old_printerr_handler); g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_stderr ("*default handler" LINE_END "*"); g_test_trap_assert_stderr ("*bu ba" LINE_END "*"); diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index 4d26221ea..878350449 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -93,6 +93,16 @@ test_message (void) g_test_message ("\nTests that multi\nline\nmessage\nworks with leading and trailing too\n"); } +static void +test_print (void) +{ + g_print ("Tests that single line message works\n"); + g_print ("test that multiple\nlines "); + g_print ("can be "); + g_print ("written "); + g_print ("separately\n"); +} + int main (int argc, char *argv[]) @@ -212,6 +222,10 @@ main (int argc, { g_test_add_func ("/message", test_message); } + else if (g_strcmp0 (argv1, "print") == 0) + { + g_test_add_func ("/print", test_print); + } else { g_assert_not_reached (); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index ed86f6e27..22f016292 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -2428,6 +2428,107 @@ test_tap_subtest_message (void) g_ptr_array_unref (argv); } +static void +test_tap_print (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **output_lines; + char **envp; + + g_test_summary ("Test the output of g_print() from the TAP output of a test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "print"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + /* Remove the G_TEST_ROOT_PROCESS env so it will be considered a standalone test */ + envp = g_get_environ (); + g_assert_nonnull (g_environ_getenv (envp, "G_TEST_ROOT_PROCESS")); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "G_TEST_ROOT_PROCESS"); + + g_spawn_sync (NULL, (char **) argv->pdata, envp, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + const char *expected_tap_header = "\n1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + output_lines = g_strsplit (interesting_lines, "\n", -1); + g_assert_cmpuint (g_strv_length (output_lines), >=, 3); + + guint i = 0; + g_assert_cmpstr (output_lines[i++], ==, "# Tests that single line message works"); + g_assert_cmpstr (output_lines[i++], ==, "# test that multiple"); + g_assert_cmpstr (output_lines[i++], ==, "# lines can be written separately"); + + g_free (output); + g_strfreev (envp); + g_strfreev (output_lines); + g_ptr_array_unref (argv); +} + +static void +test_tap_subtest_print (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **output_lines; + + g_test_summary ("Test the output of g_test_print() from the TAP output of a sub-test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "print"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + const char *expected_tap_header = "\n" TAP_SUBTEST_PREFIX "1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + interesting_lines += strlen (expected_tap_header); + + output_lines = g_strsplit (interesting_lines, "\n", -1); + g_assert_cmpuint (g_strv_length (output_lines), >=, 3); + + guint i = 0; + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# Tests that single line message works"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# test that multiple"); + g_assert_cmpstr (output_lines[i++], ==, TAP_SUBTEST_PREFIX "# lines can be written separately"); + + g_free (output); + g_strfreev (output_lines); + g_ptr_array_unref (argv); +} + static void test_tap_error (void) { @@ -2753,6 +2854,8 @@ main (int argc, g_test_add_func ("/tap/subtest/summary", test_tap_subtest_summary); g_test_add_func ("/tap/message", test_tap_message); g_test_add_func ("/tap/subtest/message", test_tap_subtest_message); + g_test_add_func ("/tap/print", test_tap_print); + g_test_add_func ("/tap/subtest/print", test_tap_subtest_print); g_test_add_func ("/tap/error", test_tap_error); g_test_add_func ("/tap/subtest/error", test_tap_subtest_error); g_test_add_func ("/tap/error-and-pass", test_tap_error_and_pass); From 03f5d0b060f3c933c60295568c5c3d1d6e27dd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 16 Jan 2023 17:51:19 +0100 Subject: [PATCH 28/29] gtestutils: Use test print handler to write subprocess output When using verbose logging, all the printing and the glib info and debug logs may end up being written in standard out, making meson TAP parser to be confused and to fail with TAP parsing errors. So, in such case write the subprocess output all at once using the the gtest printer so that we add proper formatting. Also do not write any gtest result message for subprocesses --- glib/gtestutils.c | 23 +++++++- glib/tests/testing-helper.c | 58 ++++++++++++++++++- glib/tests/testing.c | 108 ++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 486edf273..a03ff559d 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -1173,7 +1173,7 @@ g_test_log (GTestLogType lbit, } else if (g_test_verbose ()) g_print ("GTest: result: %s\n", g_test_result_names[result]); - else if (!g_test_quiet ()) + else if (!g_test_quiet () && !test_in_subprocess) g_print ("%s\n", g_test_result_names[result]); if (fail && test_mode_fatal) { @@ -3696,7 +3696,10 @@ child_read (GIOChannel *io, GIOCondition cond, gpointer user_data) { g_string_append_len (data->stdout_str, buf, nread); if (data->echo_stdout) - echo_file = stdout; + { + if G_UNLIKELY (!test_tap_log) + echo_file = stdout; + } } else { @@ -3777,6 +3780,22 @@ wait_for_child (GPid pid, g_main_loop_unref (data.loop); g_main_context_unref (context); + if (echo_stdout && test_tap_log && data.stdout_str->len > 0) + { + gboolean added_newline = FALSE; + + if (data.stdout_str->str[data.stdout_str->len - 1] != '\n') + { + g_string_append_c (data.stdout_str, '\n'); + added_newline = TRUE; + } + + g_test_print_handler_full (data.stdout_str->str, TRUE, TRUE, 1); + + if (added_newline) + g_string_truncate (data.stdout_str, data.stdout_str->len - 1); + } + test_trap_last_pid = pid; test_trap_last_status = data.child_status; test_trap_last_stdout = g_string_free (data.stdout_str, FALSE); diff --git a/glib/tests/testing-helper.c b/glib/tests/testing-helper.c index 878350449..da60f3e44 100644 --- a/glib/tests/testing-helper.c +++ b/glib/tests/testing-helper.c @@ -20,6 +20,7 @@ #include #include +#include #ifdef G_OS_WIN32 #include #include @@ -103,6 +104,45 @@ test_print (void) g_print ("separately\n"); } +static void +test_subprocess_stdout (void) +{ + if (g_test_subprocess ()) + { + printf ("Tests that single line message works\n"); + printf ("test that multiple\nlines "); + printf ("can be "); + printf ("written "); + printf ("separately\n"); + + puts ("And another line has been put"); + + return; + } + + g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); + g_test_trap_has_passed (); + + g_test_trap_assert_stdout ("/sub-stdout: Tests that single line message works\n*"); + g_test_trap_assert_stdout ("*\ntest that multiple\nlines can be written separately\n*"); + g_test_trap_assert_stdout ("*\nAnd another line has been put\n*"); +} + +static void +test_subprocess_stdout_no_nl (void) +{ + if (g_test_subprocess ()) + { + printf ("A message without trailing new line"); + return; + } + + g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_INHERIT_STDOUT); + g_test_trap_has_passed (); + + g_test_trap_assert_stdout ("/sub-stdout-no-nl: A message without trailing new line"); +} + int main (int argc, char *argv[]) @@ -226,9 +266,25 @@ main (int argc, { g_test_add_func ("/print", test_print); } + else if (g_strcmp0 (argv1, "subprocess-stdout") == 0) + { + g_test_add_func ("/sub-stdout", test_subprocess_stdout); + } + else if (g_strcmp0 (argv1, "subprocess-stdout-no-nl") == 0) + { + g_test_add_func ("/sub-stdout-no-nl", test_subprocess_stdout_no_nl); + } else { - g_assert_not_reached (); + if (g_test_subprocess ()) + { + g_test_add_func ("/sub-stdout", test_subprocess_stdout); + g_test_add_func ("/sub-stdout-no-nl", test_subprocess_stdout_no_nl); + } + else + { + g_assert_not_reached (); + } } return g_test_run (); diff --git a/glib/tests/testing.c b/glib/tests/testing.c index 22f016292..e0653857d 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -2529,6 +2529,112 @@ test_tap_subtest_print (void) g_ptr_array_unref (argv); } +static void +test_tap_subtest_stdout (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **output_lines; + + g_test_summary ("Test the stdout from the TAP output of a sub-test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "subprocess-stdout"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + const char *expected_tap_header = "\n" TAP_SUBTEST_PREFIX "1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + + interesting_lines = strstr (interesting_lines, TAP_SUBTEST_PREFIX "# /sub-stdout"); + g_assert_nonnull (interesting_lines); + + output_lines = g_strsplit (interesting_lines, "\n", -1); + g_assert_cmpuint (g_strv_length (output_lines), >=, 5); + + guint i = 0; + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "# /sub-stdout: Tests that single line message works"); + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "# test that multiple"); + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "# lines can be written separately"); + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "# And another line has been put"); + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "ok 1 /sub-stdout"); + + g_free (output); + g_strfreev (output_lines); + g_ptr_array_unref (argv); +} + +static void +test_tap_subtest_stdout_no_new_line (void) +{ + const char *testing_helper; + GPtrArray *argv; + GError *error = NULL; + int status; + gchar *output; + char **output_lines; + + g_test_summary ("Test the stdout from the TAP output of a sub-test."); + + testing_helper = g_test_get_filename (G_TEST_BUILT, "testing-helper" EXEEXT, NULL); + + argv = g_ptr_array_new (); + g_ptr_array_add (argv, (char *) testing_helper); + g_ptr_array_add (argv, "subprocess-stdout-no-nl"); + g_ptr_array_add (argv, "--tap"); + g_ptr_array_add (argv, NULL); + + g_spawn_sync (NULL, (char **) argv->pdata, NULL, + G_SPAWN_STDERR_TO_DEV_NULL, + NULL, NULL, &output, NULL, &status, + &error); + g_assert_no_error (error); + + g_spawn_check_wait_status (status, &error); + g_assert_no_error (error); + + const char *expected_tap_header = "\n" TAP_SUBTEST_PREFIX "1..1\n"; + const char *interesting_lines = strstr (output, expected_tap_header); + g_assert_nonnull (interesting_lines); + + interesting_lines = strstr (interesting_lines, TAP_SUBTEST_PREFIX "# /sub-stdout-no-nl"); + g_assert_nonnull (interesting_lines); + + output_lines = g_strsplit (interesting_lines, "\n", -1); + g_assert_cmpuint (g_strv_length (output_lines), >=, 2); + + guint i = 0; + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "# /sub-stdout-no-nl: A message without trailing new line"); + g_assert_cmpstr (output_lines[i++], ==, + TAP_SUBTEST_PREFIX "ok 1 /sub-stdout-no-nl"); + + g_free (output); + g_strfreev (output_lines); + g_ptr_array_unref (argv); +} + static void test_tap_error (void) { @@ -2856,6 +2962,8 @@ main (int argc, g_test_add_func ("/tap/subtest/message", test_tap_subtest_message); g_test_add_func ("/tap/print", test_tap_print); g_test_add_func ("/tap/subtest/print", test_tap_subtest_print); + g_test_add_func ("/tap/subtest/stdout", test_tap_subtest_stdout); + g_test_add_func ("/tap/subtest/stdout-no-new-line", test_tap_subtest_stdout_no_new_line); g_test_add_func ("/tap/error", test_tap_error); g_test_add_func ("/tap/subtest/error", test_tap_subtest_error); g_test_add_func ("/tap/error-and-pass", test_tap_error_and_pass); From 6a4f6c593c4ca532c70eb4c27dd246341aaa50f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 17 Jan 2023 19:12:55 +0100 Subject: [PATCH 29/29] gsettings: Skip tests in the proper way This will make TAP happier in reporting what's wrong --- gio/tests/gsettings.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index d3fd4289d..182e79e0a 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -798,7 +798,9 @@ test_l10n (void) str = NULL; } else - g_printerr ("warning: translation is not working... skipping test. "); + { + g_test_skip ("translation is not working"); + } g_setenv ("LC_MESSAGES", locale, TRUE); setlocale (LC_MESSAGES, locale); @@ -843,7 +845,7 @@ test_l10n_context (void) if (g_str_equal (dgettext ("test", "\"Unnamed\""), "\"Unbenannt\"")) settings_assert_cmpstr (settings, "backspace", ==, "Löschen"); else - g_printerr ("warning: translation is not working... skipping test. "); + g_test_skip ("translation is not working"); g_setenv ("LC_MESSAGES", locale, TRUE); setlocale (LC_MESSAGES, locale);