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