| 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 "testing/gtest/include/gtest/gtest.h" | 5 #include "testing/gtest/include/gtest/gtest.h" |
| 6 #include "tools/gn/operators.h" | 6 #include "tools/gn/operators.h" |
| 7 #include "tools/gn/parse_tree.h" | 7 #include "tools/gn/parse_tree.h" |
| 8 #include "tools/gn/pattern.h" | 8 #include "tools/gn/pattern.h" |
| 9 #include "tools/gn/test_with_scope.h" | 9 #include "tools/gn/test_with_scope.h" |
| 10 | 10 |
| 11 namespace { | 11 namespace { |
| 12 | 12 |
| 13 bool IsValueIntegerEqualing(const Value& v, int64 i) { | 13 bool IsValueIntegerEqualing(const Value& v, int64 i) { |
| 14 if (v.type() != Value::INTEGER) | 14 if (v.type() != Value::INTEGER) |
| 15 return false; | 15 return false; |
| 16 return v.int_value() == i; | 16 return v.int_value() == i; |
| 17 } | 17 } |
| 18 | 18 |
| 19 bool IsValueStringEqualing(const Value& v, const char* s) { | 19 bool IsValueStringEqualing(const Value& v, const char* s) { |
| 20 if (v.type() != Value::STRING) | 20 if (v.type() != Value::STRING) |
| 21 return false; | 21 return false; |
| 22 return v.string_value() == s; | 22 return v.string_value() == s; |
| 23 } | 23 } |
| 24 | 24 |
| 25 // Returns a list populated with a single literal Value corresponding to the |
| 26 // given token. The token must outlive the list (since the list will just |
| 27 // copy the reference). |
| 28 scoped_ptr<ListNode> ListWithLiteral(const Token& token) { |
| 29 scoped_ptr<ListNode> list(new ListNode); |
| 30 list->append_item(scoped_ptr<ParseNode>(new LiteralNode(token))); |
| 31 return list.Pass(); |
| 32 } |
| 33 |
| 25 } // namespace | 34 } // namespace |
| 26 | 35 |
| 27 TEST(Operators, SourcesAppend) { | 36 TEST(Operators, SourcesAppend) { |
| 28 Err err; | 37 Err err; |
| 29 TestWithScope setup; | 38 TestWithScope setup; |
| 30 | 39 |
| 31 // Set up "sources" with an empty list. | 40 // Set up "sources" with an empty list. |
| 32 const char sources[] = "sources"; | 41 const char sources[] = "sources"; |
| 33 setup.scope()->SetValue(sources, Value(NULL, Value::LIST), NULL); | 42 setup.scope()->SetValue(sources, Value(NULL, Value::LIST), NULL); |
| 34 | 43 |
| 35 // Set up the operator. | 44 // Set up the operator. |
| 36 BinaryOpNode node; | 45 BinaryOpNode node; |
| 37 const char token_value[] = "+="; | 46 const char token_value[] = "+="; |
| 38 Token op(Location(), Token::PLUS_EQUALS, token_value); | 47 Token op(Location(), Token::PLUS_EQUALS, token_value); |
| 39 node.set_op(op); | 48 node.set_op(op); |
| 40 | 49 |
| 41 // Append to the sources variable. | 50 // Append to the sources variable. |
| 42 Token identifier_token(Location(), Token::IDENTIFIER, sources); | 51 Token identifier_token(Location(), Token::IDENTIFIER, sources); |
| 43 node.set_left(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); | 52 node.set_left(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); |
| 44 | 53 |
| 45 // Set up the filter on the scope to remove everything ending with "rm" | 54 // Set up the filter on the scope to remove everything ending with "rm" |
| 46 scoped_ptr<PatternList> pattern_list(new PatternList); | 55 scoped_ptr<PatternList> pattern_list(new PatternList); |
| 47 pattern_list->Append(Pattern("*rm")); | 56 pattern_list->Append(Pattern("*rm")); |
| 48 setup.scope()->set_sources_assignment_filter(pattern_list.Pass()); | 57 setup.scope()->set_sources_assignment_filter(pattern_list.Pass()); |
| 49 | 58 |
| 50 // Append an integer. | 59 // Append an integer. |
| 51 const char integer_value[] = "5"; | 60 const char integer_value[] = "5"; |
| 52 Token integer(Location(), Token::INTEGER, integer_value); | 61 Token integer(Location(), Token::INTEGER, integer_value); |
| 53 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(integer))); | 62 node.set_right(ListWithLiteral(integer).PassAs<ParseNode>()); |
| 54 node.Execute(setup.scope(), &err); | 63 node.Execute(setup.scope(), &err); |
| 55 EXPECT_FALSE(err.has_error()); | 64 EXPECT_FALSE(err.has_error()); |
| 56 | 65 |
| 57 // Append a string that doesn't match the pattern, it should get appended. | 66 // Append a string that doesn't match the pattern, it should get appended. |
| 58 const char string_1_value[] = "\"good\""; | 67 const char string_1_value[] = "\"good\""; |
| 59 Token string_1(Location(), Token::STRING, string_1_value); | 68 Token string_1(Location(), Token::STRING, string_1_value); |
| 60 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(string_1))); | 69 node.set_right(ListWithLiteral(string_1).PassAs<ParseNode>()); |
| 61 node.Execute(setup.scope(), &err); | 70 node.Execute(setup.scope(), &err); |
| 62 EXPECT_FALSE(err.has_error()); | 71 EXPECT_FALSE(err.has_error()); |
| 63 | 72 |
| 64 // Append a string that does match the pattern, it should be a no-op. | 73 // Append a string that does match the pattern, it should be a no-op. |
| 65 const char string_2_value[] = "\"foo-rm\""; | 74 const char string_2_value[] = "\"foo-rm\""; |
| 66 Token string_2(Location(), Token::STRING, string_2_value); | 75 Token string_2(Location(), Token::STRING, string_2_value); |
| 67 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(string_2))); | 76 node.set_right(ListWithLiteral(string_2).PassAs<ParseNode>()); |
| 68 node.Execute(setup.scope(), &err); | 77 node.Execute(setup.scope(), &err); |
| 69 EXPECT_FALSE(err.has_error()); | 78 EXPECT_FALSE(err.has_error()); |
| 70 | 79 |
| 71 // Append a list with the two strings from above. | 80 // Append a list with the two strings from above. |
| 72 ListNode list; | 81 ListNode list; |
| 73 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_1))); | 82 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_1))); |
| 74 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_2))); | 83 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_2))); |
| 75 ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err); | 84 ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err); |
| 76 EXPECT_FALSE(err.has_error()); | 85 EXPECT_FALSE(err.has_error()); |
| 77 | 86 |
| 78 // The sources variable in the scope should now have: [ 5, "good", "good" ] | 87 // The sources variable in the scope should now have: [ 5, "good", "good" ] |
| 79 const Value* value = setup.scope()->GetValue(sources); | 88 const Value* value = setup.scope()->GetValue(sources); |
| 80 ASSERT_TRUE(value); | 89 ASSERT_TRUE(value); |
| 81 ASSERT_EQ(Value::LIST, value->type()); | 90 ASSERT_EQ(Value::LIST, value->type()); |
| 82 ASSERT_EQ(3u, value->list_value().size()); | 91 ASSERT_EQ(3u, value->list_value().size()); |
| 83 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5)); | 92 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5)); |
| 84 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good")); | 93 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good")); |
| 85 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[2], "good")); | 94 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[2], "good")); |
| 86 } | 95 } |
| 96 |
| 97 // Note that the SourcesAppend test above tests the basic list + list features, |
| 98 // this test handles the other cases. |
| 99 TEST(Operators, ListAppend) { |
| 100 Err err; |
| 101 TestWithScope setup; |
| 102 |
| 103 // Set up "foo" with an empty list. |
| 104 const char foo[] = "foo"; |
| 105 setup.scope()->SetValue(foo, Value(NULL, Value::LIST), NULL); |
| 106 |
| 107 // Set up the operator. |
| 108 BinaryOpNode node; |
| 109 const char token_value[] = "+="; |
| 110 Token op(Location(), Token::PLUS_EQUALS, token_value); |
| 111 node.set_op(op); |
| 112 |
| 113 // Append to the foo variable. |
| 114 Token identifier_token(Location(), Token::IDENTIFIER, foo); |
| 115 node.set_left(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token))); |
| 116 |
| 117 // Append a list with a list, the result should be a nested list. |
| 118 scoped_ptr<ListNode> outer_list(new ListNode); |
| 119 const char twelve_str[] = "12"; |
| 120 Token twelve(Location(), Token::INTEGER, twelve_str); |
| 121 outer_list->append_item(ListWithLiteral(twelve).PassAs<ParseNode>()); |
| 122 node.set_right(outer_list.PassAs<ParseNode>()); |
| 123 |
| 124 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), |
| 125 node.right(), &err); |
| 126 EXPECT_FALSE(err.has_error()); |
| 127 |
| 128 // Return from the operator should always be "none", it should update the |
| 129 // value only. |
| 130 EXPECT_EQ(Value::NONE, ret.type()); |
| 131 |
| 132 // The value should be updated with "[ [ 12 ] ]" |
| 133 Value result = *setup.scope()->GetValue(foo); |
| 134 ASSERT_EQ(Value::LIST, result.type()); |
| 135 ASSERT_EQ(1u, result.list_value().size()); |
| 136 ASSERT_EQ(Value::LIST, result.list_value()[0].type()); |
| 137 ASSERT_EQ(1u, result.list_value()[0].list_value().size()); |
| 138 ASSERT_EQ(Value::INTEGER, result.list_value()[0].list_value()[0].type()); |
| 139 ASSERT_EQ(12, result.list_value()[0].list_value()[0].int_value()); |
| 140 |
| 141 // Try to append an integer and a string directly (e.g. foo += "hi"). |
| 142 // This should fail. |
| 143 const char str_str[] = "\"hi\""; |
| 144 Token str(Location(), Token::STRING, str_str); |
| 145 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(str))); |
| 146 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); |
| 147 EXPECT_TRUE(err.has_error()); |
| 148 err = Err(); |
| 149 |
| 150 node.set_right(scoped_ptr<ParseNode>(new LiteralNode(twelve))); |
| 151 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); |
| 152 EXPECT_TRUE(err.has_error()); |
| 153 } |
| OLD | NEW |