Created a <webview> find API.
[chromium-blink-merge.git] / tools / gn / builder_unittest.cc
blobe605b9e2a82a8c7af15fffb6e0a1fe820ed3df2c
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"
12 namespace {
14 class MockLoader : public Loader {
15 public:
16 MockLoader() {
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 {
27 return Label();
29 virtual const Settings* GetToolchainSettings(
30 const Label& label) const OVERRIDE {
31 return NULL;
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) {
42 files_.clear();
43 return false;
46 bool match = (files_[0] == f);
47 files_.clear();
48 return match;
51 // Like HasLoadedOne above. Accepts any ordering.
52 bool HasLoadedTwo(const SourceFile& a, const SourceFile& b) {
53 if (files_.size() != 2u) {
54 files_.clear();
55 return false;
58 bool match = (
59 (files_[0] == a && files_[1] == b) ||
60 (files_[0] == b && files_[0] == a));
61 files_.clear();
62 return match;
65 private:
66 virtual ~MockLoader() {}
68 std::vector<SourceFile> files_;
71 class BuilderTest : public testing::Test {
72 public:
73 BuilderTest()
74 : loader_(new MockLoader),
75 builder_(new Builder(loader_.get())),
76 settings_(&build_settings_, std::string()),
77 scope_(&settings_) {
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));
86 return tc;
89 protected:
90 scoped_refptr<MockLoader> loader_;
91 scoped_refptr<Builder> builder_;
92 BuildSettings build_settings_;
93 Settings settings_;
94 Scope scope_;
97 } // namespace
99 TEST_F(BuilderTest, BasicDeps) {
100 SourceDir toolchain_dir = settings_.toolchain_label().dir();
101 std::string toolchain_name = settings_.toolchain_label().name();
103 DefineToolchain();
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));
154 // Add the C target.
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());
163 // Add the B target.
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) {
190 DefineToolchain();
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
200 // is not.
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());
206 // First define B.
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());