1 // Copyright 2015 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.
4
5 #include "gn/scheduler.h"
6 #include "gn/test_with_scheduler.h"
7 #include "gn/test_with_scope.h"
8 #include "util/test/test.h"
9
10 using FunctionForwardVariablesFromTest = TestWithScheduler;
11
TEST_F(FunctionForwardVariablesFromTest,List)12 TEST_F(FunctionForwardVariablesFromTest, List) {
13 Err err;
14 std::string program =
15 "template(\"a\") {\n"
16 " forward_variables_from(invoker, [\"x\", \"y\", \"z\"])\n"
17 " assert(!defined(z))\n" // "z" should still be undefined.
18 " print(\"$target_name, $x, $y\")\n"
19 "}\n"
20 "a(\"target\") {\n"
21 " x = 1\n"
22 " y = 2\n"
23 "}\n";
24
25 {
26 TestWithScope setup;
27
28 // Defines a template and copy the two x and y, and z values out.
29 TestParseInput input(program);
30 ASSERT_FALSE(input.has_error());
31
32 input.parsed()->Execute(setup.scope(), &err);
33 ASSERT_FALSE(err.has_error()) << err.message();
34
35 EXPECT_EQ("target, 1, 2\n", setup.print_output());
36 setup.print_output().clear();
37 }
38
39 {
40 TestWithScope setup;
41
42 // Test that the same input but forwarding a variable with the name of
43 // something in the given scope throws an error rather than clobbering it.
44 // This uses the same known-good program as before, but adds another
45 // variable in the scope before it.
46 TestParseInput clobber("x = 1\n" + program);
47 ASSERT_FALSE(clobber.has_error());
48
49 clobber.parsed()->Execute(setup.scope(), &err);
50 ASSERT_TRUE(err.has_error()); // Should thow a clobber error.
51 EXPECT_EQ("Clobbering existing value.", err.message());
52 }
53 }
54
TEST_F(FunctionForwardVariablesFromTest,LiteralList)55 TEST_F(FunctionForwardVariablesFromTest, LiteralList) {
56 TestWithScope setup;
57
58 // Forwards all variables from a literal scope into another scope definition.
59 TestParseInput input(
60 "a = {\n"
61 " forward_variables_from({x = 1 y = 2}, \"*\")\n"
62 " z = 3\n"
63 "}\n"
64 "print(\"${a.x} ${a.y} ${a.z}\")\n");
65
66 ASSERT_FALSE(input.has_error());
67
68 Err err;
69 input.parsed()->Execute(setup.scope(), &err);
70 ASSERT_FALSE(err.has_error()) << err.message();
71
72 EXPECT_EQ("1 2 3\n", setup.print_output());
73 setup.print_output().clear();
74 }
75
TEST_F(FunctionForwardVariablesFromTest,ListWithExclusion)76 TEST_F(FunctionForwardVariablesFromTest, ListWithExclusion) {
77 TestWithScope setup;
78
79 // Defines a template and copy the two x and y, and z values out.
80 TestParseInput input(
81 "template(\"a\") {\n"
82 " forward_variables_from(invoker, [\"x\", \"y\", \"z\"], [\"z\"])\n"
83 " assert(!defined(z))\n" // "z" should still be undefined.
84 " print(\"$target_name, $x, $y\")\n"
85 "}\n"
86 "a(\"target\") {\n"
87 " x = 1\n"
88 " y = 2\n"
89 " z = 3\n"
90 " print(\"$z\")\n"
91 "}\n");
92
93 ASSERT_FALSE(input.has_error());
94
95 Err err;
96 input.parsed()->Execute(setup.scope(), &err);
97 ASSERT_FALSE(err.has_error()) << err.message();
98
99 EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output());
100 setup.print_output().clear();
101 }
102
TEST_F(FunctionForwardVariablesFromTest,ErrorCases)103 TEST_F(FunctionForwardVariablesFromTest, ErrorCases) {
104 TestWithScope setup;
105
106 // Type check the source scope.
107 TestParseInput invalid_source(
108 "template(\"a\") {\n"
109 " forward_variables_from(42, [\"x\"])\n"
110 " print(\"$target_name\")\n" // Prevent unused var error.
111 "}\n"
112 "a(\"target\") {\n"
113 "}\n");
114 ASSERT_FALSE(invalid_source.has_error());
115 Err err;
116 invalid_source.parsed()->Execute(setup.scope(), &err);
117 EXPECT_TRUE(err.has_error());
118 EXPECT_EQ("This is not a scope.", err.message());
119
120 // Type check the list. We need to use a new template name each time since
121 // all of these invocations are executing in sequence in the same scope.
122 TestParseInput invalid_list(
123 "template(\"b\") {\n"
124 " forward_variables_from(invoker, 42)\n"
125 " print(\"$target_name\")\n"
126 "}\n"
127 "b(\"target\") {\n"
128 "}\n");
129 ASSERT_FALSE(invalid_list.has_error());
130 err = Err();
131 invalid_list.parsed()->Execute(setup.scope(), &err);
132 EXPECT_TRUE(err.has_error());
133 EXPECT_EQ("Not a valid list of variables to copy.", err.message());
134
135 // Type check the exclusion list.
136 TestParseInput invalid_exclusion_list(
137 "template(\"c\") {\n"
138 " forward_variables_from(invoker, \"*\", 42)\n"
139 " print(\"$target_name\")\n"
140 "}\n"
141 "c(\"target\") {\n"
142 "}\n");
143 ASSERT_FALSE(invalid_exclusion_list.has_error());
144 err = Err();
145 invalid_exclusion_list.parsed()->Execute(setup.scope(), &err);
146 EXPECT_TRUE(err.has_error());
147 EXPECT_EQ("Not a valid list of variables to exclude.", err.message());
148
149 // Programmatic values should error.
150 TestParseInput prog(
151 "template(\"d\") {\n"
152 " forward_variables_from(invoker, [\"root_out_dir\"])\n"
153 " print(\"$target_name\")\n"
154 "}\n"
155 "d(\"target\") {\n"
156 "}\n");
157 ASSERT_FALSE(prog.has_error());
158 err = Err();
159 prog.parsed()->Execute(setup.scope(), &err);
160 EXPECT_TRUE(err.has_error());
161 EXPECT_EQ("This value can't be forwarded.", err.message());
162
163 // Not enough arguments.
164 TestParseInput not_enough_arguments(
165 "template(\"e\") {\n"
166 " forward_variables_from(invoker)\n"
167 " print(\"$target_name\")\n"
168 "}\n"
169 "e(\"target\") {\n"
170 "}\n");
171 ASSERT_FALSE(not_enough_arguments.has_error());
172 err = Err();
173 not_enough_arguments.parsed()->Execute(setup.scope(), &err);
174 EXPECT_TRUE(err.has_error());
175 EXPECT_EQ("Wrong number of arguments.", err.message());
176
177 // Too many arguments.
178 TestParseInput too_many_arguments(
179 "template(\"f\") {\n"
180 " forward_variables_from(invoker, \"*\", [], [])\n"
181 " print(\"$target_name\")\n"
182 "}\n"
183 "f(\"target\") {\n"
184 "}\n");
185 ASSERT_FALSE(too_many_arguments.has_error());
186 err = Err();
187 too_many_arguments.parsed()->Execute(setup.scope(), &err);
188 EXPECT_TRUE(err.has_error());
189 EXPECT_EQ("Wrong number of arguments.", err.message());
190 }
191
TEST_F(FunctionForwardVariablesFromTest,Star)192 TEST_F(FunctionForwardVariablesFromTest, Star) {
193 TestWithScope setup;
194
195 // Defines a template and copy the two x and y values out. The "*" behavior
196 // should clobber existing variables with the same name.
197 TestParseInput input(
198 "template(\"a\") {\n"
199 " x = 1000000\n" // Should be clobbered.
200 " forward_variables_from(invoker, \"*\")\n"
201 " print(\"$target_name, $x, $y\")\n"
202 "}\n"
203 "a(\"target\") {\n"
204 " x = 1\n"
205 " y = 2\n"
206 "}\n");
207
208 ASSERT_FALSE(input.has_error());
209
210 Err err;
211 input.parsed()->Execute(setup.scope(), &err);
212 ASSERT_FALSE(err.has_error()) << err.message();
213
214 EXPECT_EQ("target, 1, 2\n", setup.print_output());
215 setup.print_output().clear();
216 }
217
TEST_F(FunctionForwardVariablesFromTest,StarWithExclusion)218 TEST_F(FunctionForwardVariablesFromTest, StarWithExclusion) {
219 TestWithScope setup;
220
221 // Defines a template and copy all values except z value. The "*" behavior
222 // should clobber existing variables with the same name.
223 TestParseInput input(
224 "template(\"a\") {\n"
225 " x = 1000000\n" // Should be clobbered.
226 " forward_variables_from(invoker, \"*\", [\"z\"])\n"
227 " print(\"$target_name, $x, $y\")\n"
228 "}\n"
229 "a(\"target\") {\n"
230 " x = 1\n"
231 " y = 2\n"
232 " z = 3\n"
233 " print(\"$z\")\n"
234 "}\n");
235
236 ASSERT_FALSE(input.has_error());
237
238 Err err;
239 input.parsed()->Execute(setup.scope(), &err);
240 ASSERT_FALSE(err.has_error()) << err.message();
241
242 EXPECT_EQ("3\ntarget, 1, 2\n", setup.print_output());
243 setup.print_output().clear();
244 }
245