OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/tools/profile_reset/jtl_parser.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/json/json_writer.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/values.h" | |
12 #include "testing/gmock/include/gmock/gmock-matchers.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace { | |
16 | |
17 // Helpers ------------------------------------------------------------------- | |
18 | |
19 void ExpectNextOperation(JtlParser* parser, | |
20 const char* expected_name, | |
21 const char* expected_args, | |
22 bool expected_ends_sentence) { | |
23 std::string actual_name; | |
24 base::ListValue actual_args; | |
25 std::string actual_args_json; | |
26 bool actual_ends_sentence; | |
27 | |
28 EXPECT_FALSE(parser->HasFinished()); | |
29 EXPECT_TRUE(parser->ParseNextOperation( | |
30 &actual_name, &actual_args, &actual_ends_sentence)); | |
31 EXPECT_EQ(expected_name, actual_name); | |
32 base::JSONWriter::Write(&actual_args, &actual_args_json); | |
33 EXPECT_EQ(expected_args, actual_args_json); | |
34 EXPECT_EQ(expected_ends_sentence, actual_ends_sentence); | |
35 } | |
36 | |
37 void ExpectNextOperationToFail(JtlParser* parser, | |
38 size_t expected_line_number, | |
39 const char* expected_context_prefix) { | |
40 std::string actual_name; | |
41 base::ListValue actual_args; | |
42 bool actual_ends_sentence; | |
43 | |
44 EXPECT_FALSE(parser->HasFinished()); | |
45 EXPECT_FALSE(parser->ParseNextOperation( | |
46 &actual_name, &actual_args, &actual_ends_sentence)); | |
47 EXPECT_THAT(parser->last_context(), | |
48 testing::StartsWith(expected_context_prefix)); | |
49 EXPECT_EQ(expected_line_number, parser->last_line_number()); | |
50 } | |
51 | |
52 JtlParser* CreateParserFromVerboseText(const std::string& verbose_text) { | |
53 std::string compacted_source_code; | |
54 std::vector<size_t> newline_indices; | |
55 EXPECT_TRUE(JtlParser::RemoveCommentsAndAllWhitespace( | |
56 verbose_text, &compacted_source_code, &newline_indices, NULL)); | |
57 return new JtlParser(compacted_source_code, newline_indices); | |
58 } | |
59 | |
60 // Tests --------------------------------------------------------------------- | |
61 | |
62 TEST(JtlParser, CompactingEmpty) { | |
63 const char kSourceCode[] = ""; | |
64 const char kCompactedSourceCode[] = ""; | |
65 | |
66 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
67 EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); | |
68 } | |
69 | |
70 TEST(JtlParser, CompactingTrivial) { | |
71 const char kSourceCode[] = "foo"; | |
72 const char kCompactedSourceCode[] = "foo"; | |
73 | |
74 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
75 EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); | |
76 } | |
77 | |
78 TEST(JtlParser, CompactingOneLine) { | |
79 const char kSourceCode[] = " \r f\to o ( true ) "; | |
80 const char kCompactedSourceCode[] = "foo(true)"; | |
81 | |
82 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
83 EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); | |
84 for (size_t i = 0; i < arraysize(kCompactedSourceCode) - 1; ++i) { | |
85 SCOPED_TRACE(testing::Message("Position ") << i); | |
86 EXPECT_EQ(0u, parser->GetOriginalLineNumber(i)); | |
87 } | |
88 } | |
89 | |
90 TEST(JtlParser, CompactingMultipleLines) { | |
91 const char kSourceCode[] = "a\nbb\n \nccc \n\n d( \n e \n )"; | |
92 const char kCompactedSourceCode[] = "abbcccd(e)"; | |
93 const size_t kLineNumbers[] = {0u, 1u, 1u, 3u, 3u, 3u, 5u, 5u, 6u, 7u}; | |
94 COMPILE_ASSERT(arraysize(kCompactedSourceCode) == arraysize(kLineNumbers) + 1, | |
95 mismatched_test_data); | |
96 | |
97 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
98 EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); | |
99 for (size_t i = 0; i < arraysize(kLineNumbers); ++i) { | |
100 SCOPED_TRACE(testing::Message("Position ") << i); | |
101 EXPECT_EQ(kLineNumbers[i], parser->GetOriginalLineNumber(i)); | |
102 } | |
103 } | |
104 | |
105 TEST(JtlParser, HandlingCommentsAndStringLiterals) { | |
106 struct TestCase { | |
107 const char* source_code; | |
108 const char* compacted_source_code; | |
109 } cases[] = { | |
110 {"//", ""}, | |
111 {"//comment", ""}, | |
112 {"foo //comment", "foo"}, | |
113 {"\"literal\"", "\"literal\""}, | |
114 {"\"literal with space\"", "\"literal with space\""}, | |
115 {"\"\"", "\"\""}, | |
116 {"\"\"\"\"", "\"\"\"\""}, | |
117 {"\"\" // comment", "\"\""}, | |
118 {"\"literal\" // comment", "\"literal\""}, | |
119 {"\"literal\" \"literal\" // comment", "\"literal\"\"literal\""}, | |
120 {"foo // \"not a literal\"", "foo"}, | |
121 {"foo // \"not even matched", "foo"}, | |
122 {"foo // \"not a literal\" \"not even matched", "foo"}, | |
123 {"\"literal\" // \"not a literal\"", "\"literal\""}, | |
124 {"\"literal\" // \"not even matched", "\"literal\""}, | |
125 {"\"//not a comment//\"", "\"//not a comment//\""}, | |
126 {"\"//not a comment//\" // comment", "\"//not a comment//\""}, | |
127 {"// \"//not a literal//\" // comment", ""}, | |
128 {"\"literal // \"not a literal or a comment//\"", | |
129 "\"literal // \"notaliteraloracomment"} | |
130 }; | |
131 | |
132 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
133 SCOPED_TRACE(cases[i].source_code); | |
134 scoped_ptr<JtlParser> parser( | |
135 CreateParserFromVerboseText(cases[i].source_code)); | |
136 EXPECT_EQ(cases[i].compacted_source_code, parser->compacted_source()); | |
137 } | |
138 } | |
139 | |
140 TEST(JtlParser, MismatchedDoubleQuotesInLine) { | |
141 struct TestCase { | |
142 const char* source_code; | |
143 size_t error_line_number; | |
144 } cases[] = { | |
145 {"\"", 0}, | |
146 {"\"mismatched literal", 0}, | |
147 {"\n\"", 1}, | |
148 {"\"\n\"", 0}, | |
149 {"\"\"\"", 0}, | |
150 {"\"\"\n\"", 1}, | |
151 {"\"\"\n\"\n\"", 1}, | |
152 {"\" // comment", 0}, | |
153 {"\"\" // comment\n\"", 1}, | |
154 {"\"\" // comment\n\"// comment", 1}, | |
155 {"\" // not a comment\"\n\"// comment", 1}, | |
156 {"foo(\"bar\");\nfoo(\"mismatched);", 1}, | |
157 {"foo(\n\"bar\", \"mismatched);", 1}, | |
158 {"foo(\n\"bar\", \"mismatched); //comment", 1}, | |
159 {"foo(\n\"bar\", \"mismatched);\ngood(\"bar\")", 1} | |
160 }; | |
161 | |
162 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
163 SCOPED_TRACE(cases[i].source_code); | |
164 std::string compacted_source_code; | |
165 std::vector<size_t> newline_indices; | |
166 size_t error_line_number; | |
167 EXPECT_FALSE(JtlParser::RemoveCommentsAndAllWhitespace( | |
168 cases[i].source_code, | |
169 &compacted_source_code, | |
170 &newline_indices, | |
171 &error_line_number)); | |
172 EXPECT_EQ(cases[i].error_line_number, error_line_number); | |
173 } | |
174 } | |
175 | |
176 TEST(JtlParser, CompactingMultipleLinesWithComments) { | |
177 const char kSourceCode[] = | |
178 "a/ /b//Comment \n//\n// Full line comment\n cd //"; | |
battre
2013/10/01 12:18:26
Nit: change format?
"a/ /b//Comment \n"
"/
engedy
2013/10/01 15:09:33
Done.
| |
179 const char kCompactedSourceCode[] = "a//bcd"; | |
180 const size_t kLineNumbers[] = {0u, 0u, 0u, 0u, 3u, 3u}; | |
181 COMPILE_ASSERT(arraysize(kCompactedSourceCode) == arraysize(kLineNumbers) + 1, | |
182 mismatched_test_data); | |
183 | |
184 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
185 EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); | |
186 for (size_t i = 0; i < arraysize(kLineNumbers); ++i) { | |
187 SCOPED_TRACE(testing::Message("Position ") << i); | |
188 EXPECT_EQ(kLineNumbers[i], parser->GetOriginalLineNumber(i)); | |
189 } | |
190 } | |
191 | |
192 TEST(JtlParser, ParsingEmpty) { | |
193 const char kSourceCode[] = ""; | |
194 | |
195 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
196 EXPECT_TRUE(parser->HasFinished()); | |
197 } | |
198 | |
199 TEST(JtlParser, ParsingOneWellFormedOperation) { | |
200 struct TestCase { | |
201 const char* source_code; | |
202 const char* expected_name; | |
203 const char* expected_args; | |
204 const bool expected_ends_sentence; | |
205 } cases[] = { | |
206 {"foo1;", "foo1", "[]", true}, | |
207 {"foo2()/", "foo2", "[]", false}, | |
208 {"foo3(true);", "foo3", "[true]", true}, | |
209 {"foo4(false)/", "foo4", "[false]", false}, | |
210 {"foo5(\"bar\")/", "foo5", "[\"bar\"]", false}, | |
battre
2013/10/01 12:18:26
\"foo bar\" to add whitespaces?
engedy
2013/10/01 15:09:33
Done.
| |
211 {"foo6(true, \"bar\")/", "foo6", "[true,\"bar\"]", false}, | |
212 {"foo7(\"bar\", false, true);", "foo7", "[\"bar\",false,true]", true} | |
213 }; | |
214 | |
215 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
216 SCOPED_TRACE(cases[i].expected_name); | |
217 scoped_ptr<JtlParser> parser( | |
218 CreateParserFromVerboseText(cases[i].source_code)); | |
219 ExpectNextOperation(parser.get(), | |
220 cases[i].expected_name, | |
221 cases[i].expected_args, | |
222 cases[i].expected_ends_sentence); | |
223 EXPECT_TRUE(parser->HasFinished()); | |
224 } | |
225 } | |
226 | |
227 TEST(JtlParser, ParsingMultipleWellFormedOperations) { | |
228 const char kSourceCode[] = | |
229 "foo1(true)/foo2/foo3(\"bar\");" | |
230 "foo4(\"bar\", false);"; | |
231 | |
232 scoped_ptr<JtlParser> parser(CreateParserFromVerboseText(kSourceCode)); | |
233 ExpectNextOperation(parser.get(), "foo1", "[true]", false); | |
234 ExpectNextOperation(parser.get(), "foo2", "[]", false); | |
235 ExpectNextOperation(parser.get(), "foo3", "[\"bar\"]", true); | |
236 ExpectNextOperation(parser.get(), "foo4", "[\"bar\",false]", true); | |
237 EXPECT_TRUE(parser->HasFinished()); | |
238 } | |
239 | |
240 TEST(JtlParser, ParsingTrickyStringLiterals) { | |
241 struct TestCase { | |
242 const char* source_code; | |
243 const char* expected_name; | |
244 const char* expected_args; | |
245 const bool expected_ends_sentence; | |
246 } cases[] = { | |
247 {"prev()/foo1(\"\");next(true);", "foo1", "[\"\"]", true}, | |
248 {"prev()/foo2(\",\",true);next(true);", "foo2", "[\",\",true]", true}, | |
249 {"prev()/foo3(\")\",true);next(true);", "foo3", "[\")\",true]", true}, | |
250 {"prev()/foo4(\";\",true);next(true);", "foo4", "[\";\",true]", true}, | |
251 {"prev()/foo5(\"/\",true)/next(true);", "foo5", "[\"/\",true]", false}, | |
252 {"prev()/foo6(\"//\",true)/next(true);", "foo6", "[\"//\",true]", false}, | |
253 }; | |
254 | |
255 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
256 SCOPED_TRACE(cases[i].expected_name); | |
257 scoped_ptr<JtlParser> parser( | |
258 CreateParserFromVerboseText(cases[i].source_code)); | |
259 ExpectNextOperation(parser.get(), "prev", "[]", false); | |
260 ExpectNextOperation(parser.get(), | |
261 cases[i].expected_name, | |
262 cases[i].expected_args, | |
263 cases[i].expected_ends_sentence); | |
264 ExpectNextOperation(parser.get(), "next", "[true]", true); | |
265 EXPECT_TRUE(parser->HasFinished()); | |
266 } | |
267 } | |
268 | |
269 TEST(JtlParser, FirstOperationIsIllFormed) { | |
270 struct TestCase { | |
271 const char* source_code; | |
272 const char* operation_name; | |
273 } cases[] = { | |
274 {";;", ";"}, | |
275 {"bad_args1(not a boolean value);", "bad_args1"}, | |
276 {"bad_args2(,);", "bad_args2"}, | |
277 {"bad_args3(...);", "bad_args3"}, | |
278 {"bad_args4(1);", "bad_args4"}, | |
279 {"bad_args5(1.2);", "bad_args5"}, | |
280 {"bad_args6([\"bar\"]);", "bad_args6"}, | |
281 {"bad_args7(False);", "bad_args7"}, | |
282 {"bad_args8(True);", "bad_args8"}, | |
283 {"bad_quotes1(missing two, true)/good();", "bad_quotes1"}, | |
284 {"bad_quotes2(true, \"missing one)/good(); //\"", "bad_quotes2"}, | |
285 {"bad_quotes3(\"too\" \"much\", true)/good();", "bad_quotes3"}, | |
286 {"bad_missing_separator1", "bad_missing_separator1"}, | |
287 {"bad_missing_separator2()good();", "bad_missing_separator2"}, | |
288 {"bad_parenthesis1(true/good();", "bad_parenthesis1"}, | |
289 {"bad_parenthesis2(true/good());", "bad_parenthesis2"}, | |
290 {"bad_parenthesis3)/good();", "bad_parenthesis3"} | |
291 }; | |
292 | |
293 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
294 SCOPED_TRACE(cases[i].operation_name); | |
295 scoped_ptr<JtlParser> parser( | |
296 CreateParserFromVerboseText(cases[i].source_code)); | |
297 ExpectNextOperationToFail(parser.get(), 0, cases[i].operation_name); | |
298 } | |
299 } | |
300 | |
301 TEST(JtlParser, SecondOperationIsIllFormed) { | |
302 struct TestCase { | |
303 const char* source_code; | |
304 const char* bad_operation_name; | |
305 } cases[] = { | |
306 {"\ngood(true,false)\n/bad_args(,);", "bad_args"}, | |
307 {"\ngood(true,false)\n/bad_quotes1(missing two, true)/good();", | |
308 "bad_quotes1"}, | |
309 {"\ngood(true,false)\n/bad_quotes2(\"missing one, true)/good(); //\"", | |
310 "bad_quotes2"}, | |
311 {"\ngood(true,false)\n/bad_quotes3(\"too\" \"many\", true)/good();", | |
312 "bad_quotes3"}, | |
313 {"\ngood(true,false)\n/missing_separator1", "missing_separator1"}, | |
314 {"\ngood(true,false)\n/missing_separator2()good()", "missing_separator2"}, | |
315 {"\ngood(true,false)\n/bad_parens1(true/good();", "bad_parens1"}, | |
316 {"\ngood(true,false)\n/bad_parens2(true/good());", "bad_parens2"}, | |
317 {"\ngood(true,false)\n/bad_parens3)/good();", "bad_parens3"} | |
318 }; | |
319 | |
320 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
321 SCOPED_TRACE(cases[i].bad_operation_name); | |
322 scoped_ptr<JtlParser> parser( | |
323 CreateParserFromVerboseText(cases[i].source_code)); | |
324 ExpectNextOperation(parser.get(), "good", "[true,false]", false); | |
325 ExpectNextOperationToFail(parser.get(), 2, cases[i].bad_operation_name); | |
326 } | |
327 } | |
328 | |
329 } // namespace | |
OLD | NEW |