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.
4
5 #include "gn/scheduler.h"
6 #include "gn/scope.h"
7 #include "gn/test_with_scheduler.h"
8 #include "gn/test_with_scope.h"
9 #include "util/test/test.h"
10
11 using FunctionsTarget = TestWithScheduler;
12
13 // Checks that we find unused identifiers in targets.
TEST_F(FunctionsTarget,CheckUnused)14 TEST_F(FunctionsTarget, CheckUnused) {
15 TestWithScope setup;
16
17 // The target generator needs a place to put the targets or it will fail.
18 Scope::ItemVector item_collector;
19 setup.scope()->set_item_collector(&item_collector);
20
21 // Test a good one first.
22 TestParseInput good_input(
23 "source_set(\"foo\") {\n"
24 "}\n");
25 ASSERT_FALSE(good_input.has_error());
26 Err err;
27 good_input.parsed()->Execute(setup.scope(), &err);
28 ASSERT_FALSE(err.has_error()) << err.message();
29
30 // Test a source set with an unused variable.
31 TestParseInput source_set_input(
32 "source_set(\"foo\") {\n"
33 " unused = 5\n"
34 "}\n");
35 ASSERT_FALSE(source_set_input.has_error());
36 err = Err();
37 source_set_input.parsed()->Execute(setup.scope(), &err);
38 ASSERT_TRUE(err.has_error());
39 }
40
41 // Checks that we find uses of identifiers marked as not needed.
TEST_F(FunctionsTarget,CheckNotNeeded)42 TEST_F(FunctionsTarget, CheckNotNeeded) {
43 TestWithScope setup;
44
45 // The target generator needs a place to put the targets or it will fail.
46 Scope::ItemVector item_collector;
47 setup.scope()->set_item_collector(&item_collector);
48
49 TestParseInput nonscoped_input(
50 "source_set(\"foo\") {\n"
51 " a = 1\n"
52 " not_needed([ \"a\" ])\n"
53 "}\n");
54 ASSERT_FALSE(nonscoped_input.has_error());
55 Err err;
56 nonscoped_input.parsed()->Execute(setup.scope(), &err);
57 ASSERT_FALSE(err.has_error()) << err.message();
58
59 TestParseInput scoped_input(
60 "source_set(\"foo\") {\n"
61 " a = {x = 1 y = 2}\n"
62 " not_needed(a, \"*\")\n"
63 "}\n");
64 ASSERT_FALSE(scoped_input.has_error());
65 err = Err();
66 scoped_input.parsed()->Execute(setup.scope(), &err);
67 ASSERT_FALSE(err.has_error()) << err.message();
68
69 TestParseInput nonexistent_arg_input(
70 "source_set(\"foo\") {\n"
71 " a = {x = 1}\n"
72 " not_needed(a, [ \"x\", \"y\" ])\n"
73 "}\n");
74 ASSERT_FALSE(nonexistent_arg_input.has_error());
75 err = Err();
76 nonexistent_arg_input.parsed()->Execute(setup.scope(), &err);
77 ASSERT_FALSE(err.has_error()) << err.message();
78
79 TestParseInput exclusion_input(
80 "source_set(\"foo\") {\n"
81 " x = 1\n"
82 " y = 2\n"
83 " not_needed(\"*\", [ \"y\" ])\n"
84 "}\n");
85 ASSERT_FALSE(exclusion_input.has_error());
86 err = Err();
87 exclusion_input.parsed()->Execute(setup.scope(), &err);
88 ASSERT_TRUE(err.has_error()) << err.message();
89 EXPECT_EQ("Assignment had no effect.", err.message());
90
91 TestParseInput error_input(
92 "source_set(\"foo\") {\n"
93 " a = {x = 1 y = 2}\n"
94 " not_needed(a, [ \"x \"], [ \"y\" ])\n"
95 "}\n");
96 ASSERT_FALSE(error_input.has_error());
97 err = Err();
98 error_input.parsed()->Execute(setup.scope(), &err);
99 ASSERT_TRUE(err.has_error());
100 EXPECT_EQ("Not supported with a variable list.", err.message());
101
102 TestParseInput argcount_error_input(
103 "source_set(\"foo\") {\n"
104 " not_needed()\n"
105 "}\n");
106 ASSERT_FALSE(argcount_error_input.has_error());
107 err = Err();
108 argcount_error_input.parsed()->Execute(setup.scope(), &err);
109 ASSERT_TRUE(err.has_error());
110 EXPECT_EQ("Wrong number of arguments.", err.message());
111
112 TestParseInput scope_error_input(
113 "source_set(\"foo\") {\n"
114 " a = {x = 1 y = 2}\n"
115 " not_needed(a)\n"
116 "}\n");
117 ASSERT_FALSE(scope_error_input.has_error());
118 err = Err();
119 scope_error_input.parsed()->Execute(setup.scope(), &err);
120 ASSERT_TRUE(err.has_error());
121 EXPECT_EQ("Wrong number of arguments.", err.message());
122
123 TestParseInput string_error_input(
124 "source_set(\"foo\") {\n"
125 " not_needed(\"*\", {}, \"*\")\n"
126 "}\n");
127 ASSERT_FALSE(string_error_input.has_error());
128 err = Err();
129 string_error_input.parsed()->Execute(setup.scope(), &err);
130 ASSERT_TRUE(err.has_error());
131 EXPECT_EQ("Wrong number of arguments.", err.message());
132
133 TestParseInput template_input(
134 R"(# Test that not_needed() propagates through templates correctly;
135 # no error should arise from not using "a".
136 template("inner_templ") {
137 source_set(target_name) {
138 not_needed(invoker, [ "a" ])
139 }
140 }
141 template("outer_templ") {
142 inner_templ(target_name) {
143 forward_variables_from(invoker, "*")
144 }
145 }
146 outer_templ("foo") {
147 a = 1
148 })");
149 ASSERT_FALSE(template_input.has_error());
150 err = Err();
151 template_input.parsed()->Execute(setup.scope(), &err);
152 ASSERT_FALSE(err.has_error()) << err.message();
153 }
154
155 // Checks that the defaults applied to a template invoked by target() use
156 // the name of the template, rather than the string "target" (which is the
157 // name of the actual function being called).
TEST_F(FunctionsTarget,TemplateDefaults)158 TEST_F(FunctionsTarget, TemplateDefaults) {
159 TestWithScope setup;
160
161 // The target generator needs a place to put the targets or it will fail.
162 Scope::ItemVector item_collector;
163 setup.scope()->set_item_collector(&item_collector);
164
165 // Test a good one first.
166 TestParseInput good_input(
167 R"(# Make a template with defaults set.
168 template("my_templ") {
169 source_set(target_name) {
170 forward_variables_from(invoker, "*")
171 }
172 }
173 set_defaults("my_templ") {
174 default_value = 1
175 }
176
177 # Invoke the template with target(). This will fail to execute if the
178 # defaults were not set properly, because "default_value" won't exist.
179 target("my_templ", "foo") {
180 print(default_value)
181 })");
182 ASSERT_FALSE(good_input.has_error());
183 Err err;
184 good_input.parsed()->Execute(setup.scope(), &err);
185 ASSERT_FALSE(err.has_error()) << err.message();
186 }
187
188 // Checks that we find unused identifiers in targets.
TEST_F(FunctionsTarget,MixedSourceError)189 TEST_F(FunctionsTarget, MixedSourceError) {
190 TestWithScope setup;
191
192 // The target generator needs a place to put the targets or it will fail.
193 Scope::ItemVector item_collector;
194 setup.scope()->set_item_collector(&item_collector);
195
196 // Test a good one first.
197 TestParseInput good_input(
198 "source_set(\"foo\") {\n"
199 " sources = [ \"cpp.cc\", \"rust.rs\" ]"
200 "}\n");
201 ASSERT_FALSE(good_input.has_error());
202 Err err;
203 good_input.parsed()->Execute(setup.scope(), &err);
204 ASSERT_TRUE(err.has_error());
205 ASSERT_EQ(err.message(), "More than one language used in target sources.");
206 }
207