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 }; |
| 268 |
| 269 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| 270 SCOPED_TRACE(cases[i].expected_name); |
| 271 scoped_ptr<JtlParser> parser( |
| 272 CreateParserFromVerboseText(cases[i].source_code)); |
| 273 ExpectNextOperation(parser.get(), "prev", "[]", false); |
| 274 ExpectNextOperation(parser.get(), |
| 275 cases[i].expected_name, |
| 276 cases[i].expected_args, |
| 277 cases[i].expected_ends_sentence); |
| 278 ExpectNextOperation(parser.get(), "next", "[true]", true); |
| 279 EXPECT_TRUE(parser->HasFinished()); |
| 280 } |
| 281 } |
| 282 |
| 283 TEST(JtlParser, FirstOperationIsIllFormed) { |
| 284 struct TestCase { |
| 285 const char* source_code; |
| 286 const char* operation_name; |
| 287 } cases[] = { |
| 288 {";;", ";"}, |
| 289 {"bad_args1(not a boolean value);", "bad_args1"}, |
| 290 {"bad_args2(,);", "bad_args2"}, |
| 291 {"bad_args3(...);", "bad_args3"}, |
| 292 {"bad_args4(1);", "bad_args4"}, |
| 293 {"bad_args5(1.2);", "bad_args5"}, |
| 294 {"bad_args6([\"bar\"]);", "bad_args6"}, |
| 295 {"bad_args7(False);", "bad_args7"}, |
| 296 {"bad_args8(True);", "bad_args8"}, |
| 297 {"bad_quotes1(missing both, true)/good();", "bad_quotes1"}, |
| 298 {"bad_quotes2(true, \"missing one)/good(); //\"", "bad_quotes2"}, |
| 299 {"bad_quotes3(\"too\" \"much\", true)/good();", "bad_quotes3"}, |
| 300 {"bad_missing_separator1", "bad_missing_separator1"}, |
| 301 {"bad_missing_separator2()good();", "bad_missing_separator2"}, |
| 302 {"bad_parenthesis1(true/good();", "bad_parenthesis1"}, |
| 303 {"bad_parenthesis2(true/good());", "bad_parenthesis2"}, |
| 304 {"bad_parenthesis3)/good();", "bad_parenthesis3"} |
| 305 }; |
| 306 |
| 307 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| 308 SCOPED_TRACE(cases[i].operation_name); |
| 309 scoped_ptr<JtlParser> parser( |
| 310 CreateParserFromVerboseText(cases[i].source_code)); |
| 311 ExpectNextOperationToFail(parser.get(), 0, cases[i].operation_name); |
| 312 } |
| 313 } |
| 314 |
| 315 TEST(JtlParser, SecondOperationIsIllFormed) { |
| 316 struct TestCase { |
| 317 const char* source_code; |
| 318 const char* bad_operation_name; |
| 319 } cases[] = { |
| 320 {"\ngood(true,false)\n/bad_args(,);", "bad_args"}, |
| 321 {"\ngood(true,false)\n/bad_quotes1(missing both, true)/good();", |
| 322 "bad_quotes1"}, |
| 323 {"\ngood(true,false)\n/bad_quotes2(\"missing one, true)/good(); //\"", |
| 324 "bad_quotes2"}, |
| 325 {"\ngood(true,false)\n/bad_quotes3(\"too\" \"many\", true)/good();", |
| 326 "bad_quotes3"}, |
| 327 {"\ngood(true,false)\n/missing_separator1", "missing_separator1"}, |
| 328 {"\ngood(true,false)\n/missing_separator2()good()", "missing_separator2"}, |
| 329 {"\ngood(true,false)\n/bad_parens1(true/good();", "bad_parens1"}, |
| 330 {"\ngood(true,false)\n/bad_parens2(true/good());", "bad_parens2"}, |
| 331 {"\ngood(true,false)\n/bad_parens3)/good();", "bad_parens3"} |
| 332 }; |
| 333 |
| 334 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| 335 SCOPED_TRACE(cases[i].bad_operation_name); |
| 336 scoped_ptr<JtlParser> parser( |
| 337 CreateParserFromVerboseText(cases[i].source_code)); |
| 338 ExpectNextOperation(parser.get(), "good", "[true,false]", false); |
| 339 ExpectNextOperationToFail(parser.get(), 2, cases[i].bad_operation_name); |
| 340 } |
| 341 } |
| 342 |
| 343 } // namespace |
OLD | NEW |