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.
5 #include "testing/gtest/include/gtest/gtest.h"
6 #include "tools/gn/builder.h"
7 #include "tools/gn/loader.h"
8 #include "tools/gn/target.h"
9 #include "tools/gn/test_with_scope.h"
10 #include "tools/gn/toolchain.h"
14 class MockLoader
: public Loader
{
19 // Loader implementation:
20 void Load(const SourceFile
& file
,
21 const LocationRange
& origin
,
22 const Label
& toolchain_name
) override
{
23 files_
.push_back(file
);
25 void ToolchainLoaded(const Toolchain
* toolchain
) override
{}
26 Label
GetDefaultToolchain() const override
{ return Label(); }
27 const Settings
* GetToolchainSettings(const Label
& label
) const override
{
31 bool HasLoadedNone() const {
32 return files_
.empty();
35 // Returns true if two loads have been requested and they match the given
36 // file. This will clear the records so it will be empty for the next call.
37 bool HasLoadedTwo(const SourceFile
& a
, const SourceFile
& b
) {
38 if (files_
.size() != 2u) {
44 (files_
[0] == a
&& files_
[1] == b
) ||
45 (files_
[0] == b
&& files_
[1] == a
));
51 ~MockLoader() override
{}
53 std::vector
<SourceFile
> files_
;
56 class BuilderTest
: public testing::Test
{
59 : loader_(new MockLoader
),
60 builder_(new Builder(loader_
.get())),
61 settings_(&build_settings_
, std::string()),
63 build_settings_
.SetBuildDir(SourceDir("//out/"));
64 settings_
.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
65 settings_
.set_default_toolchain_label(settings_
.toolchain_label());
68 Toolchain
* DefineToolchain() {
69 Toolchain
* tc
= new Toolchain(&settings_
, settings_
.toolchain_label());
70 TestWithScope::SetupToolchain(tc
);
71 builder_
->ItemDefined(scoped_ptr
<Item
>(tc
));
76 scoped_refptr
<MockLoader
> loader_
;
77 scoped_refptr
<Builder
> builder_
;
78 BuildSettings build_settings_
;
85 TEST_F(BuilderTest
, BasicDeps
) {
86 SourceDir toolchain_dir
= settings_
.toolchain_label().dir();
87 std::string toolchain_name
= settings_
.toolchain_label().name();
89 // Construct a dependency chain: A -> B -> C. Define A first with a
90 // forward-reference to B, then C, then B to test the different orders that
91 // the dependencies are hooked up.
92 Label
a_label(SourceDir("//a/"), "a", toolchain_dir
, toolchain_name
);
93 Label
b_label(SourceDir("//b/"), "b", toolchain_dir
, toolchain_name
);
94 Label
c_label(SourceDir("//c/"), "c", toolchain_dir
, toolchain_name
);
96 // The builder will take ownership of the pointers.
97 Target
* a
= new Target(&settings_
, a_label
);
98 a
->public_deps().push_back(LabelTargetPair(b_label
));
99 a
->set_output_type(Target::EXECUTABLE
);
100 builder_
->ItemDefined(scoped_ptr
<Item
>(a
));
102 // Should have requested that B and the toolchain is loaded.
103 EXPECT_TRUE(loader_
->HasLoadedTwo(SourceFile("//tc/BUILD.gn"),
104 SourceFile("//b/BUILD.gn")));
106 // Define the toolchain.
108 BuilderRecord
* toolchain_record
=
109 builder_
->GetRecord(settings_
.toolchain_label());
110 ASSERT_TRUE(toolchain_record
);
111 EXPECT_EQ(BuilderRecord::ITEM_TOOLCHAIN
, toolchain_record
->type());
113 // A should be unresolved with an item
114 BuilderRecord
* a_record
= builder_
->GetRecord(a_label
);
115 EXPECT_TRUE(a_record
->item());
116 EXPECT_FALSE(a_record
->resolved());
117 EXPECT_FALSE(a_record
->can_resolve());
119 // B should be unresolved, have no item, and no deps.
120 BuilderRecord
* b_record
= builder_
->GetRecord(b_label
);
121 EXPECT_FALSE(b_record
->item());
122 EXPECT_FALSE(b_record
->resolved());
123 EXPECT_FALSE(b_record
->can_resolve());
124 EXPECT_TRUE(b_record
->all_deps().empty());
126 // A should have two deps: B and the toolchain. Only B should be unresolved.
127 EXPECT_EQ(2u, a_record
->all_deps().size());
128 EXPECT_EQ(1u, a_record
->unresolved_deps().size());
129 EXPECT_NE(a_record
->all_deps().end(),
130 a_record
->all_deps().find(toolchain_record
));
131 EXPECT_NE(a_record
->all_deps().end(),
132 a_record
->all_deps().find(b_record
));
133 EXPECT_NE(a_record
->unresolved_deps().end(),
134 a_record
->unresolved_deps().find(b_record
));
136 // B should be marked as having A waiting on it.
137 EXPECT_EQ(1u, b_record
->waiting_on_resolution().size());
138 EXPECT_NE(b_record
->waiting_on_resolution().end(),
139 b_record
->waiting_on_resolution().find(a_record
));
142 Target
* c
= new Target(&settings_
, c_label
);
143 c
->set_output_type(Target::STATIC_LIBRARY
);
144 c
->visibility().SetPublic();
145 builder_
->ItemDefined(scoped_ptr
<Item
>(c
));
147 // C only depends on the already-loaded toolchain so we shouldn't have
148 // requested anything else.
149 EXPECT_TRUE(loader_
->HasLoadedNone());
152 Target
* b
= new Target(&settings_
, b_label
);
153 a
->public_deps().push_back(LabelTargetPair(c_label
));
154 b
->set_output_type(Target::SHARED_LIBRARY
);
155 b
->visibility().SetPublic();
156 builder_
->ItemDefined(scoped_ptr
<Item
>(b
));
158 // B depends only on the already-loaded C and toolchain so we shouldn't have
159 // requested anything else.
160 EXPECT_TRUE(loader_
->HasLoadedNone());
162 // All targets should now be resolved.
163 BuilderRecord
* c_record
= builder_
->GetRecord(c_label
);
164 EXPECT_TRUE(a_record
->resolved());
165 EXPECT_TRUE(b_record
->resolved());
166 EXPECT_TRUE(c_record
->resolved());
168 EXPECT_TRUE(a_record
->unresolved_deps().empty());
169 EXPECT_TRUE(b_record
->unresolved_deps().empty());
170 EXPECT_TRUE(c_record
->unresolved_deps().empty());
172 EXPECT_TRUE(a_record
->waiting_on_resolution().empty());
173 EXPECT_TRUE(b_record
->waiting_on_resolution().empty());
174 EXPECT_TRUE(c_record
->waiting_on_resolution().empty());
177 // Tests that the should generate bit is set and propogated properly.
178 TEST_F(BuilderTest
, ShouldGenerate
) {
181 // Define a secondary toolchain.
182 Settings
settings2(&build_settings_
, "secondary/");
183 Label
toolchain_label2(SourceDir("//tc/"), "secondary");
184 settings2
.set_toolchain_label(toolchain_label2
);
185 Toolchain
* tc2
= new Toolchain(&settings2
, toolchain_label2
);
186 TestWithScope::SetupToolchain(tc2
);
187 builder_
->ItemDefined(scoped_ptr
<Item
>(tc2
));
189 // Construct a dependency chain: A -> B. A is in the default toolchain, B
191 Label
a_label(SourceDir("//foo/"), "a",
192 settings_
.toolchain_label().dir(), "a");
193 Label
b_label(SourceDir("//foo/"), "b",
194 toolchain_label2
.dir(), toolchain_label2
.name());
197 Target
* b
= new Target(&settings2
, b_label
);
198 b
->visibility().SetPublic();
199 b
->set_output_type(Target::EXECUTABLE
);
200 builder_
->ItemDefined(scoped_ptr
<Item
>(b
));
202 // B should not be marked generated by default.
203 BuilderRecord
* b_record
= builder_
->GetRecord(b_label
);
204 EXPECT_FALSE(b_record
->should_generate());
206 // Define A with a dependency on B.
207 Target
* a
= new Target(&settings_
, a_label
);
208 a
->public_deps().push_back(LabelTargetPair(b_label
));
209 a
->set_output_type(Target::EXECUTABLE
);
210 builder_
->ItemDefined(scoped_ptr
<Item
>(a
));
212 // A should have the generate bit set since it's in the default toolchain.
213 BuilderRecord
* a_record
= builder_
->GetRecord(a_label
);
214 EXPECT_TRUE(a_record
->should_generate());
216 // It should have gotten pushed to B.
217 EXPECT_TRUE(b_record
->should_generate());