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 12namespace { 13 14class MockLoader : public Loader { 15 public: 16 MockLoader() { 17 } 18 19 // Loader implementation: 20 virtual void Load(const SourceFile& file, 21 const LocationRange& origin, 22 const Label& toolchain_name) OVERRIDE { 23 files_.push_back(file); 24 } 25 virtual void ToolchainLoaded(const Toolchain* toolchain) OVERRIDE { 26 } 27 virtual Label GetDefaultToolchain() const OVERRIDE { 28 return Label(); 29 } 30 virtual const Settings* GetToolchainSettings( 31 const Label& label) const OVERRIDE { 32 return NULL; 33 } 34 35 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. 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: 55 virtual ~MockLoader() {} 56 57 std::vector<SourceFile> files_; 58}; 59 60class BuilderTest : public testing::Test { 61 public: 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 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 89TEST_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. 182TEST_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