• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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