1 //
2 // Copyright (C) 2022 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include <iostream>
17
18 #include <gtest/gtest.h>
19
20 #include "host/commands/cvd/selector/arguments_lexer.h"
21 #include "host/commands/cvd/unittests/selector/client_lexer_helper.h"
22
23 namespace cuttlefish {
24 namespace selector {
25 namespace {
26
27 const LexerFlagsSpecification empty_known_flags;
28 const LexerFlagsSpecification boolean_known_flags{
29 .known_boolean_flags = {"clean"}};
30 const LexerFlagsSpecification non_boolean_known_flags{
31 .known_value_flags = {"group_name"}};
32 const LexerFlagsSpecification both_known_flags{
33 .known_boolean_flags = {"clean"}, .known_value_flags = {"group_name"}};
34
35 } // namespace
36
TEST_P(EmptyArgsLexTest,SuccessExpectedTest)37 TEST_P(EmptyArgsLexTest, SuccessExpectedTest) {
38 auto lexer_gen_result = ArgumentsLexerBuilder::Build(known_flags_);
39 std::unique_ptr<ArgumentsLexer> lexer =
40 lexer_gen_result.ok() ? std::move(*lexer_gen_result) : nullptr;
41 if (!lexer) {
42 GTEST_SKIP() << "Memory allocation failed but it is not in the test scope.";
43 }
44 auto tokenized_result = lexer->Tokenize(lex_input_);
45
46 ASSERT_TRUE(tokenized_result.ok()) << tokenized_result.error().Trace();
47 ASSERT_EQ(*tokenized_result, *expected_tokens_);
48 }
49
50 INSTANTIATE_TEST_SUITE_P(
51 ClientSpecificOptionParser, EmptyArgsLexTest,
52 testing::Values(LexerInputOutput{.known_flags_ = empty_known_flags,
53 .lex_input_ = "",
54 .expected_tokens_ = Tokens{}},
55 LexerInputOutput{.known_flags_ = boolean_known_flags,
56 .lex_input_ = "",
57 .expected_tokens_ = Tokens{}},
58 LexerInputOutput{.known_flags_ = non_boolean_known_flags,
59 .lex_input_ = "",
60 .expected_tokens_ = Tokens{}},
61 LexerInputOutput{.known_flags_ = both_known_flags,
62 .lex_input_ = "",
63 .expected_tokens_ = Tokens{}}));
64
TEST_P(NonBooleanArgsTest,SuccessExpectedTest)65 TEST_P(NonBooleanArgsTest, SuccessExpectedTest) {
66 auto lexer_gen_result = ArgumentsLexerBuilder::Build(known_flags_);
67 std::unique_ptr<ArgumentsLexer> lexer =
68 lexer_gen_result.ok() ? std::move(*lexer_gen_result) : nullptr;
69 if (!lexer) {
70 GTEST_SKIP() << "Memory allocation failed but it is not in the test scope.";
71 }
72 auto tokenized_result = lexer->Tokenize(lex_input_);
73
74 ASSERT_TRUE(tokenized_result.ok()) << tokenized_result.error().Trace();
75 ASSERT_EQ(*tokenized_result, *expected_tokens_);
76 }
77
78 INSTANTIATE_TEST_SUITE_P(
79 ClientSpecificOptionParser, NonBooleanArgsTest,
80 testing::Values(
81 LexerInputOutput{
82 .known_flags_ = non_boolean_known_flags,
83 .lex_input_ = "cvd --group_name=yumi",
84 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
85 ArgToken{ArgType::kKnownFlagAndValue,
86 "--group_name=yumi"}}},
87 LexerInputOutput{
88 .known_flags_ = non_boolean_known_flags,
89 .lex_input_ = "cvd --group_name yumi",
90 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
91 ArgToken{ArgType::kKnownValueFlag,
92 "--group_name"},
93 ArgToken{ArgType::kPositional, "yumi"}}},
94 LexerInputOutput{.known_flags_ = non_boolean_known_flags,
95 .lex_input_ = "cvd --group_name yumi start --daemon",
96 .expected_tokens_ = Tokens{
97 ArgToken{ArgType::kPositional, "cvd"},
98 ArgToken{ArgType::kKnownValueFlag, "--group_name"},
99 ArgToken{ArgType::kPositional, "yumi"},
100 ArgToken{ArgType::kPositional, "start"},
101 ArgToken{ArgType::kUnknownFlag, "--daemon"}}}));
102
TEST_P(BooleanArgsTest,SuccessExpectedTest)103 TEST_P(BooleanArgsTest, SuccessExpectedTest) {
104 auto lexer_gen_result = ArgumentsLexerBuilder::Build(known_flags_);
105 std::unique_ptr<ArgumentsLexer> lexer =
106 lexer_gen_result.ok() ? std::move(*lexer_gen_result) : nullptr;
107 if (!lexer) {
108 GTEST_SKIP() << "Memory allocation failed but it is not in the test scope.";
109 }
110 auto tokenized_result = lexer->Tokenize(lex_input_);
111
112 ASSERT_TRUE(tokenized_result.ok()) << tokenized_result.error().Trace();
113 ASSERT_EQ(*tokenized_result, *expected_tokens_);
114 }
115
116 INSTANTIATE_TEST_SUITE_P(
117 ClientSpecificOptionParser, BooleanArgsTest,
118 testing::Values(
119 LexerInputOutput{
120 .known_flags_ = boolean_known_flags,
121 .lex_input_ = "cvd --clean",
122 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
123 ArgToken{ArgType::kKnownBoolFlag,
124 "--clean"}}},
125 LexerInputOutput{
126 .known_flags_ = boolean_known_flags,
127 .lex_input_ = "cvd --clean=TrUe",
128 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
129 ArgToken{ArgType::kKnownBoolFlag,
130 "--clean"}}},
131 LexerInputOutput{
132 .known_flags_ = boolean_known_flags,
133 .lex_input_ = "cvd --noclean",
134 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
135 ArgToken{ArgType::kKnownBoolNoFlag,
136 "--noclean"}}},
137 LexerInputOutput{
138 .known_flags_ = boolean_known_flags,
139 .lex_input_ = "cvd --noclean=redundant",
140 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
141 ArgToken{ArgType::kKnownBoolNoFlag,
142 "--noclean"}}},
143 LexerInputOutput{
144 .known_flags_ = boolean_known_flags,
145 .lex_input_ = "cvd --clean=no --norandom=y",
146 .expected_tokens_ = Tokens{
147 ArgToken{ArgType::kPositional, "cvd"},
148 ArgToken{ArgType::kKnownBoolNoFlag, "--noclean"},
149 ArgToken{ArgType::kUnknownFlag, "--norandom=y"}}}));
150
TEST_P(BothArgsTest,SuccessExpectedTest)151 TEST_P(BothArgsTest, SuccessExpectedTest) {
152 auto lexer_gen_result = ArgumentsLexerBuilder::Build(known_flags_);
153 std::unique_ptr<ArgumentsLexer> lexer =
154 lexer_gen_result.ok() ? std::move(*lexer_gen_result) : nullptr;
155 if (!lexer) {
156 GTEST_SKIP() << "Memory allocation failed but it is not in the test scope.";
157 }
158 auto tokenized_result = lexer->Tokenize(lex_input_);
159
160 ASSERT_TRUE(tokenized_result.ok()) << tokenized_result.error().Trace();
161 ASSERT_EQ(*tokenized_result, *expected_tokens_);
162 }
163
164 INSTANTIATE_TEST_SUITE_P(
165 ClientSpecificOptionParser, BothArgsTest,
166 testing::Values(
167 LexerInputOutput{
168 .known_flags_ = both_known_flags,
169 .lex_input_ = "cvd --clean -group_name=yumi",
170 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
171 ArgToken{ArgType::kKnownBoolFlag,
172 "--clean"},
173 ArgToken{ArgType::kKnownFlagAndValue,
174 "-group_name=yumi"}}},
175 LexerInputOutput{
176 .known_flags_ = both_known_flags,
177 .lex_input_ = "cvd --group_name -noclean",
178 .expected_tokens_ = Tokens{
179 ArgToken{ArgType::kPositional, "cvd"},
180 ArgToken{ArgType::kKnownValueFlag, "--group_name"},
181 ArgToken{ArgType::kKnownBoolNoFlag, "-noclean"}}}));
182
TEST_P(BooleanBadArgsTest,FailureExpectedTest)183 TEST_P(BooleanBadArgsTest, FailureExpectedTest) {
184 auto lexer_gen_result = ArgumentsLexerBuilder::Build(known_flags_);
185 std::unique_ptr<ArgumentsLexer> lexer =
186 lexer_gen_result.ok() ? std::move(*lexer_gen_result) : nullptr;
187 if (!lexer) {
188 GTEST_SKIP() << "Memory allocation failed but it is not in the test scope.";
189 }
190 auto tokenized_result = lexer->Tokenize(lex_input_);
191
192 if (!expected_tokens_) {
193 ASSERT_FALSE(tokenized_result.ok())
194 << "Lexing " << lex_input_ << " should have failed.";
195 return;
196 }
197 ASSERT_TRUE(tokenized_result.ok()) << tokenized_result.error().Trace();
198 ASSERT_EQ(*tokenized_result, *expected_tokens_);
199 }
200
201 INSTANTIATE_TEST_SUITE_P(
202 ClientSpecificOptionParser, BooleanBadArgsTest,
203 testing::Values(
204 LexerInputOutput{
205 .known_flags_ = boolean_known_flags,
206 .lex_input_ = "cvd --yesclean",
207 .expected_tokens_ = Tokens{ArgToken{ArgType::kPositional, "cvd"},
208 ArgToken{ArgType::kUnknownFlag,
209 "--yesclean"}}},
210 LexerInputOutput{.known_flags_ = boolean_known_flags,
211 .lex_input_ = "cvd --clean=Hello",
212 .expected_tokens_ = std::nullopt},
213 LexerInputOutput{.known_flags_ = boolean_known_flags,
214 .lex_input_ = "cvd --clean false",
215 .expected_tokens_ = Tokens{
216 ArgToken{ArgType::kPositional, "cvd"},
217 ArgToken{ArgType::kKnownBoolFlag, "--clean"},
218 ArgToken{ArgType::kPositional, "false"}}}));
219
220 } // namespace selector
221 } // namespace cuttlefish
222