Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(898)

Side by Side Diff: tools/gn/operators_unittest.cc

Issue 2224343003: GN: Throw an error overwriting a nonempty scope. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comment Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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"
11 #include "tools/gn/parse_tree.h" 11 #include "tools/gn/parse_tree.h"
12 #include "tools/gn/pattern.h" 12 #include "tools/gn/pattern.h"
13 #include "tools/gn/test_with_scope.h" 13 #include "tools/gn/test_with_scope.h"
14 14
15 namespace { 15 namespace {
16 16
17 bool IsValueIntegerEqualing(const Value& v, int64_t i) { 17 bool IsValueIntegerEqualing(const Value& v, int64_t i) {
18 if (v.type() != Value::INTEGER) 18 if (v.type() != Value::INTEGER)
19 return false; 19 return false;
20 return v.int_value() == i; 20 return v.int_value() == i;
21 } 21 }
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
30 // given token. The token must outlive the list (since the list will just
31 // copy the reference).
32 std::unique_ptr<ListNode> ListWithLiteral(const Token& token) {
33 std::unique_ptr<ListNode> list(new ListNode);
34 list->append_item(std::unique_ptr<ParseNode>(new LiteralNode(token)));
35 return list;
36 }
37
38 // This parse node is for passing to tests. It returns a canned value for 29 // This parse node is for passing to tests. It returns a canned value for
39 // Execute(). 30 // Execute().
40 class TestParseNode : public ParseNode { 31 class TestParseNode : public ParseNode {
41 public: 32 public:
42 TestParseNode(const Value& v) : value_(v) { 33 TestParseNode(const Value& v) : value_(v) {
43 } 34 }
44 35
45 Value Execute(Scope* scope, Err* err) const override { 36 Value Execute(Scope* scope, Err* err) const override {
46 return value_; 37 return value_;
47 } 38 }
48 LocationRange GetRange() const override { 39 LocationRange GetRange() const override {
49 return LocationRange(); 40 return LocationRange();
50 } 41 }
51 Err MakeErrorDescribing(const std::string& msg, 42 Err MakeErrorDescribing(const std::string& msg,
52 const std::string& help) const override { 43 const std::string& help) const override {
53 return Err(this, msg); 44 return Err(this, msg);
54 } 45 }
55 void Print(std::ostream& out, int indent) const override { 46 void Print(std::ostream& out, int indent) const override {
56 } 47 }
57 48
58 private: 49 private:
59 Value value_; 50 Value value_;
60 }; 51 };
61 52
53 // Sets up a BinaryOpNode for testing.
54 class TestBinaryOpNode : public BinaryOpNode {
55 public:
56 // Input token value string must outlive class.
57 TestBinaryOpNode(Token::Type op_token_type,
58 const char* op_token_value)
59 : BinaryOpNode(),
60 op_token_ownership_(Location(), op_token_type, op_token_value) {
61 set_op(op_token_ownership_);
62 }
63
64 void SetLeftToValue(const Value& value) {
65 set_left(std::unique_ptr<ParseNode>(new TestParseNode(value)));
66 }
67
68 // Sets the left-hand side of the operator to an identifier node, this is
69 // used for testing assignments. Input string must outlive class.
70 void SetLeftToIdentifier(const char* identifier) {
71 left_identifier_token_ownership_ =
72 Token(Location(), Token::IDENTIFIER, identifier);
73 set_left(std::unique_ptr<ParseNode>(
74 new IdentifierNode(left_identifier_token_ownership_)));
75 }
76
77 void SetRightToValue(const Value& value) {
78 set_right(std::unique_ptr<ParseNode>(new TestParseNode(value)));
79 }
80 void SetRightToListOfValue(const Value& value) {
81 Value list(nullptr, Value::LIST);
82 list.list_value().push_back(value);
83 set_right(std::unique_ptr<ParseNode>(new TestParseNode(list)));
84 }
85 void SetRightToListOfValue(const Value& value1, const Value& value2) {
86 Value list(nullptr, Value::LIST);
87 list.list_value().push_back(value1);
88 list.list_value().push_back(value2);
89 set_right(std::unique_ptr<ParseNode>(new TestParseNode(list)));
90 }
91
92 private:
93 // The base class takes the Token by reference, this manages the lifetime.
94 Token op_token_ownership_;
95
96 // When setting the left to an identifier, this manages the lifetime of
97 // the identifier token.
98 Token left_identifier_token_ownership_;
99 };
100
62 } // namespace 101 } // namespace
63 102
64 TEST(Operators, SourcesAppend) { 103 TEST(Operators, SourcesAppend) {
65 Err err; 104 Err err;
66 TestWithScope setup; 105 TestWithScope setup;
67 106
68 // Set up "sources" with an empty list. 107 // Set up "sources" with an empty list.
69 const char sources[] = "sources"; 108 const char sources[] = "sources";
70 setup.scope()->SetValue(sources, Value(nullptr, Value::LIST), nullptr); 109 setup.scope()->SetValue(sources, Value(nullptr, Value::LIST), nullptr);
71 110
72 // Set up the operator. 111 // Set up the operator.
73 BinaryOpNode node; 112 TestBinaryOpNode node(Token::PLUS_EQUALS, "+=");
74 const char token_value[] = "+="; 113 node.SetLeftToIdentifier(sources);
75 Token op(Location(), Token::PLUS_EQUALS, token_value);
76 node.set_op(op);
77
78 // Append to the sources variable.
79 Token identifier_token(Location(), Token::IDENTIFIER, sources);
80 node.set_left(
81 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token)));
82 114
83 // Set up the filter on the scope to remove everything ending with "rm" 115 // Set up the filter on the scope to remove everything ending with "rm"
84 std::unique_ptr<PatternList> pattern_list(new PatternList); 116 std::unique_ptr<PatternList> pattern_list(new PatternList);
85 pattern_list->Append(Pattern("*rm")); 117 pattern_list->Append(Pattern("*rm"));
86 setup.scope()->set_sources_assignment_filter(std::move(pattern_list)); 118 setup.scope()->set_sources_assignment_filter(std::move(pattern_list));
87 119
88 // Append an integer. 120 // Append an integer.
89 const char integer_value[] = "5"; 121 node.SetRightToListOfValue(Value(nullptr, static_cast<int64_t>(5)));
90 Token integer(Location(), Token::INTEGER, integer_value);
91 node.set_right(ListWithLiteral(integer));
92 node.Execute(setup.scope(), &err); 122 node.Execute(setup.scope(), &err);
93 EXPECT_FALSE(err.has_error()); 123 EXPECT_FALSE(err.has_error());
94 124
95 // Append a string that doesn't match the pattern, it should get appended. 125 // Append a string that doesn't match the pattern, it should get appended.
96 const char string_1_value[] = "\"good\""; 126 const char string1[] = "good";
97 Token string_1(Location(), Token::STRING, string_1_value); 127 node.SetRightToListOfValue(Value(nullptr, string1));
98 node.set_right(ListWithLiteral(string_1));
99 node.Execute(setup.scope(), &err); 128 node.Execute(setup.scope(), &err);
100 EXPECT_FALSE(err.has_error()); 129 EXPECT_FALSE(err.has_error());
101 130
102 // Append a string that does match the pattern, it should be a no-op. 131 // Append a string that does match the pattern, it should be a no-op.
103 const char string_2_value[] = "\"foo-rm\""; 132 const char string2[] = "foo-rm";
104 Token string_2(Location(), Token::STRING, string_2_value); 133 node.SetRightToListOfValue(Value(nullptr, string2));
105 node.set_right(ListWithLiteral(string_2));
106 node.Execute(setup.scope(), &err); 134 node.Execute(setup.scope(), &err);
107 EXPECT_FALSE(err.has_error()); 135 EXPECT_FALSE(err.has_error());
108 136
109 // Append a list with the two strings from above. 137 // Append a list with the two strings from above.
110 ListNode list; 138 node.SetRightToListOfValue(Value(nullptr, string1), Value(nullptr, string2));
111 list.append_item(std::unique_ptr<ParseNode>(new LiteralNode(string_1))); 139 node.Execute(setup.scope(), &err);
112 list.append_item(std::unique_ptr<ParseNode>(new LiteralNode(string_2)));
113 ExecuteBinaryOperator(setup.scope(), &node, node.left(), &list, &err);
114 EXPECT_FALSE(err.has_error()); 140 EXPECT_FALSE(err.has_error());
115 141
116 // The sources variable in the scope should now have: [ 5, "good", "good" ] 142 // The sources variable in the scope should now have: [ 5, "good", "good" ]
117 const Value* value = setup.scope()->GetValue(sources); 143 const Value* value = setup.scope()->GetValue(sources);
118 ASSERT_TRUE(value); 144 ASSERT_TRUE(value);
119 ASSERT_EQ(Value::LIST, value->type()); 145 ASSERT_EQ(Value::LIST, value->type());
120 ASSERT_EQ(3u, value->list_value().size()); 146 ASSERT_EQ(3u, value->list_value().size());
121 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5)); 147 EXPECT_TRUE(IsValueIntegerEqualing(value->list_value()[0], 5));
122 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good")); 148 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[1], "good"));
123 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[2], "good")); 149 EXPECT_TRUE(IsValueStringEqualing(value->list_value()[2], "good"));
124 } 150 }
125 151
126 // Note that the SourcesAppend test above tests the basic list + list features, 152 // Note that the SourcesAppend test above tests the basic list + list features,
127 // this test handles the other cases. 153 // this test handles the other cases.
128 TEST(Operators, ListAppend) { 154 TEST(Operators, ListAppend) {
129 Err err; 155 Err err;
130 TestWithScope setup; 156 TestWithScope setup;
131 157
132 // Set up "foo" with an empty list. 158 // Set up "foo" with an empty list.
133 const char foo[] = "foo"; 159 const char foo[] = "foo";
134 setup.scope()->SetValue(foo, Value(nullptr, Value::LIST), nullptr); 160 setup.scope()->SetValue(foo, Value(nullptr, Value::LIST), nullptr);
135 161
136 // Set up the operator. 162 // Set up the operator to append to "foo".
137 BinaryOpNode node; 163 TestBinaryOpNode node(Token::PLUS_EQUALS, "+=");
138 const char token_value[] = "+="; 164 node.SetLeftToIdentifier(foo);
139 Token op(Location(), Token::PLUS_EQUALS, token_value);
140 node.set_op(op);
141
142 // Append to the foo variable.
143 Token identifier_token(Location(), Token::IDENTIFIER, foo);
144 node.set_left(
145 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token)));
146 165
147 // Append a list with a list, the result should be a nested list. 166 // Append a list with a list, the result should be a nested list.
148 std::unique_ptr<ListNode> outer_list(new ListNode); 167 Value inner_list(nullptr, Value::LIST);
149 const char twelve_str[] = "12"; 168 inner_list.list_value().push_back(Value(nullptr, static_cast<int64_t>(12)));
150 Token twelve(Location(), Token::INTEGER, twelve_str); 169 node.SetRightToListOfValue(inner_list);
151 outer_list->append_item(ListWithLiteral(twelve));
152 node.set_right(std::move(outer_list));
153 170
154 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), 171 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
155 node.right(), &err); 172 node.right(), &err);
156 EXPECT_FALSE(err.has_error()); 173 EXPECT_FALSE(err.has_error());
157 174
158 // Return from the operator should always be "none", it should update the 175 // Return from the operator should always be "none", it should update the
159 // value only. 176 // value only.
160 EXPECT_EQ(Value::NONE, ret.type()); 177 EXPECT_EQ(Value::NONE, ret.type());
161 178
162 // The value should be updated with "[ [ 12 ] ]" 179 // The value should be updated with "[ [ 12 ] ]"
163 Value result = *setup.scope()->GetValue(foo); 180 Value result = *setup.scope()->GetValue(foo);
164 ASSERT_EQ(Value::LIST, result.type()); 181 ASSERT_EQ(Value::LIST, result.type());
165 ASSERT_EQ(1u, result.list_value().size()); 182 ASSERT_EQ(1u, result.list_value().size());
166 ASSERT_EQ(Value::LIST, result.list_value()[0].type()); 183 ASSERT_EQ(Value::LIST, result.list_value()[0].type());
167 ASSERT_EQ(1u, result.list_value()[0].list_value().size()); 184 ASSERT_EQ(1u, result.list_value()[0].list_value().size());
168 ASSERT_EQ(Value::INTEGER, result.list_value()[0].list_value()[0].type()); 185 ASSERT_EQ(Value::INTEGER, result.list_value()[0].list_value()[0].type());
169 ASSERT_EQ(12, result.list_value()[0].list_value()[0].int_value()); 186 ASSERT_EQ(12, result.list_value()[0].list_value()[0].int_value());
170 187
171 // Try to append an integer and a string directly (e.g. foo += "hi"). 188 // Try to append an integer and a string directly (e.g. foo += "hi").
172 // This should fail. 189 // This should fail.
173 const char str_str[] = "\"hi\""; 190 const char str_str[] = "\"hi\"";
174 Token str(Location(), Token::STRING, str_str); 191 Token str(Location(), Token::STRING, str_str);
175 node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(str))); 192 node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(str)));
176 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); 193 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err);
177 EXPECT_TRUE(err.has_error()); 194 EXPECT_TRUE(err.has_error());
178 err = Err(); 195 err = Err();
179 196
180 node.set_right(std::unique_ptr<ParseNode>(new LiteralNode(twelve))); 197 node.SetRightToValue(Value(nullptr, static_cast<int64_t>(12)));
181 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err); 198 ExecuteBinaryOperator(setup.scope(), &node, node.left(), node.right(), &err);
182 EXPECT_TRUE(err.has_error()); 199 EXPECT_TRUE(err.has_error());
183 } 200 }
184 201
185 TEST(Operators, ListRemove) { 202 TEST(Operators, ListRemove) {
186 Err err; 203 Err err;
187 TestWithScope setup; 204 TestWithScope setup;
188 205
189 const char foo_str[] = "foo"; 206 const char foo_str[] = "foo";
190 const char bar_str[] = "bar"; 207 const char bar_str[] = "bar";
191 Value test_list(nullptr, Value::LIST); 208 Value test_list(nullptr, Value::LIST);
192 test_list.list_value().push_back(Value(nullptr, foo_str)); 209 test_list.list_value().push_back(Value(nullptr, foo_str));
193 test_list.list_value().push_back(Value(nullptr, bar_str)); 210 test_list.list_value().push_back(Value(nullptr, bar_str));
194 test_list.list_value().push_back(Value(nullptr, foo_str)); 211 test_list.list_value().push_back(Value(nullptr, foo_str));
195 212
196 // Set up "var" with an the test list. 213 // Set up "var" with an the test list.
197 const char var_str[] = "var"; 214 const char var[] = "var";
198 setup.scope()->SetValue(var_str, test_list, nullptr); 215 setup.scope()->SetValue(var, test_list, nullptr);
199 216
200 // Set up the operator. 217 TestBinaryOpNode node(Token::MINUS_EQUALS, "-=");
201 BinaryOpNode node; 218 node.SetLeftToIdentifier(var);
202 const char token_value[] = "-=";
203 Token op(Location(), Token::MINUS_EQUALS, token_value);
204 node.set_op(op);
205
206 // Do -= on the var.
207 Token identifier_token(Location(), Token::IDENTIFIER, var_str);
208 node.set_left(
209 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token)));
210 219
211 // Subtract a list consisting of "foo". 220 // Subtract a list consisting of "foo".
212 Value foo_list(nullptr, Value::LIST); 221 node.SetRightToListOfValue(Value(nullptr, foo_str));
213 foo_list.list_value().push_back(Value(nullptr, foo_str));
214 std::unique_ptr<ParseNode> outer_list(new TestParseNode(foo_list));
215 node.set_right(std::move(outer_list));
216
217 Value result = ExecuteBinaryOperator( 222 Value result = ExecuteBinaryOperator(
218 setup.scope(), &node, node.left(), node.right(), &err); 223 setup.scope(), &node, node.left(), node.right(), &err);
219 EXPECT_FALSE(err.has_error()); 224 EXPECT_FALSE(err.has_error());
220 225
221 // -= returns an empty value to reduce the possibility of writing confusing 226 // -= returns an empty value to reduce the possibility of writing confusing
222 // cases like foo = bar += 1. 227 // cases like foo = bar += 1.
223 EXPECT_EQ(Value::NONE, result.type()); 228 EXPECT_EQ(Value::NONE, result.type());
224 229
225 // The "var" variable should have been updated. Both instances of "foo" are 230 // The "var" variable should have been updated. Both instances of "foo" are
226 // deleted. 231 // deleted.
227 const Value* new_value = setup.scope()->GetValue(var_str); 232 const Value* new_value = setup.scope()->GetValue(var);
228 ASSERT_TRUE(new_value); 233 ASSERT_TRUE(new_value);
229 ASSERT_EQ(Value::LIST, new_value->type()); 234 ASSERT_EQ(Value::LIST, new_value->type());
230 ASSERT_EQ(1u, new_value->list_value().size()); 235 ASSERT_EQ(1u, new_value->list_value().size());
231 ASSERT_EQ(Value::STRING, new_value->list_value()[0].type()); 236 ASSERT_EQ(Value::STRING, new_value->list_value()[0].type());
232 EXPECT_EQ("bar", new_value->list_value()[0].string_value()); 237 EXPECT_EQ("bar", new_value->list_value()[0].string_value());
233 } 238 }
234 239
235 TEST(Operators, ShortCircuitAnd) { 240 TEST(Operators, ShortCircuitAnd) {
236 Err err; 241 Err err;
237 TestWithScope setup; 242 TestWithScope setup;
238 243
239 // Set up the operator. 244 // Set a && operator with the left to false.
240 BinaryOpNode node; 245 TestBinaryOpNode node(Token::BOOLEAN_AND, "&&");
241 const char token_value[] = "&&"; 246 node.SetLeftToValue(Value(nullptr, false));
242 Token op(Location(), Token::BOOLEAN_AND, token_value);
243 node.set_op(op);
244
245 // Set the left to false.
246 const char false_str[] = "false";
247 Token false_tok(Location(), Token::FALSE_TOKEN, false_str);
248 node.set_left(std::unique_ptr<ParseNode>(new LiteralNode(false_tok)));
249 247
250 // Set right as foo, but don't define a value for it. 248 // Set right as foo, but don't define a value for it.
251 const char foo[] = "foo"; 249 const char foo[] = "foo";
252 Token identifier_token(Location(), Token::IDENTIFIER, foo); 250 Token identifier_token(Location(), Token::IDENTIFIER, foo);
253 node.set_right( 251 node.set_right(
254 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); 252 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token)));
255 253
256 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), 254 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
257 node.right(), &err); 255 node.right(), &err);
258 EXPECT_FALSE(err.has_error()); 256 EXPECT_FALSE(err.has_error());
259 } 257 }
260 258
261 TEST(Operators, ShortCircuitOr) { 259 TEST(Operators, ShortCircuitOr) {
262 Err err; 260 Err err;
263 TestWithScope setup; 261 TestWithScope setup;
264 262
265 // Set up the operator. 263 // Set a || operator with the left to true.
266 BinaryOpNode node; 264 TestBinaryOpNode node(Token::BOOLEAN_OR, "||");
267 const char token_value[] = "||"; 265 node.SetLeftToValue(Value(nullptr, true));
268 Token op(Location(), Token::BOOLEAN_OR, token_value);
269 node.set_op(op);
270
271 // Set the left to false.
272 const char false_str[] = "true";
273 Token false_tok(Location(), Token::TRUE_TOKEN, false_str);
274 node.set_left(std::unique_ptr<ParseNode>(new LiteralNode(false_tok)));
275 266
276 // Set right as foo, but don't define a value for it. 267 // Set right as foo, but don't define a value for it.
277 const char foo[] = "foo"; 268 const char foo[] = "foo";
278 Token identifier_token(Location(), Token::IDENTIFIER, foo); 269 Token identifier_token(Location(), Token::IDENTIFIER, foo);
279 node.set_right( 270 node.set_right(
280 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token))); 271 std::unique_ptr<ParseNode>(new IdentifierNode(identifier_token)));
281 272
282 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(), 273 Value ret = ExecuteBinaryOperator(setup.scope(), &node, node.left(),
283 node.right(), &err); 274 node.right(), &err);
284 EXPECT_FALSE(err.has_error()); 275 EXPECT_FALSE(err.has_error());
285 } 276 }
277
278 // Overwriting nonempty lists and scopes with other nonempty lists and scopes
279 // should be disallowed.
280 TEST(Operators, NonemptyOverwriting) {
281 Err err;
282 TestWithScope setup;
283
284 // Set up "foo" with a nonempty list.
285 const char foo[] = "foo";
286 Value old_value(nullptr, Value::LIST);
287 old_value.list_value().push_back(Value(nullptr, "string"));
288 setup.scope()->SetValue(foo, old_value, nullptr);
289
290 TestBinaryOpNode node(Token::EQUAL, "=");
291 node.SetLeftToIdentifier(foo);
292
293 // Assigning a nonempty list should fail.
294 node.SetRightToListOfValue(Value(nullptr, "string"));
295 node.Execute(setup.scope(), &err);
296 ASSERT_TRUE(err.has_error());
297 EXPECT_EQ("Replacing nonempty list.", err.message());
298 err = Err();
299
300 // Assigning an empty list should succeed.
301 node.SetRightToValue(Value(nullptr, Value::LIST));
302 node.Execute(setup.scope(), &err);
303 ASSERT_FALSE(err.has_error());
304 const Value* new_value = setup.scope()->GetValue(foo);
305 ASSERT_TRUE(new_value);
306 ASSERT_EQ(Value::LIST, new_value->type());
307 ASSERT_TRUE(new_value->list_value().empty());
308
309 // Set up "foo" with a nonempty scope.
310 const char bar[] = "bar";
311 old_value = Value(
312 nullptr, std::unique_ptr<Scope>(new Scope(setup.settings())));
313 old_value.scope_value()->SetValue(bar, Value(nullptr, "bar"), nullptr);
314 setup.scope()->SetValue(foo, old_value, nullptr);
315
316 // Assigning a nonempty scope should fail (re-use old_value copy).
317 node.SetRightToValue(old_value);
318 node.Execute(setup.scope(), &err);
319 ASSERT_TRUE(err.has_error());
320 EXPECT_EQ("Replacing nonempty scope.", err.message());
321 err = Err();
322
323 // Assigning an empty list should succeed.
324 node.SetRightToValue(
325 Value(nullptr, std::unique_ptr<Scope>(new Scope(setup.settings()))));
326 node.Execute(setup.scope(), &err);
327 ASSERT_FALSE(err.has_error());
328 new_value = setup.scope()->GetValue(foo);
329 ASSERT_TRUE(new_value);
330 ASSERT_EQ(Value::SCOPE, new_value->type());
331 ASSERT_FALSE(new_value->scope_value()->HasValues(Scope::SEARCH_CURRENT));
332 }
OLDNEW
« tools/gn/operators.cc ('K') | « tools/gn/operators.cc ('k') | tools/gn/scope.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698