• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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/setup.h"
6 
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "gn/builder_record.h"
12 #include "gn/filesystem_utils.h"
13 #include "gn/switches.h"
14 #include "gn/test_with_scheduler.h"
15 #include "util/build_config.h"
16 
17 using SetupTest = TestWithScheduler;
18 
WriteFile(const base::FilePath & file,const std::string & data)19 static void WriteFile(const base::FilePath& file, const std::string& data) {
20   CHECK_EQ(static_cast<int>(data.size()),  // Way smaller than INT_MAX.
21            base::WriteFile(file, data.data(), data.size()));
22 }
23 
TEST_F(SetupTest,DotGNFileIsGenDep)24 TEST_F(SetupTest, DotGNFileIsGenDep) {
25   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
26 
27   // Create a temp directory containing a .gn file and a BUILDCONFIG.gn file,
28   // pass it as --root.
29   base::ScopedTempDir in_temp_dir;
30   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
31   base::FilePath in_path = in_temp_dir.GetPath();
32   base::FilePath dot_gn_name = in_path.Append(FILE_PATH_LITERAL(".gn"));
33   WriteFile(dot_gn_name, "buildconfig = \"//BUILDCONFIG.gn\"\n");
34   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
35   cmdline.AppendSwitchPath(switches::kRoot, in_path);
36 
37   // Create another temp dir for writing the generated files to.
38   base::ScopedTempDir build_temp_dir;
39   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
40 
41   // Run setup and check that the .gn file is in the scheduler's gen deps.
42   Setup setup;
43   EXPECT_TRUE(
44       setup.DoSetup(FilePathToUTF8(build_temp_dir.GetPath()), true, cmdline));
45   std::vector<base::FilePath> gen_deps = g_scheduler->GetGenDependencies();
46   ASSERT_EQ(1u, gen_deps.size());
47   EXPECT_EQ(gen_deps[0], base::MakeAbsoluteFilePath(dot_gn_name));
48 }
49 
TEST_F(SetupTest,EmptyScriptExecutableDoesNotGenerateError)50 TEST_F(SetupTest, EmptyScriptExecutableDoesNotGenerateError) {
51   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
52 
53   const char kDotfileContents[] = R"(
54 buildconfig = "//BUILDCONFIG.gn"
55 script_executable = ""
56 )";
57 
58   // Create a temp directory containing a .gn file and a BUILDCONFIG.gn file,
59   // pass it as --root.
60   base::ScopedTempDir in_temp_dir;
61   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
62   base::FilePath in_path = in_temp_dir.GetPath();
63   base::FilePath dot_gn_name = in_path.Append(FILE_PATH_LITERAL(".gn"));
64   WriteFile(dot_gn_name, kDotfileContents);
65 
66   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
67   cmdline.AppendSwitchPath(switches::kRoot, in_path);
68 
69   // Create another temp dir for writing the generated files to.
70   base::ScopedTempDir build_temp_dir;
71   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
72 
73   // Run setup and check that the .gn file is in the scheduler's gen deps.
74   Setup setup;
75   Err err;
76   EXPECT_TRUE(setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()),
77                                    true, cmdline, &err));
78 }
79 
80 #if defined(OS_WIN)
81 TEST_F(SetupTest, MissingScriptExeGeneratesSetupErrorOnWindows) {
82   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
83 
84   const char kDotfileContents[] = R"(
85 buildconfig = "//BUILDCONFIG.gn"
86 script_executable = "this_does_not_exist"
87 )";
88 
89   // Create a temp directory containing a .gn file and a BUILDCONFIG.gn file,
90   // pass it as --root.
91   base::ScopedTempDir in_temp_dir;
92   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
93   base::FilePath in_path = in_temp_dir.GetPath();
94   base::FilePath dot_gn_name = in_path.Append(FILE_PATH_LITERAL(".gn"));
95   WriteFile(dot_gn_name, kDotfileContents);
96 
97   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
98   cmdline.AppendSwitchPath(switches::kRoot, in_path);
99 
100   // Create another temp dir for writing the generated files to.
101   base::ScopedTempDir build_temp_dir;
102   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
103 
104   // Run setup and check that the .gn file is in the scheduler's gen deps.
105   Setup setup;
106   Err err;
107   EXPECT_FALSE(setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()),
108                                     true, cmdline, &err));
109   EXPECT_TRUE(err.has_error());
110 }
111 #endif  // defined(OS_WIN)
112 
113 static void RunExtensionCheckTest(std::string extension,
114                                   bool success,
115                                   const std::string& expected_error_message) {
116   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
117 
118   // Create a temp directory containing a .gn file and a BUILDCONFIG.gn file,
119   // pass it as --root.
120   base::ScopedTempDir in_temp_dir;
121   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
122   base::FilePath in_path = in_temp_dir.GetPath();
123   base::FilePath dot_gn_name = in_path.Append(FILE_PATH_LITERAL(".gn"));
124   WriteFile(dot_gn_name,
125             "buildconfig = \"//BUILDCONFIG.gn\"\n\
126       build_file_extension = \"" +
127                 extension + "\"");
128   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
129   cmdline.AppendSwitchPath(switches::kRoot, in_path);
130 
131   // Create another temp dir for writing the generated files to.
132   base::ScopedTempDir build_temp_dir;
133   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
134 
135   // Run setup and check that its status.
136   Setup setup;
137   Err err;
138   EXPECT_EQ(success,
139             setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()), true,
140                                  cmdline, &err));
141   EXPECT_EQ(success, !err.has_error());
142 }
143 
TEST_F(SetupTest,NoSeparatorInExtension)144 TEST_F(SetupTest, NoSeparatorInExtension) {
145   RunExtensionCheckTest(
146       "hello" + std::string(1, base::FilePath::kSeparators[0]) + "world", false,
147 #if defined(OS_WIN)
148       "Build file extension 'hello\\world' cannot contain a path separator"
149 #else
150       "Build file extension 'hello/world' cannot contain a path separator"
151 #endif
152   );
153 }
154 
TEST_F(SetupTest,Extension)155 TEST_F(SetupTest, Extension) {
156   RunExtensionCheckTest("yay", true, "");
157 }
158 
TEST_F(SetupTest,AddExportCompileCommands)159 TEST_F(SetupTest, AddExportCompileCommands) {
160   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
161 
162   // Provide a project default export compile command list.
163   const char kDotfileContents[] = R"(
164 buildconfig = "//BUILDCONFIG.gn"
165 export_compile_commands = [ "//base/*" ]
166 )";
167 
168   // Create a temp directory containing the build.
169   base::ScopedTempDir in_temp_dir;
170   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
171   base::FilePath in_path = in_temp_dir.GetPath();
172   base::FilePath dot_gn_name = in_path.Append(FILE_PATH_LITERAL(".gn"));
173   WriteFile(dot_gn_name, kDotfileContents);
174 
175   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
176   cmdline.AppendSwitch(switches::kRoot, FilePathToUTF8(in_path));
177 
178   // Two additions to the compile commands list.
179   cmdline.AppendSwitch(switches::kAddExportCompileCommands,
180                        "//tools:doom_melon");
181   cmdline.AppendSwitch(switches::kAddExportCompileCommands, "//src/gn:*");
182 
183   // Create another temp dir for writing the generated files to.
184   base::ScopedTempDir build_temp_dir;
185   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
186 
187   // Run setup and check that the .gn file is in the scheduler's gen deps.
188   Setup setup;
189   Err err;
190   EXPECT_TRUE(setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()),
191                                    true, cmdline, &err));
192 
193   // The export compile commands should have three items.
194   const std::vector<LabelPattern>& export_cc = setup.export_compile_commands();
195   ASSERT_EQ(3u, export_cc.size());
196   EXPECT_EQ("//base/*", export_cc[0].Describe());
197   EXPECT_EQ("//tools:doom_melon", export_cc[1].Describe());
198   EXPECT_EQ("//src/gn:*", export_cc[2].Describe());
199 }
200 
TEST_F(SetupTest,RootPatternsInGnConfig)201 TEST_F(SetupTest, RootPatternsInGnConfig) {
202   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
203 
204   // Provide a default root pattern for all top-level targets from //BUILD.gn
205   const char kDotfileContents[] = R"(
206 buildconfig = "//BUILDCONFIG.gn"
207 root_patterns = [ "//:*" ]
208 )";
209 
210   // Create a temp directory containing the build.
211   base::ScopedTempDir in_temp_dir;
212   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
213   base::FilePath in_path = in_temp_dir.GetPath();
214 
215   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
216   WriteFile(in_path.Append(FILE_PATH_LITERAL(".gn")), kDotfileContents);
217 
218   cmdline.AppendSwitch(switches::kRoot, FilePathToUTF8(in_path));
219 
220   // Create another temp dir for writing the generated files to.
221   base::ScopedTempDir build_temp_dir;
222   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
223 
224   // Run setup and check that the .gn file is in the scheduler's gen deps.
225   Setup setup;
226   Err err;
227   EXPECT_TRUE(setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()),
228                                    true, cmdline, &err));
229 
230   const std::vector<LabelPattern>& root_patterns =
231       setup.build_settings().root_patterns();
232   ASSERT_EQ(1u, root_patterns.size());
233   EXPECT_EQ("//.:*", root_patterns[0].Describe());
234 }
235 
TEST_F(SetupTest,RootPatternsOnCommandLineOverrideGnConfig)236 TEST_F(SetupTest, RootPatternsOnCommandLineOverrideGnConfig) {
237   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
238 
239   // Provide a default root pattern for only //:foo
240   const char kDotfileContents[] = R"(
241 buildconfig = "//BUILDCONFIG.gn"
242 root_patterns = [ "//:foo" ]
243 )";
244 
245   // Create a temp directory containing the build.
246   base::ScopedTempDir in_temp_dir;
247   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
248   base::FilePath in_path = in_temp_dir.GetPath();
249 
250   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")), "");
251   WriteFile(in_path.Append(FILE_PATH_LITERAL(".gn")), kDotfileContents);
252 
253   cmdline.AppendSwitch(switches::kRoot, FilePathToUTF8(in_path));
254 
255   // Override the default root pattern list.
256   cmdline.AppendSwitch(switches::kRootPattern, "//:bar");
257   cmdline.AppendSwitch(switches::kRootPattern, "//:qux");
258 
259   // Create another temp dir for writing the generated files to.
260   base::ScopedTempDir build_temp_dir;
261   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
262 
263   // Run setup and check that the .gn file is in the scheduler's gen deps.
264   Setup setup;
265   Err err;
266   EXPECT_TRUE(setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()),
267                                    true, cmdline, &err));
268 
269   const std::vector<LabelPattern>& root_patterns =
270       setup.build_settings().root_patterns();
271   ASSERT_EQ(2u, root_patterns.size());
272   EXPECT_EQ("//.:bar", root_patterns[0].Describe());
273   EXPECT_EQ("//.:qux", root_patterns[1].Describe());
274 }
275 
TEST_F(SetupTest,RootPatternsFiltersPatterns)276 TEST_F(SetupTest, RootPatternsFiltersPatterns) {
277   base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
278 
279   const char kDotfileContents[] = R"(
280 buildconfig = "//BUILDCONFIG.gn"
281 root_patterns = [ "//:foo" ]
282 )";
283 
284   const char kBuildConfigContents[] = R"(
285 set_default_toolchain("//:toolchain")
286 )";
287 
288   const char kBuildGnContents[] = R"(
289 group("foo") {
290   deps = [ ":bar" ]
291 }
292 
293 group("bar") {
294 }
295 
296 group("zoo") {
297 }
298 
299 group("qux") {
300 }
301 
302 # Minimal default toolchain definition for this test. Non-functional.
303 toolchain("toolchain") {
304   tool("stamp") {
305     command = "stamp"
306   }
307 }
308 )";
309 
310   // Create a temp directory containing the build.
311   base::ScopedTempDir in_temp_dir;
312   ASSERT_TRUE(in_temp_dir.CreateUniqueTempDir());
313   base::FilePath in_path = in_temp_dir.GetPath();
314 
315   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILD.gn")), kBuildGnContents);
316   WriteFile(in_path.Append(FILE_PATH_LITERAL("BUILDCONFIG.gn")),
317             kBuildConfigContents);
318   WriteFile(in_path.Append(FILE_PATH_LITERAL(".gn")), kDotfileContents);
319 
320   cmdline.AppendSwitch(switches::kRoot, FilePathToUTF8(in_path));
321 
322   // Create another temp dir for writing the generated files to.
323   base::ScopedTempDir build_temp_dir;
324   ASSERT_TRUE(build_temp_dir.CreateUniqueTempDir());
325 
326   // Run setup and check that the .gn file is in the scheduler's gen deps.
327   Setup setup;
328   Err err;
329   EXPECT_TRUE(setup.DoSetupWithErr(FilePathToUTF8(build_temp_dir.GetPath()),
330                                    true, cmdline, &err));
331 
332   const std::vector<LabelPattern>& root_patterns =
333       setup.build_settings().root_patterns();
334   ASSERT_EQ(1u, root_patterns.size());
335   EXPECT_EQ("//.:foo", root_patterns[0].Describe());
336 
337   // Now build the graph, then verify it only includes //:foo and //:bar
338   ASSERT_TRUE(setup.Run(cmdline));
339 
340   SourceDir top_dir("//");
341 
342   const BuilderRecord* foo_record =
343       setup.builder().GetRecord(Label(top_dir, "foo", top_dir, "toolchain"));
344   const BuilderRecord* bar_record =
345       setup.builder().GetRecord(Label(top_dir, "bar", top_dir, "toolchain"));
346   const BuilderRecord* qux_record =
347       setup.builder().GetRecord(Label(top_dir, "qux", top_dir, "toolchain"));
348   const BuilderRecord* zoo_record =
349       setup.builder().GetRecord(Label(top_dir, "zoo", top_dir, "toolchain"));
350 
351   // All four targets were added as build graph records.
352   ASSERT_TRUE(foo_record);
353   ASSERT_TRUE(bar_record);
354   ASSERT_TRUE(zoo_record);
355   ASSERT_TRUE(qux_record);
356 
357   // But only foo and bar should be generated in the Ninja plan.
358   EXPECT_TRUE(foo_record->should_generate());
359   EXPECT_TRUE(bar_record->should_generate());
360   EXPECT_FALSE(qux_record->should_generate());
361   EXPECT_FALSE(zoo_record->should_generate());
362 }
363