1 // Copyright 2016 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/analyzer.h"
6
7 #include "gn/build_settings.h"
8 #include "gn/builder.h"
9 #include "gn/c_tool.h"
10 #include "gn/config.h"
11 #include "gn/general_tool.h"
12 #include "gn/loader.h"
13 #include "gn/pool.h"
14 #include "gn/settings.h"
15 #include "gn/source_file.h"
16 #include "gn/substitution_list.h"
17 #include "gn/target.h"
18 #include "gn/tool.h"
19 #include "gn/toolchain.h"
20 #include "util/test/test.h"
21
22 namespace gn_analyzer_unittest {
23
24 class MockLoader : public Loader {
25 public:
26 MockLoader() = default;
27
Load(const SourceFile & file,const LocationRange & origin,const Label & toolchain_name)28 void Load(const SourceFile& file,
29 const LocationRange& origin,
30 const Label& toolchain_name) override {}
ToolchainLoaded(const Toolchain * toolchain)31 void ToolchainLoaded(const Toolchain* toolchain) override {}
GetDefaultToolchain() const32 Label GetDefaultToolchain() const override {
33 return Label(SourceDir("//tc/"), "default");
34 }
GetToolchainSettings(const Label & label) const35 const Settings* GetToolchainSettings(const Label& label) const override {
36 return nullptr;
37 }
BuildFileForLabel(const Label & label) const38 SourceFile BuildFileForLabel(const Label& label) const override {
39 return SourceFile(label.dir().value() + "BUILD.gn");
40 }
41
42 private:
43 ~MockLoader() override = default;
44 };
45
46 class AnalyzerTest : public testing::Test {
47 public:
AnalyzerTest()48 AnalyzerTest()
49 : loader_(new MockLoader),
50 builder_(loader_.get()),
51 settings_(&build_settings_, std::string()),
52 other_settings_(&build_settings_, std::string()) {
53 build_settings_.SetBuildDir(SourceDir("//out/"));
54
55 settings_.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
56 settings_.set_default_toolchain_label(settings_.toolchain_label());
57 tc_dir_ = settings_.toolchain_label().dir();
58 tc_name_ = settings_.toolchain_label().name();
59
60 other_settings_.set_toolchain_label(Label(SourceDir("//other/"), "tc"));
61 other_settings_.set_default_toolchain_label(
62 other_settings_.toolchain_label());
63 tc_other_dir_ = other_settings_.toolchain_label().dir();
64 tc_other_name_ = other_settings_.toolchain_label().name();
65 }
66
MakeTarget(const std::string & dir,const std::string & name)67 std::unique_ptr<Target> MakeTarget(const std::string& dir,
68 const std::string& name) {
69 Label label(SourceDir(dir), name, tc_dir_, tc_name_);
70 return std::make_unique<Target>(&settings_, label);
71 }
72
MakeTargetOtherToolchain(const std::string & dir,const std::string & name)73 std::unique_ptr<Target> MakeTargetOtherToolchain(const std::string& dir,
74 const std::string& name) {
75 Label label(SourceDir(dir), name, tc_other_dir_, tc_other_name_);
76 return std::make_unique<Target>(&other_settings_, label);
77 }
78
MakeConfig(const std::string & dir,const std::string & name)79 std::unique_ptr<Config> MakeConfig(const std::string& dir,
80 const std::string& name) {
81 Label label(SourceDir(dir), name, tc_dir_, tc_name_);
82 return std::make_unique<Config>(&settings_, label);
83 }
84
MakePool(const std::string & dir,const std::string & name)85 std::unique_ptr<Pool> MakePool(const std::string& dir,
86 const std::string& name) {
87 Label label(SourceDir(dir), name, tc_dir_, tc_name_);
88 return std::make_unique<Pool>(&settings_, label);
89 }
90
RunAnalyzerTest(const std::string & input,const std::string & expected_output)91 void RunAnalyzerTest(const std::string& input,
92 const std::string& expected_output) {
93 Analyzer analyzer(builder_, SourceFile("//build/config/BUILDCONFIG.gn"),
94 SourceFile("//.gn"),
95 {SourceFile("//out/debug/args.gn"),
96 SourceFile("//build/default_args.gn")});
97 Err err;
98 std::string actual_output = analyzer.Analyze(input, &err);
99 EXPECT_EQ(err.has_error(), false);
100 EXPECT_EQ(expected_output, actual_output);
101 }
102
103 protected:
104 scoped_refptr<MockLoader> loader_;
105 Builder builder_;
106 BuildSettings build_settings_;
107
108 Settings settings_;
109 SourceDir tc_dir_;
110 std::string tc_name_;
111
112 Settings other_settings_;
113 SourceDir tc_other_dir_;
114 std::string tc_other_name_;
115 };
116
117 // Tests that a target is marked as affected if its sources are modified.
TEST_F(AnalyzerTest,TargetRefersToSources)118 TEST_F(AnalyzerTest, TargetRefersToSources) {
119 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
120 Target* t_raw = t.get();
121 builder_.ItemDefined(std::move(t));
122 RunAnalyzerTest(
123 R"({
124 "files": [ "//dir/file_name.cc" ],
125 "additional_compile_targets": [ "all" ],
126 "test_targets": [ "//dir:target_name" ]
127 })",
128 "{"
129 R"("compile_targets":[],)"
130 R"/("status":"No dependency",)/"
131 R"("test_targets":[])"
132 "}");
133
134 t_raw->sources().push_back(SourceFile("//dir/file_name.cc"));
135 RunAnalyzerTest(
136 R"({
137 "files": [ "//dir/file_name.cc" ],
138 "additional_compile_targets": [ "all" ],
139 "test_targets": [ "//dir:target_name" ]
140 })",
141 "{"
142 R"("compile_targets":["all"],)"
143 R"/("status":"Found dependency",)/"
144 R"("test_targets":["//dir:target_name"])"
145 "}");
146 }
147
148 // Tests that a target is marked as affected if its public headers are modified.
TEST_F(AnalyzerTest,TargetRefersToPublicHeaders)149 TEST_F(AnalyzerTest, TargetRefersToPublicHeaders) {
150 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
151 Target* t_raw = t.get();
152 builder_.ItemDefined(std::move(t));
153 RunAnalyzerTest(
154 R"({
155 "files": [ "//dir/header_name.h" ],
156 "additional_compile_targets": [ "all" ],
157 "test_targets": [ "//dir:target_name" ]
158 })",
159 "{"
160 R"("compile_targets":[],)"
161 R"/("status":"No dependency",)/"
162 R"("test_targets":[])"
163 "}");
164
165 t_raw->public_headers().push_back(SourceFile("//dir/header_name.h"));
166 RunAnalyzerTest(
167 R"({
168 "files": [ "//dir/header_name.h" ],
169 "additional_compile_targets": [ "all" ],
170 "test_targets": [ "//dir:target_name" ]
171 })",
172 "{"
173 R"("compile_targets":["all"],)"
174 R"/("status":"Found dependency",)/"
175 R"("test_targets":["//dir:target_name"])"
176 "}");
177 }
178
179 // Tests that a target is marked as affected if its inputs are modified.
TEST_F(AnalyzerTest,TargetRefersToInputs)180 TEST_F(AnalyzerTest, TargetRefersToInputs) {
181 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
182 Target* t_raw = t.get();
183 builder_.ItemDefined(std::move(t));
184 RunAnalyzerTest(
185 R"({
186 "files": [ "//dir/extra_input.cc" ],
187 "additional_compile_targets": [ "all" ],
188 "test_targets": [ "//dir:target_name" ]
189 })",
190 "{"
191 R"("compile_targets":[],)"
192 R"/("status":"No dependency",)/"
193 R"("test_targets":[])"
194 "}");
195
196 SourceFile extra_input(SourceFile("//dir/extra_input.cc"));
197 t_raw->config_values().inputs().push_back(extra_input);
198 RunAnalyzerTest(
199 R"({
200 "files": [ "//dir/extra_input.cc" ],
201 "additional_compile_targets": [ "all" ],
202 "test_targets": [ "//dir:target_name" ]
203 })",
204 "{"
205 R"("compile_targets":["all"],)"
206 R"/("status":"Found dependency",)/"
207 R"("test_targets":["//dir:target_name"])"
208 "}");
209
210 t_raw->config_values().inputs().clear();
211 std::unique_ptr<Config> c = MakeConfig("//dir", "config_name");
212 c->own_values().inputs().push_back(extra_input);
213 t_raw->configs().push_back(LabelConfigPair(c.get()));
214 builder_.ItemDefined(std::move(c));
215
216 RunAnalyzerTest(
217 R"({
218 "files": [ "//dir/extra_input.cc" ],
219 "additional_compile_targets": [ "all" ],
220 "test_targets": [ "//dir:target_name" ]
221 })",
222 "{"
223 R"("compile_targets":["all"],)"
224 R"/("status":"Found dependency",)/"
225 R"("test_targets":["//dir:target_name"])"
226 "}");
227 }
228
229 // Tests that a target is marked as affected if a sub-config is modified.
230 //
231 // This test uses two levels of sub-configs to ensure the config hierarchy
232 // is completely traversed.
TEST_F(AnalyzerTest,SubConfigIsModified)233 TEST_F(AnalyzerTest, SubConfigIsModified) {
234 std::unique_ptr<Config> ssc = MakeConfig("//dir3", "subsubconfig_name");
235 ssc->build_dependency_files().insert(SourceFile("//dir3/BUILD.gn"));
236
237 std::unique_ptr<Config> sc = MakeConfig("//dir2", "subconfig_name");
238 sc->configs().push_back(LabelConfigPair(ssc->label()));
239
240 std::unique_ptr<Config> c = MakeConfig("//dir", "config_name");
241 c->configs().push_back(LabelConfigPair(sc->label()));
242
243 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
244 t->configs().push_back(LabelConfigPair(c.get()));
245
246 builder_.ItemDefined(std::move(ssc));
247 builder_.ItemDefined(std::move(sc));
248 builder_.ItemDefined(std::move(c));
249 builder_.ItemDefined(std::move(t));
250 RunAnalyzerTest(
251 R"({
252 "files": [ "//dir3/BUILD.gn" ],
253 "additional_compile_targets": [],
254 "test_targets": [ "//dir:target_name" ]
255 })",
256 "{"
257 R"("compile_targets":[],)"
258 R"/("status":"Found dependency",)/"
259 R"("test_targets":["//dir:target_name"])"
260 "}");
261 }
262
263 // Tests that a target is marked as affected if its data are modified.
TEST_F(AnalyzerTest,TargetRefersToData)264 TEST_F(AnalyzerTest, TargetRefersToData) {
265 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
266 Target* t_raw = t.get();
267 builder_.ItemDefined(std::move(t));
268 RunAnalyzerTest(
269 R"({
270 "files": [ "//dir/data.html" ],
271 "additional_compile_targets": [ "all" ],
272 "test_targets": [ "//dir:target_name" ]
273 })",
274 "{"
275 R"("compile_targets":[],)"
276 R"/("status":"No dependency",)/"
277 R"("test_targets":[])"
278 "}");
279
280 t_raw->data().push_back("//dir/data.html");
281 RunAnalyzerTest(
282 R"({
283 "files": [ "//dir/data.html" ],
284 "additional_compile_targets": [ "all" ],
285 "test_targets": [ "//dir:target_name" ]
286 })",
287 "{"
288 R"("compile_targets":["all"],)"
289 R"/("status":"Found dependency",)/"
290 R"("test_targets":["//dir:target_name"])"
291 "}");
292 }
293
294 // Tests that a target is marked as affected if the target is an action and its
295 // action script is modified.
TEST_F(AnalyzerTest,TargetRefersToActionScript)296 TEST_F(AnalyzerTest, TargetRefersToActionScript) {
297 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
298 Target* t_raw = t.get();
299 t->set_output_type(Target::ACTION);
300 builder_.ItemDefined(std::move(t));
301 RunAnalyzerTest(
302 R"({
303 "files": [ "//dir/script.py" ],
304 "additional_compile_targets": [ "all" ],
305 "test_targets": [ "//dir:target_name" ]
306 })",
307 "{"
308 R"("compile_targets":[],)"
309 R"/("status":"No dependency",)/"
310 R"("test_targets":[])"
311 "}");
312
313 t_raw->action_values().set_script(SourceFile("//dir/script.py"));
314 RunAnalyzerTest(
315 R"({
316 "files": [ "//dir/script.py" ],
317 "additional_compile_targets": [ "all" ],
318 "test_targets": [ "//dir:target_name" ]
319 })",
320 "{"
321 R"("compile_targets":["all"],)"
322 R"/("status":"Found dependency",)/"
323 R"("test_targets":["//dir:target_name"])"
324 "}");
325 }
326
327 // Tests that a target is marked as affected if its build dependency files are
328 // modified.
TEST_F(AnalyzerTest,TargetRefersToBuildDependencyFiles)329 TEST_F(AnalyzerTest, TargetRefersToBuildDependencyFiles) {
330 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
331 Target* t_raw = t.get();
332 builder_.ItemDefined(std::move(t));
333 RunAnalyzerTest(
334 R"({
335 "files": [ "//dir/BUILD.gn" ],
336 "additional_compile_targets": [ "all" ],
337 "test_targets": [ "//dir:target_name" ]
338 })",
339 "{"
340 R"("compile_targets":[],)"
341 R"/("status":"No dependency",)/"
342 R"("test_targets":[])"
343 "}");
344
345 t_raw->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
346 RunAnalyzerTest(
347 R"({
348 "files": [ "//dir/BUILD.gn" ],
349 "additional_compile_targets": [ "all" ],
350 "test_targets": [ "//dir:target_name" ]
351 })",
352 "{"
353 R"("compile_targets":["all"],)"
354 R"/("status":"Found dependency",)/"
355 R"("test_targets":["//dir:target_name"])"
356 "}");
357 }
358
359 // Tests that if a target is marked as affected, then it propagates to dependent
360 // test_targets.
TEST_F(AnalyzerTest,AffectedTargetpropagatesToDependentTargets)361 TEST_F(AnalyzerTest, AffectedTargetpropagatesToDependentTargets) {
362 std::unique_ptr<Target> t1 = MakeTarget("//dir", "target_name1");
363 std::unique_ptr<Target> t2 = MakeTarget("//dir", "target_name2");
364 std::unique_ptr<Target> t3 = MakeTarget("//dir", "target_name3");
365 t1->private_deps().push_back(LabelTargetPair(t2.get()));
366 t2->private_deps().push_back(LabelTargetPair(t3.get()));
367 builder_.ItemDefined(std::move(t1));
368 builder_.ItemDefined(std::move(t2));
369
370 Target* t3_raw = t3.get();
371 builder_.ItemDefined(std::move(t3));
372
373 RunAnalyzerTest(
374 R"({
375 "files": [ "//dir/BUILD.gn" ],
376 "additional_compile_targets": [ "all" ],
377 "test_targets": [ "//dir:target_name1", "//dir:target_name2" ]
378 })",
379 "{"
380 R"("compile_targets":[],)"
381 R"/("status":"No dependency",)/"
382 R"("test_targets":[])"
383 "}");
384
385 t3_raw->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
386 RunAnalyzerTest(
387 R"({
388 "files": [ "//dir/BUILD.gn" ],
389 "additional_compile_targets": [ "all" ],
390 "test_targets": [ "//dir:target_name1", "//dir:target_name2" ]
391 })",
392 "{"
393 R"("compile_targets":["all"],)"
394 R"/("status":"Found dependency",)/"
395 R"("test_targets":["//dir:target_name1","//dir:target_name2"])"
396 "}");
397 }
398
399 // Tests that if a config is marked as affected, then it propagates to dependent
400 // test_targets.
TEST_F(AnalyzerTest,AffectedConfigpropagatesToDependentTargets)401 TEST_F(AnalyzerTest, AffectedConfigpropagatesToDependentTargets) {
402 std::unique_ptr<Config> c = MakeConfig("//dir", "config_name");
403 Config* c_raw = c.get();
404 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
405 t->configs().push_back(LabelConfigPair(c.get()));
406 builder_.ItemDefined(std::move(t));
407 builder_.ItemDefined(std::move(c));
408 RunAnalyzerTest(
409 R"({
410 "files": [ "//dir/BUILD.gn" ],
411 "additional_compile_targets": [ "all" ],
412 "test_targets": [ "//dir:target_name" ]
413 })",
414 "{"
415 R"("compile_targets":[],)"
416 R"/("status":"No dependency",)/"
417 R"("test_targets":[])"
418 "}");
419
420 c_raw->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
421 RunAnalyzerTest(
422 R"({
423 "files": [ "//dir/BUILD.gn" ],
424 "additional_compile_targets": [ "all" ],
425 "test_targets": [ "//dir:target_name" ]
426 })",
427 "{"
428 R"("compile_targets":["all"],)"
429 R"/("status":"Found dependency",)/"
430 R"("test_targets":["//dir:target_name"])"
431 "}");
432 }
433
434 // Tests that if toolchain is marked as affected, then it propagates to
435 // dependent test_targets.
TEST_F(AnalyzerTest,AffectedToolchainpropagatesToDependentTargets)436 TEST_F(AnalyzerTest, AffectedToolchainpropagatesToDependentTargets) {
437 std::unique_ptr<Target> target = MakeTarget("//dir", "target_name");
438 target->set_output_type(Target::EXECUTABLE);
439 Toolchain* toolchain = new Toolchain(&settings_, settings_.toolchain_label());
440
441 // The tool is not used anywhere, but is required to construct the dependency
442 // between a target and the toolchain.
443 std::unique_ptr<Tool> fake_tool = Tool::CreateTool(CTool::kCToolLink);
444 fake_tool->set_outputs(
445 SubstitutionList::MakeForTest("//out/debug/output.txt"));
446 toolchain->SetTool(std::move(fake_tool));
447 builder_.ItemDefined(std::move(target));
448 builder_.ItemDefined(std::unique_ptr<Item>(toolchain));
449
450 RunAnalyzerTest(
451 R"({
452 "files": [ "//tc/BUILD.gn" ],
453 "additional_compile_targets": [ "all" ],
454 "test_targets": [ "//dir:target_name" ]
455 })",
456 "{"
457 R"("compile_targets":[],)"
458 R"/("status":"No dependency",)/"
459 R"("test_targets":[])"
460 "}");
461
462 toolchain->build_dependency_files().insert(SourceFile("//tc/BUILD.gn"));
463 RunAnalyzerTest(
464 R"({
465 "files": [ "//tc/BUILD.gn" ],
466 "additional_compile_targets": [ "all" ],
467 "test_targets": [ "//dir:target_name" ]
468 })",
469 "{"
470 R"("compile_targets":["all"],)"
471 R"/("status":"Found dependency",)/"
472 R"("test_targets":["//dir:target_name"])"
473 "}");
474 }
475
476 // Tests that if a pool is marked as affected, then it propagates to dependent
477 // targets.
TEST_F(AnalyzerTest,AffectedPoolpropagatesToDependentTargets)478 TEST_F(AnalyzerTest, AffectedPoolpropagatesToDependentTargets) {
479 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
480 t->set_output_type(Target::ACTION);
481 std::unique_ptr<Pool> p = MakePool("//dir", "pool_name");
482 Pool* p_raw = p.get();
483 t->set_pool(LabelPtrPair<Pool>(p.get()));
484
485 builder_.ItemDefined(std::move(t));
486 builder_.ItemDefined(std::move(p));
487
488 RunAnalyzerTest(
489 R"({
490 "files": [ "//dir/BUILD.gn" ],
491 "additional_compile_targets": [ "all" ],
492 "test_targets": [ "//dir:target_name" ]
493 })",
494 "{"
495 R"("compile_targets":[],)"
496 R"/("status":"No dependency",)/"
497 R"("test_targets":[])"
498 "}");
499
500 p_raw->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
501 RunAnalyzerTest(
502 R"({
503 "files": [ "//dir/BUILD.gn" ],
504 "additional_compile_targets": [ "all" ],
505 "test_targets": [ "//dir:target_name" ]
506 })",
507 "{"
508 R"("compile_targets":["all"],)"
509 R"/("status":"Found dependency",)/"
510 R"("test_targets":["//dir:target_name"])"
511 "}");
512 }
513
514 // Tests that when dependency was found, the "compile_targets" in the output is
515 // not "all".
TEST_F(AnalyzerTest,CompileTargetsAllWasPruned)516 TEST_F(AnalyzerTest, CompileTargetsAllWasPruned) {
517 std::unique_ptr<Target> t1 = MakeTarget("//dir", "target_name1");
518 std::unique_ptr<Target> t2 = MakeTarget("//dir", "target_name2");
519 t2->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
520 builder_.ItemDefined(std::move(t1));
521 builder_.ItemDefined(std::move(t2));
522
523 RunAnalyzerTest(
524 R"({
525 "files": [ "//dir/BUILD.gn" ],
526 "additional_compile_targets": [ "all" ],
527 "test_targets": []
528 })",
529 "{"
530 R"("compile_targets":["//dir:target_name2"],)"
531 R"/("status":"Found dependency",)/"
532 R"("test_targets":[])"
533 "}");
534 }
535
536 // Tests that output is "No dependency" when no dependency is found.
TEST_F(AnalyzerTest,NoDependency)537 TEST_F(AnalyzerTest, NoDependency) {
538 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
539 builder_.ItemDefined(std::move(t));
540
541 RunAnalyzerTest(
542 R"({
543 "files": [ "//dir/BUILD.gn" ],
544 "additional_compile_targets": [ "all" ],
545 "test_targets": []
546 })",
547 "{"
548 R"("compile_targets":[],)"
549 R"/("status":"No dependency",)/"
550 R"("test_targets":[])"
551 "}");
552 }
553
554 // Tests that output is "No dependency" when no files or targets are provided.
TEST_F(AnalyzerTest,NoFilesNoTargets)555 TEST_F(AnalyzerTest, NoFilesNoTargets) {
556 RunAnalyzerTest(
557 R"({
558 "files": [],
559 "additional_compile_targets": [],
560 "test_targets": []
561 })",
562 "{"
563 R"("compile_targets":[],)"
564 R"("status":"No dependency",)"
565 R"("test_targets":[])"
566 "}");
567 }
568
569 // Tests that output displays proper error message when given files aren't
570 // source-absolute or absolute path.
TEST_F(AnalyzerTest,FilesArentSourceAbsolute)571 TEST_F(AnalyzerTest, FilesArentSourceAbsolute) {
572 RunAnalyzerTest(
573 R"({
574 "files": [ "a.cc" ],
575 "additional_compile_targets": [],
576 "test_targets": [ "//dir:target_name" ]
577 })",
578 "{"
579 R"("error":)"
580 R"("\"a.cc\" is not a source-absolute or absolute path.",)"
581 R"("invalid_targets":[])"
582 "}");
583 }
584
585 // Tests that output displays proper error message when input is ill-formed.
TEST_F(AnalyzerTest,WrongInputFields)586 TEST_F(AnalyzerTest, WrongInputFields) {
587 RunAnalyzerTest(
588 R"({
589 "files": [ "//a.cc" ],
590 "compile_targets": [],
591 "test_targets": [ "//dir:target_name" ]
592 })",
593 "{"
594 R"("error":)"
595 R"("Unknown analyze input key \"compile_targets\".",)"
596 R"("invalid_targets":[])"
597 "}");
598 }
599
600 // Bails out early with "Found dependency (all)" if dot file is modified.
TEST_F(AnalyzerTest,DotFileWasModified)601 TEST_F(AnalyzerTest, DotFileWasModified) {
602 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
603 builder_.ItemDefined(std::move(t));
604
605 RunAnalyzerTest(
606 R"({
607 "files": [ "//.gn" ],
608 "additional_compile_targets": [],
609 "test_targets": [ "//dir:target_name" ]
610 })",
611 "{"
612 R"("compile_targets":["//dir:target_name"],)"
613 R"/("status":"Found dependency (all)",)/"
614 R"("test_targets":["//dir:target_name"])"
615 "}");
616 }
617
618 // Bails out early with "Found dependency (all)" if master build config file is
619 // modified.
TEST_F(AnalyzerTest,BuildConfigFileWasModified)620 TEST_F(AnalyzerTest, BuildConfigFileWasModified) {
621 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
622 builder_.ItemDefined(std::move(t));
623
624 RunAnalyzerTest(
625 R"({
626 "files": [ "//build/config/BUILDCONFIG.gn" ],
627 "additional_compile_targets": [],
628 "test_targets": [ "//dir:target_name" ]
629 })",
630 "{"
631 R"("compile_targets":["//dir:target_name"],)"
632 R"/("status":"Found dependency (all)",)/"
633 R"("test_targets":["//dir:target_name"])"
634 "}");
635 }
636
637 // Bails out early with "Found dependency (all)" if a build args dependency file
638 // is modified.
TEST_F(AnalyzerTest,BuildArgsDependencyFileWasModified)639 TEST_F(AnalyzerTest, BuildArgsDependencyFileWasModified) {
640 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
641 builder_.ItemDefined(std::move(t));
642
643 RunAnalyzerTest(
644 R"({
645 "files": [ "//build/default_args.gn" ],
646 "additional_compile_targets": [],
647 "test_targets": [ "//dir:target_name" ]
648 })",
649 "{"
650 R"("compile_targets":["//dir:target_name"],)"
651 R"/("status":"Found dependency (all)",)/"
652 R"("test_targets":["//dir:target_name"])"
653 "}");
654 }
655
656 // Tests that targets in explicitly labelled with the default toolchain are
657 // included when their sources change.
658 // change.
TEST_F(AnalyzerTest,TargetToolchainSpecifiedRefersToSources)659 TEST_F(AnalyzerTest, TargetToolchainSpecifiedRefersToSources) {
660 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
661 Target* t_raw = t.get();
662 builder_.ItemDefined(std::move(t));
663
664 RunAnalyzerTest(
665 R"/({
666 "files": [ "//dir/file_name.cc" ],
667 "additional_compile_targets": ["all"],
668 "test_targets": [ "//dir:target_name(//tc:default)" ]
669 })/",
670 "{"
671 R"("compile_targets":[],)"
672 R"/("status":"No dependency",)/"
673 R"("test_targets":[])"
674 "}");
675
676 t_raw->sources().push_back(SourceFile("//dir/file_name.cc"));
677
678 RunAnalyzerTest(
679 R"*({
680 "files": [ "//dir/file_name.cc" ],
681 "additional_compile_targets": [],
682 "test_targets": [ "//dir:target_name(//tc:default)" ]
683 })*",
684 "{"
685 R"("compile_targets":[],)"
686 R"/("status":"Found dependency",)/"
687 R"/("test_targets":["//dir:target_name"])/"
688 "}");
689 }
690
691 // Tests that targets in alternate toolchains are affected when their sources
692 // change.
TEST_F(AnalyzerTest,TargetAlternateToolchainRefersToSources)693 TEST_F(AnalyzerTest, TargetAlternateToolchainRefersToSources) {
694 std::unique_ptr<Target> t = MakeTarget("//dir", "target_name");
695 std::unique_ptr<Target> t_alt =
696 MakeTargetOtherToolchain("//dir", "target_name");
697 Target* t_raw = t.get();
698 Target* t_alt_raw = t_alt.get();
699 builder_.ItemDefined(std::move(t));
700 builder_.ItemDefined(std::move(t_alt));
701
702 RunAnalyzerTest(
703 R"/({
704 "files": [ "//dir/file_name.cc" ],
705 "additional_compile_targets": ["all"],
706 "test_targets": [ "//dir:target_name", "//dir:target_name(//other:tc)" ]
707 })/",
708 "{"
709 R"("compile_targets":[],)"
710 R"/("status":"No dependency",)/"
711 R"("test_targets":[])"
712 "}");
713
714 t_raw->sources().push_back(SourceFile("//dir/file_name.cc"));
715 t_alt_raw->sources().push_back(SourceFile("//dir/alt_file_name.cc"));
716
717 RunAnalyzerTest(
718 R"*({
719 "files": [ "//dir/file_name.cc" ],
720 "additional_compile_targets": [],
721 "test_targets": [ "//dir:target_name", "//dir:target_name(//other:tc)" ]
722 })*",
723 "{"
724 R"("compile_targets":[],)"
725 R"/("status":"Found dependency",)/"
726 R"("test_targets":["//dir:target_name"])"
727 "}");
728
729 RunAnalyzerTest(
730 R"*({
731 "files": [ "//dir/alt_file_name.cc" ],
732 "additional_compile_targets": [],
733 "test_targets": [ "//dir:target_name", "//dir:target_name(//other:tc)" ]
734 })*",
735 "{"
736 R"("compile_targets":[],)"
737 R"/("status":"Found dependency",)/"
738 R"/("test_targets":["//dir:target_name(//other:tc)"])/"
739 "}");
740
741 RunAnalyzerTest(
742 R"*({
743 "files": [ "//dir/file_name.cc", "//dir/alt_file_name.cc" ],
744 "additional_compile_targets": [],
745 "test_targets": [ "//dir:target_name", "//dir:target_name(//other:tc)" ]
746 })*",
747 "{"
748 R"("compile_targets":[],)"
749 R"/("status":"Found dependency",)/"
750 R"/("test_targets":["//dir:target_name","//dir:target_name(//other:tc)"])/"
751 "}");
752 }
753
754 } // namespace gn_analyzer_unittest
755