197 lines
6.7 KiB
C++
197 lines
6.7 KiB
C++
// Copyright 2023 The Pigweed Authors
|
|
//
|
|
// 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
|
|
//
|
|
// https://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 "pw_rpc/fuzz/argparse.h"
|
|
|
|
#include <cstdint>
|
|
#include <limits>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace pw::rpc::fuzz {
|
|
namespace {
|
|
|
|
TEST(ArgsParseTest, ParseBoolFlag) {
|
|
auto parser1 = BoolParser("-t", "--true").set_default(true);
|
|
auto parser2 = BoolParser("-f").set_default(false);
|
|
EXPECT_TRUE(parser1.value());
|
|
EXPECT_FALSE(parser2.value());
|
|
|
|
EXPECT_EQ(parser1.Parse("-t"), ParseStatus::kParsedOne);
|
|
EXPECT_EQ(parser2.Parse("-t"), ParseStatus::kParseMismatch);
|
|
EXPECT_TRUE(parser1.value());
|
|
EXPECT_FALSE(parser2.value());
|
|
|
|
EXPECT_EQ(parser1.Parse("--true"), ParseStatus::kParsedOne);
|
|
EXPECT_EQ(parser2.Parse("--true"), ParseStatus::kParseMismatch);
|
|
EXPECT_TRUE(parser1.value());
|
|
EXPECT_FALSE(parser2.value());
|
|
|
|
EXPECT_EQ(parser1.Parse("--no-true"), ParseStatus::kParsedOne);
|
|
EXPECT_EQ(parser2.Parse("--no-true"), ParseStatus::kParseMismatch);
|
|
EXPECT_FALSE(parser1.value());
|
|
EXPECT_FALSE(parser2.value());
|
|
|
|
EXPECT_EQ(parser1.Parse("-f"), ParseStatus::kParseMismatch);
|
|
EXPECT_EQ(parser2.Parse("-f"), ParseStatus::kParsedOne);
|
|
EXPECT_FALSE(parser1.value());
|
|
EXPECT_TRUE(parser2.value());
|
|
}
|
|
|
|
template <typename T>
|
|
void ParseUnsignedFlag() {
|
|
auto parser = UnsignedParser<T>("-u", "--unsigned").set_default(137);
|
|
EXPECT_EQ(parser.value(), 137u);
|
|
|
|
// Wrong name.
|
|
EXPECT_EQ(parser.Parse("-s"), ParseStatus::kParseMismatch);
|
|
EXPECT_EQ(parser.Parse("--signed"), ParseStatus::kParseMismatch);
|
|
EXPECT_EQ(parser.value(), 137u);
|
|
|
|
// Missing values.
|
|
EXPECT_EQ(parser.Parse("-u"), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.Parse("--unsigned"), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.value(), 137u);
|
|
|
|
// Non-numeric values.
|
|
EXPECT_EQ(parser.Parse("-u", "foo"), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.Parse("--unsigned", "bar"), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.value(), 137u);
|
|
|
|
// Minimum values.
|
|
EXPECT_EQ(parser.Parse("-u", "0"), ParseStatus::kParsedTwo);
|
|
EXPECT_EQ(parser.Parse("--unsigned", "0"), ParseStatus::kParsedTwo);
|
|
EXPECT_EQ(parser.value(), 0u);
|
|
|
|
// Maximum values.
|
|
T max = std::numeric_limits<T>::max();
|
|
StringBuffer<32> buf;
|
|
buf << max;
|
|
EXPECT_EQ(parser.Parse("-u", buf.c_str()), ParseStatus::kParsedTwo);
|
|
EXPECT_EQ(parser.value(), max);
|
|
EXPECT_EQ(parser.Parse("--unsigned", buf.c_str()), ParseStatus::kParsedTwo);
|
|
EXPECT_EQ(parser.value(), max);
|
|
|
|
// Out of-range value.
|
|
if (max < std::numeric_limits<uint64_t>::max()) {
|
|
buf.clear();
|
|
buf << (max + 1ULL);
|
|
EXPECT_EQ(parser.Parse("-u", buf.c_str()), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.Parse("--unsigned", buf.c_str()),
|
|
ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.value(), max);
|
|
}
|
|
}
|
|
|
|
TEST(ArgsParseTest, ParseUnsignedFlags) {
|
|
ParseUnsignedFlag<uint8_t>();
|
|
ParseUnsignedFlag<uint16_t>();
|
|
ParseUnsignedFlag<uint32_t>();
|
|
ParseUnsignedFlag<uint64_t>();
|
|
}
|
|
|
|
TEST(ArgsParseTest, ParsePositional) {
|
|
auto parser = UnsignedParser<size_t>("positional").set_default(1);
|
|
EXPECT_EQ(parser.Parse("-p", "2"), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.value(), 1u);
|
|
|
|
EXPECT_EQ(parser.Parse("--positional", "2"), ParseStatus::kParseFailure);
|
|
EXPECT_EQ(parser.value(), 1u);
|
|
|
|
// Second arg is ignored..
|
|
EXPECT_EQ(parser.Parse("2", "3"), ParseStatus::kParsedOne);
|
|
EXPECT_EQ(parser.value(), 2u);
|
|
|
|
// Positional only matches once.
|
|
EXPECT_EQ(parser.Parse("3"), ParseStatus::kParseMismatch);
|
|
EXPECT_EQ(parser.value(), 2u);
|
|
}
|
|
|
|
TEST(ArgsParseTest, PrintUsage) {
|
|
// Just verify it compiles and runs.
|
|
Vector<ArgParserVariant, 3> parsers = {
|
|
BoolParser("-v", "--verbose").set_default(false),
|
|
UnsignedParser<size_t>("-r", "--runs").set_default(1000),
|
|
UnsignedParser<size_t>("port").set_default(11111),
|
|
};
|
|
PrintUsage(parsers, "test-bin");
|
|
}
|
|
|
|
void CheckArgs(Vector<ArgParserVariant>& parsers,
|
|
bool verbose,
|
|
size_t runs,
|
|
uint16_t port) {
|
|
bool actual_verbose;
|
|
EXPECT_EQ(GetArg(parsers, "--verbose", &actual_verbose), OkStatus());
|
|
EXPECT_EQ(verbose, actual_verbose);
|
|
EXPECT_EQ(ResetArg(parsers, "--verbose"), OkStatus());
|
|
|
|
size_t actual_runs;
|
|
EXPECT_EQ(GetArg(parsers, "--runs", &actual_runs), OkStatus());
|
|
EXPECT_EQ(runs, actual_runs);
|
|
EXPECT_EQ(ResetArg(parsers, "--runs"), OkStatus());
|
|
|
|
uint16_t actual_port;
|
|
EXPECT_EQ(GetArg(parsers, "port", &actual_port), OkStatus());
|
|
EXPECT_EQ(port, actual_port);
|
|
EXPECT_EQ(ResetArg(parsers, "port"), OkStatus());
|
|
}
|
|
|
|
TEST(ArgsParseTest, ParseArgs) {
|
|
Vector<ArgParserVariant, 3> parsers{
|
|
BoolParser("-v", "--verbose").set_default(false),
|
|
UnsignedParser<size_t>("-r", "--runs").set_default(1000),
|
|
UnsignedParser<uint16_t>("port").set_default(11111),
|
|
};
|
|
|
|
char const* argv1[] = {"test-bin"};
|
|
EXPECT_EQ(ParseArgs(parsers, 1, const_cast<char**>(argv1)), OkStatus());
|
|
CheckArgs(parsers, false, 1000, 11111);
|
|
|
|
char const* argv2[] = {"test-bin", "22222"};
|
|
EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv2)), OkStatus());
|
|
CheckArgs(parsers, false, 1000, 22222);
|
|
|
|
// Out of range argument.
|
|
char const* argv3[] = {"test-bin", "65536"};
|
|
EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv3)),
|
|
Status::InvalidArgument());
|
|
|
|
// Extra argument.
|
|
char const* argv4[] = {"test-bin", "1", "2"};
|
|
EXPECT_EQ(ParseArgs(parsers, 3, const_cast<char**>(argv4)),
|
|
Status::InvalidArgument());
|
|
EXPECT_EQ(ResetArg(parsers, "port"), OkStatus());
|
|
|
|
// Flag missing value.
|
|
char const* argv5[] = {"test-bin", "--runs"};
|
|
EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv5)),
|
|
Status::InvalidArgument());
|
|
|
|
char const* argv6[] = {"test-bin", "-v", "33333", "--runs", "300"};
|
|
EXPECT_EQ(ParseArgs(parsers, 5, const_cast<char**>(argv6)), OkStatus());
|
|
CheckArgs(parsers, true, 300, 33333);
|
|
|
|
char const* argv7[] = {"test-bin", "-r", "400", "--verbose"};
|
|
EXPECT_EQ(ParseArgs(parsers, 4, const_cast<char**>(argv7)), OkStatus());
|
|
CheckArgs(parsers, true, 400, 11111);
|
|
|
|
char const* argv8[] = {"test-bin", "--no-verbose", "-r", "5000", "55555"};
|
|
EXPECT_EQ(ParseArgs(parsers, 5, const_cast<char**>(argv8)), OkStatus());
|
|
CheckArgs(parsers, false, 5000, 55555);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::rpc::fuzz
|