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 virtual void Load(const SourceFile
& file
,
21 const Label
& toolchain_name
) OVERRIDE
{
22 files_
.push_back(file
);
24 virtual void ToolchainLoaded(const Toolchain
* toolchain
) OVERRIDE
{
26 virtual Label
GetDefaultToolchain() const OVERRIDE
{
29 virtual const Settings
* GetToolchainSettings(
30 const Label
& label
) const OVERRIDE
{
34 bool HasLoadedNone() const {
35 return files_
.empty();
38 // Returns true if one load has been requested and it matches the given
39 // file. This will clear the records so it will be empty for the next call.
40 bool HasLoadedOne(const SourceFile
& f
) {
41 if (files_
.size() != 1u) {
46 bool match
= (files_
[0] == f
);
51 // Like HasLoadedOne above. Accepts any ordering.
52 bool HasLoadedTwo(const SourceFile
& a
, const SourceFile
& b
) {
53 if (files_
.size() != 2u) {
59 (files_
[0] == a
&& files_
[1] == b
) ||
60 (files_
[0] == b
&& files_
[0] == a
));
66 virtual ~MockLoader() {}
68 std::vector
<SourceFile
> files_
;
71 class BuilderTest
: public testing::Test
{
74 : loader_(new MockLoader
),
75 builder_(new Builder(loader_
.get())),
76 settings_(&build_settings_
, std::string()),
78 build_settings_
.SetBuildDir(SourceDir("//out/"));
79 settings_
.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
80 settings_
.set_default_toolchain_label(settings_
.toolchain_label());
83 Toolchain
* DefineToolchain() {
84 Toolchain
* tc
= new Toolchain(&settings_
, settings_
.toolchain_label());
85 builder_
->ItemDefined(scoped_ptr
<Item
>(tc
));
90 scoped_refptr
<MockLoader
> loader_
;
91 scoped_refptr
<Builder
> builder_
;
92 BuildSettings build_settings_
;
99 TEST_F(BuilderTest
, BasicDeps
) {
100 SourceDir toolchain_dir
= settings_
.toolchain_label().dir();
101 std::string toolchain_name
= settings_
.toolchain_label().name();
104 BuilderRecord
* toolchain_record
=
105 builder_
->GetRecord(settings_
.toolchain_label());
106 ASSERT_TRUE(toolchain_record
);
107 EXPECT_EQ(BuilderRecord::ITEM_TOOLCHAIN
, toolchain_record
->type());
109 // Construct a dependency chain: A -> B -> C. Define A first with a
110 // forward-reference to B, then C, then B to test the different orders that
111 // the dependencies are hooked up.
112 Label
a_label(SourceDir("//a/"), "a", toolchain_dir
, toolchain_name
);
113 Label
b_label(SourceDir("//b/"), "b", toolchain_dir
, toolchain_name
);
114 Label
c_label(SourceDir("//c/"), "c", toolchain_dir
, toolchain_name
);
116 // The builder will take ownership of the pointers.
117 Target
* a
= new Target(&settings_
, a_label
);
118 a
->deps().push_back(LabelTargetPair(b_label
));
119 a
->set_output_type(Target::EXECUTABLE
);
120 builder_
->ItemDefined(scoped_ptr
<Item
>(a
));
122 // Should have requested that B and the toolchain is loaded.
123 EXPECT_TRUE(loader_
->HasLoadedTwo(SourceFile("//tc/BUILD.gn"),
124 SourceFile("//b/BUILD.gn")));
126 // A should be unresolved with an item
127 BuilderRecord
* a_record
= builder_
->GetRecord(a_label
);
128 EXPECT_TRUE(a_record
->item());
129 EXPECT_FALSE(a_record
->resolved());
130 EXPECT_FALSE(a_record
->can_resolve());
132 // B should be unresolved, have no item, and no deps.
133 BuilderRecord
* b_record
= builder_
->GetRecord(b_label
);
134 EXPECT_FALSE(b_record
->item());
135 EXPECT_FALSE(b_record
->resolved());
136 EXPECT_FALSE(b_record
->can_resolve());
137 EXPECT_TRUE(b_record
->all_deps().empty());
139 // A should have two deps: B and the toolchain. Only B should be unresolved.
140 EXPECT_EQ(2u, a_record
->all_deps().size());
141 EXPECT_EQ(1u, a_record
->unresolved_deps().size());
142 EXPECT_NE(a_record
->all_deps().end(),
143 a_record
->all_deps().find(toolchain_record
));
144 EXPECT_NE(a_record
->all_deps().end(),
145 a_record
->all_deps().find(b_record
));
146 EXPECT_NE(a_record
->unresolved_deps().end(),
147 a_record
->unresolved_deps().find(b_record
));
149 // B should be marked as having A waiting on it.
150 EXPECT_EQ(1u, b_record
->waiting_on_resolution().size());
151 EXPECT_NE(b_record
->waiting_on_resolution().end(),
152 b_record
->waiting_on_resolution().find(a_record
));
155 Target
* c
= new Target(&settings_
, c_label
);
156 c
->set_output_type(Target::STATIC_LIBRARY
);
157 builder_
->ItemDefined(scoped_ptr
<Item
>(c
));
159 // C only depends on the already-loaded toolchain so we shouldn't have
160 // requested anything else.
161 EXPECT_TRUE(loader_
->HasLoadedNone());
164 Target
* b
= new Target(&settings_
, b_label
);
165 a
->deps().push_back(LabelTargetPair(c_label
));
166 b
->set_output_type(Target::SHARED_LIBRARY
);
167 builder_
->ItemDefined(scoped_ptr
<Item
>(b
));
169 // B depends only on the already-loaded C and toolchain so we shouldn't have
170 // requested anything else.
171 EXPECT_TRUE(loader_
->HasLoadedNone());
173 // All targets should now be resolved.
174 BuilderRecord
* c_record
= builder_
->GetRecord(c_label
);
175 EXPECT_TRUE(a_record
->resolved());
176 EXPECT_TRUE(b_record
->resolved());
177 EXPECT_TRUE(c_record
->resolved());
179 EXPECT_TRUE(a_record
->unresolved_deps().empty());
180 EXPECT_TRUE(b_record
->unresolved_deps().empty());
181 EXPECT_TRUE(c_record
->unresolved_deps().empty());
183 EXPECT_TRUE(a_record
->waiting_on_resolution().empty());
184 EXPECT_TRUE(b_record
->waiting_on_resolution().empty());
185 EXPECT_TRUE(c_record
->waiting_on_resolution().empty());
188 // Tests that the should generate bit is set and propogated properly.
189 TEST_F(BuilderTest
, ShouldGenerate
) {
192 // Define a secondary toolchain.
193 Settings
settings2(&build_settings_
, "secondary");
194 Label
toolchain_label2(SourceDir("//tc/"), "secondary");
195 settings2
.set_toolchain_label(toolchain_label2
);
196 Toolchain
* tc2
= new Toolchain(&settings2
, toolchain_label2
);
197 builder_
->ItemDefined(scoped_ptr
<Item
>(tc2
));
199 // Construct a dependency chain: A -> B. A is in the default toolchain, B
201 Label
a_label(SourceDir("//foo/"), "a",
202 settings_
.toolchain_label().dir(), "a");
203 Label
b_label(SourceDir("//foo/"), "b",
204 toolchain_label2
.dir(), toolchain_label2
.name());
207 Target
* b
= new Target(&settings2
, b_label
);
208 b
->set_output_type(Target::EXECUTABLE
);
209 builder_
->ItemDefined(scoped_ptr
<Item
>(b
));
211 // B should not be marked generated by default.
212 BuilderRecord
* b_record
= builder_
->GetRecord(b_label
);
213 EXPECT_FALSE(b_record
->should_generate());
215 // Define A with a dependency on B.
216 Target
* a
= new Target(&settings_
, a_label
);
217 a
->deps().push_back(LabelTargetPair(b_label
));
218 a
->set_output_type(Target::EXECUTABLE
);
219 builder_
->ItemDefined(scoped_ptr
<Item
>(a
));
221 // A should have the generate bit set since it's in the default toolchain.
222 BuilderRecord
* a_record
= builder_
->GetRecord(a_label
);
223 EXPECT_TRUE(a_record
->should_generate());
225 // It should have gotten pushed to B.
226 EXPECT_TRUE(b_record
->should_generate());