Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Unified Diff: tools/gn/builder_unittest.cc

Issue 56433003: GN threading refactor (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/gn/builder_record.cc ('k') | tools/gn/command_desc.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/gn/builder_unittest.cc
diff --git a/tools/gn/builder_unittest.cc b/tools/gn/builder_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dfcf49b050e703923483d12ab5253eed540beb9b
--- /dev/null
+++ b/tools/gn/builder_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/builder.h"
+#include "tools/gn/loader.h"
+#include "tools/gn/target.h"
+#include "tools/gn/test_with_scope.h"
+#include "tools/gn/toolchain.h"
+
+namespace {
+
+class MockLoader : public Loader {
+ public:
+ MockLoader() {
+ }
+
+ // Loader implementation:
+ virtual void Load(const SourceFile& file,
+ const Label& toolchain_name) OVERRIDE {
+ files_.push_back(file);
+ }
+ virtual void ToolchainLoaded(const Toolchain* toolchain) OVERRIDE {
+ }
+ virtual Label GetDefaultToolchain() const OVERRIDE {
+ return Label();
+ }
+ virtual const Settings* GetToolchainSettings(const Label& label) OVERRIDE {
+ return NULL;
+ }
+
+ bool HasLoadedNone() const {
+ return files_.empty();
+ }
+
+ // Returns true if one load has been requested and it matches the given
+ // file. This will clear the records so it will be empty for the next call.
+ bool HasLoadedOne(const SourceFile& f) {
+ if (files_.size() != 1u) {
+ files_.clear();
+ return false;
+ }
+
+ bool match = (files_[0] == f);
+ files_.clear();
+ return match;
+ }
+
+ // Like HasLoadedOne above. Accepts any ordering.
+ bool HasLoadedTwo(const SourceFile& a, const SourceFile& b) {
+ if (files_.size() != 2u) {
+ files_.clear();
+ return false;
+ }
+
+ bool match = (
+ (files_[0] == a && files_[1] == b) ||
+ (files_[0] == b && files_[0] == a));
+ files_.clear();
+ return match;
+ }
+
+ private:
+ virtual ~MockLoader() {}
+
+ std::vector<SourceFile> files_;
+};
+
+class BuilderTest : public testing::Test {
+ public:
+ BuilderTest()
+ : loader_(new MockLoader),
+ builder_(new Builder(loader_.get())),
+ settings_(&build_settings_, std::string()),
+ scope_(&settings_) {
+ build_settings_.SetBuildDir(SourceDir("//out/"));
+ settings_.set_toolchain_label(Label(SourceDir("//tc/"), "default"));
+ settings_.set_default_toolchain_label(settings_.toolchain_label());
+ }
+
+ Toolchain* DefineToolchain() {
+ Toolchain* tc = new Toolchain(&settings_, settings_.toolchain_label());
+ builder_->ItemDefined(scoped_ptr<Item>(tc));
+ return tc;
+ }
+
+ protected:
+ scoped_refptr<MockLoader> loader_;
+ scoped_refptr<Builder> builder_;
+ BuildSettings build_settings_;
+ Settings settings_;
+ Scope scope_;
+};
+
+} // namespace
+
+TEST_F(BuilderTest, BasicDeps) {
+ SourceDir toolchain_dir = settings_.toolchain_label().dir();
+ std::string toolchain_name = settings_.toolchain_label().name();
+
+ DefineToolchain();
+ BuilderRecord* toolchain_record =
+ builder_->GetRecord(settings_.toolchain_label());
+ ASSERT_TRUE(toolchain_record);
+ EXPECT_EQ(BuilderRecord::ITEM_TOOLCHAIN, toolchain_record->type());
+
+ // Construct a dependency chain: A -> B -> C. Define A first with a
+ // forward-reference to B, then C, then B to test the different orders that
+ // the dependencies are hooked up.
+ Label a_label(SourceDir("//a/"), "a", toolchain_dir, toolchain_name);
+ Label b_label(SourceDir("//b/"), "b", toolchain_dir, toolchain_name);
+ Label c_label(SourceDir("//c/"), "c", toolchain_dir, toolchain_name);
+
+ // The builder will take ownership of the pointers.
+ Target* a = new Target(&settings_, a_label);
+ a->deps().push_back(LabelTargetPair(b_label));
+ a->set_output_type(Target::EXECUTABLE);
+ builder_->ItemDefined(scoped_ptr<Item>(a));
+
+ // Should have requested that B and the toolchain is loaded.
+ EXPECT_TRUE(loader_->HasLoadedTwo(SourceFile("//tc/BUILD.gn"),
+ SourceFile("//b/BUILD.gn")));
+
+ // A should be unresolved with an item
+ BuilderRecord* a_record = builder_->GetRecord(a_label);
+ EXPECT_TRUE(a_record->item());
+ EXPECT_FALSE(a_record->resolved());
+ EXPECT_FALSE(a_record->can_resolve());
+
+ // B should be unresolved, have no item, and no deps.
+ BuilderRecord* b_record = builder_->GetRecord(b_label);
+ EXPECT_FALSE(b_record->item());
+ EXPECT_FALSE(b_record->resolved());
+ EXPECT_FALSE(b_record->can_resolve());
+ EXPECT_TRUE(b_record->all_deps().empty());
+
+ // A should have two deps: B and the toolchain. Only B should be unresolved.
+ EXPECT_EQ(2u, a_record->all_deps().size());
+ EXPECT_EQ(1u, a_record->unresolved_deps().size());
+ EXPECT_NE(a_record->all_deps().end(),
+ a_record->all_deps().find(toolchain_record));
+ EXPECT_NE(a_record->all_deps().end(),
+ a_record->all_deps().find(b_record));
+ EXPECT_NE(a_record->unresolved_deps().end(),
+ a_record->unresolved_deps().find(b_record));
+
+ // B should be marked as having A waiting on it.
+ EXPECT_EQ(1u, b_record->waiting_on_resolution().size());
+ EXPECT_NE(b_record->waiting_on_resolution().end(),
+ b_record->waiting_on_resolution().find(a_record));
+
+ // Add the C target.
+ Target* c = new Target(&settings_, c_label);
+ c->set_output_type(Target::STATIC_LIBRARY);
+ builder_->ItemDefined(scoped_ptr<Item>(c));
+
+ // C only depends on the already-loaded toolchain so we shouldn't have
+ // requested anything else.
+ EXPECT_TRUE(loader_->HasLoadedNone());
+
+ // Add the B target.
+ Target* b = new Target(&settings_, b_label);
+ a->deps().push_back(LabelTargetPair(c_label));
+ b->set_output_type(Target::SHARED_LIBRARY);
+ builder_->ItemDefined(scoped_ptr<Item>(b));
+
+ // B depends only on the already-loaded C and toolchain so we shouldn't have
+ // requested anything else.
+ EXPECT_TRUE(loader_->HasLoadedNone());
+
+ // All targets should now be resolved.
+ BuilderRecord* c_record = builder_->GetRecord(c_label);
+ EXPECT_TRUE(a_record->resolved());
+ EXPECT_TRUE(b_record->resolved());
+ EXPECT_TRUE(c_record->resolved());
+
+ EXPECT_TRUE(a_record->unresolved_deps().empty());
+ EXPECT_TRUE(b_record->unresolved_deps().empty());
+ EXPECT_TRUE(c_record->unresolved_deps().empty());
+
+ EXPECT_TRUE(a_record->waiting_on_resolution().empty());
+ EXPECT_TRUE(b_record->waiting_on_resolution().empty());
+ EXPECT_TRUE(c_record->waiting_on_resolution().empty());
+}
+
+// Tests that the should generate bit is set and propogated properly.
+TEST_F(BuilderTest, ShouldGenerate) {
+ DefineToolchain();
+
+ // Define a secondary toolchain.
+ Settings settings2(&build_settings_, "secondary");
+ Label toolchain_label2(SourceDir("//tc/"), "secondary");
+ settings2.set_toolchain_label(toolchain_label2);
+ Toolchain* tc2 = new Toolchain(&settings2, toolchain_label2);
+ builder_->ItemDefined(scoped_ptr<Item>(tc2));
+
+ // Construct a dependency chain: A -> B. A is in the default toolchain, B
+ // is not.
+ Label a_label(SourceDir("//foo/"), "a",
+ settings_.toolchain_label().dir(), "a");
+ Label b_label(SourceDir("//foo/"), "b",
+ toolchain_label2.dir(), toolchain_label2.name());
+
+ // First define B.
+ Target* b = new Target(&settings2, b_label);
+ b->set_output_type(Target::EXECUTABLE);
+ builder_->ItemDefined(scoped_ptr<Item>(b));
+
+ // B should not be marked generated by default.
+ BuilderRecord* b_record = builder_->GetRecord(b_label);
+ EXPECT_FALSE(b_record->should_generate());
+
+ // Define A with a dependency on B.
+ Target* a = new Target(&settings_, a_label);
+ a->deps().push_back(LabelTargetPair(b_label));
+ a->set_output_type(Target::EXECUTABLE);
+ builder_->ItemDefined(scoped_ptr<Item>(a));
+
+ // A should have the generate bit set since it's in the default toolchain.
+ BuilderRecord* a_record = builder_->GetRecord(a_label);
+ EXPECT_TRUE(a_record->should_generate());
+
+ // It should have gotten pushed to B.
+ EXPECT_TRUE(b_record->should_generate());
+}
« no previous file with comments | « tools/gn/builder_record.cc ('k') | tools/gn/command_desc.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698