Add the ability to code generated prepopulated static nested structs
[chromium-blink-merge.git] / tools / gn / scope_unittest.cc
blob1dd1e65ca148a317b26f1b7a89754e6268d056fb
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/input_file.h"
7 #include "tools/gn/parse_tree.h"
8 #include "tools/gn/scope.h"
9 #include "tools/gn/template.h"
10 #include "tools/gn/test_with_scope.h"
12 namespace {
14 bool HasStringValueEqualTo(const Scope* scope,
15 const char* name,
16 const char* expected_value) {
17 const Value* value = scope->GetValue(name);
18 if (!value)
19 return false;
20 if (value->type() != Value::STRING)
21 return false;
22 return value->string_value() == expected_value;
25 } // namespace
27 TEST(Scope, NonRecursiveMergeTo) {
28 TestWithScope setup;
30 // Make a pretend parse node with proper tracking that we can blame for the
31 // given value.
32 InputFile input_file(SourceFile("//foo"));
33 Token assignment_token(Location(&input_file, 1, 1, 1), Token::STRING,
34 "\"hello\"");
35 LiteralNode assignment;
36 assignment.set_value(assignment_token);
38 // Add some values to the scope.
39 Value old_value(&assignment, "hello");
40 setup.scope()->SetValue("v", old_value, &assignment);
41 base::StringPiece private_var_name("_private");
42 setup.scope()->SetValue(private_var_name, old_value, &assignment);
44 // Add some templates to the scope.
45 FunctionCallNode templ_definition;
46 scoped_refptr<Template> templ(new Template(setup.scope(), &templ_definition));
47 setup.scope()->AddTemplate("templ", templ.get());
48 scoped_refptr<Template> private_templ(
49 new Template(setup.scope(), &templ_definition));
50 setup.scope()->AddTemplate("_templ", private_templ.get());
52 // Detect collisions of values' values.
54 Scope new_scope(setup.settings());
55 Value new_value(&assignment, "goodbye");
56 new_scope.SetValue("v", new_value, &assignment);
58 Err err;
59 EXPECT_FALSE(setup.scope()->NonRecursiveMergeTo(
60 &new_scope, Scope::MergeOptions(),
61 &assignment, "error", &err));
62 EXPECT_TRUE(err.has_error());
65 // Template name collisions.
67 Scope new_scope(setup.settings());
69 scoped_refptr<Template> new_templ(
70 new Template(&new_scope, &templ_definition));
71 new_scope.AddTemplate("templ", new_templ.get());
73 Err err;
74 EXPECT_FALSE(setup.scope()->NonRecursiveMergeTo(
75 &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
76 EXPECT_TRUE(err.has_error());
79 // The clobber flag should just overwrite colliding values.
81 Scope new_scope(setup.settings());
82 Value new_value(&assignment, "goodbye");
83 new_scope.SetValue("v", new_value, &assignment);
85 Err err;
86 Scope::MergeOptions options;
87 options.clobber_existing = true;
88 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
89 &new_scope, options, &assignment, "error", &err));
90 EXPECT_FALSE(err.has_error());
92 const Value* found_value = new_scope.GetValue("v");
93 ASSERT_TRUE(found_value);
94 EXPECT_TRUE(old_value == *found_value);
97 // Clobber flag for templates.
99 Scope new_scope(setup.settings());
101 scoped_refptr<Template> new_templ(
102 new Template(&new_scope, &templ_definition));
103 new_scope.AddTemplate("templ", new_templ.get());
104 Scope::MergeOptions options;
105 options.clobber_existing = true;
107 Err err;
108 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
109 &new_scope, options, &assignment, "error", &err));
110 EXPECT_FALSE(err.has_error());
112 const Template* found_value = new_scope.GetTemplate("templ");
113 ASSERT_TRUE(found_value);
114 EXPECT_TRUE(templ.get() == found_value);
117 // Don't flag values that technically collide but have the same value.
119 Scope new_scope(setup.settings());
120 Value new_value(&assignment, "hello");
121 new_scope.SetValue("v", new_value, &assignment);
123 Err err;
124 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
125 &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
126 EXPECT_FALSE(err.has_error());
129 // Templates that technically collide but are the same.
131 Scope new_scope(setup.settings());
133 scoped_refptr<Template> new_templ(
134 new Template(&new_scope, &templ_definition));
135 new_scope.AddTemplate("templ", templ.get());
137 Err err;
138 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
139 &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
140 EXPECT_FALSE(err.has_error());
143 // Copy private values and templates.
145 Scope new_scope(setup.settings());
147 Err err;
148 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
149 &new_scope, Scope::MergeOptions(), &assignment, "error", &err));
150 EXPECT_FALSE(err.has_error());
151 EXPECT_TRUE(new_scope.GetValue(private_var_name));
152 EXPECT_TRUE(new_scope.GetTemplate("_templ"));
155 // Skip private values and templates.
157 Scope new_scope(setup.settings());
159 Err err;
160 Scope::MergeOptions options;
161 options.skip_private_vars = true;
162 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
163 &new_scope, options, &assignment, "error", &err));
164 EXPECT_FALSE(err.has_error());
165 EXPECT_FALSE(new_scope.GetValue(private_var_name));
166 EXPECT_FALSE(new_scope.GetTemplate("_templ"));
169 // Don't mark used.
171 Scope new_scope(setup.settings());
173 Err err;
174 Scope::MergeOptions options;
175 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
176 &new_scope, options, &assignment, "error", &err));
177 EXPECT_FALSE(err.has_error());
178 EXPECT_FALSE(new_scope.CheckForUnusedVars(&err));
179 EXPECT_TRUE(err.has_error());
182 // Mark used.
184 Scope new_scope(setup.settings());
186 Err err;
187 Scope::MergeOptions options;
188 options.mark_used = true;
189 EXPECT_TRUE(setup.scope()->NonRecursiveMergeTo(
190 &new_scope, options, &assignment, "error", &err));
191 EXPECT_FALSE(err.has_error());
192 EXPECT_TRUE(new_scope.CheckForUnusedVars(&err));
193 EXPECT_FALSE(err.has_error());
197 TEST(Scope, MakeClosure) {
198 // Create 3 nested scopes [const root from setup] <- nested1 <- nested2.
199 TestWithScope setup;
201 // Make a pretend parse node with proper tracking that we can blame for the
202 // given value.
203 InputFile input_file(SourceFile("//foo"));
204 Token assignment_token(Location(&input_file, 1, 1, 1), Token::STRING,
205 "\"hello\"");
206 LiteralNode assignment;
207 assignment.set_value(assignment_token);
208 setup.scope()->SetValue("on_root", Value(&assignment, "on_root"),
209 &assignment);
211 // Root scope should be const from the nested caller's perspective.
212 Scope nested1(static_cast<const Scope*>(setup.scope()));
213 nested1.SetValue("on_one", Value(&assignment, "on_one"), &assignment);
215 Scope nested2(&nested1);
216 nested2.SetValue("on_one", Value(&assignment, "on_two"), &assignment);
217 nested2.SetValue("on_two", Value(&assignment, "on_two2"), &assignment);
219 // Making a closure from the root scope.
220 scoped_ptr<Scope> result = setup.scope()->MakeClosure();
221 EXPECT_FALSE(result->containing()); // Should have no containing scope.
222 EXPECT_TRUE(result->GetValue("on_root")); // Value should be copied.
224 // Making a closure from the second nested scope.
225 result = nested2.MakeClosure();
226 EXPECT_EQ(setup.scope(),
227 result->containing()); // Containing scope should be the root.
228 EXPECT_TRUE(HasStringValueEqualTo(result.get(), "on_root", "on_root"));
229 EXPECT_TRUE(HasStringValueEqualTo(result.get(), "on_one", "on_two"));
230 EXPECT_TRUE(HasStringValueEqualTo(result.get(), "on_two", "on_two2"));
233 TEST(Scope, GetMutableValue) {
234 TestWithScope setup;
236 // Make a pretend parse node with proper tracking that we can blame for the
237 // given value.
238 InputFile input_file(SourceFile("//foo"));
239 Token assignment_token(Location(&input_file, 1, 1, 1), Token::STRING,
240 "\"hello\"");
241 LiteralNode assignment;
242 assignment.set_value(assignment_token);
244 const char kOnConst[] = "on_const";
245 const char kOnMutable1[] = "on_mutable1";
246 const char kOnMutable2[] = "on_mutable2";
248 Value value(&assignment, "hello");
250 // Create a root scope with one value.
251 Scope root_scope(setup.settings());
252 root_scope.SetValue(kOnConst, value, &assignment);
254 // Create a first nested scope with a different value.
255 const Scope* const_root_scope = &root_scope;
256 Scope mutable_scope1(const_root_scope);
257 mutable_scope1.SetValue(kOnMutable1, value, &assignment);
259 // Create a second nested scope with a different value.
260 Scope mutable_scope2(&mutable_scope1);
261 mutable_scope2.SetValue(kOnMutable2, value, &assignment);
263 // Check getting root scope values.
264 EXPECT_TRUE(mutable_scope2.GetValue(kOnConst, true));
265 EXPECT_FALSE(mutable_scope2.GetMutableValue(kOnConst, true));
267 // Test reading a value from scope 1.
268 Value* mutable1_result = mutable_scope2.GetMutableValue(kOnMutable1, false);
269 ASSERT_TRUE(mutable1_result);
270 EXPECT_TRUE(*mutable1_result == value);
272 // Make sure CheckForUnusedVars works on scope1 (we didn't mark the value as
273 // used in the previous step).
274 Err err;
275 EXPECT_FALSE(mutable_scope1.CheckForUnusedVars(&err));
276 mutable1_result = mutable_scope2.GetMutableValue(kOnMutable1, true);
277 EXPECT_TRUE(mutable1_result);
278 err = Err();
279 EXPECT_TRUE(mutable_scope1.CheckForUnusedVars(&err));
281 // Test reading a value from scope 2.
282 Value* mutable2_result = mutable_scope2.GetMutableValue(kOnMutable2, true);
283 ASSERT_TRUE(mutable2_result);
284 EXPECT_TRUE(*mutable2_result == value);
287 TEST(Scope, RemovePrivateIdentifiers) {
288 TestWithScope setup;
289 setup.scope()->SetValue("a", Value(nullptr, true), nullptr);
290 setup.scope()->SetValue("_b", Value(nullptr, true), nullptr);
292 setup.scope()->RemovePrivateIdentifiers();
293 EXPECT_TRUE(setup.scope()->GetValue("a"));
294 EXPECT_FALSE(setup.scope()->GetValue("_b"));