blob: 43db99676a19c8b8f8e4f0fceef98c6045f6b12f [file] [log] [blame]
// 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);
}