1 // Copyright 2014 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/functions.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "gn/parse_tree.h"
11 #include "gn/test_with_scope.h"
12 #include "gn/value.h"
13 #include "util/test/test.h"
14
TEST(Functions,Assert)15 TEST(Functions, Assert) {
16 TestWithScope setup;
17
18 // Verify cases where the assertion passes.
19 std::vector<std::string> assert_pass_examples = {
20 R"gn(assert(true))gn",
21 R"gn(assert(true, "This message is ignored for passed assertions."))gn",
22 };
23 for (const auto& assert_pass_example : assert_pass_examples) {
24 TestParseInput input(assert_pass_example);
25 ASSERT_FALSE(input.has_error());
26 Err err;
27 input.parsed()->Execute(setup.scope(), &err);
28 ASSERT_FALSE(err.has_error()) << assert_pass_example;
29 }
30
31 // Verify case where the assertion fails, with no message.
32 {
33 TestParseInput input("assert(false)");
34 ASSERT_FALSE(input.has_error());
35 Err err;
36 input.parsed()->Execute(setup.scope(), &err);
37 ASSERT_TRUE(err.has_error());
38 ASSERT_EQ(err.message(), "Assertion failed.");
39 }
40
41 // Verify case where the assertion fails, with a message.
42 {
43 TestParseInput input("assert(false, \"What failed\")");
44 ASSERT_FALSE(input.has_error());
45 Err err;
46 input.parsed()->Execute(setup.scope(), &err);
47 ASSERT_TRUE(err.has_error());
48 ASSERT_EQ(err.message(), "Assertion failed.");
49 ASSERT_EQ(err.help_text(), "What failed");
50 }
51
52 // Verify usage errors are detected.
53 std::vector<std::string> bad_usage_examples = {
54 // Number of arguments.
55 R"gn(assert())gn",
56 R"gn(assert(1, 2, 3))gn",
57
58 // Argument types.
59 R"gn(assert(1))gn",
60 R"gn(assert("oops"))gn",
61 R"gn(assert(true, 1))gn",
62 R"gn(assert(true, []))gn",
63 };
64 for (const auto& bad_usage_example : bad_usage_examples) {
65 TestParseInput input(bad_usage_example);
66 ASSERT_FALSE(input.has_error());
67 Err err;
68 input.parsed()->Execute(setup.scope(), &err);
69 ASSERT_TRUE(err.has_error()) << bad_usage_example;
70 // We are checking for usage errors, not assertion failures.
71 ASSERT_NE(err.message(), "Assertion failed.") << bad_usage_example;
72 }
73 }
74
TEST(Functions,Defined)75 TEST(Functions, Defined) {
76 TestWithScope setup;
77
78 FunctionCallNode function_call;
79 Err err;
80
81 // Test an undefined identifier.
82 Token undefined_token(Location(), Token::IDENTIFIER, "undef");
83 ListNode args_list_identifier_undefined;
84 args_list_identifier_undefined.append_item(
85 std::make_unique<IdentifierNode>(undefined_token));
86 Value result = functions::RunDefined(setup.scope(), &function_call,
87 &args_list_identifier_undefined, &err);
88 ASSERT_EQ(Value::BOOLEAN, result.type());
89 EXPECT_FALSE(result.boolean_value());
90
91 // Define a value that's itself a scope value.
92 const char kDef[] = "def"; // Defined variable name.
93 setup.scope()->SetValue(
94 kDef, Value(nullptr, std::make_unique<Scope>(setup.scope())), nullptr);
95
96 // Test the defined identifier.
97 Token defined_token(Location(), Token::IDENTIFIER, kDef);
98 ListNode args_list_identifier_defined;
99 args_list_identifier_defined.append_item(
100 std::make_unique<IdentifierNode>(defined_token));
101 result = functions::RunDefined(setup.scope(), &function_call,
102 &args_list_identifier_defined, &err);
103 ASSERT_EQ(Value::BOOLEAN, result.type());
104 EXPECT_TRUE(result.boolean_value());
105
106 // Should also work by passing an accessor node so you can do
107 // "defined(def.foo)" to see if foo is defined on the def scope.
108 std::unique_ptr<AccessorNode> undef_accessor =
109 std::make_unique<AccessorNode>();
110 undef_accessor->set_base(defined_token);
111 undef_accessor->set_member(std::make_unique<IdentifierNode>(undefined_token));
112 ListNode args_list_accessor_defined;
113 args_list_accessor_defined.append_item(std::move(undef_accessor));
114 result = functions::RunDefined(setup.scope(), &function_call,
115 &args_list_accessor_defined, &err);
116 ASSERT_EQ(Value::BOOLEAN, result.type());
117 EXPECT_FALSE(result.boolean_value());
118 }
119
120 // Tests that an error is thrown when a {} is supplied to a function that
121 // doesn't take one.
TEST(Functions,FunctionsWithBlock)122 TEST(Functions, FunctionsWithBlock) {
123 TestWithScope setup;
124 Err err;
125
126 // No scope to print() is OK.
127 TestParseInput print_no_scope("print(6)");
128 EXPECT_FALSE(print_no_scope.has_error());
129 Value result = print_no_scope.parsed()->Execute(setup.scope(), &err);
130 EXPECT_FALSE(err.has_error());
131
132 // Passing a scope should pass parsing (it doesn't know about what kind of
133 // function it is) and then throw an error during execution.
134 TestParseInput print_with_scope("print(foo) {}");
135 EXPECT_FALSE(print_with_scope.has_error());
136 result = print_with_scope.parsed()->Execute(setup.scope(), &err);
137 EXPECT_TRUE(err.has_error());
138 err = Err();
139
140 // defined() is a special function so test it separately.
141 TestParseInput defined_no_scope("defined(foo)");
142 EXPECT_FALSE(defined_no_scope.has_error());
143 result = defined_no_scope.parsed()->Execute(setup.scope(), &err);
144 EXPECT_FALSE(err.has_error());
145
146 // A block to defined should fail.
147 TestParseInput defined_with_scope("defined(foo) {}");
148 EXPECT_FALSE(defined_with_scope.has_error());
149 result = defined_with_scope.parsed()->Execute(setup.scope(), &err);
150 EXPECT_TRUE(err.has_error());
151 }
152
TEST(Functions,SplitList)153 TEST(Functions, SplitList) {
154 TestWithScope setup;
155
156 TestParseInput input(
157 // Empty input with varying result items.
158 "out1 = split_list([], 1)\n"
159 "out2 = split_list([], 3)\n"
160 "print(\"empty = $out1 $out2\")\n"
161
162 // One item input.
163 "out3 = split_list([1], 1)\n"
164 "out4 = split_list([1], 2)\n"
165 "print(\"one = $out3 $out4\")\n"
166
167 // Multiple items.
168 "out5 = split_list([1, 2, 3, 4, 5, 6, 7, 8, 9], 2)\n"
169 "print(\"many = $out5\")\n"
170
171 // Rounding.
172 "out6 = split_list([1, 2, 3, 4, 5, 6], 4)\n"
173 "print(\"rounding = $out6\")\n");
174 ASSERT_FALSE(input.has_error());
175
176 Err err;
177 input.parsed()->Execute(setup.scope(), &err);
178 ASSERT_FALSE(err.has_error()) << err.message();
179
180 EXPECT_EQ(
181 "empty = [[]] [[], [], []]\n"
182 "one = [[1]] [[1], []]\n"
183 "many = [[1, 2, 3, 4, 5], [6, 7, 8, 9]]\n"
184 "rounding = [[1, 2], [3, 4], [5], [6]]\n",
185 setup.print_output());
186 }
187
TEST(Functions,StringJoin)188 TEST(Functions, StringJoin) {
189 TestWithScope setup;
190
191 // Verify outputs when string_join() is called correctly.
192 {
193 TestParseInput input(R"gn(
194 # No elements in the list and empty separator.
195 print("<" + string_join("", []) + ">")
196
197 # No elements in the list.
198 print("<" + string_join(" ", []) + ">")
199
200 # One element in the list.
201 print(string_join("|", ["a"]))
202
203 # Multiple elements in the list.
204 print(string_join(" ", ["a", "b", "c"]))
205
206 # Multi-character separator.
207 print(string_join("-.", ["a", "b", "c"]))
208
209 # Empty separator.
210 print(string_join("", ["x", "y", "z"]))
211
212 # Empty string list elements.
213 print(string_join("x", ["", "", ""]))
214
215 # Empty string list elements and separator
216 print(string_join("", ["", "", ""]))
217 )gn");
218 ASSERT_FALSE(input.has_error());
219
220 Err err;
221 input.parsed()->Execute(setup.scope(), &err);
222 ASSERT_FALSE(err.has_error()) << err.message();
223
224 EXPECT_EQ(
225 "<>\n"
226 "<>\n"
227 "a\n"
228 "a b c\n"
229 "a-.b-.c\n"
230 "xyz\n"
231 "xx\n"
232 "\n",
233 setup.print_output()) << setup.print_output();
234 }
235
236 // Verify usage errors are detected.
237 std::vector<std::string> bad_usage_examples = {
238 // Number of arguments.
239 R"gn(string_join())gn",
240 R"gn(string_join(["oops"]))gn",
241 R"gn(string_join("kk", [], "oops"))gn",
242
243 // Argument types.
244 R"gn(string_join(1, []))gn",
245 R"gn(string_join("kk", "oops"))gn",
246 R"gn(string_join(["oops"], []))gn",
247
248 // Non-string elements in list of strings.
249 R"gn(string_join("kk", [1]))gn",
250 R"gn(string_join("kk", ["hello", 1]))gn",
251 R"gn(string_join("kk", ["hello", []]))gn",
252 };
253 for (const auto& bad_usage_example : bad_usage_examples) {
254 TestParseInput input(bad_usage_example);
255 ASSERT_FALSE(input.has_error());
256
257 Err err;
258 input.parsed()->Execute(setup.scope(), &err);
259 ASSERT_TRUE(err.has_error()) << bad_usage_example;
260 }
261 }
262
TEST(Functions,StringReplace)263 TEST(Functions, StringReplace) {
264 TestWithScope setup;
265
266 TestParseInput input(
267 // Replace all occurrences of string.
268 "out1 = string_replace(\"abbcc\", \"b\", \"d\")\n"
269 "print(out1)\n"
270
271 // Replace only the first occurrence.
272 "out2 = string_replace(\"abbcc\", \"b\", \"d\", 1)\n"
273 "print(out2)\n"
274
275 // Duplicate string to be replaced.
276 "out3 = string_replace(\"abbcc\", \"b\", \"bb\")\n"
277 "print(out3)\n"
278
279 // Handle overlapping occurrences.
280 "out4 = string_replace(\"aaa\", \"aa\", \"b\")\n"
281 "print(out4)\n");
282 ASSERT_FALSE(input.has_error());
283
284 Err err;
285 input.parsed()->Execute(setup.scope(), &err);
286 ASSERT_FALSE(err.has_error()) << err.message();
287
288 EXPECT_EQ(
289 "addcc\n"
290 "adbcc\n"
291 "abbbbcc\n"
292 "ba\n",
293 setup.print_output());
294 }
295
TEST(Functions,StringSplit)296 TEST(Functions, StringSplit) {
297 TestWithScope setup;
298
299 // Verify outputs when string_join() is called correctly.
300 {
301 TestParseInput input(R"gn(
302 # Split on all whitespace: empty string.
303 print(string_split(""))
304
305 # Split on all whitespace: string is only whitespace
306 print(string_split(" "))
307
308 # Split on all whitespace: leading, trailing, runs; one element.
309 print(string_split("hello"))
310 print(string_split(" hello"))
311 print(string_split(" hello "))
312 print(string_split("hello "))
313
314 # Split on all whitespace: leading, trailing, runs; multiple elements.
315 print(string_split("a b")) # Pre-stripped
316 print(string_split(" a b")) # Leading whitespace
317 print(string_split(" a b ")) # Leading & trailing whitespace
318 print(string_split("a b ")) # Trailing whitespace
319 print(string_split("a b ")) # Whitespace run between words
320 print(string_split(" a b cc ddd")) # More & multi-character elements
321
322 # Split on string.
323 print(string_split("", "|")) # Empty string
324 print(string_split("|", "|")) # Only a separator
325 print(string_split("||", "|")) # Only separators
326 print(string_split("ab", "|")) # String is missing separator
327 print(string_split("a|b", "|")) # Two elements
328 print(string_split("|a|b", "|")) # Leading separator
329 print(string_split("a|b|", "|")) # Trailing separator
330 print(string_split("||x", "|")) # Leading consecutive separators
331 print(string_split("x||", "|")) # Trailing consecutive separators
332 print(string_split("a|bb|ccc", "|")) # Multiple elements
333 print(string_split(".x.x.x.", ".x.")) # Self-overlapping separators 1
334 print(string_split("x.x.x.", ".x.")) # Self-overlapping separators 2
335 )gn");
336 ASSERT_FALSE(input.has_error());
337
338 Err err;
339 input.parsed()->Execute(setup.scope(), &err);
340 ASSERT_FALSE(err.has_error()) << err.message();
341
342 EXPECT_EQ(
343 // Split on all whitespace: empty string.
344 "[]\n"
345
346 // Split on all whitespace: string is only whitespace.
347 "[]\n"
348
349 // Split on all whitespace: leading, trailing, runs; one element.
350 "[\"hello\"]\n"
351 "[\"hello\"]\n"
352 "[\"hello\"]\n"
353 "[\"hello\"]\n"
354
355 // Split on all whitespace: leading, trailing, runs; multiple elements.
356 "[\"a\", \"b\"]\n"
357 "[\"a\", \"b\"]\n"
358 "[\"a\", \"b\"]\n"
359 "[\"a\", \"b\"]\n"
360 "[\"a\", \"b\"]\n"
361 "[\"a\", \"b\", \"cc\", \"ddd\"]\n"
362
363 // Split on string.
364 "[\"\"]\n" // Empty string (like Python)
365 "[\"\", \"\"]\n" // Only a separator
366 "[\"\", \"\", \"\"]\n" // Only separators
367 "[\"ab\"]\n" // String is missing separator
368 "[\"a\", \"b\"]\n" // Two elements
369 "[\"\", \"a\", \"b\"]\n" // Leading
370 "[\"a\", \"b\", \"\"]\n" // Trailing
371 "[\"\", \"\", \"x\"]\n" // Leading consecutive separators
372 "[\"x\", \"\", \"\"]\n" // Trailing consecutive separators
373 "[\"a\", \"bb\", \"ccc\"]\n" // Multiple elements
374 "[\"\", \"x\", \"\"]\n" // Self-overlapping separators 1
375 "[\"x\", \"x.\"]\n" // Self-overlapping separators 2
376 ,
377 setup.print_output()) << setup.print_output();
378 }
379
380 // Verify usage errors are detected.
381 std::vector<std::string> bad_usage_examples = {
382 // Number of arguments.
383 R"gn(string_split())gn",
384 R"gn(string_split("a", "b", "c"))gn",
385
386 // Argument types.
387 R"gn(string_split(1))gn",
388 R"gn(string_split(["oops"]))gn",
389 R"gn(string_split("kk", 1))gn",
390 R"gn(string_split("kk", ["oops"]))gn",
391
392 // Empty separator argument.
393 R"gn(string_split("kk", ""))gn",
394 };
395 for (const auto& bad_usage_example : bad_usage_examples) {
396 TestParseInput input(bad_usage_example);
397 ASSERT_FALSE(input.has_error());
398 Err err;
399 input.parsed()->Execute(setup.scope(), &err);
400 ASSERT_TRUE(err.has_error()) << bad_usage_example;
401 }
402 }
403
TEST(Functions,DeclareArgs)404 TEST(Functions, DeclareArgs) {
405 TestWithScope setup;
406 Err err;
407
408 // It is not legal to read the value of an argument declared in a
409 // declare_args() from inside the call, but outside the call and in
410 // a separate call should work.
411
412 TestParseInput reading_from_same_call(R"(
413 declare_args() {
414 foo = true
415 bar = foo
416 })");
417 reading_from_same_call.parsed()->Execute(setup.scope(), &err);
418 ASSERT_TRUE(err.has_error());
419
420 TestParseInput reading_from_outside_call(R"(
421 declare_args() {
422 foo = true
423 }
424
425 bar = foo
426 assert(bar)
427 )");
428 err = Err();
429 reading_from_outside_call.parsed()->Execute(setup.scope(), &err);
430 ASSERT_FALSE(err.has_error());
431
432 TestParseInput reading_from_different_call(R"(
433 declare_args() {
434 foo = true
435 }
436
437 declare_args() {
438 bar = foo
439 }
440
441 assert(bar)
442 )");
443 err = Err();
444 TestWithScope setup2;
445 reading_from_different_call.parsed()->Execute(setup2.scope(), &err);
446 ASSERT_FALSE(err.has_error());
447 }
448
TEST(Functions,NotNeeded)449 TEST(Functions, NotNeeded) {
450 TestWithScope setup;
451
452 TestParseInput input("not_needed({ a = 1 }, \"*\")");
453 ASSERT_FALSE(input.has_error());
454
455 Err err;
456 input.parsed()->Execute(setup.scope(), &err);
457 ASSERT_FALSE(err.has_error())
458 << err.message() << err.location().Describe(true);
459 }
460