diff options
Diffstat (limited to 'absl/flags/parse_test.cc')
-rw-r--r-- | absl/flags/parse_test.cc | 346 |
1 files changed, 252 insertions, 94 deletions
diff --git a/absl/flags/parse_test.cc b/absl/flags/parse_test.cc index 8dc91db2..cd32efc8 100644 --- a/absl/flags/parse_test.cc +++ b/absl/flags/parse_test.cc @@ -18,6 +18,7 @@ #include <stdlib.h> #include <fstream> +#include <iostream> #include <string> #include <vector> @@ -25,7 +26,6 @@ #include "gtest/gtest.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/scoped_set_env.h" -#include "absl/flags/declare.h" #include "absl/flags/flag.h" #include "absl/flags/internal/parse.h" #include "absl/flags/internal/usage.h" @@ -39,6 +39,36 @@ #include <windows.h> #endif +// Define 125 similar flags to test kMaxHints for flag suggestions. +#define FLAG_MULT(x) F3(x) +#define TEST_FLAG_HEADER FLAG_HEADER_ + +#define F(name) ABSL_FLAG(int, name, 0, ""); + +#define F1(name) \ + F(name##1); \ + F(name##2); \ + F(name##3); \ + F(name##4); \ + F(name##5); +/**/ +#define F2(name) \ + F1(name##1); \ + F1(name##2); \ + F1(name##3); \ + F1(name##4); \ + F1(name##5); +/**/ +#define F3(name) \ + F2(name##1); \ + F2(name##2); \ + F2(name##3); \ + F2(name##4); \ + F2(name##5); +/**/ + +FLAG_MULT(TEST_FLAG_HEADER) + namespace { using absl::base_internal::ScopedSetEnv; @@ -168,7 +198,7 @@ constexpr const char* const ff2_data[] = { // Builds flagfile flag in the flagfile_flag buffer and returns it. This // function also creates a temporary flagfile based on FlagfileData input. // We create a flagfile in a temporary directory with the name specified in -// FlagfileData and populate it with lines specifed in FlagfileData. If $0 is +// FlagfileData and populate it with lines specified in FlagfileData. If $0 is // referenced in any of the lines in FlagfileData they are replaced with // temporary directory location. This way we can test inclusion of one flagfile // from another flagfile. @@ -206,7 +236,9 @@ ABSL_RETIRED_FLAG(std::string, legacy_str, "l", ""); namespace { namespace flags = absl::flags_internal; +using testing::AllOf; using testing::ElementsAreArray; +using testing::HasSubstr; class ParseTest : public testing::Test { public: @@ -219,6 +251,38 @@ class ParseTest : public testing::Test { // -------------------------------------------------------------------- template <int N> +flags::HelpMode InvokeParseAbslOnlyImpl(const char* (&in_argv)[N]) { + std::vector<char*> positional_args; + std::vector<absl::UnrecognizedFlag> unrecognized_flags; + + return flags::ParseAbseilFlagsOnlyImpl(N, const_cast<char**>(in_argv), + positional_args, unrecognized_flags, + flags::UsageFlagsAction::kHandleUsage); +} + +// -------------------------------------------------------------------- + +template <int N> +void InvokeParseAbslOnly(const char* (&in_argv)[N]) { + std::vector<char*> positional_args; + std::vector<absl::UnrecognizedFlag> unrecognized_flags; + + absl::ParseAbseilFlagsOnly(2, const_cast<char**>(in_argv), positional_args, + unrecognized_flags); +} + +// -------------------------------------------------------------------- + +template <int N> +std::vector<char*> InvokeParseCommandLineImpl(const char* (&in_argv)[N]) { + return flags::ParseCommandLineImpl( + N, const_cast<char**>(in_argv), flags::UsageFlagsAction::kHandleUsage, + flags::OnUndefinedFlag::kAbortIfUndefined, std::cerr); +} + +// -------------------------------------------------------------------- + +template <int N> std::vector<char*> InvokeParse(const char* (&in_argv)[N]) { return absl::ParseCommandLine(N, const_cast<char**>(in_argv)); } @@ -565,6 +629,49 @@ TEST_F(ParseDeathTest, TestInvalidUDTFlagFormat) { // -------------------------------------------------------------------- +TEST_F(ParseDeathTest, TestFlagSuggestions) { + const char* in_args1[] = { + "testbin", + "--legacy_boo", + }; + EXPECT_DEATH_IF_SUPPORTED( + InvokeParse(in_args1), + "Unknown command line flag 'legacy_boo'. Did you mean: legacy_bool ?"); + + const char* in_args2[] = {"testbin", "--foo", "--undefok=foo1"}; + EXPECT_DEATH_IF_SUPPORTED( + InvokeParse(in_args2), + "Unknown command line flag 'foo'. Did you mean: foo1 \\(undefok\\)?"); + + const char* in_args3[] = { + "testbin", + "--nolegacy_ino", + }; + EXPECT_DEATH_IF_SUPPORTED(InvokeParse(in_args3), + "Unknown command line flag 'nolegacy_ino'. Did " + "you mean: nolegacy_bool, legacy_int ?"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, GetHints) { + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("legacy_boo"), + testing::ContainerEq(std::vector<std::string>{"legacy_bool"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_itn"), + testing::ContainerEq(std::vector<std::string>{"legacy_int"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_int1"), + testing::ContainerEq(std::vector<std::string>{"legacy_int"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_int"), + testing::ContainerEq(std::vector<std::string>{"legacy_int"})); + EXPECT_THAT(absl::flags_internal::GetMisspellingHints("nolegacy_ino"), + testing::ContainerEq( + std::vector<std::string>{"nolegacy_bool", "legacy_int"})); + EXPECT_THAT( + absl::flags_internal::GetMisspellingHints("FLAG_HEADER_000").size(), 100); +} + +// -------------------------------------------------------------------- + TEST_F(ParseTest, TestLegacyFlags) { const char* in_args1[] = { "testbin", @@ -780,129 +887,66 @@ TEST_F(ParseTest, TestReadingFlagsFromEnvMoxedWithRegularFlags) { // -------------------------------------------------------------------- -TEST_F(ParseTest, TestKeepParsedArgs) { - const char* in_args1[] = { - "testbin", "arg1", "--bool_flag", - "--int_flag=211", "arg2", "--double_flag=1.1", - "--string_flag", "asd", "--", - "arg3", "arg4", - }; - - auto out_args1 = InvokeParse(in_args1); - - EXPECT_THAT( - out_args1, - ElementsAreArray({absl::string_view("testbin"), absl::string_view("arg1"), - absl::string_view("arg2"), absl::string_view("arg3"), - absl::string_view("arg4")})); - - auto out_args2 = flags::ParseCommandLineImpl( - 11, const_cast<char**>(in_args1), flags::ArgvListAction::kKeepParsedArgs, - flags::UsageFlagsAction::kHandleUsage, - flags::OnUndefinedFlag::kAbortIfUndefined); - - EXPECT_THAT( - out_args2, - ElementsAreArray({absl::string_view("testbin"), - absl::string_view("--bool_flag"), - absl::string_view("--int_flag=211"), - absl::string_view("--double_flag=1.1"), - absl::string_view("--string_flag"), - absl::string_view("asd"), absl::string_view("--"), - absl::string_view("arg1"), absl::string_view("arg2"), - absl::string_view("arg3"), absl::string_view("arg4")})); -} - -// -------------------------------------------------------------------- - -TEST_F(ParseTest, TestIgnoreUndefinedFlags) { +TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) { const char* in_args1[] = { "testbin", - "arg1", - "--undef_flag=aa", - "--int_flag=21", + "--help", }; - auto out_args1 = flags::ParseCommandLineImpl( - 4, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs, - flags::UsageFlagsAction::kHandleUsage, - flags::OnUndefinedFlag::kIgnoreUndefined); - - EXPECT_THAT(out_args1, ElementsAreArray({absl::string_view("testbin"), - absl::string_view("arg1")})); - - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 21); + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kImportant); + EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), ""); const char* in_args2[] = { "testbin", - "arg1", - "--undef_flag=aa", - "--string_flag=AA", + "--help", + "--int_flag=3", }; - auto out_args2 = flags::ParseCommandLineImpl( - 4, const_cast<char**>(in_args2), flags::ArgvListAction::kKeepParsedArgs, - flags::UsageFlagsAction::kHandleUsage, - flags::OnUndefinedFlag::kIgnoreUndefined); + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args2), flags::HelpMode::kImportant); + EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); - EXPECT_THAT( - out_args2, - ElementsAreArray( - {absl::string_view("testbin"), absl::string_view("--undef_flag=aa"), - absl::string_view("--string_flag=AA"), absl::string_view("arg1")})); + const char* in_args3[] = {"testbin", "--help", "some_positional_arg"}; - EXPECT_EQ(absl::GetFlag(FLAGS_string_flag), "AA"); + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args3), flags::HelpMode::kImportant); } // -------------------------------------------------------------------- -TEST_F(ParseDeathTest, TestSimpleHelpFlagHandling) { +TEST_F(ParseTest, TestSubstringHelpFlagHandling) { const char* in_args1[] = { "testbin", - "--help", - }; - - EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(1), ""); - - const char* in_args2[] = { - "testbin", - "--help", - "--int_flag=3", + "--help=abcd", }; - auto out_args2 = flags::ParseCommandLineImpl( - 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs, - flags::UsageFlagsAction::kIgnoreUsage, - flags::OnUndefinedFlag::kAbortIfUndefined); - - EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant); - EXPECT_EQ(absl::GetFlag(FLAGS_int_flag), 3); + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kMatch); + EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd"); } // -------------------------------------------------------------------- -TEST_F(ParseDeathTest, TestSubstringHelpFlagHandling) { +TEST_F(ParseDeathTest, TestVersionHandling) { const char* in_args1[] = { "testbin", - "--help=abcd", + "--version", }; - auto out_args1 = flags::ParseCommandLineImpl( - 2, const_cast<char**>(in_args1), flags::ArgvListAction::kRemoveParsedArgs, - flags::UsageFlagsAction::kIgnoreUsage, - flags::OnUndefinedFlag::kAbortIfUndefined); + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kVersion); +} - EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kMatch); - EXPECT_EQ(flags::GetFlagsHelpMatchSubstr(), "abcd"); +// -------------------------------------------------------------------- + +TEST_F(ParseTest, TestCheckArgsHandling) { + const char* in_args1[] = {"testbin", "--only_check_args", "--int_flag=211"}; - const char* in_args2[] = {"testbin", "--help", "some_positional_arg"}; + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args1), flags::HelpMode::kOnlyCheckArgs); + EXPECT_EXIT(InvokeParseAbslOnly(in_args1), testing::ExitedWithCode(0), ""); + EXPECT_EXIT(InvokeParse(in_args1), testing::ExitedWithCode(0), ""); - auto out_args2 = flags::ParseCommandLineImpl( - 3, const_cast<char**>(in_args2), flags::ArgvListAction::kRemoveParsedArgs, - flags::UsageFlagsAction::kIgnoreUsage, - flags::OnUndefinedFlag::kAbortIfUndefined); + const char* in_args2[] = {"testbin", "--only_check_args", "--unknown_flag=a"}; - EXPECT_EQ(flags::GetFlagsHelpMode(), flags::HelpMode::kImportant); + EXPECT_EQ(InvokeParseAbslOnlyImpl(in_args2), flags::HelpMode::kOnlyCheckArgs); + EXPECT_EXIT(InvokeParseAbslOnly(in_args2), testing::ExitedWithCode(0), ""); + EXPECT_EXIT(InvokeParse(in_args2), testing::ExitedWithCode(1), ""); } // -------------------------------------------------------------------- @@ -927,4 +971,118 @@ TEST_F(ParseTest, WasPresentOnCommandLine) { // -------------------------------------------------------------------- +TEST_F(ParseTest, ParseAbseilFlagsOnlySuccess) { + const char* in_args[] = { + "testbin", + "arg1", + "--bool_flag", + "--int_flag=211", + "arg2", + "--double_flag=1.1", + "--undef_flag1", + "--undef_flag2=123", + "--string_flag", + "asd", + "--", + "--some_flag", + "arg4", + }; + + std::vector<char*> positional_args; + std::vector<absl::UnrecognizedFlag> unrecognized_flags; + + absl::ParseAbseilFlagsOnly(13, const_cast<char**>(in_args), positional_args, + unrecognized_flags); + EXPECT_THAT(positional_args, + ElementsAreArray( + {absl::string_view("testbin"), absl::string_view("arg1"), + absl::string_view("arg2"), absl::string_view("--some_flag"), + absl::string_view("arg4")})); + EXPECT_THAT(unrecognized_flags, + ElementsAreArray( + {absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv, + "undef_flag1"), + absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv, + "undef_flag2")})); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, ParseAbseilFlagsOnlyFailure) { + const char* in_args[] = { + "testbin", + "--int_flag=21.1", + }; + + EXPECT_DEATH_IF_SUPPORTED( + InvokeParseAbslOnly(in_args), + "Illegal value '21.1' specified for flag 'int_flag'"); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, UndefOkFlagsAreIgnored) { + const char* in_args[] = { + "testbin", "--undef_flag1", + "--undef_flag2=123", "--undefok=undef_flag2", + "--undef_flag3", "value", + }; + + std::vector<char*> positional_args; + std::vector<absl::UnrecognizedFlag> unrecognized_flags; + + absl::ParseAbseilFlagsOnly(6, const_cast<char**>(in_args), positional_args, + unrecognized_flags); + EXPECT_THAT(positional_args, ElementsAreArray({absl::string_view("testbin"), + absl::string_view("value")})); + EXPECT_THAT(unrecognized_flags, + ElementsAreArray( + {absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv, + "undef_flag1"), + absl::UnrecognizedFlag(absl::UnrecognizedFlag::kFromArgv, + "undef_flag3")})); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseTest, AllUndefOkFlagsAreIgnored) { + const char* in_args[] = { + "testbin", + "--undef_flag1", + "--undef_flag2=123", + "--undefok=undef_flag2,undef_flag1,undef_flag3", + "--undef_flag3", + "value", + "--", + "--undef_flag4", + }; + + std::vector<char*> positional_args; + std::vector<absl::UnrecognizedFlag> unrecognized_flags; + + absl::ParseAbseilFlagsOnly(8, const_cast<char**>(in_args), positional_args, + unrecognized_flags); + EXPECT_THAT(positional_args, + ElementsAreArray({absl::string_view("testbin"), + absl::string_view("value"), + absl::string_view("--undef_flag4")})); + EXPECT_THAT(unrecognized_flags, testing::IsEmpty()); +} + +// -------------------------------------------------------------------- + +TEST_F(ParseDeathTest, ExitOnUnrecognizedFlagPrintsHelp) { + const char* in_args[] = { + "testbin", + "--undef_flag1", + "--help=int_flag", + }; + + EXPECT_EXIT(InvokeParseCommandLineImpl(in_args), testing::ExitedWithCode(1), + AllOf(HasSubstr("Unknown command line flag 'undef_flag1'"), + HasSubstr("Try --helpfull to get a list of all flags"))); +} + +// -------------------------------------------------------------------- + } // namespace |