Add ICU message format support
[chromium-blink-merge.git] / tools / gn / operators_unittest.cc
blobb5b3b0201471895b5e055bf4c455150c7bef5678
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
3 // found in the LICENSE file.
5 #include "testing/gtest/include/gtest/gtest.h"
6 #include "tools/gn/operators.h"
7 #include "tools/gn/parse_tree.h"
8 #include "tools/gn/pattern.h"
9 #include "tools/gn/test_with_scope.h"
11 namespace {
13 bool IsValueIntegerEqualing(const Value& v, int64 i) {
14 if (v.type() != Value::INTEGER)
15 return false;
16 return v.int_value() == i;
19 bool IsValueStringEqualing(const Value& v, const char* s) {
20 if (v.type() != Value::STRING)
21 return false;
22 return v.string_value() == s;
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();
34 } // namespace
36 TEST(Operators, SourcesAppend) {
37 Err err;
38 TestWithScope setup;
40 // Set up "sources" with an empty list.
41 const char sources[] = "sources";
42 setup.scope()->SetValue(sources, Value(nullptr, Value::LIST), nullptr);
44 // Set up the operator.
45 BinaryOpNode node;
46 const char token_value[] = "+=";
47 Token op(Location(), Token::PLUS_EQUALS, token_value);
48 node.set_op(op);
50 // Append to the sources variable.
51 Token identifier_token(Location(), Token::IDENTIFIER, sources);
52 node.set_left(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token)));
54 // Set up the filter on the scope to remove everything ending with "rm"
55 scoped_ptr<PatternList> pattern_list(new PatternList);
56 pattern_list->Append(Pattern("*rm"));
57 setup.scope()->set_sources_assignment_filter(pattern_list.Pass());
59 // Append an integer.
60 const char integer_value[] = "5";
61 Token integer(Location(), Token::INTEGER, integer_value);
62 node.set_right(ListWithLiteral(integer));
63 node.Execute(setup.scope(), &err);
64 EXPECT_FALSE(err.has_error());
66 // Append a string that doesn't match the pattern, it should get appended.
67 const char string_1_value[] = "\"good\"";
68 Token string_1(Location(), Token::STRING, string_1_value);
69 node.set_right(ListWithLiteral(string_1));
70 node.Execute(setup.scope(), &err);
71 EXPECT_FALSE(err.has_error());
73 // Append a string that does match the pattern, it should be a no-op.
74 const char string_2_value[] = "\"foo-rm\"";
75 Token string_2(Location(), Token::STRING, string_2_value);
76 node.set_right(ListWithLiteral(string_2));
77 node.Execute(setup.scope(), &err);
78 EXPECT_FALSE(err.has_error());
80 // Append a list with the two strings from above.
81 ListNode list;
82 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_1)));
83 list.append_item(scoped_ptr<ParseNode>(new LiteralNode(string_2)));
84 ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err);
85 EXPECT_FALSE(err.has_error());
87 // The sources variable in the scope should now have: [ 5, "good", "good" ]
88 const Value* value = setup.scope()->GetValue(sources);
89 ASSERT_TRUE(value);
90 ASSERT_EQ(Value::LIST, value->type());
91 ASSERT_EQ(3u, value->list_value().size());
92 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5));
93 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good"));
94 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[2], "good"));
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;
103 // Set up "foo" with an empty list.
104 const char foo[] = "foo";
105 setup.scope()->SetValue(foo, Value(nullptr, Value::LIST), nullptr);
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);
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)));
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));
122 node.set_right(outer_list.Pass());
124 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
125 node.right(), &err);
126 EXPECT_FALSE(err.has_error());
128 // Return from the operator should always be "none", it should update the
129 // value only.
130 EXPECT_EQ(Value::NONE, ret.type());
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());
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();
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());
155 TEST(Operators, ShortCircuitAnd) {
156 Err err;
157 TestWithScope setup;
159 // Set up the operator.
160 BinaryOpNode node;
161 const char token_value[] = "&&";
162 Token op(Location(), Token::BOOLEAN_AND, token_value);
163 node.set_op(op);
165 // Set the left to false.
166 const char false_str[] = "false";
167 Token false_tok(Location(), Token::FALSE_TOKEN, false_str);
168 node.set_left(scoped_ptr<ParseNode>(new LiteralNode(false_tok)));
170 // Set right as foo, but don't define a value for it.
171 const char foo[] = "foo";
172 Token identifier_token(Location(), Token::IDENTIFIER, foo);
173 node.set_right(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token)));
175 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
176 node.right(), &err);
177 EXPECT_FALSE(err.has_error());
180 TEST(Operators, ShortCircuitOr) {
181 Err err;
182 TestWithScope setup;
184 // Set up the operator.
185 BinaryOpNode node;
186 const char token_value[] = "||";
187 Token op(Location(), Token::BOOLEAN_OR, token_value);
188 node.set_op(op);
190 // Set the left to false.
191 const char false_str[] = "true";
192 Token false_tok(Location(), Token::TRUE_TOKEN, false_str);
193 node.set_left(scoped_ptr<ParseNode>(new LiteralNode(false_tok)));
195 // Set right as foo, but don't define a value for it.
196 const char foo[] = "foo";
197 Token identifier_token(Location(), Token::IDENTIFIER, foo);
198 node.set_right(scoped_ptr<ParseNode>(new IdentifierNode(identifier_token)));
200 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
201 node.right(), &err);
202 EXPECT_FALSE(err.has_error());