| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/operators.h" | 5 #include "tools/gn/operators.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 | 22 |
| 23 bool IsValueStringEqualing(const Value& v, const char* s) { | 23 bool IsValueStringEqualing(const Value& v, const char* s) { |
| 24 if (v.type() != Value::STRING) | 24 if (v.type() != Value::STRING) |
| 25 return false; | 25 return false; |
| 26 return v.string_value() == s; | 26 return v.string_value() == s; |
| 27 } | 27 } |
| 28 | 28 |
| 29 // Returns a list populated with a single literal Value corresponding to the | 29 // Returns a list populated with a single literal Value corresponding to the |
| 30 // given token. The token must outlive the list (since the list will just | 30 // given token. The token must outlive the list (since the list will just |
| 31 // copy the reference). | 31 // copy the reference). |
| 32 scoped_ptr<ListNode> ListWithLiteral(const Token& token) { | 32 std::unique_ptr<ListNode> ListWithLiteral(const Token& token) { |
| 33 scoped_ptr<ListNode> list(new ListNode); | 33 std::unique_ptr<ListNode> list(new ListNode); |
| 34 list->append_item(scoped_ptr<ParseNode>(new LiteralNode(token))); | 34 list->append_item(std::unique_ptr<ParseNode>(new LiteralNode(token))); |
| 35 return list; | 35 return list; |
| 36 } | 36 } |
| 37 | 37 |
| 38 } // namespace | 38 } // namespace |
| 39 | 39 |
| 40 TEST(Operators, SourcesAppend) { | 40 TEST(Operators, SourcesAppend) { |
| 41 Err err; | 41 Err err; |
| 42 TestWithScope setup; | 42 TestWithScope setup; |
| 43 | 43 |
| 44 // Set up "sources" with an empty list. | 44 // Set up "sources" with an empty list. |
| 45 const char sources[] = "sources"; | 45 const char sources[] = "sources"; |
| 46 setup.scope()->SetValue(sources, Value(nullptr, Value::LIST), nullptr); | 46 setup.scope()->SetValue(sources, Value(nullptr, Value::LIST), nullptr); |
| 47 | 47 |
| 48 // Set up the operator. | 48 // Set up the operator. |
| 49 BinaryOpNode node; | 49 BinaryOpNode node; |
| 50 const char token_value[] = "+="; | 50 const char token_value[] = "+="; |
| 51 Token op(Location(), Token::PLUS_EQUALS, token_value); | 51 Token op(Location(), Token::PLUS_EQUALS, token_value); |
| 52 node.set_op(op); | 52 node.set_op(op); |
| 53 | 53 |
| 54 // Append to the sources variable. | 54 // Append to the sources variable. |
| 55 Token identifier_token(Location(), Token::IDENTIFIER, sources); | 55 Token identifier_token(Location(), Token::IDENTIFIER, sources); |
| 56 node.set_left(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); | 56 node.set_left( |
| 57 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); |
| 57 | 58 |
| 58 // Set up the filter on the scope to remove everything ending with "rm" | 59 // Set up the filter on the scope to remove everything ending with "rm" |
| 59 scoped_ptr<PatternList> pattern_list(new PatternList); | 60 std::unique_ptr<PatternList> pattern_list(new PatternList); |
| 60 pattern_list->Append(Pattern("*rm")); | 61 pattern_list->Append(Pattern("*rm")); |
| 61 setup.scope()->set_sources_assignment_filter(std::move(pattern_list)); | 62 setup.scope()->set_sources_assignment_filter(std::move(pattern_list)); |
| 62 | 63 |
| 63 // Append an integer. | 64 // Append an integer. |
| 64 const char integer_value[] = "5"; | 65 const char integer_value[] = "5"; |
| 65 Token integer(Location(), Token::INTEGER, integer_value); | 66 Token integer(Location(), Token::INTEGER, integer_value); |
| 66 node.set_right(ListWithLiteral(integer)); | 67 node.set_right(ListWithLiteral(integer)); |
| 67 node.Execute(setup.scope(), &err); | 68 node.Execute(setup.scope(), &err); |
| 68 EXPECT_FALSE(err.has_error()); | 69 EXPECT_FALSE(err.has_error()); |
| 69 | 70 |
| 70 // Append a string that doesn't match the pattern, it should get appended. | 71 // Append a string that doesn't match the pattern, it should get appended. |
| 71 const char string_1_value[] = "\"good\""; | 72 const char string_1_value[] = "\"good\""; |
| 72 Token string_1(Location(), Token::STRING, string_1_value); | 73 Token string_1(Location(), Token::STRING, string_1_value); |
| 73 node.set_right(ListWithLiteral(string_1)); | 74 node.set_right(ListWithLiteral(string_1)); |
| 74 node.Execute(setup.scope(), &err); | 75 node.Execute(setup.scope(), &err); |
| 75 EXPECT_FALSE(err.has_error()); | 76 EXPECT_FALSE(err.has_error()); |
| 76 | 77 |
| 77 // Append a string that does match the pattern, it should be a no-op. | 78 // Append a string that does match the pattern, it should be a no-op. |
| 78 const char string_2_value[] = "\"foo-rm\""; | 79 const char string_2_value[] = "\"foo-rm\""; |
| 79 Token string_2(Location(), Token::STRING, string_2_value); | 80 Token string_2(Location(), Token::STRING, string_2_value); |
| 80 node.set_right(ListWithLiteral(string_2)); | 81 node.set_right(ListWithLiteral(string_2)); |
| 81 node.Execute(setup.scope(), &err); | 82 node.Execute(setup.scope(), &err); |
| 82 EXPECT_FALSE(err.has_error()); | 83 EXPECT_FALSE(err.has_error()); |
| 83 | 84 |
| 84 // Append a list with the two strings from above. | 85 // Append a list with the two strings from above. |
| 85 ListNode list; | 86 ListNode list; |
| 86 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_1))); | 87 list.append_item(std::unique_ptr<ParseNode>(new LiteralNode(string_1))); |
| 87 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_2))); | 88 list.append_item(std::unique_ptr<ParseNode>(new LiteralNode(string_2))); |
| 88 ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err); | 89 ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err); |
| 89 EXPECT_FALSE(err.has_error()); | 90 EXPECT_FALSE(err.has_error()); |
| 90 | 91 |
| 91 // The sources variable in the scope should now have: [ 5, "good", "good" ] | 92 // The sources variable in the scope should now have: [ 5, "good", "good" ] |
| 92 const Value* value = setup.scope()->GetValue(sources); | 93 const Value* value = setup.scope()->GetValue(sources); |
| 93 ASSERT_TRUE(value); | 94 ASSERT_TRUE(value); |
| 94 ASSERT_EQ(Value::LIST, value->type()); | 95 ASSERT_EQ(Value::LIST, value->type()); |
| 95 ASSERT_EQ(3u, value->list_value().size()); | 96 ASSERT_EQ(3u, value->list_value().size()); |
| 96 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5)); | 97 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5)); |
| 97 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good")); | 98 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good")); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 109 setup.scope()->SetValue(foo, Value(nullptr, Value::LIST), nullptr); | 110 setup.scope()->SetValue(foo, Value(nullptr, Value::LIST), nullptr); |
| 110 | 111 |
| 111 // Set up the operator. | 112 // Set up the operator. |
| 112 BinaryOpNode node; | 113 BinaryOpNode node; |
| 113 const char token_value[] = "+="; | 114 const char token_value[] = "+="; |
| 114 Token op(Location(), Token::PLUS_EQUALS, token_value); | 115 Token op(Location(), Token::PLUS_EQUALS, token_value); |
| 115 node.set_op(op); | 116 node.set_op(op); |
| 116 | 117 |
| 117 // Append to the foo variable. | 118 // Append to the foo variable. |
| 118 Token identifier_token(Location(), Token::IDENTIFIER, foo); | 119 Token identifier_token(Location(), Token::IDENTIFIER, foo); |
| 119 node.set_left(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); | 120 node.set_left( |
| 121 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); |
| 120 | 122 |
| 121 // Append a list with a list, the result should be a nested list. | 123 // Append a list with a list, the result should be a nested list. |
| 122 scoped_ptr<ListNode> outer_list(new ListNode); | 124 std::unique_ptr<ListNode> outer_list(new ListNode); |
| 123 const char twelve_str[] = "12"; | 125 const char twelve_str[] = "12"; |
| 124 Token twelve(Location(), Token::INTEGER, twelve_str); | 126 Token twelve(Location(), Token::INTEGER, twelve_str); |
| 125 outer_list->append_item(ListWithLiteral(twelve)); | 127 outer_list->append_item(ListWithLiteral(twelve)); |
| 126 node.set_right(std::move(outer_list)); | 128 node.set_right(std::move(outer_list)); |
| 127 | 129 |
| 128 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), | 130 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), |
| 129 node.right(), &err); | 131 node.right(), &err); |
| 130 EXPECT_FALSE(err.has_error()); | 132 EXPECT_FALSE(err.has_error()); |
| 131 | 133 |
| 132 // Return from the operator should always be "none", it should update the | 134 // Return from the operator should always be "none", it should update the |
| 133 // value only. | 135 // value only. |
| 134 EXPECT_EQ(Value::NONE, ret.type()); | 136 EXPECT_EQ(Value::NONE, ret.type()); |
| 135 | 137 |
| 136 // The value should be updated with "[ [ 12 ] ]" | 138 // The value should be updated with "[ [ 12 ] ]" |
| 137 Value result = *setup.scope()->GetValue(foo); | 139 Value result = *setup.scope()->GetValue(foo); |
| 138 ASSERT_EQ(Value::LIST, result.type()); | 140 ASSERT_EQ(Value::LIST, result.type()); |
| 139 ASSERT_EQ(1u, result.list_value().size()); | 141 ASSERT_EQ(1u, result.list_value().size()); |
| 140 ASSERT_EQ(Value::LIST, result.list_value()[0].type()); | 142 ASSERT_EQ(Value::LIST, result.list_value()[0].type()); |
| 141 ASSERT_EQ(1u, result.list_value()[0].list_value().size()); | 143 ASSERT_EQ(1u, result.list_value()[0].list_value().size()); |
| 142 ASSERT_EQ(Value::INTEGER, result.list_value()[0].list_value()[0].type()); | 144 ASSERT_EQ(Value::INTEGER, result.list_value()[0].list_value()[0].type()); |
| 143 ASSERT_EQ(12, result.list_value()[0].list_value()[0].int_value()); | 145 ASSERT_EQ(12, result.list_value()[0].list_value()[0].int_value()); |
| 144 | 146 |
| 145 // Try to append an integer and a string directly (e.g. foo += "hi"). | 147 // Try to append an integer and a string directly (e.g. foo += "hi"). |
| 146 // This should fail. | 148 // This should fail. |
| 147 const char str_str[] = "\"hi\""; | 149 const char str_str[] = "\"hi\""; |
| 148 Token str(Location(), Token::STRING, str_str); | 150 Token str(Location(), Token::STRING, str_str); |
| 149 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(str))); | 151 node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(str))); |
| 150 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); | 152 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); |
| 151 EXPECT_TRUE(err.has_error()); | 153 EXPECT_TRUE(err.has_error()); |
| 152 err = Err(); | 154 err = Err(); |
| 153 | 155 |
| 154 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(twelve))); | 156 node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(twelve))); |
| 155 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); | 157 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); |
| 156 EXPECT_TRUE(err.has_error()); | 158 EXPECT_TRUE(err.has_error()); |
| 157 } | 159 } |
| 158 | 160 |
| 159 TEST(Operators, ShortCircuitAnd) { | 161 TEST(Operators, ShortCircuitAnd) { |
| 160 Err err; | 162 Err err; |
| 161 TestWithScope setup; | 163 TestWithScope setup; |
| 162 | 164 |
| 163 // Set up the operator. | 165 // Set up the operator. |
| 164 BinaryOpNode node; | 166 BinaryOpNode node; |
| 165 const char token_value[] = "&&"; | 167 const char token_value[] = "&&"; |
| 166 Token op(Location(), Token::BOOLEAN_AND, token_value); | 168 Token op(Location(), Token::BOOLEAN_AND, token_value); |
| 167 node.set_op(op); | 169 node.set_op(op); |
| 168 | 170 |
| 169 // Set the left to false. | 171 // Set the left to false. |
| 170 const char false_str[] = "false"; | 172 const char false_str[] = "false"; |
| 171 Token false_tok(Location(), Token::FALSE_TOKEN, false_str); | 173 Token false_tok(Location(), Token::FALSE_TOKEN, false_str); |
| 172 node.set_left(scoped_ptr<ParseNode>(new LiteralNode(false_tok))); | 174 node.set_left(std::unique_ptr<ParseNode>(new LiteralNode(false_tok))); |
| 173 | 175 |
| 174 // Set right as foo, but don't define a value for it. | 176 // Set right as foo, but don't define a value for it. |
| 175 const char foo[] = "foo"; | 177 const char foo[] = "foo"; |
| 176 Token identifier_token(Location(), Token::IDENTIFIER, foo); | 178 Token identifier_token(Location(), Token::IDENTIFIER, foo); |
| 177 node.set_right(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); | 179 node.set_right( |
| 180 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); |
| 178 | 181 |
| 179 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), | 182 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), |
| 180 node.right(), &err); | 183 node.right(), &err); |
| 181 EXPECT_FALSE(err.has_error()); | 184 EXPECT_FALSE(err.has_error()); |
| 182 } | 185 } |
| 183 | 186 |
| 184 TEST(Operators, ShortCircuitOr) { | 187 TEST(Operators, ShortCircuitOr) { |
| 185 Err err; | 188 Err err; |
| 186 TestWithScope setup; | 189 TestWithScope setup; |
| 187 | 190 |
| 188 // Set up the operator. | 191 // Set up the operator. |
| 189 BinaryOpNode node; | 192 BinaryOpNode node; |
| 190 const char token_value[] = "||"; | 193 const char token_value[] = "||"; |
| 191 Token op(Location(), Token::BOOLEAN_OR, token_value); | 194 Token op(Location(), Token::BOOLEAN_OR, token_value); |
| 192 node.set_op(op); | 195 node.set_op(op); |
| 193 | 196 |
| 194 // Set the left to false. | 197 // Set the left to false. |
| 195 const char false_str[] = "true"; | 198 const char false_str[] = "true"; |
| 196 Token false_tok(Location(), Token::TRUE_TOKEN, false_str); | 199 Token false_tok(Location(), Token::TRUE_TOKEN, false_str); |
| 197 node.set_left(scoped_ptr<ParseNode>(new LiteralNode(false_tok))); | 200 node.set_left(std::unique_ptr<ParseNode>(new LiteralNode(false_tok))); |
| 198 | 201 |
| 199 // Set right as foo, but don't define a value for it. | 202 // Set right as foo, but don't define a value for it. |
| 200 const char foo[] = "foo"; | 203 const char foo[] = "foo"; |
| 201 Token identifier_token(Location(), Token::IDENTIFIER, foo); | 204 Token identifier_token(Location(), Token::IDENTIFIER, foo); |
| 202 node.set_right(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); | 205 node.set_right( |
| 206 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); |
| 203 | 207 |
| 204 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), | 208 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), |
| 205 node.right(), &err); | 209 node.right(), &err); |
| 206 EXPECT_FALSE(err.has_error()); | 210 EXPECT_FALSE(err.has_error()); |
| 207 } | 211 } |
| OLD | NEW |