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 two loads have been requested and they match the given
39 // file. This will clear the records so it will be empty for the next call.
40 bool HasLoadedTwo(const SourceFile
& a
, const SourceFile
& b
) {
41 if (files_
.size() != 2u) {
47 (files_
[0] == a
&& files_
[1] == b
) ||
48 (files_
[0] == b
&& files_
[0] == a
));
54 virtual ~MockLoader() {}
56 std::vector
<SourceFile
> files_
;
59 class BuilderTest
: public testing::Test
{
62 : loader_(new MockLoader
),
63 builder_(new Builder(loader_
.get())),
64 settings_(&build_settings_
, std::string()),
66 build_settings_
.SetBuildDir(SourceDir("//out/"));
67 settings_
.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
68 settings_
.set_default_toolchain_label(settings_
.toolchain_label());
71 Toolchain
* DefineToolchain() {
72 Toolchain
* tc
= new Toolchain(&settings_
, settings_
.toolchain_label());
73 builder_
->ItemDefined(scoped_ptr
<Item
>(tc
));
78 scoped_refptr
<MockLoader
> loader_
;
79 scoped_refptr
<Builder
> builder_
;
80 BuildSettings build_settings_
;
87 TEST_F(BuilderTest
, BasicDeps
) {
88 SourceDir toolchain_dir
= settings_
.toolchain_label().dir();
89 std::string toolchain_name
= settings_
.toolchain_label().name();
92 BuilderRecord
* toolchain_record
=
93 builder_
->GetRecord(settings_
.toolchain_label());
94 ASSERT_TRUE(toolchain_record
);
95 EXPECT_EQ(BuilderRecord::ITEM_TOOLCHAIN
, toolchain_record
->type());
97 // Construct a dependency chain: A -> B -> C. Define A first with a
98 // forward-reference to B, then C, then B to test the different orders that
99 // the dependencies are hooked up.
100 Label
a_label(SourceDir("//a/"), "a", toolchain_dir
, toolchain_name
);
101 Label
b_label(SourceDir("//b/"), "b", toolchain_dir
, toolchain_name
);
102 Label
c_label(SourceDir("//c/"), "c", toolchain_dir
, toolchain_name
);
104 // The builder will take ownership of the pointers.
105 Target
* a
= new Target(&settings_
, a_label
);
106 a
->deps().push_back(LabelTargetPair(b_label
));
107 a
->set_output_type(Target::EXECUTABLE
);
108 builder_
->ItemDefined(scoped_ptr
<Item
>(a
));
110 // Should have requested that B and the toolchain is loaded.
111 EXPECT_TRUE(loader_
->HasLoadedTwo(SourceFile("//tc/BUILD.gn"),
112 SourceFile("//b/BUILD.gn")));
114 // A should be unresolved with an item
115 BuilderRecord
* a_record
= builder_
->GetRecord(a_label
);
116 EXPECT_TRUE(a_record
->item());
117 EXPECT_FALSE(a_record
->resolved());
118 EXPECT_FALSE(a_record
->can_resolve());
120 // B should be unresolved, have no item, and no deps.
121 BuilderRecord
* b_record
= builder_
->GetRecord(b_label
);
122 EXPECT_FALSE(b_record
->item());
123 EXPECT_FALSE(b_record
->resolved());
124 EXPECT_FALSE(b_record
->can_resolve());
125 EXPECT_TRUE(b_record
->all_deps().empty());
127 // A should have two deps: B and the toolchain. Only B should be unresolved.
128 EXPECT_EQ(2u, a_record
->all_deps().size());
129 EXPECT_EQ(1u, a_record
->unresolved_deps().size());
130 EXPECT_NE(a_record
->all_deps().end(),
131 a_record
->all_deps().find(toolchain_record
));
132 EXPECT_NE(a_record
->all_deps().end(),
133 a_record
->all_deps().find(b_record
));
134 EXPECT_NE(a_record
->unresolved_deps().end(),
135 a_record
->unresolved_deps().find(b_record
));
137 // B should be marked as having A waiting on it.
138 EXPECT_EQ(1u, b_record
->waiting_on_resolution().size());
139 EXPECT_NE(b_record
->waiting_on_resolution().end(),
140 b_record
->waiting_on_resolution().find(a_record
));
143 Target
* c
= new Target(&settings_
, c_label
);
144 c
->set_output_type(Target::STATIC_LIBRARY
);
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
->deps().push_back(LabelTargetPair(c_label
));
154 b
->set_output_type(Target::SHARED_LIBRARY
);
155 builder_
->ItemDefined(scoped_ptr
<Item
>(b
));
157 // B depends only on the already-loaded C and toolchain so we shouldn't have
158 // requested anything else.
159 EXPECT_TRUE(loader_
->HasLoadedNone());
161 // All targets should now be resolved.
162 BuilderRecord
* c_record
= builder_
->GetRecord(c_label
);
163 EXPECT_TRUE(a_record
->resolved());
164 EXPECT_TRUE(b_record
->resolved());
165 EXPECT_TRUE(c_record
->resolved());
167 EXPECT_TRUE(a_record
->unresolved_deps().empty());
168 EXPECT_TRUE(b_record
->unresolved_deps().empty());
169 EXPECT_TRUE(c_record
->unresolved_deps().empty());
171 EXPECT_TRUE(a_record
->waiting_on_resolution().empty());
172 EXPECT_TRUE(b_record
->waiting_on_resolution().empty());
173 EXPECT_TRUE(c_record
->waiting_on_resolution().empty());
176 // Tests that the should generate bit is set and propogated properly.
177 TEST_F(BuilderTest
, ShouldGenerate
) {
180 // Define a secondary toolchain.
181 Settings
settings2(&build_settings_
, "secondary");
182 Label
toolchain_label2(SourceDir("//tc/"), "secondary");
183 settings2
.set_toolchain_label(toolchain_label2
);
184 Toolchain
* tc2
= new Toolchain(&settings2
, toolchain_label2
);
185 builder_
->ItemDefined(scoped_ptr
<Item
>(tc2
));
187 // Construct a dependency chain: A -> B. A is in the default toolchain, B
189 Label
a_label(SourceDir("//foo/"), "a",
190 settings_
.toolchain_label().dir(), "a");
191 Label
b_label(SourceDir("//foo/"), "b",
192 toolchain_label2
.dir(), toolchain_label2
.name());
195 Target
* b
= new Target(&settings2
, b_label
);
196 b
->set_output_type(Target::EXECUTABLE
);
197 builder_
->ItemDefined(scoped_ptr
<Item
>(b
));
199 // B should not be marked generated by default.
200 BuilderRecord
* b_record
= builder_
->GetRecord(b_label
);
201 EXPECT_FALSE(b_record
->should_generate());
203 // Define A with a dependency on B.
204 Target
* a
= new Target(&settings_
, a_label
);
205 a
->deps().push_back(LabelTargetPair(b_label
));
206 a
->set_output_type(Target::EXECUTABLE
);
207 builder_
->ItemDefined(scoped_ptr
<Item
>(a
));
209 // A should have the generate bit set since it's in the default toolchain.
210 BuilderRecord
* a_record
= builder_
->GetRecord(a_label
);
211 EXPECT_TRUE(a_record
->should_generate());
213 // It should have gotten pushed to B.
214 EXPECT_TRUE(b_record
->should_generate());