Chromium Code Reviews| Index: chrome/tools/profile_reset/jtl_parser_unittest.cc |
| diff --git a/chrome/tools/profile_reset/jtl_parser_unittest.cc b/chrome/tools/profile_reset/jtl_parser_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9a9df777ca41d4d15db5f18b4892c5eb7b289a23 |
| --- /dev/null |
| +++ b/chrome/tools/profile_reset/jtl_parser_unittest.cc |
| @@ -0,0 +1,270 @@ |
| +// Copyright 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/tools/profile_reset/jtl_parser.h" |
| + |
| +#include <string> |
| + |
| +#include "base/json/json_writer.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/values.h" |
| +#include "testing/gmock/include/gmock/gmock-matchers.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace { |
| + |
| +// Helpers ------------------------------------------------------------------- |
| + |
| +void ExpectNextOperation(JtlParser* parser, |
| + const char* expected_name, |
| + const char* expected_args, |
| + bool expected_ends_sentence) { |
| + std::string actual_name; |
| + base::ListValue actual_args; |
| + std::string actual_args_json; |
| + bool actual_ends_sentence; |
| + |
| + EXPECT_TRUE(parser->HasNextOperation()); |
| + EXPECT_TRUE(parser->ParseNextOperation( |
| + &actual_name, &actual_args, &actual_ends_sentence)); |
| + EXPECT_EQ(expected_name, actual_name); |
| + base::JSONWriter::Write(&actual_args, &actual_args_json); |
| + EXPECT_EQ(expected_args, actual_args_json); |
| + EXPECT_EQ(expected_ends_sentence, actual_ends_sentence); |
| +} |
| + |
| +void ExpectNextOperationToFail(JtlParser* parser, |
| + size_t expected_line_number, |
| + const char* expected_context_prefix) { |
| + std::string actual_name; |
| + base::ListValue actual_args; |
| + bool actual_ends_sentence; |
| + |
| + EXPECT_TRUE(parser->HasNextOperation()); |
| + EXPECT_FALSE(parser->ParseNextOperation( |
| + &actual_name, &actual_args, &actual_ends_sentence)); |
| + EXPECT_THAT(parser->last_context(), |
| + testing::StartsWith(expected_context_prefix)); |
| + EXPECT_EQ(expected_line_number, parser->last_line_number()); |
| +} |
| + |
| +// Tests --------------------------------------------------------------------- |
| + |
| +TEST(JtlParser, CompactingEmpty) { |
| + const char kSourceCode[] = ""; |
| + const char kCompactedSourceCode[] = ""; |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); |
| +} |
| + |
| +TEST(JtlParser, CompactingTrivial) { |
| + const char kSourceCode[] = "foo"; |
| + const char kCompactedSourceCode[] = "foo"; |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); |
| +} |
| + |
| +TEST(JtlParser, CompactingOneLine) { |
| + const char kSourceCode[] = " \r f\to o ( true ) "; |
| + const char kCompactedSourceCode[] = "foo(true)"; |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); |
| + for (size_t i = 0; i < arraysize(kCompactedSourceCode) - 1; ++i) { |
| + SCOPED_TRACE(testing::Message("Position ") << i); |
| + EXPECT_EQ(0u, parser->GetOriginalLineNumber(i)); |
| + } |
| +} |
| + |
| +TEST(JtlParser, CompactingMultipleLines) { |
| + const char kSourceCode[] = "a\nbb\n \nccc \n\n d( \n e \n )"; |
| + const char kCompactedSourceCode[] = "abbcccd(e)"; |
| + const size_t kLineNumbers[] = {0u, 1u, 1u, 3u, 3u, 3u, 5u, 5u, 6u, 7u}; |
| + COMPILE_ASSERT(arraysize(kCompactedSourceCode) == arraysize(kLineNumbers) + 1, |
| + mismatched_test_data); |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); |
| + for (size_t i = 0; i < arraysize(kLineNumbers); ++i) { |
| + SCOPED_TRACE(testing::Message("Position ") << i); |
| + EXPECT_EQ(kLineNumbers[i], parser->GetOriginalLineNumber(i)); |
| + } |
| +} |
| + |
| +TEST(JtlParser, HandlingCommentsAndStringLiterals) { |
| + struct TestCase { |
| + const char* source_code; |
| + const char* compacted_source_code; |
| + } cases[] = { |
| + {"//", ""}, |
| + {"//comment", ""}, |
| + {"foo //comment", "foo"}, |
| + {"\"\"", "\"\""}, |
| + {"\"\" // comment", "\"\""}, |
| + {"\"literal\" // comment", "\"literal\""}, |
| + {"\"literal\" \"literal\" // comment", "\"literal\"\"literal\""}, |
| + {"foo // \"not a literal\"", "foo"}, |
| + {"foo // \"not even matched", "foo"}, |
| + {"foo // \"not a literal\" \"not even matched", "foo"}, |
| + {"\"literal\" // \"not a literal\"", "\"literal\""}, |
| + {"\"literal\" // \"not even matched", "\"literal\""}, |
| + {"\"//not a comment//\"", "\"//notacomment//\""}, |
|
battre
2013/09/27 15:00:01
This looks incorrect. You strip whitespaces in lit
engedy
2013/10/01 10:48:41
This is done as well.
|
| + {"\"//not a comment//\" // comment", "\"//notacomment//\""}, |
| + {"// \"//not a literal//\" // comment", ""}, |
| + {"\"mistmachedliteral // comment", "\"mistmachedliteral"}, |
| + {"\"literal // \"not a literal\"", "\"literal//\"notaliteral\""}, }; |
|
battre
2013/09/27 15:00:01
Please add
"\"//literal\" \"//literal\""
engedy
2013/10/01 10:48:10
This is already done 3 lines above.
|
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + SCOPED_TRACE(cases[i].source_code); |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(cases[i].source_code)); |
| + EXPECT_EQ(cases[i].compacted_source_code, parser->compacted_source()); |
| + } |
| +} |
| + |
| +TEST(JtlParser, CompactingOneLinesWithComments) { |
| + const char kSourceCode[] = |
| + "a/ /b//Comment \n//\n// Full line comment\n cd //"; |
| + const char kCompactedSourceCode[] = "a//bcd"; |
| + const size_t kLineNumbers[] = {0u, 0u, 0u, 0u, 3u, 3u}; |
| + COMPILE_ASSERT(arraysize(kCompactedSourceCode) == arraysize(kLineNumbers) + 1, |
| + mismatched_test_data); |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + EXPECT_EQ(kCompactedSourceCode, parser->compacted_source()); |
| + for (size_t i = 0; i < arraysize(kLineNumbers); ++i) { |
| + SCOPED_TRACE(testing::Message("Position ") << i); |
| + EXPECT_EQ(kLineNumbers[i], parser->GetOriginalLineNumber(i)); |
| + } |
| +} |
| + |
| +TEST(JtlParser, ParsingEmpty) { |
| + const char kSourceCode[] = ""; |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + EXPECT_FALSE(parser->HasNextOperation()); |
| +} |
| + |
| +TEST(JtlParser, ParsingOneWellFormedOperation) { |
| + struct TestCase { |
| + const char* source_code; |
| + const char* expected_name; |
| + const char* expected_args; |
| + const bool expected_ends_sentence; |
| + } cases[] = { |
| + {"foo1;", "foo1", "[]", true}, |
| + {"foo2()/", "foo2", "[]", false}, |
| + {"foo3(true);", "foo3", "[true]", true}, |
| + {"foo4(false)/", "foo4", "[false]", false}, |
| + {"foo5(\"bar\")/", "foo5", "[\"bar\"]", false}, |
| + {"foo6(true, \"bar\")/", "foo6", "[true,\"bar\"]", false}, |
| + {"foo7(\"bar\", false, true);", "foo7", "[\"bar\",false,true]", true} |
| + }; |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + SCOPED_TRACE(cases[i].expected_name); |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(cases[i].source_code)); |
| + ExpectNextOperation(parser.get(), |
| + cases[i].expected_name, |
| + cases[i].expected_args, |
| + cases[i].expected_ends_sentence); |
| + EXPECT_FALSE(parser->HasNextOperation()); |
| + } |
| +} |
| + |
| +TEST(JtlParser, ParsingMultipleWellFormedOperations) { |
| + const char kSourceCode[] = |
| + "foo1(true)/foo2/foo3(\"bar\");" |
| + "foo4(\"bar\", false);"; |
| + |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(kSourceCode)); |
| + ExpectNextOperation(parser.get(), "foo1", "[true]", false); |
| + ExpectNextOperation(parser.get(), "foo2", "[]", false); |
| + ExpectNextOperation(parser.get(), "foo3", "[\"bar\"]", true); |
| + ExpectNextOperation(parser.get(), "foo4", "[\"bar\",false]", true); |
| + EXPECT_FALSE(parser->HasNextOperation()); |
| +} |
| + |
| +TEST(JtlParser, ParsingTrickyStringLiterals) { |
| + struct TestCase { |
| + const char* source_code; |
| + const char* expected_name; |
| + const char* expected_args; |
| + const bool expected_ends_sentence; |
| + } cases[] = { |
| + {"prev()/foo1(\"\");next(true);", "foo1", "[\"\"]", true}, |
| + {"prev()/foo2(\",\",true);next(true);", "foo2", "[\",\",true]", true}, |
| + {"prev()/foo3(\")\",true);next(true);", "foo3", "[\")\",true]", true}, |
| + {"prev()/foo4(\";\",true);next(true);", "foo4", "[\";\",true]", true}, |
| + {"prev()/foo5(\"/\",true)/next(true);", "foo5", "[\"/\",true]", false}, |
| + {"prev()/foo6(\"//\",true)/next(true);", "foo6", "[\"//\",true]", false}, |
| + }; |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + SCOPED_TRACE(cases[i].expected_name); |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(cases[i].source_code)); |
| + ExpectNextOperation(parser.get(), "prev", "[]", false); |
| + ExpectNextOperation(parser.get(), |
| + cases[i].expected_name, |
| + cases[i].expected_args, |
| + cases[i].expected_ends_sentence); |
| + ExpectNextOperation(parser.get(), "next", "[true]", true); |
| + EXPECT_FALSE(parser->HasNextOperation()); |
| + } |
| +} |
| + |
| +TEST(JtlParser, FirstOperationIsIllFormed) { |
|
battre
2013/09/27 15:00:01
Add a test for parsing program ";;"?
engedy
2013/10/01 10:48:10
Done.
|
| + struct TestCase { |
| + const char* source_code; |
| + const char* operation_name; |
| + } cases[] = { |
| + {"bad_args1(not a boolean value);", "bad_args1"}, |
| + {"bad_args2(,);", "bad_args2"}, |
| + {"bad_args3(...);", "bad_args3"}, |
| + {"bad_args4(1);", "bad_args4"}, |
| + {"bad_args5(1.2);", "bad_args5"}, |
| + {"bad_args6([\"bar\"]);", "bad_args6"}, |
| + {"bad_args7(False);", "bad_args7"}, |
| + {"bad_args8(True);", "bad_args8"}, |
| + {"bad_quotes1(\"missing, true)/good();", "bad_quotes1"}, |
| + {"bad_quotes2(\", true)/good();", "bad_quotes2"}, |
| + {"bad_missing_separator1", "bad_missing_separator1"}, |
| + {"bad_missing_separator2()good();", "bad_missing_separator2"}, |
| + {"bad_parenthesis1(true/good();", "bad_parenthesis1"}, |
| + {"bad_parenthesis2(true/good());", "bad_parenthesis2"}, |
| + {"bad_parenthesis3)/good();", "bad_parenthesis3"} |
| + }; |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + SCOPED_TRACE(cases[i].operation_name); |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(cases[i].source_code)); |
| + ExpectNextOperationToFail(parser.get(), 0, cases[i].operation_name); |
| + } |
| +} |
| + |
| +TEST(JtlParser, SecondOperationIsIllFormed) { |
| + struct TestCase { |
| + const char* source_code; |
| + const char* bad_operation_name; |
| + } cases[] = { |
| + {"\ngood(true,false)\n/bad_args(,);", "bad_args"}, |
| + {"\ngood(true,false)\n/bad_quotes1(bar\", true)/good();", "bad_quotes1"}, |
| + {"\ngood(true,false)\n/bad_quotes2(\", true)/good();", "bad_quotes2"}, |
| + {"\ngood(true,false)\n/missing_separator1", "missing_separator1"}, |
| + {"\ngood(true,false)\n/missing_separator2()good()", "missing_separator2"}, |
| + {"\ngood(true,false)\n/bad_parens1(true/good();", "bad_parens1"}, |
| + {"\ngood(true,false)\n/bad_parens2(true/good());", "bad_parens2"}, |
| + {"\ngood(true,false)\n/bad_parens3)/good();", "bad_parens3"} |
| + }; |
| + |
| + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| + SCOPED_TRACE(cases[i].bad_operation_name); |
| + scoped_ptr<JtlParser> parser(JtlParser::Create(cases[i].source_code)); |
| + ExpectNextOperation(parser.get(), "good", "[true,false]", false); |
| + ExpectNextOperationToFail(parser.get(), 2, cases[i].bad_operation_name); |
| + } |
| +} |
| + |
| +} // namespace |