From 25dcdc7e8bfac8967f20fb2c0a628f5cf442188d Mon Sep 17 00:00:00 2001 From: Derek Mauro Date: Mon, 4 Apr 2022 07:38:23 -0700 Subject: [PATCH] Use the Abseil flags library when Abseil is present When built with `--define=absl=1` under Bazel, GoogleTest flags use ABSL_FLAG instead of GoogleTest's own implementation. There are some minor behavior differences in this mode. The most notable difference is that unrecognized flags result in a flag parsing error, and are not returned to the user though a modified argc/argv, unless they appear after the positional argument delimiter ("--"). For example, to pass a non-Abseil flag, you would have to do ./mytest --gtest_color=false -- --myflag=myvalue The documentation at https://abseil.io/docs/cpp/guides/flags may be helpful in understanding the behavior. There are some other minor differences. For example, passing --help results in the program returning 1 instead of 0. https://github.com/google/googletest/issues/3646 PiperOrigin-RevId: 439312700 Change-Id: Id696a25f50f24a5b1785c45ca8fa59794f86fd5c --- BUILD.bazel | 14 +++- WORKSPACE | 6 +- .../include/gmock/internal/gmock-port.h | 67 +++++++++++----- .../include/gtest/internal/custom/README.md | 14 ---- .../include/gtest/internal/gtest-port.h | 80 ++++++++++++------- googletest/src/gtest.cc | 33 +++++++- googletest/test/BUILD.bazel | 4 + googletest/test/gtest_help_test.py | 67 ++++++++++------ googletest/test/gtest_unittest.cc | 70 +++++++++++----- 9 files changed, 242 insertions(+), 113 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 1df5ff5f99..192f18e60f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -120,8 +120,14 @@ cc_library( linkopts = select({ ":qnx": ["-lregex"], ":windows": [], - ":freebsd": ["-lm", "-pthread"], - ":openbsd": ["-lm", "-pthread"], + ":freebsd": [ + "-lm", + "-pthread", + ], + ":openbsd": [ + "-lm", + "-pthread", + ], "//conditions:default": ["-pthread"], }), deps = select({ @@ -129,6 +135,10 @@ cc_library( "@com_google_absl//absl/debugging:failure_signal_handler", "@com_google_absl//absl/debugging:stacktrace", "@com_google_absl//absl/debugging:symbolize", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/flags:reflection", + "@com_google_absl//absl/flags:usage", "@com_google_absl//absl/strings", "@com_google_absl//absl/types:any", "@com_google_absl//absl/types:optional", diff --git a/WORKSPACE b/WORKSPACE index 7eb18eb984..842f1339b3 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -4,9 +4,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "com_google_absl", - sha256 = "aeba534f7307e36fe084b452299e49b97420667a8d28102cf9a0daeed340b859", - strip_prefix = "abseil-cpp-7971fb358ae376e016d2d4fc9327aad95659b25e", - urls = ["https://github.com/abseil/abseil-cpp/archive/7971fb358ae376e016d2d4fc9327aad95659b25e.zip"], # 2021-05-20T02:59:16Z + sha256 = "93451aaccbf6a9618df7182fdf9ecf281284d6418a0d66eff33ae0cf05eba417", + strip_prefix = "abseil-cpp-ec33f404bb16564a9aea3044cd8504d6885165b0", + urls = ["https://github.com/abseil/abseil-cpp/archive/ec33f404bb16564a9aea3044cd8504d6885165b0.zip"], # 2022-03-03T14:43:16Z ) http_archive( diff --git a/googlemock/include/gmock/internal/gmock-port.h b/googlemock/include/gmock/internal/gmock-port.h index f3e63c1463..bc18a25f34 100644 --- a/googlemock/include/gmock/internal/gmock-port.h +++ b/googlemock/include/gmock/internal/gmock-port.h @@ -42,7 +42,6 @@ #include #include - #include #include @@ -57,6 +56,11 @@ #include "gmock/internal/custom/gmock-port.h" #include "gtest/internal/gtest-port.h" +#if GTEST_HAS_ABSL +#include "absl/flags/declare.h" +#include "absl/flags/flag.h" +#endif + // For MS Visual C++, check the compiler version. At least VS 2015 is // required to compile Google Mock. #if defined(_MSC_VER) && _MSC_VER < 1900 @@ -65,26 +69,33 @@ // Macro for referencing flags. This is public as we want the user to // use this syntax to reference Google Mock flags. +#define GMOCK_FLAG_NAME_(name) gmock_##name #define GMOCK_FLAG(name) FLAGS_gmock_##name -#if !defined(GMOCK_DECLARE_bool_) +// Pick a command line flags implementation. +#if GTEST_HAS_ABSL + +// Macros for defining flags. +#define GMOCK_DEFINE_bool_(name, default_val, doc) \ + ABSL_FLAG(bool, GMOCK_FLAG_NAME_(name), default_val, doc) +#define GMOCK_DEFINE_int32_(name, default_val, doc) \ + ABSL_FLAG(int32_t, GMOCK_FLAG_NAME_(name), default_val, doc) +#define GMOCK_DEFINE_string_(name, default_val, doc) \ + ABSL_FLAG(std::string, GMOCK_FLAG_NAME_(name), default_val, doc) // Macros for declaring flags. -#define GMOCK_DECLARE_bool_(name) \ - namespace testing { \ - GTEST_API_ extern bool GMOCK_FLAG(name); \ - } \ - static_assert(true, "no-op to require trailing semicolon") -#define GMOCK_DECLARE_int32_(name) \ - namespace testing { \ - GTEST_API_ extern int32_t GMOCK_FLAG(name); \ - } \ - static_assert(true, "no-op to require trailing semicolon") -#define GMOCK_DECLARE_string_(name) \ - namespace testing { \ - GTEST_API_ extern ::std::string GMOCK_FLAG(name); \ - } \ - static_assert(true, "no-op to require trailing semicolon") +#define GMOCK_DECLARE_bool_(name) \ + ABSL_DECLARE_FLAG(bool, GMOCK_FLAG_NAME_(name)) +#define GMOCK_DECLARE_int32_(name) \ + ABSL_DECLARE_FLAG(int32_t, GMOCK_FLAG_NAME_(name)) +#define GMOCK_DECLARE_string_(name) \ + ABSL_DECLARE_FLAG(std::string, GMOCK_FLAG_NAME_(name)) + +#define GMOCK_FLAG_GET(name) ::absl::GetFlag(GMOCK_FLAG(name)) +#define GMOCK_FLAG_SET(name, value) \ + (void)(::absl::SetFlag(&GMOCK_FLAG(name), value)) + +#else // GTEST_HAS_ABSL // Macros for defining flags. #define GMOCK_DEFINE_bool_(name, default_val, doc) \ @@ -102,11 +113,27 @@ GTEST_API_ ::std::string GMOCK_FLAG(name) = (default_val); \ } \ static_assert(true, "no-op to require trailing semicolon") -#endif // !defined(GMOCK_DECLARE_bool_) -#if !defined(GMOCK_FLAG_GET) +// Macros for declaring flags. +#define GMOCK_DECLARE_bool_(name) \ + namespace testing { \ + GTEST_API_ extern bool GMOCK_FLAG(name); \ + } \ + static_assert(true, "no-op to require trailing semicolon") +#define GMOCK_DECLARE_int32_(name) \ + namespace testing { \ + GTEST_API_ extern int32_t GMOCK_FLAG(name); \ + } \ + static_assert(true, "no-op to require trailing semicolon") +#define GMOCK_DECLARE_string_(name) \ + namespace testing { \ + GTEST_API_ extern ::std::string GMOCK_FLAG(name); \ + } \ + static_assert(true, "no-op to require trailing semicolon") + #define GMOCK_FLAG_GET(name) ::testing::GMOCK_FLAG(name) #define GMOCK_FLAG_SET(name, value) (void)(::testing::GMOCK_FLAG(name) = value) -#endif // !defined(GMOCK_FLAG_GET) + +#endif // GTEST_HAS_ABSL #endif // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_ diff --git a/googletest/include/gtest/internal/custom/README.md b/googletest/include/gtest/internal/custom/README.md index 0af3539abf..cb49e2c754 100644 --- a/googletest/include/gtest/internal/custom/README.md +++ b/googletest/include/gtest/internal/custom/README.md @@ -15,20 +15,6 @@ The custom directory is an injection point for custom user configurations. The following macros can be defined: -### Flag related macros: - -* `GTEST_FLAG(flag_name)` -* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its - own flagfile flag parsing. -* `GTEST_DECLARE_bool_(name)` -* `GTEST_DECLARE_int32_(name)` -* `GTEST_DECLARE_string_(name)` -* `GTEST_DEFINE_bool_(name, default_val, doc)` -* `GTEST_DEFINE_int32_(name, default_val, doc)` -* `GTEST_DEFINE_string_(name, default_val, doc)` -* `GTEST_FLAG_GET(flag_name)` -* `GTEST_FLAG_SET(flag_name, value)` - ### Logging: * `GTEST_LOG_(severity)` diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index e178782ccd..574af24f25 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -240,8 +240,6 @@ // BiggestInt - the biggest signed integer type. // // Command-line utilities: -// GTEST_DECLARE_*() - declares a flag. -// GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: @@ -287,6 +285,12 @@ #include "gtest/internal/custom/gtest-port.h" #include "gtest/internal/gtest-port-arch.h" +#if GTEST_HAS_ABSL +#include "absl/flags/declare.h" +#include "absl/flags/flag.h" +#include "absl/flags/reflection.h" +#endif + #if !defined(GTEST_DEV_EMAIL_) #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" @@ -2157,32 +2161,37 @@ using TimeInMillis = int64_t; // Represents time in milliseconds. // Macro for referencing flags. #if !defined(GTEST_FLAG) +#define GTEST_FLAG_NAME_(name) gtest_##name #define GTEST_FLAG(name) FLAGS_gtest_##name #endif // !defined(GTEST_FLAG) -#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) -#define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 -#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) +// Pick a command line flags implementation. +#if GTEST_HAS_ABSL -#if !defined(GTEST_DECLARE_bool_) -#define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + ABSL_FLAG(bool, GTEST_FLAG_NAME_(name), default_val, doc) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + ABSL_FLAG(int32_t, GTEST_FLAG_NAME_(name), default_val, doc) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + ABSL_FLAG(std::string, GTEST_FLAG_NAME_(name), default_val, doc) // Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) \ - namespace testing { \ - GTEST_API_ extern bool GTEST_FLAG(name); \ - } \ - static_assert(true, "no-op to require trailing semicolon") -#define GTEST_DECLARE_int32_(name) \ - namespace testing { \ - GTEST_API_ extern std::int32_t GTEST_FLAG(name); \ - } \ - static_assert(true, "no-op to require trailing semicolon") -#define GTEST_DECLARE_string_(name) \ - namespace testing { \ - GTEST_API_ extern ::std::string GTEST_FLAG(name); \ - } \ - static_assert(true, "no-op to require trailing semicolon") +#define GTEST_DECLARE_bool_(name) \ + ABSL_DECLARE_FLAG(bool, GTEST_FLAG_NAME_(name)) +#define GTEST_DECLARE_int32_(name) \ + ABSL_DECLARE_FLAG(int32_t, GTEST_FLAG_NAME_(name)) +#define GTEST_DECLARE_string_(name) \ + ABSL_DECLARE_FLAG(std::string, GTEST_FLAG_NAME_(name)) + +#define GTEST_FLAG_SAVER_ ::absl::FlagSaver + +#define GTEST_FLAG_GET(name) ::absl::GetFlag(GTEST_FLAG(name)) +#define GTEST_FLAG_SET(name, value) \ + (void)(::absl::SetFlag(>EST_FLAG(name), value)) +#define GTEST_USE_OWN_FLAGFILE_FLAG_ 0 + +#else // GTEST_HAS_ABSL // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ @@ -2201,12 +2210,30 @@ using TimeInMillis = int64_t; // Represents time in milliseconds. } \ static_assert(true, "no-op to require trailing semicolon") -#endif // !defined(GTEST_DECLARE_bool_) +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) \ + namespace testing { \ + GTEST_API_ extern bool GTEST_FLAG(name); \ + } \ + static_assert(true, "no-op to require trailing semicolon") +#define GTEST_DECLARE_int32_(name) \ + namespace testing { \ + GTEST_API_ extern std::int32_t GTEST_FLAG(name); \ + } \ + static_assert(true, "no-op to require trailing semicolon") +#define GTEST_DECLARE_string_(name) \ + namespace testing { \ + GTEST_API_ extern ::std::string GTEST_FLAG(name); \ + } \ + static_assert(true, "no-op to require trailing semicolon") + +#define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver -#if !defined(GTEST_FLAG_GET) #define GTEST_FLAG_GET(name) ::testing::GTEST_FLAG(name) #define GTEST_FLAG_SET(name, value) (void)(::testing::GTEST_FLAG(name) = value) -#endif // !defined(GTEST_FLAG_GET) +#define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 + +#endif // GTEST_HAS_ABSL // Thread annotations #if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) @@ -2362,8 +2389,7 @@ template using Variant = ::std::variant; } // namespace internal } // namespace testing - // The case where absl is configured NOT to alias std::variant is not - // supported. +// The case where absl is configured NOT to alias std::variant is not supported. #endif // __has_include() && __cplusplus >= 201703L #endif // __has_include #endif // GTEST_HAS_ABSL diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 10cff8e847..acfb941e74 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -136,7 +136,10 @@ #include "absl/debugging/failure_signal_handler.h" #include "absl/debugging/stacktrace.h" #include "absl/debugging/symbolize.h" +#include "absl/flags/parse.h" +#include "absl/flags/usage.h" #include "absl/strings/str_cat.h" +#include "absl/strings/str_replace.h" #endif // GTEST_HAS_ABSL namespace testing { @@ -6590,9 +6593,7 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { LoadFlagsFromFile(flagfile_value); remove_flag = true; #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { + } else if (arg_string == "--help" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; @@ -6627,7 +6628,27 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { +#if GTEST_HAS_ABSL + if (*argc > 0) { + // absl::ParseCommandLine() requires *argc > 0. + auto positional_args = absl::flags_internal::ParseCommandLineImpl( + *argc, argv, absl::flags_internal::ArgvListAction::kRemoveParsedArgs, + absl::flags_internal::UsageFlagsAction::kHandleUsage, + absl::flags_internal::OnUndefinedFlag::kReportUndefined); + // Any command-line positional arguments not part of any command-line flag + // (or arguments to a flag) are copied back out to argv, with the program + // invocation name at position 0, and argc is resized. This includes + // positional arguments after the flag-terminating delimiter '--'. + // See https://abseil.io/docs/cpp/guides/flags. + std::copy(positional_args.begin(), positional_args.end(), argv); + if (static_cast(positional_args.size()) < *argc) { + argv[positional_args.size()] = nullptr; + *argc = static_cast(positional_args.size()); + } + } +#else ParseGoogleTestFlagsOnlyImpl(argc, argv); +#endif // Fix the value of *_NSGetArgc() on macOS, but if and only if // *_NSGetArgv() == argv @@ -6662,6 +6683,12 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { #if GTEST_HAS_ABSL absl::InitializeSymbolizer(g_argvs[0].c_str()); + + // When using the Abseil Flags library, set the program usage message to the + // help message, but remove the color-encoding from the message first. + absl::SetProgramUsageMessage(absl::StrReplaceAll( + kColorEncodedHelpMessage, + {{"@D", ""}, {"@R", ""}, {"@G", ""}, {"@Y", ""}, {"@@", "@"}})); #endif // GTEST_HAS_ABSL ParseGoogleTestFlagsOnly(argc, argv); diff --git a/googletest/test/BUILD.bazel b/googletest/test/BUILD.bazel index 8fd595c705..7754c1303f 100644 --- a/googletest/test/BUILD.bazel +++ b/googletest/test/BUILD.bazel @@ -174,6 +174,10 @@ py_test( name = "gtest_help_test", size = "small", srcs = ["gtest_help_test.py"], + args = select({ + "//:has_absl": ["--has_absl_flags"], + "//conditions:default": [], + }), data = [":gtest_help_test_"], deps = [":gtest_test_utils"], ) diff --git a/googletest/test/gtest_help_test.py b/googletest/test/gtest_help_test.py index 6d2dde00db..642ab86506 100755 --- a/googletest/test/gtest_help_test.py +++ b/googletest/test/gtest_help_test.py @@ -39,6 +39,7 @@ import os import re +import sys from googletest.test import gtest_test_utils @@ -52,16 +53,15 @@ FLAG_PREFIX = '--gtest_' DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style' STREAM_RESULT_TO_FLAG = FLAG_PREFIX + 'stream_result_to' -UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing' +UNKNOWN_GTEST_PREFIXED_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing' LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' -INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG), - re.sub('^--', '/', LIST_TESTS_FLAG), - re.sub('_', '-', LIST_TESTS_FLAG)] INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing' SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess( [PROGRAM_PATH, LIST_TESTS_FLAG]).output +HAS_ABSL_FLAGS = '--has_absl_flags' in sys.argv + # The help message must match this regex. HELP_REGEX = re.compile( FLAG_PREFIX + r'list_tests.*' + @@ -111,18 +111,37 @@ def TestHelpFlag(self, flag): """ exit_code, output = RunWithFlag(flag) - self.assertEquals(0, exit_code) - self.assert_(HELP_REGEX.search(output), output) + if HAS_ABSL_FLAGS: + # The Abseil flags library prints the ProgramUsageMessage() with + # --help and returns 1. + self.assertEqual(1, exit_code) + else: + self.assertEqual(0, exit_code) + + self.assertTrue(HELP_REGEX.search(output), output) if IS_LINUX or IS_GNUHURD or IS_GNUKFREEBSD or IS_OPENBSD: - self.assert_(STREAM_RESULT_TO_FLAG in output, output) + self.assertIn(STREAM_RESULT_TO_FLAG, output) else: - self.assert_(STREAM_RESULT_TO_FLAG not in output, output) + self.assertNotIn(STREAM_RESULT_TO_FLAG, output) if SUPPORTS_DEATH_TESTS and not IS_WINDOWS: - self.assert_(DEATH_TEST_STYLE_FLAG in output, output) + self.assertIn(DEATH_TEST_STYLE_FLAG, output) else: - self.assert_(DEATH_TEST_STYLE_FLAG not in output, output) + self.assertNotIn(DEATH_TEST_STYLE_FLAG, output) + + def TestUnknownFlagWithAbseil(self, flag): + """Verifies correct behavior when an unknown flag is specified. + + The right message must be printed and the tests must + skipped when the given flag is specified. + + Args: + flag: A flag to pass to the binary or None. + """ + exit_code, output = RunWithFlag(flag) + self.assertEqual(1, exit_code) + self.assertIn('ERROR: Unknown command line flag', output) def TestNonHelpFlag(self, flag): """Verifies correct behavior when no help flag is specified. @@ -135,27 +154,21 @@ def TestNonHelpFlag(self, flag): """ exit_code, output = RunWithFlag(flag) - self.assert_(exit_code != 0) - self.assert_(not HELP_REGEX.search(output), output) + self.assertNotEqual(exit_code, 0) + self.assertFalse(HELP_REGEX.search(output), output) def testPrintsHelpWithFullFlag(self): self.TestHelpFlag('--help') - def testPrintsHelpWithShortFlag(self): - self.TestHelpFlag('-h') - - def testPrintsHelpWithQuestionFlag(self): - self.TestHelpFlag('-?') - - def testPrintsHelpWithWindowsStyleQuestionFlag(self): - self.TestHelpFlag('/?') - def testPrintsHelpWithUnrecognizedGoogleTestFlag(self): - self.TestHelpFlag(UNKNOWN_FLAG) - - def testPrintsHelpWithIncorrectFlagStyle(self): - for incorrect_flag in INCORRECT_FLAG_VARIANTS: - self.TestHelpFlag(incorrect_flag) + # The behavior is slightly different when Abseil flags is + # used. Abseil flags rejects all unknown flags, while the builtin + # GTest flags implementation interprets an unknown flag with a + # '--gtest_' prefix as a request for help. + if HAS_ABSL_FLAGS: + self.TestUnknownFlagWithAbseil(UNKNOWN_GTEST_PREFIXED_FLAG) + else: + self.TestHelpFlag(UNKNOWN_GTEST_PREFIXED_FLAG) def testRunsTestsWithoutHelpFlag(self): """Verifies that when no help flag is specified, the tests are run @@ -171,4 +184,6 @@ def testRunsTestsWithGtestInternalFlag(self): if __name__ == '__main__': + if '--has_absl_flags' in sys.argv: + sys.argv.remove('--has_absl_flags') gtest_test_utils.Main() diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 9b2689946d..8ed0921b7a 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -5770,15 +5770,6 @@ TEST_F(ParseFlagsTest, FailFast) { GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::FailFast(true), false); } -// Tests parsing a bad --gtest_filter flag. -TEST_F(ParseFlagsTest, FilterBad) { - const char* argv[] = {"foo.exe", "--gtest_filter", nullptr}; - - const char* argv2[] = {"foo.exe", "--gtest_filter", nullptr}; - - GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true); -} - // Tests parsing an empty --gtest_filter flag. TEST_F(ParseFlagsTest, FilterEmpty) { const char* argv[] = {"foo.exe", "--gtest_filter=", nullptr}; @@ -5931,15 +5922,6 @@ TEST_F(ParseFlagsTest, ListTestsFalse_F) { GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false); } -// Tests parsing --gtest_output (invalid). -TEST_F(ParseFlagsTest, OutputEmpty) { - const char* argv[] = {"foo.exe", "--gtest_output", nullptr}; - - const char* argv2[] = {"foo.exe", "--gtest_output", nullptr}; - - GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true); -} - // Tests parsing --gtest_output=xml TEST_F(ParseFlagsTest, OutputXml) { const char* argv[] = {"foo.exe", "--gtest_output=xml", nullptr}; @@ -6179,6 +6161,58 @@ TEST_F(ParseFlagsTest, ThrowOnFailureTrue) { GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); } +// Tests parsing a bad --gtest_filter flag. +TEST_F(ParseFlagsTest, FilterBad) { + const char* argv[] = {"foo.exe", "--gtest_filter", nullptr}; + + const char* argv2[] = {"foo.exe", "--gtest_filter", nullptr}; + +#if GTEST_HAS_ABSL && GTEST_HAS_DEATH_TEST + // Invalid flag arguments are a fatal error when using the Abseil Flags. + EXPECT_EXIT(GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true), + testing::ExitedWithCode(1), + "ERROR: Missing the value for the flag 'gtest_filter'"); +#elif !GTEST_HAS_ABSL + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true); +#else + static_cast(argv); + static_cast(argv2); +#endif +} + +// Tests parsing --gtest_output (invalid). +TEST_F(ParseFlagsTest, OutputEmpty) { + const char* argv[] = {"foo.exe", "--gtest_output", nullptr}; + + const char* argv2[] = {"foo.exe", "--gtest_output", nullptr}; + +#if GTEST_HAS_ABSL && GTEST_HAS_DEATH_TEST + // Invalid flag arguments are a fatal error when using the Abseil Flags. + EXPECT_EXIT(GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true), + testing::ExitedWithCode(1), + "ERROR: Missing the value for the flag 'gtest_output'"); +#elif !GTEST_HAS_ABSL + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true); +#else + static_cast(argv); + static_cast(argv2); +#endif +} + +#if GTEST_HAS_ABSL +TEST_F(ParseFlagsTest, AbseilPositionalFlags) { + const char* argv[] = {"foo.exe", "--gtest_throw_on_failure=1", "--", + "--other_flag", nullptr}; + + // When using Abseil flags, it should be possible to pass flags not recognized + // using "--" to delimit positional arguments. These flags should be returned + // though argv. + const char* argv2[] = {"foo.exe", "--other_flag", nullptr}; + + GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false); +} +#endif + #if GTEST_OS_WINDOWS // Tests parsing wide strings. TEST_F(ParseFlagsTest, WideStrings) {