Index: tools/gn/line_breaker_unittest.cc |
diff --git a/tools/gn/line_breaker_unittest.cc b/tools/gn/line_breaker_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4bfe71c5b72f44847103c1bda5e55a0c5d565344 |
--- /dev/null |
+++ b/tools/gn/line_breaker_unittest.cc |
@@ -0,0 +1,192 @@ |
+// Copyright 2014 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 "tools/gn/line_breaker.h" |
+ |
+#include <sstream> |
+ |
+#include "testing/gtest/include/gtest/gtest.h" |
+#include "tools/gn/input_file.h" |
+#include "tools/gn/parser.h" |
+#include "tools/gn/source_file.h" |
+#include "tools/gn/tokenizer.h" |
+ |
+namespace commands { |
+ |
+namespace { |
+ |
+bool GetTokens(const InputFile* input, std::vector<Token>* result) { |
+ result->clear(); |
+ Err err; |
+ *result = Tokenizer::Tokenize(input, &err); |
+ return !err.has_error(); |
+} |
+ |
+const char* NameForAnnotatedTokenType(int type) { |
+ switch (type) { |
+ case Token::INVALID: return "INVALID"; |
+ case Token::INTEGER: return "INTEGER"; |
+ case Token::STRING: return "STRING"; |
+ case Token::TRUE_TOKEN: return "TRUE_TOKEN"; |
+ case Token::FALSE_TOKEN: return "FALSE_TOKEN"; |
+ case Token::EQUAL: return "EQUAL"; |
+ case Token::PLUS: return "PLUS"; |
+ case Token::MINUS: return "MINUS"; |
+ case Token::PLUS_EQUALS: return "PLUS_EQUALS"; |
+ case Token::MINUS_EQUALS: return "MINUS_EQUALS"; |
+ case Token::EQUAL_EQUAL: return "EQUAL_EQUAL"; |
+ case Token::NOT_EQUAL: return "NOT_EQUAL"; |
+ case Token::LESS_EQUAL: return "LESS_EQUAL"; |
+ case Token::GREATER_EQUAL: return "GREATER_EQUAL"; |
+ case Token::LESS_THAN: return "LESS_THAN"; |
+ case Token::GREATER_THAN: return "GREATER_THAN"; |
+ case Token::BOOLEAN_AND: return "BOOLEAN_AND"; |
+ case Token::BOOLEAN_OR: return "BOOLEAN_OR"; |
+ case Token::BANG: return "BANG"; |
+ case Token::DOT: return "DOT"; |
+ case Token::LEFT_PAREN: return "LEFT_PAREN"; |
+ case Token::RIGHT_PAREN: return "RIGHT_PAREN"; |
+ case Token::LEFT_BRACKET: return "LEFT_BRACKET"; |
+ case Token::RIGHT_BRACKET: return "RIGHT_BRACKET"; |
+ case Token::LEFT_BRACE: return "LEFT_BRACE"; |
+ case Token::RIGHT_BRACE: return "RIGHT_BRACE"; |
+ case Token::IF: return "IF"; |
+ case Token::ELSE: return "ELSE"; |
+ case Token::IDENTIFIER: return "IDENTIFIER"; |
+ case Token::COMMA: return "COMMA"; |
+ case Token::UNCLASSIFIED_COMMENT: return "UNCLASSIFIED_COMMENT"; |
+ case Token::LINE_COMMENT: return "LINE_COMMENT"; |
+ case Token::SUFFIX_COMMENT: return "SUFFIX_COMMENT"; |
+ case Token::BLOCK_COMMENT: return "BLOCK_COMMENT"; |
+ case Token::UNCLASSIFIED_OPERATOR: return "UNCLASSIFIED_OPERATOR"; |
+ case AnnotatedToken::LEFT_PAREN_FUNCTION_CALL: |
+ return "LEFT_PAREN_FUNCTION_CALL"; |
+ case AnnotatedToken::LEFT_PAREN_GROUPING: return "LEFT_PAREN_GROUPING"; |
+ case AnnotatedToken::LEFT_BRACKET_LIST_LITERAL: |
+ return "LEFT_BRACKET_LIST_LITERAL"; |
+ case AnnotatedToken::LEFT_BRACKET_ACCESSOR: return "LEFT_BRACKET_ACCESSOR"; |
+ default: |
+ NOTREACHED(); |
+ return "???"; |
+ } |
+} |
+ |
+// This tests the parse tree segmentation and token annotation. |
+void AnnotationTest(const char* input, const char* expected) { |
+ std::vector<Token> tokens; |
+ InputFile input_file(SourceFile("/test")); |
+ input_file.SetContents(input); |
+ ASSERT_TRUE(GetTokens(&input_file, &tokens)); |
+ |
+ Err err; |
+ scoped_ptr<ParseNode> result = Parser::Parse(tokens, &err); |
+ if (!result) |
+ err.PrintToStdout(); |
+ ASSERT_TRUE(result); |
+ |
+ std::vector<AnnotatedToken> annotated = BuildAnnotatedTokenList(result.get()); |
+ std::ostringstream collector; |
+ for (const auto& tok : annotated) { |
+ collector << NameForAnnotatedTokenType(tok.type()) << " (" << tok.value() |
+ << ")\n"; |
+ } |
+ EXPECT_EQ(expected, collector.str()); |
+} |
+ |
+// This tests that we actually break at a desirable locations. |
+void BreakTest(const char* input, const char* expected) { |
+ std::vector<Token> tokens; |
+ InputFile input_file(SourceFile("/test")); |
+ input_file.SetContents(input); |
+ ASSERT_TRUE(GetTokens(&input_file, &tokens)); |
+ |
+ Err err; |
+ scoped_ptr<ParseNode> result = Parser::Parse(tokens, &err); |
+ if (!result) |
+ err.PrintToStdout(); |
+ ASSERT_TRUE(result); |
+ |
+ std::vector<AnnotatedToken> annotated = BuildAnnotatedTokenList(result.get()); |
+ LineBreaker line_breaker(annotated, 0); |
+ std::string final = line_breaker.GetBestLayout(); |
+ EXPECT_EQ(expected, final); |
+} |
+ |
+} // namespace |
+ |
+TEST(Annotation, Trivial) { |
+ AnnotationTest("a = 0", |
+ "IDENTIFIER (a)\n" |
+ "EQUAL (=)\n" |
+ "INTEGER (0)\n"); |
+} |
+ |
+TEST(Annotation, StopAtBreak) { |
+ AnnotationTest("a = 0\nb = 2", |
+ "IDENTIFIER (a)\n" |
+ "EQUAL (=)\n" |
+ "INTEGER (0)\n"); |
+} |
+ |
+TEST(Annotation, DistinguishFunctionFromBinop) { |
+ AnnotationTest("stuff()", |
+ "IDENTIFIER (stuff)\n" |
+ "LEFT_PAREN_FUNCTION_CALL (()\n" |
+ "RIGHT_PAREN ())\n"); |
+ |
+ AnnotationTest("stuff(1)", |
+ "IDENTIFIER (stuff)\n" |
+ "LEFT_PAREN_FUNCTION_CALL (()\n" |
+ "INTEGER (1)\n" |
+ "RIGHT_PAREN ())\n"); |
+ |
+ AnnotationTest("stuff(1, 2)", |
+ "IDENTIFIER (stuff)\n" |
+ "LEFT_PAREN_FUNCTION_CALL (()\n" |
+ "INTEGER (1)\n" |
+ "COMMA (,)\n" |
+ "INTEGER (2)\n" |
+ "RIGHT_PAREN ())\n"); |
+ |
+ AnnotationTest("a = is_win && (is_mac || is_ios)", |
+ "IDENTIFIER (a)\n" |
+ "EQUAL (=)\n" |
+ "IDENTIFIER (is_win)\n" |
+ "BOOLEAN_AND (&&)\n" |
+ "LEFT_PAREN_GROUPING (()\n" |
+ "IDENTIFIER (is_mac)\n" |
+ "BOOLEAN_OR (||)\n" |
+ "IDENTIFIER (is_ios)\n" |
+ "RIGHT_PAREN ())\n"); |
+} |
+ |
+TEST(Annotation, DistinguishAccessorFromList) { |
+ AnnotationTest("stuff = [\"a\", \"b\"]", |
+ "IDENTIFIER (stuff)\n" |
+ "EQUAL (=)\n" |
+ "LEFT_BRACKET_LIST_LITERAL ([)\n" |
+ "STRING (\"a\")\n" |
+ "COMMA (,)\n" |
+ "STRING (\"b\")\n" |
+ "RIGHT_BRACKET (])\n"); |
+ |
+ AnnotationTest("stuff = a[4]", |
+ "IDENTIFIER (stuff)\n" |
+ "EQUAL (=)\n" |
+ "LEFT_BRACKET_ACCESSOR ([)\n" |
+ "INTEGER (4)\n" |
+ "RIGHT_BRACKET (])\n"); |
+} |
+ |
+TEST(LineBreaker, Trivial) { |
+ BreakTest("", ""); |
+ BreakTest("a()", "a()"); |
+} |
+ |
+TEST(LineBreaker, StatementsAt0) { |
+ BreakTest("stuff = []", "stuff = []"); |
+ BreakTest("import(\"wee.gni\")", "import(\"wee.gni\")"); |
+} |
+ |
+} // namespace commands |