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