OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 "tools/gn/line_breaker.h" |
| 6 |
| 7 #include <sstream> |
| 8 |
| 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 #include "tools/gn/input_file.h" |
| 11 #include "tools/gn/parser.h" |
| 12 #include "tools/gn/source_file.h" |
| 13 #include "tools/gn/tokenizer.h" |
| 14 |
| 15 namespace commands { |
| 16 |
| 17 namespace { |
| 18 |
| 19 bool GetTokens(const InputFile* input, std::vector<Token>* result) { |
| 20 result->clear(); |
| 21 Err err; |
| 22 *result = Tokenizer::Tokenize(input, &err); |
| 23 return !err.has_error(); |
| 24 } |
| 25 |
| 26 const char* NameForAnnotatedTokenType(int type) { |
| 27 switch (type) { |
| 28 case Token::INVALID: return "INVALID"; |
| 29 case Token::INTEGER: return "INTEGER"; |
| 30 case Token::STRING: return "STRING"; |
| 31 case Token::TRUE_TOKEN: return "TRUE_TOKEN"; |
| 32 case Token::FALSE_TOKEN: return "FALSE_TOKEN"; |
| 33 case Token::EQUAL: return "EQUAL"; |
| 34 case Token::PLUS: return "PLUS"; |
| 35 case Token::MINUS: return "MINUS"; |
| 36 case Token::PLUS_EQUALS: return "PLUS_EQUALS"; |
| 37 case Token::MINUS_EQUALS: return "MINUS_EQUALS"; |
| 38 case Token::EQUAL_EQUAL: return "EQUAL_EQUAL"; |
| 39 case Token::NOT_EQUAL: return "NOT_EQUAL"; |
| 40 case Token::LESS_EQUAL: return "LESS_EQUAL"; |
| 41 case Token::GREATER_EQUAL: return "GREATER_EQUAL"; |
| 42 case Token::LESS_THAN: return "LESS_THAN"; |
| 43 case Token::GREATER_THAN: return "GREATER_THAN"; |
| 44 case Token::BOOLEAN_AND: return "BOOLEAN_AND"; |
| 45 case Token::BOOLEAN_OR: return "BOOLEAN_OR"; |
| 46 case Token::BANG: return "BANG"; |
| 47 case Token::DOT: return "DOT"; |
| 48 case Token::LEFT_PAREN: return "LEFT_PAREN"; |
| 49 case Token::RIGHT_PAREN: return "RIGHT_PAREN"; |
| 50 case Token::LEFT_BRACKET: return "LEFT_BRACKET"; |
| 51 case Token::RIGHT_BRACKET: return "RIGHT_BRACKET"; |
| 52 case Token::LEFT_BRACE: return "LEFT_BRACE"; |
| 53 case Token::RIGHT_BRACE: return "RIGHT_BRACE"; |
| 54 case Token::IF: return "IF"; |
| 55 case Token::ELSE: return "ELSE"; |
| 56 case Token::IDENTIFIER: return "IDENTIFIER"; |
| 57 case Token::COMMA: return "COMMA"; |
| 58 case Token::UNCLASSIFIED_COMMENT: return "UNCLASSIFIED_COMMENT"; |
| 59 case Token::LINE_COMMENT: return "LINE_COMMENT"; |
| 60 case Token::SUFFIX_COMMENT: return "SUFFIX_COMMENT"; |
| 61 case Token::BLOCK_COMMENT: return "BLOCK_COMMENT"; |
| 62 case Token::UNCLASSIFIED_OPERATOR: return "UNCLASSIFIED_OPERATOR"; |
| 63 case AnnotatedToken::LEFT_PAREN_FUNCTION_CALL: |
| 64 return "LEFT_PAREN_FUNCTION_CALL"; |
| 65 case AnnotatedToken::LEFT_PAREN_GROUPING: return "LEFT_PAREN_GROUPING"; |
| 66 case AnnotatedToken::LEFT_BRACKET_LIST_LITERAL: |
| 67 return "LEFT_BRACKET_LIST_LITERAL"; |
| 68 case AnnotatedToken::LEFT_BRACKET_ACCESSOR: return "LEFT_BRACKET_ACCESSOR"; |
| 69 default: |
| 70 NOTREACHED(); |
| 71 return "???"; |
| 72 } |
| 73 } |
| 74 |
| 75 // This tests the parse tree segmentation and token annotation. |
| 76 void AnnotationTest(const char* input, const char* expected) { |
| 77 std::vector<Token> tokens; |
| 78 InputFile input_file(SourceFile("/test")); |
| 79 input_file.SetContents(input); |
| 80 ASSERT_TRUE(GetTokens(&input_file, &tokens)); |
| 81 |
| 82 Err err; |
| 83 scoped_ptr<ParseNode> result = Parser::Parse(tokens, &err); |
| 84 if (!result) |
| 85 err.PrintToStdout(); |
| 86 ASSERT_TRUE(result); |
| 87 |
| 88 std::vector<AnnotatedToken> annotated = BuildAnnotatedTokenList(result.get()); |
| 89 std::ostringstream collector; |
| 90 for (const auto& tok : annotated) { |
| 91 collector << NameForAnnotatedTokenType(tok.type()) << " (" << tok.value() |
| 92 << ")\n"; |
| 93 } |
| 94 EXPECT_EQ(expected, collector.str()); |
| 95 } |
| 96 |
| 97 // This tests that we actually break at a desirable locations. |
| 98 void BreakTest(const char* input, const char* expected) { |
| 99 std::vector<Token> tokens; |
| 100 InputFile input_file(SourceFile("/test")); |
| 101 input_file.SetContents(input); |
| 102 ASSERT_TRUE(GetTokens(&input_file, &tokens)); |
| 103 |
| 104 Err err; |
| 105 scoped_ptr<ParseNode> result = Parser::Parse(tokens, &err); |
| 106 if (!result) |
| 107 err.PrintToStdout(); |
| 108 ASSERT_TRUE(result); |
| 109 |
| 110 std::vector<AnnotatedToken> annotated = BuildAnnotatedTokenList(result.get()); |
| 111 LineBreaker line_breaker(annotated, 0); |
| 112 std::string final = line_breaker.GetBestLayout(); |
| 113 EXPECT_EQ(expected, final); |
| 114 } |
| 115 |
| 116 } // namespace |
| 117 |
| 118 TEST(Annotation, Trivial) { |
| 119 AnnotationTest("a = 0", |
| 120 "IDENTIFIER (a)\n" |
| 121 "EQUAL (=)\n" |
| 122 "INTEGER (0)\n"); |
| 123 } |
| 124 |
| 125 TEST(Annotation, StopAtBreak) { |
| 126 AnnotationTest("a = 0\nb = 2", |
| 127 "IDENTIFIER (a)\n" |
| 128 "EQUAL (=)\n" |
| 129 "INTEGER (0)\n"); |
| 130 } |
| 131 |
| 132 TEST(Annotation, DistinguishFunctionFromBinop) { |
| 133 AnnotationTest("stuff()", |
| 134 "IDENTIFIER (stuff)\n" |
| 135 "LEFT_PAREN_FUNCTION_CALL (()\n" |
| 136 "RIGHT_PAREN ())\n"); |
| 137 |
| 138 AnnotationTest("stuff(1)", |
| 139 "IDENTIFIER (stuff)\n" |
| 140 "LEFT_PAREN_FUNCTION_CALL (()\n" |
| 141 "INTEGER (1)\n" |
| 142 "RIGHT_PAREN ())\n"); |
| 143 |
| 144 AnnotationTest("stuff(1, 2)", |
| 145 "IDENTIFIER (stuff)\n" |
| 146 "LEFT_PAREN_FUNCTION_CALL (()\n" |
| 147 "INTEGER (1)\n" |
| 148 "COMMA (,)\n" |
| 149 "INTEGER (2)\n" |
| 150 "RIGHT_PAREN ())\n"); |
| 151 |
| 152 AnnotationTest("a = is_win && (is_mac || is_ios)", |
| 153 "IDENTIFIER (a)\n" |
| 154 "EQUAL (=)\n" |
| 155 "IDENTIFIER (is_win)\n" |
| 156 "BOOLEAN_AND (&&)\n" |
| 157 "LEFT_PAREN_GROUPING (()\n" |
| 158 "IDENTIFIER (is_mac)\n" |
| 159 "BOOLEAN_OR (||)\n" |
| 160 "IDENTIFIER (is_ios)\n" |
| 161 "RIGHT_PAREN ())\n"); |
| 162 } |
| 163 |
| 164 TEST(Annotation, DistinguishAccessorFromList) { |
| 165 AnnotationTest("stuff = [\"a\", \"b\"]", |
| 166 "IDENTIFIER (stuff)\n" |
| 167 "EQUAL (=)\n" |
| 168 "LEFT_BRACKET_LIST_LITERAL ([)\n" |
| 169 "STRING (\"a\")\n" |
| 170 "COMMA (,)\n" |
| 171 "STRING (\"b\")\n" |
| 172 "RIGHT_BRACKET (])\n"); |
| 173 |
| 174 AnnotationTest("stuff = a[4]", |
| 175 "IDENTIFIER (stuff)\n" |
| 176 "EQUAL (=)\n" |
| 177 "LEFT_BRACKET_ACCESSOR ([)\n" |
| 178 "INTEGER (4)\n" |
| 179 "RIGHT_BRACKET (])\n"); |
| 180 } |
| 181 |
| 182 TEST(LineBreaker, Trivial) { |
| 183 BreakTest("", ""); |
| 184 BreakTest("a()", "a()"); |
| 185 } |
| 186 |
| 187 TEST(LineBreaker, StatementsAt0) { |
| 188 BreakTest("stuff = []", "stuff = []"); |
| 189 BreakTest("import(\"wee.gni\")", "import(\"wee.gni\")"); |
| 190 } |
| 191 |
| 192 } // namespace commands |
OLD | NEW |