| // Copyright (c) 2023 Google LLC. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "tools/util/flags.h" | |
| #include "gmock/gmock.h" | |
| #ifdef UTIL_FLAGS_FLAG | |
| #undef UTIL_FLAGS_FLAG | |
| #define UTIL_FLAGS_FLAG(Type, Prefix, Name, Default, Required, IsShort) \ | |
| flags::Flag<Type> Name(Default); \ | |
| flags::FlagRegistration Name##_registration(Name, Prefix #Name, Required, \ | |
| IsShort) | |
| #else | |
| #error \ | |
| "UTIL_FLAGS_FLAG is not defined. Either flags.h is not included of the flag name changed." | |
| #endif | |
| class FlagTest : public ::testing::Test { | |
| protected: | |
| void SetUp() override { flags::FlagList::reset(); } | |
| }; | |
| TEST_F(FlagTest, NoFlags) { | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, DashIsPositional) { | |
| const char* argv[] = {"binary", "-", nullptr}; | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(flags::positional_arguments.size(), 1); | |
| EXPECT_EQ(flags::positional_arguments[0], "-"); | |
| } | |
| TEST_F(FlagTest, Positional) { | |
| const char* argv[] = {"binary", "A", "BCD", nullptr}; | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(flags::positional_arguments.size(), 2); | |
| EXPECT_EQ(flags::positional_arguments[0], "A"); | |
| EXPECT_EQ(flags::positional_arguments[1], "BCD"); | |
| } | |
| TEST_F(FlagTest, MissingRequired) { | |
| FLAG_SHORT_bool(g, false, true); | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, BooleanShortValue) { | |
| FLAG_SHORT_bool(g, false, false); | |
| const char* argv[] = {"binary", "-g", nullptr}; | |
| EXPECT_FALSE(g.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_TRUE(g.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, BooleanShortDefaultValue) { | |
| FLAG_SHORT_bool(g, true, false); | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_TRUE(g.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_TRUE(g.value()); | |
| } | |
| TEST_F(FlagTest, BooleanLongValueNotParsed) { | |
| FLAG_SHORT_bool(g, false, false); | |
| const char* argv[] = {"binary", "-g", "false", nullptr}; | |
| EXPECT_FALSE(g.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_TRUE(g.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 1); | |
| EXPECT_EQ(flags::positional_arguments[0], "false"); | |
| } | |
| TEST_F(FlagTest, BooleanLongSplitNotParsed) { | |
| FLAG_LONG_bool(foo, false, false); | |
| const char* argv[] = {"binary", "--foo", "true", nullptr}; | |
| EXPECT_FALSE(foo.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_TRUE(foo.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 1); | |
| EXPECT_EQ(flags::positional_arguments[0], "true"); | |
| } | |
| TEST_F(FlagTest, BooleanLongExplicitTrue) { | |
| FLAG_LONG_bool(foo, false, false); | |
| const char* argv[] = {"binary", "--foo=true", nullptr}; | |
| EXPECT_FALSE(foo.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_TRUE(foo.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, BooleanLongExplicitFalse) { | |
| FLAG_LONG_bool(foo, false, false); | |
| const char* argv[] = {"binary", "--foo=false", nullptr}; | |
| EXPECT_FALSE(foo.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_FALSE(foo.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, BooleanLongDefaultValue) { | |
| FLAG_LONG_bool(foo, true, false); | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_TRUE(foo.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_TRUE(foo.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, BooleanLongDefaultValueCancelled) { | |
| FLAG_LONG_bool(foo, true, false); | |
| const char* argv[] = {"binary", "--foo=false", nullptr}; | |
| EXPECT_TRUE(foo.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_FALSE(foo.value()); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, StringFlagDefaultValue) { | |
| FLAG_SHORT_string(f, "default", false); | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_EQ(f.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(f.value(), "default"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, StringFlagShortMissingString) { | |
| FLAG_SHORT_string(f, "default", false); | |
| const char* argv[] = {"binary", "-f", nullptr}; | |
| EXPECT_EQ(f.value(), "default"); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, StringFlagDefault) { | |
| FLAG_SHORT_string(f, "default", false); | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_EQ(f.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(f.value(), "default"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, StringFlagSet) { | |
| FLAG_SHORT_string(f, "default", false); | |
| const char* argv[] = {"binary", "-f", "toto", nullptr}; | |
| EXPECT_EQ(f.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(f.value(), "toto"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, StringLongFlagSetSplit) { | |
| FLAG_LONG_string(foo, "default", false); | |
| const char* argv[] = {"binary", "--foo", "toto", nullptr}; | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), "toto"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, StringLongFlagSetUnified) { | |
| FLAG_LONG_string(foo, "default", false); | |
| const char* argv[] = {"binary", "--foo=toto", nullptr}; | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), "toto"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, StringLongFlagSetEmpty) { | |
| FLAG_LONG_string(foo, "default", false); | |
| const char* argv[] = {"binary", "--foo=", nullptr}; | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), ""); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, AllPositionalAfterDoubleDash) { | |
| FLAG_LONG_string(foo, "default", false); | |
| const char* argv[] = {"binary", "--", "--foo=toto", nullptr}; | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 1); | |
| EXPECT_EQ(flags::positional_arguments[0], "--foo=toto"); | |
| } | |
| TEST_F(FlagTest, NothingAfterDoubleDash) { | |
| FLAG_LONG_string(foo, "default", false); | |
| const char* argv[] = {"binary", "--", nullptr}; | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, FlagDoubleSetNotAllowed) { | |
| FLAG_LONG_string(foo, "default", false); | |
| const char* argv[] = {"binary", "--foo=abc", "--foo=def", nullptr}; | |
| EXPECT_EQ(foo.value(), "default"); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, MultipleFlags) { | |
| FLAG_LONG_string(foo, "default foo", false); | |
| FLAG_LONG_string(bar, "default_bar", false); | |
| const char* argv[] = {"binary", "--foo", "abc", "--bar=def", nullptr}; | |
| EXPECT_EQ(foo.value(), "default foo"); | |
| EXPECT_EQ(bar.value(), "default_bar"); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), "abc"); | |
| EXPECT_EQ(bar.value(), "def"); | |
| } | |
| TEST_F(FlagTest, MixedStringAndBool) { | |
| FLAG_LONG_string(foo, "default foo", false); | |
| FLAG_LONG_string(bar, "default_bar", false); | |
| FLAG_SHORT_bool(g, false, false); | |
| const char* argv[] = {"binary", "--foo", "abc", "-g", "--bar=def", nullptr}; | |
| EXPECT_EQ(foo.value(), "default foo"); | |
| EXPECT_EQ(bar.value(), "default_bar"); | |
| EXPECT_FALSE(g.value()); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), "abc"); | |
| EXPECT_EQ(bar.value(), "def"); | |
| EXPECT_TRUE(g.value()); | |
| } | |
| TEST_F(FlagTest, UintFlagDefaultValue) { | |
| FLAG_SHORT_uint(f, 18, false); | |
| const char* argv[] = {"binary", nullptr}; | |
| EXPECT_EQ(f.value(), 18); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(f.value(), 18); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, UintFlagShortMissingValue) { | |
| FLAG_SHORT_uint(f, 19, false); | |
| const char* argv[] = {"binary", "-f", nullptr}; | |
| EXPECT_EQ(f.value(), 19); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintFlagSet) { | |
| FLAG_SHORT_uint(f, 20, false); | |
| const char* argv[] = {"binary", "-f", "21", nullptr}; | |
| EXPECT_EQ(f.value(), 20); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(f.value(), 21); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetSplit) { | |
| FLAG_LONG_uint(foo, 22, false); | |
| const char* argv[] = {"binary", "--foo", "23", nullptr}; | |
| EXPECT_EQ(foo.value(), 22); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), 23); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetUnified) { | |
| FLAG_LONG_uint(foo, 24, false); | |
| const char* argv[] = {"binary", "--foo=25", nullptr}; | |
| EXPECT_EQ(foo.value(), 24); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), 25); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetEmptyIsWrong) { | |
| FLAG_LONG_uint(foo, 26, false); | |
| const char* argv[] = {"binary", "--foo=", nullptr}; | |
| EXPECT_EQ(foo.value(), 26); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetNegativeFails) { | |
| FLAG_LONG_uint(foo, 26, false); | |
| const char* argv[] = {"binary", "--foo=-2", nullptr}; | |
| EXPECT_EQ(foo.value(), 26); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetOverflowFails) { | |
| FLAG_LONG_uint(foo, 27, false); | |
| const char* argv[] = { | |
| "binary", "--foo=99999999999999999999999999999999999999999999999999999", | |
| nullptr}; | |
| EXPECT_EQ(foo.value(), 27); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetInvalidCharTrailing) { | |
| FLAG_LONG_uint(foo, 28, false); | |
| const char* argv[] = {"binary", "--foo=12A", nullptr}; | |
| EXPECT_EQ(foo.value(), 28); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSetSpaces) { | |
| FLAG_LONG_uint(foo, 29, false); | |
| const char* argv[] = {"binary", "--foo= 12", nullptr}; | |
| EXPECT_EQ(foo.value(), 29); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), 12); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSpacesOnly) { | |
| FLAG_LONG_uint(foo, 30, false); | |
| const char* argv[] = {"binary", "--foo= ", nullptr}; | |
| EXPECT_EQ(foo.value(), 30); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagSplitNumber) { | |
| FLAG_LONG_uint(foo, 31, false); | |
| const char* argv[] = {"binary", "--foo= 2 2", nullptr}; | |
| EXPECT_EQ(foo.value(), 31); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagHex) { | |
| FLAG_LONG_uint(foo, 32, false); | |
| const char* argv[] = {"binary", "--foo=0xA", nullptr}; | |
| EXPECT_EQ(foo.value(), 32); | |
| EXPECT_FALSE(flags::Parse(argv)); | |
| } | |
| TEST_F(FlagTest, UintLongFlagZeros) { | |
| FLAG_LONG_uint(foo, 33, false); | |
| const char* argv[] = {"binary", "--foo=0000", nullptr}; | |
| EXPECT_EQ(foo.value(), 33); | |
| EXPECT_TRUE(flags::Parse(argv)); | |
| EXPECT_EQ(foo.value(), 0); | |
| EXPECT_EQ(flags::positional_arguments.size(), 0); | |
| } |