• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gtest/gtest.h"
21 
22 namespace pw::rpc::fuzz {
23 namespace {
24 
TEST(ArgsParseTest,ParseBoolFlag)25 TEST(ArgsParseTest, ParseBoolFlag) {
26   auto parser1 = BoolParser("-t", "--true").set_default(true);
27   auto parser2 = BoolParser("-f").set_default(false);
28   EXPECT_TRUE(parser1.value());
29   EXPECT_FALSE(parser2.value());
30 
31   EXPECT_EQ(parser1.Parse("-t"), ParseStatus::kParsedOne);
32   EXPECT_EQ(parser2.Parse("-t"), ParseStatus::kParseMismatch);
33   EXPECT_TRUE(parser1.value());
34   EXPECT_FALSE(parser2.value());
35 
36   EXPECT_EQ(parser1.Parse("--true"), ParseStatus::kParsedOne);
37   EXPECT_EQ(parser2.Parse("--true"), ParseStatus::kParseMismatch);
38   EXPECT_TRUE(parser1.value());
39   EXPECT_FALSE(parser2.value());
40 
41   EXPECT_EQ(parser1.Parse("--no-true"), ParseStatus::kParsedOne);
42   EXPECT_EQ(parser2.Parse("--no-true"), ParseStatus::kParseMismatch);
43   EXPECT_FALSE(parser1.value());
44   EXPECT_FALSE(parser2.value());
45 
46   EXPECT_EQ(parser1.Parse("-f"), ParseStatus::kParseMismatch);
47   EXPECT_EQ(parser2.Parse("-f"), ParseStatus::kParsedOne);
48   EXPECT_FALSE(parser1.value());
49   EXPECT_TRUE(parser2.value());
50 }
51 
52 template <typename T>
ParseUnsignedFlag()53 void ParseUnsignedFlag() {
54   auto parser = UnsignedParser<T>("-u", "--unsigned").set_default(137);
55   EXPECT_EQ(parser.value(), 137u);
56 
57   // Wrong name.
58   EXPECT_EQ(parser.Parse("-s"), ParseStatus::kParseMismatch);
59   EXPECT_EQ(parser.Parse("--signed"), ParseStatus::kParseMismatch);
60   EXPECT_EQ(parser.value(), 137u);
61 
62   // Missing values.
63   EXPECT_EQ(parser.Parse("-u"), ParseStatus::kParseFailure);
64   EXPECT_EQ(parser.Parse("--unsigned"), ParseStatus::kParseFailure);
65   EXPECT_EQ(parser.value(), 137u);
66 
67   // Non-numeric values.
68   EXPECT_EQ(parser.Parse("-u", "foo"), ParseStatus::kParseFailure);
69   EXPECT_EQ(parser.Parse("--unsigned", "bar"), ParseStatus::kParseFailure);
70   EXPECT_EQ(parser.value(), 137u);
71 
72   // Minimum values.
73   EXPECT_EQ(parser.Parse("-u", "0"), ParseStatus::kParsedTwo);
74   EXPECT_EQ(parser.Parse("--unsigned", "0"), ParseStatus::kParsedTwo);
75   EXPECT_EQ(parser.value(), 0u);
76 
77   // Maximum values.
78   T max = std::numeric_limits<T>::max();
79   StringBuffer<32> buf;
80   buf << max;
81   EXPECT_EQ(parser.Parse("-u", buf.c_str()), ParseStatus::kParsedTwo);
82   EXPECT_EQ(parser.value(), max);
83   EXPECT_EQ(parser.Parse("--unsigned", buf.c_str()), ParseStatus::kParsedTwo);
84   EXPECT_EQ(parser.value(), max);
85 
86   // Out of-range value.
87   if (max < std::numeric_limits<uint64_t>::max()) {
88     buf.clear();
89     buf << (max + 1ULL);
90     EXPECT_EQ(parser.Parse("-u", buf.c_str()), ParseStatus::kParseFailure);
91     EXPECT_EQ(parser.Parse("--unsigned", buf.c_str()),
92               ParseStatus::kParseFailure);
93     EXPECT_EQ(parser.value(), max);
94   }
95 }
96 
TEST(ArgsParseTest,ParseUnsignedFlags)97 TEST(ArgsParseTest, ParseUnsignedFlags) {
98   ParseUnsignedFlag<uint8_t>();
99   ParseUnsignedFlag<uint16_t>();
100   ParseUnsignedFlag<uint32_t>();
101   ParseUnsignedFlag<uint64_t>();
102 }
103 
TEST(ArgsParseTest,ParsePositional)104 TEST(ArgsParseTest, ParsePositional) {
105   auto parser = UnsignedParser<size_t>("positional").set_default(1);
106   EXPECT_EQ(parser.Parse("-p", "2"), ParseStatus::kParseFailure);
107   EXPECT_EQ(parser.value(), 1u);
108 
109   EXPECT_EQ(parser.Parse("--positional", "2"), ParseStatus::kParseFailure);
110   EXPECT_EQ(parser.value(), 1u);
111 
112   // Second arg is ignored..
113   EXPECT_EQ(parser.Parse("2", "3"), ParseStatus::kParsedOne);
114   EXPECT_EQ(parser.value(), 2u);
115 
116   // Positional only matches once.
117   EXPECT_EQ(parser.Parse("3"), ParseStatus::kParseMismatch);
118   EXPECT_EQ(parser.value(), 2u);
119 }
120 
TEST(ArgsParseTest,PrintUsage)121 TEST(ArgsParseTest, PrintUsage) {
122   // Just verify it compiles and runs.
123   Vector<ArgParserVariant, 3> parsers = {
124       BoolParser("-v", "--verbose").set_default(false),
125       UnsignedParser<size_t>("-r", "--runs").set_default(1000),
126       UnsignedParser<size_t>("port").set_default(11111),
127   };
128   PrintUsage(parsers, "test-bin");
129 }
130 
CheckArgs(Vector<ArgParserVariant> & parsers,bool verbose,size_t runs,uint16_t port)131 void CheckArgs(Vector<ArgParserVariant>& parsers,
132                bool verbose,
133                size_t runs,
134                uint16_t port) {
135   bool actual_verbose;
136   EXPECT_EQ(GetArg(parsers, "--verbose", &actual_verbose), OkStatus());
137   EXPECT_EQ(verbose, actual_verbose);
138   EXPECT_EQ(ResetArg(parsers, "--verbose"), OkStatus());
139 
140   size_t actual_runs;
141   EXPECT_EQ(GetArg(parsers, "--runs", &actual_runs), OkStatus());
142   EXPECT_EQ(runs, actual_runs);
143   EXPECT_EQ(ResetArg(parsers, "--runs"), OkStatus());
144 
145   uint16_t actual_port;
146   EXPECT_EQ(GetArg(parsers, "port", &actual_port), OkStatus());
147   EXPECT_EQ(port, actual_port);
148   EXPECT_EQ(ResetArg(parsers, "port"), OkStatus());
149 }
150 
TEST(ArgsParseTest,ParseArgs)151 TEST(ArgsParseTest, ParseArgs) {
152   Vector<ArgParserVariant, 3> parsers{
153       BoolParser("-v", "--verbose").set_default(false),
154       UnsignedParser<size_t>("-r", "--runs").set_default(1000),
155       UnsignedParser<uint16_t>("port").set_default(11111),
156   };
157 
158   char const* argv1[] = {"test-bin"};
159   EXPECT_EQ(ParseArgs(parsers, 1, const_cast<char**>(argv1)), OkStatus());
160   CheckArgs(parsers, false, 1000, 11111);
161 
162   char const* argv2[] = {"test-bin", "22222"};
163   EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv2)), OkStatus());
164   CheckArgs(parsers, false, 1000, 22222);
165 
166   // Out of range argument.
167   char const* argv3[] = {"test-bin", "65536"};
168   EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv3)),
169             Status::InvalidArgument());
170 
171   // Extra argument.
172   char const* argv4[] = {"test-bin", "1", "2"};
173   EXPECT_EQ(ParseArgs(parsers, 3, const_cast<char**>(argv4)),
174             Status::InvalidArgument());
175   EXPECT_EQ(ResetArg(parsers, "port"), OkStatus());
176 
177   // Flag missing value.
178   char const* argv5[] = {"test-bin", "--runs"};
179   EXPECT_EQ(ParseArgs(parsers, 2, const_cast<char**>(argv5)),
180             Status::InvalidArgument());
181 
182   char const* argv6[] = {"test-bin", "-v", "33333", "--runs", "300"};
183   EXPECT_EQ(ParseArgs(parsers, 5, const_cast<char**>(argv6)), OkStatus());
184   CheckArgs(parsers, true, 300, 33333);
185 
186   char const* argv7[] = {"test-bin", "-r", "400", "--verbose"};
187   EXPECT_EQ(ParseArgs(parsers, 4, const_cast<char**>(argv7)), OkStatus());
188   CheckArgs(parsers, true, 400, 11111);
189 
190   char const* argv8[] = {"test-bin", "--no-verbose", "-r", "5000", "55555"};
191   EXPECT_EQ(ParseArgs(parsers, 5, const_cast<char**>(argv8)), OkStatus());
192   CheckArgs(parsers, false, 5000, 55555);
193 }
194 
195 }  // namespace
196 }  // namespace pw::rpc::fuzz
197