• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
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"
11 
12 namespace {
13 
14 class MockLoader : public Loader {
15  public:
MockLoader()16   MockLoader() {
17   }
18 
19   // Loader implementation:
Load(const SourceFile & file,const LocationRange & origin,const Label & toolchain_name)20   virtual void Load(const SourceFile& file,
21                     const LocationRange& origin,
22                     const Label& toolchain_name) OVERRIDE {
23     files_.push_back(file);
24   }
ToolchainLoaded(const Toolchain * toolchain)25   virtual void ToolchainLoaded(const Toolchain* toolchain) OVERRIDE {
26   }
GetDefaultToolchain() const27   virtual Label GetDefaultToolchain() const OVERRIDE {
28     return Label();
29   }
GetToolchainSettings(const Label & label) const30   virtual const Settings* GetToolchainSettings(
31       const Label& label) const OVERRIDE {
32     return NULL;
33   }
34 
HasLoadedNone() const35   bool HasLoadedNone() const {
36     return files_.empty();
37   }
38 
39   // Returns true if two loads have been requested and they match the given
40   // file. This will clear the records so it will be empty for the next call.
HasLoadedTwo(const SourceFile & a,const SourceFile & b)41   bool HasLoadedTwo(const SourceFile& a, const SourceFile& b) {
42     if (files_.size() != 2u) {
43       files_.clear();
44       return false;
45     }
46 
47     bool match = (
48         (files_[0] == a && files_[1] == b) ||
49         (files_[0] == b && files_[1] == a));
50     files_.clear();
51     return match;
52   }
53 
54  private:
~MockLoader()55   virtual ~MockLoader() {}
56 
57   std::vector<SourceFile> files_;
58 };
59 
60 class BuilderTest : public testing::Test {
61  public:
BuilderTest()62   BuilderTest()
63       : loader_(new MockLoader),
64         builder_(new Builder(loader_.get())),
65         settings_(&build_settings_, std::string()),
66         scope_(&settings_) {
67     build_settings_.SetBuildDir(SourceDir("//out/"));
68     settings_.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
69     settings_.set_default_toolchain_label(settings_.toolchain_label());
70   }
71 
DefineToolchain()72   Toolchain* DefineToolchain() {
73     Toolchain* tc = new Toolchain(&settings_, settings_.toolchain_label());
74     TestWithScope::SetupToolchain(tc);
75     builder_->ItemDefined(scoped_ptr<Item>(tc));
76     return tc;
77   }
78 
79  protected:
80   scoped_refptr<MockLoader> loader_;
81   scoped_refptr<Builder> builder_;
82   BuildSettings build_settings_;
83   Settings settings_;
84   Scope scope_;
85 };
86 
87 }  // namespace
88 
TEST_F(BuilderTest,BasicDeps)89 TEST_F(BuilderTest, BasicDeps) {
90   SourceDir toolchain_dir = settings_.toolchain_label().dir();
91   std::string toolchain_name = settings_.toolchain_label().name();
92 
93   // Construct a dependency chain: A -> B -> C. Define A first with a
94   // forward-reference to B, then C, then B to test the different orders that
95   // the dependencies are hooked up.
96   Label a_label(SourceDir("//a/"), "a", toolchain_dir, toolchain_name);
97   Label b_label(SourceDir("//b/"), "b", toolchain_dir, toolchain_name);
98   Label c_label(SourceDir("//c/"), "c", toolchain_dir, toolchain_name);
99 
100   // The builder will take ownership of the pointers.
101   Target* a = new Target(&settings_, a_label);
102   a->public_deps().push_back(LabelTargetPair(b_label));
103   a->set_output_type(Target::EXECUTABLE);
104   builder_->ItemDefined(scoped_ptr<Item>(a));
105 
106   // Should have requested that B and the toolchain is loaded.
107   EXPECT_TRUE(loader_->HasLoadedTwo(SourceFile("//tc/BUILD.gn"),
108                                     SourceFile("//b/BUILD.gn")));
109 
110   // Define the toolchain.
111   DefineToolchain();
112   BuilderRecord* toolchain_record =
113       builder_->GetRecord(settings_.toolchain_label());
114   ASSERT_TRUE(toolchain_record);
115   EXPECT_EQ(BuilderRecord::ITEM_TOOLCHAIN, toolchain_record->type());
116 
117   // A should be unresolved with an item
118   BuilderRecord* a_record = builder_->GetRecord(a_label);
119   EXPECT_TRUE(a_record->item());
120   EXPECT_FALSE(a_record->resolved());
121   EXPECT_FALSE(a_record->can_resolve());
122 
123   // B should be unresolved, have no item, and no deps.
124   BuilderRecord* b_record = builder_->GetRecord(b_label);
125   EXPECT_FALSE(b_record->item());
126   EXPECT_FALSE(b_record->resolved());
127   EXPECT_FALSE(b_record->can_resolve());
128   EXPECT_TRUE(b_record->all_deps().empty());
129 
130   // A should have two deps: B and the toolchain. Only B should be unresolved.
131   EXPECT_EQ(2u, a_record->all_deps().size());
132   EXPECT_EQ(1u, a_record->unresolved_deps().size());
133   EXPECT_NE(a_record->all_deps().end(),
134             a_record->all_deps().find(toolchain_record));
135   EXPECT_NE(a_record->all_deps().end(),
136             a_record->all_deps().find(b_record));
137   EXPECT_NE(a_record->unresolved_deps().end(),
138             a_record->unresolved_deps().find(b_record));
139 
140   // B should be marked as having A waiting on it.
141   EXPECT_EQ(1u, b_record->waiting_on_resolution().size());
142   EXPECT_NE(b_record->waiting_on_resolution().end(),
143             b_record->waiting_on_resolution().find(a_record));
144 
145   // Add the C target.
146   Target* c = new Target(&settings_, c_label);
147   c->set_output_type(Target::STATIC_LIBRARY);
148   c->visibility().SetPublic();
149   builder_->ItemDefined(scoped_ptr<Item>(c));
150 
151   // C only depends on the already-loaded toolchain so we shouldn't have
152   // requested anything else.
153   EXPECT_TRUE(loader_->HasLoadedNone());
154 
155   // Add the B target.
156   Target* b = new Target(&settings_, b_label);
157   a->public_deps().push_back(LabelTargetPair(c_label));
158   b->set_output_type(Target::SHARED_LIBRARY);
159   b->visibility().SetPublic();
160   builder_->ItemDefined(scoped_ptr<Item>(b));
161 
162   // B depends only on the already-loaded C and toolchain so we shouldn't have
163   // requested anything else.
164   EXPECT_TRUE(loader_->HasLoadedNone());
165 
166   // All targets should now be resolved.
167   BuilderRecord* c_record = builder_->GetRecord(c_label);
168   EXPECT_TRUE(a_record->resolved());
169   EXPECT_TRUE(b_record->resolved());
170   EXPECT_TRUE(c_record->resolved());
171 
172   EXPECT_TRUE(a_record->unresolved_deps().empty());
173   EXPECT_TRUE(b_record->unresolved_deps().empty());
174   EXPECT_TRUE(c_record->unresolved_deps().empty());
175 
176   EXPECT_TRUE(a_record->waiting_on_resolution().empty());
177   EXPECT_TRUE(b_record->waiting_on_resolution().empty());
178   EXPECT_TRUE(c_record->waiting_on_resolution().empty());
179 }
180 
181 // Tests that the should generate bit is set and propogated properly.
TEST_F(BuilderTest,ShouldGenerate)182 TEST_F(BuilderTest, ShouldGenerate) {
183   DefineToolchain();
184 
185   // Define a secondary toolchain.
186   Settings settings2(&build_settings_, "secondary/");
187   Label toolchain_label2(SourceDir("//tc/"), "secondary");
188   settings2.set_toolchain_label(toolchain_label2);
189   Toolchain* tc2 = new Toolchain(&settings2, toolchain_label2);
190   TestWithScope::SetupToolchain(tc2);
191   builder_->ItemDefined(scoped_ptr<Item>(tc2));
192 
193   // Construct a dependency chain: A -> B. A is in the default toolchain, B
194   // is not.
195   Label a_label(SourceDir("//foo/"), "a",
196                 settings_.toolchain_label().dir(), "a");
197   Label b_label(SourceDir("//foo/"), "b",
198                 toolchain_label2.dir(), toolchain_label2.name());
199 
200   // First define B.
201   Target* b = new Target(&settings2, b_label);
202   b->visibility().SetPublic();
203   b->set_output_type(Target::EXECUTABLE);
204   builder_->ItemDefined(scoped_ptr<Item>(b));
205 
206   // B should not be marked generated by default.
207   BuilderRecord* b_record = builder_->GetRecord(b_label);
208   EXPECT_FALSE(b_record->should_generate());
209 
210   // Define A with a dependency on B.
211   Target* a = new Target(&settings_, a_label);
212   a->public_deps().push_back(LabelTargetPair(b_label));
213   a->set_output_type(Target::EXECUTABLE);
214   builder_->ItemDefined(scoped_ptr<Item>(a));
215 
216   // A should have the generate bit set since it's in the default toolchain.
217   BuilderRecord* a_record = builder_->GetRecord(a_label);
218   EXPECT_TRUE(a_record->should_generate());
219 
220   // It should have gotten pushed to B.
221   EXPECT_TRUE(b_record->should_generate());
222 }
223