1*61c4878aSAndroid Build Coastguard Worker // Copyright 2023 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/fuzz/argparse.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <cstdint>
18*61c4878aSAndroid Build Coastguard Worker #include <limits>
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard Worker #include "pw_string/string_builder.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker namespace pw::rpc::fuzz {
24*61c4878aSAndroid Build Coastguard Worker namespace {
25*61c4878aSAndroid Build Coastguard Worker
TEST(ArgsParseTest,ParseBoolFlag)26*61c4878aSAndroid Build Coastguard Worker TEST(ArgsParseTest, ParseBoolFlag) {
27*61c4878aSAndroid Build Coastguard Worker auto parser1 = BoolParser("-t", "--true").set_default(true);
28*61c4878aSAndroid Build Coastguard Worker auto parser2 = BoolParser("-f").set_default(false);
29*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(parser1.value());
30*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(parser2.value());
31*61c4878aSAndroid Build Coastguard Worker
32*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser1.Parse("-t"), ParseStatus::kParsedOne);
33*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser2.Parse("-t"), ParseStatus::kParseMismatch);
34*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(parser1.value());
35*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(parser2.value());
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser1.Parse("--true"), ParseStatus::kParsedOne);
38*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser2.Parse("--true"), ParseStatus::kParseMismatch);
39*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(parser1.value());
40*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(parser2.value());
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser1.Parse("--no-true"), ParseStatus::kParsedOne);
43*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser2.Parse("--no-true"), ParseStatus::kParseMismatch);
44*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(parser1.value());
45*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(parser2.value());
46*61c4878aSAndroid Build Coastguard Worker
47*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser1.Parse("-f"), ParseStatus::kParseMismatch);
48*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser2.Parse("-f"), ParseStatus::kParsedOne);
49*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(parser1.value());
50*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(parser2.value());
51*61c4878aSAndroid Build Coastguard Worker }
52*61c4878aSAndroid Build Coastguard Worker
53*61c4878aSAndroid Build Coastguard Worker template <typename T>
ParseUnsignedFlag()54*61c4878aSAndroid Build Coastguard Worker void ParseUnsignedFlag() {
55*61c4878aSAndroid Build Coastguard Worker auto parser = UnsignedParser<T>("-u", "--unsigned").set_default(137);
56*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 137u);
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard Worker // Wrong name.
59*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-s"), ParseStatus::kParseMismatch);
60*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--signed"), ParseStatus::kParseMismatch);
61*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 137u);
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker // Missing values.
64*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-u"), ParseStatus::kParseFailure);
65*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--unsigned"), ParseStatus::kParseFailure);
66*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 137u);
67*61c4878aSAndroid Build Coastguard Worker
68*61c4878aSAndroid Build Coastguard Worker // Non-numeric values.
69*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-u", "foo"), ParseStatus::kParseFailure);
70*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--unsigned", "bar"), ParseStatus::kParseFailure);
71*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 137u);
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker // Minimum values.
74*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-u", "0"), ParseStatus::kParsedTwo);
75*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--unsigned", "0"), ParseStatus::kParsedTwo);
76*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 0u);
77*61c4878aSAndroid Build Coastguard Worker
78*61c4878aSAndroid Build Coastguard Worker // Maximum values.
79*61c4878aSAndroid Build Coastguard Worker T max = std::numeric_limits<T>::max();
80*61c4878aSAndroid Build Coastguard Worker StringBuffer<32> buf;
81*61c4878aSAndroid Build Coastguard Worker buf << max;
82*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-u", buf.c_str()), ParseStatus::kParsedTwo);
83*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), max);
84*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--unsigned", buf.c_str()), ParseStatus::kParsedTwo);
85*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), max);
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker // Out of-range value.
88*61c4878aSAndroid Build Coastguard Worker if (max < std::numeric_limits<uint64_t>::max()) {
89*61c4878aSAndroid Build Coastguard Worker buf.clear();
90*61c4878aSAndroid Build Coastguard Worker buf << (max + 1ULL);
91*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-u", buf.c_str()), ParseStatus::kParseFailure);
92*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--unsigned", buf.c_str()),
93*61c4878aSAndroid Build Coastguard Worker ParseStatus::kParseFailure);
94*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), max);
95*61c4878aSAndroid Build Coastguard Worker }
96*61c4878aSAndroid Build Coastguard Worker }
97*61c4878aSAndroid Build Coastguard Worker
TEST(ArgsParseTest,ParseUnsignedFlags)98*61c4878aSAndroid Build Coastguard Worker TEST(ArgsParseTest, ParseUnsignedFlags) {
99*61c4878aSAndroid Build Coastguard Worker ParseUnsignedFlag<uint8_t>();
100*61c4878aSAndroid Build Coastguard Worker ParseUnsignedFlag<uint16_t>();
101*61c4878aSAndroid Build Coastguard Worker ParseUnsignedFlag<uint32_t>();
102*61c4878aSAndroid Build Coastguard Worker ParseUnsignedFlag<uint64_t>();
103*61c4878aSAndroid Build Coastguard Worker }
104*61c4878aSAndroid Build Coastguard Worker
TEST(ArgsParseTest,ParsePositional)105*61c4878aSAndroid Build Coastguard Worker TEST(ArgsParseTest, ParsePositional) {
106*61c4878aSAndroid Build Coastguard Worker auto parser = UnsignedParser<size_t>("positional").set_default(1);
107*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("-p", "2"), ParseStatus::kParseFailure);
108*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 1u);
109*61c4878aSAndroid Build Coastguard Worker
110*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("--positional", "2"), ParseStatus::kParseFailure);
111*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 1u);
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker // Second arg is ignored..
114*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("2", "3"), ParseStatus::kParsedOne);
115*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 2u);
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker // Positional only matches once.
118*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.Parse("3"), ParseStatus::kParseMismatch);
119*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser.value(), 2u);
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker
TEST(ArgsParseTest,PrintUsage)122*61c4878aSAndroid Build Coastguard Worker TEST(ArgsParseTest, PrintUsage) {
123*61c4878aSAndroid Build Coastguard Worker // Just verify it compiles and runs.
124*61c4878aSAndroid Build Coastguard Worker Vector<ArgParserVariant, 3> parsers = {
125*61c4878aSAndroid Build Coastguard Worker BoolParser("-v", "--verbose").set_default(false),
126*61c4878aSAndroid Build Coastguard Worker UnsignedParser<size_t>("-r", "--runs").set_default(1000),
127*61c4878aSAndroid Build Coastguard Worker UnsignedParser<size_t>("port").set_default(11111),
128*61c4878aSAndroid Build Coastguard Worker };
129*61c4878aSAndroid Build Coastguard Worker PrintUsage(parsers, "test-bin");
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker
CheckArgs(Vector<ArgParserVariant> & parsers,bool verbose,size_t runs,uint16_t port)132*61c4878aSAndroid Build Coastguard Worker void CheckArgs(Vector<ArgParserVariant>& parsers,
133*61c4878aSAndroid Build Coastguard Worker bool verbose,
134*61c4878aSAndroid Build Coastguard Worker size_t runs,
135*61c4878aSAndroid Build Coastguard Worker uint16_t port) {
136*61c4878aSAndroid Build Coastguard Worker bool actual_verbose = false;
137*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(GetArg(parsers, "--verbose", &actual_verbose), OkStatus());
138*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(verbose, actual_verbose);
139*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ResetArg(parsers, "--verbose"), OkStatus());
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker size_t actual_runs = 0u;
142*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(GetArg(parsers, "--runs", &actual_runs), OkStatus());
143*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(runs, actual_runs);
144*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ResetArg(parsers, "--runs"), OkStatus());
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard Worker uint16_t actual_port = 0u;
147*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(GetArg(parsers, "port", &actual_port), OkStatus());
148*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(port, actual_port);
149*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ResetArg(parsers, "port"), OkStatus());
150*61c4878aSAndroid Build Coastguard Worker }
151*61c4878aSAndroid Build Coastguard Worker
TEST(ArgsParseTest,ParseArgs)152*61c4878aSAndroid Build Coastguard Worker TEST(ArgsParseTest, ParseArgs) {
153*61c4878aSAndroid Build Coastguard Worker Vector<ArgParserVariant, 3> parsers{
154*61c4878aSAndroid Build Coastguard Worker BoolParser("-v", "--verbose").set_default(false),
155*61c4878aSAndroid Build Coastguard Worker UnsignedParser<size_t>("-r", "--runs").set_default(1000),
156*61c4878aSAndroid Build Coastguard Worker UnsignedParser<uint16_t>("port").set_default(11111),
157*61c4878aSAndroid Build Coastguard Worker };
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker char const* argv1[] = {"test-bin"};
160*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 1, const_cast<char**>(argv1)), OkStatus());
161*61c4878aSAndroid Build Coastguard Worker CheckArgs(parsers, false, 1000, 11111);
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker char const* argv2[] = {"test-bin", "22222"};
164*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv2)), OkStatus());
165*61c4878aSAndroid Build Coastguard Worker CheckArgs(parsers, false, 1000, 22222);
166*61c4878aSAndroid Build Coastguard Worker
167*61c4878aSAndroid Build Coastguard Worker // Out of range argument.
168*61c4878aSAndroid Build Coastguard Worker char const* argv3[] = {"test-bin", "65536"};
169*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv3)),
170*61c4878aSAndroid Build Coastguard Worker Status::InvalidArgument());
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard Worker // Extra argument.
173*61c4878aSAndroid Build Coastguard Worker char const* argv4[] = {"test-bin", "1", "2"};
174*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 3, const_cast<char**>(argv4)),
175*61c4878aSAndroid Build Coastguard Worker Status::InvalidArgument());
176*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ResetArg(parsers, "port"), OkStatus());
177*61c4878aSAndroid Build Coastguard Worker
178*61c4878aSAndroid Build Coastguard Worker // Flag missing value.
179*61c4878aSAndroid Build Coastguard Worker char const* argv5[] = {"test-bin", "--runs"};
180*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv5)),
181*61c4878aSAndroid Build Coastguard Worker Status::InvalidArgument());
182*61c4878aSAndroid Build Coastguard Worker
183*61c4878aSAndroid Build Coastguard Worker char const* argv6[] = {"test-bin", "-v", "33333", "--runs", "300"};
184*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 5, const_cast<char**>(argv6)), OkStatus());
185*61c4878aSAndroid Build Coastguard Worker CheckArgs(parsers, true, 300, 33333);
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker char const* argv7[] = {"test-bin", "-r", "400", "--verbose"};
188*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 4, const_cast<char**>(argv7)), OkStatus());
189*61c4878aSAndroid Build Coastguard Worker CheckArgs(parsers, true, 400, 11111);
190*61c4878aSAndroid Build Coastguard Worker
191*61c4878aSAndroid Build Coastguard Worker char const* argv8[] = {"test-bin", "--no-verbose", "-r", "5000", "55555"};
192*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(ParseArgs(parsers, 5, const_cast<char**>(argv8)), OkStatus());
193*61c4878aSAndroid Build Coastguard Worker CheckArgs(parsers, false, 5000, 55555);
194*61c4878aSAndroid Build Coastguard Worker }
195*61c4878aSAndroid Build Coastguard Worker
196*61c4878aSAndroid Build Coastguard Worker } // namespace
197*61c4878aSAndroid Build Coastguard Worker } // namespace pw::rpc::fuzz
198