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

Unified Diff: tools/gn/loader_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/loader.cc ('k') | tools/gn/ninja_target_writer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/gn/loader_unittest.cc
diff --git a/tools/gn/loader_unittest.cc b/tools/gn/loader_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7aa267dc55226375649b20766018ec4caa09b5fb
--- /dev/null
+++ b/tools/gn/loader_unittest.cc
@@ -0,0 +1,191 @@
+// 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 <map>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/linked_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "tools/gn/build_settings.h"
+#include "tools/gn/err.h"
+#include "tools/gn/loader.h"
+#include "tools/gn/parse_tree.h"
+#include "tools/gn/parser.h"
+#include "tools/gn/scheduler.h"
+#include "tools/gn/tokenizer.h"
+
+namespace {
+
+class MockInputFileManager {
+ public:
+ typedef base::Callback<void(const ParseNode*)> Callback;
+
+ MockInputFileManager() {
+ }
+
+ LoaderImpl::AsyncLoadFileCallback GetCallback();
+
+ // Sets a given response for a given source file.
+ void AddCannedResponse(const SourceFile& source_file,
+ const std::string& source);
+
+ // Returns true if there is/are pending load(s) matching the given file(s).
+ bool HasOnePending(const SourceFile& f) const;
+ bool HasTwoPending(const SourceFile& f1, const SourceFile& f2) const;
+
+ void IssueAllPending();
+
+ private:
+ struct CannedResult {
+ scoped_ptr<InputFile> input_file;
+ std::vector<Token> tokens;
+ scoped_ptr<ParseNode> root;
+ };
+
+ bool AsyncLoadFile(const LocationRange& origin,
+ const BuildSettings* build_settings,
+ const SourceFile& file_name,
+ const Callback& callback,
+ Err* err) {
+ pending_.push_back(std::make_pair(file_name, callback));
+ return true;
+ }
+
+ // Owning pointers.
+ typedef std::map<SourceFile, linked_ptr<CannedResult> > CannedResponseMap;
+ CannedResponseMap canned_responses_;
+
+ std::vector< std::pair<SourceFile, Callback> > pending_;
+};
+
+LoaderImpl::AsyncLoadFileCallback MockInputFileManager::GetCallback() {
+ return base::Bind(&MockInputFileManager::AsyncLoadFile,
+ base::Unretained(this));
+}
+
+// Sets a given response for a given source file.
+void MockInputFileManager::AddCannedResponse(const SourceFile& source_file,
+ const std::string& source) {
+ CannedResult* canned = new CannedResult;
+ canned->input_file.reset(new InputFile(source_file));
+ canned->input_file->SetContents(source);
+
+ // Tokenize.
+ Err err;
+ canned->tokens = Tokenizer::Tokenize(canned->input_file.get(), &err);
+ EXPECT_FALSE(err.has_error());
+
+ // Parse.
+ canned->root = Parser::Parse(canned->tokens, &err).Pass();
+ EXPECT_FALSE(err.has_error());
+
+ canned_responses_[source_file] = linked_ptr<CannedResult>(canned);
+}
+
+bool MockInputFileManager::HasOnePending(const SourceFile& f) const {
+ return pending_.size() == 1u && pending_[0].first == f;
+}
+
+bool MockInputFileManager::HasTwoPending(const SourceFile& f1,
+ const SourceFile& f2) const {
+ if (pending_.size() != 2u)
+ return false;
+ return pending_[0].first == f1 && pending_[1].first == f2;
+}
+
+void MockInputFileManager::IssueAllPending() {
+ BlockNode block(false); // Default response.
+
+ for (size_t i = 0; i < pending_.size(); i++) {
+ CannedResponseMap::const_iterator found =
+ canned_responses_.find(pending_[i].first);
+ if (found == canned_responses_.end())
+ pending_[i].second.Run(&block);
+ else
+ pending_[i].second.Run(found->second->root.get());
+ }
+ pending_.clear();
+}
+
+// LoaderTest ------------------------------------------------------------------
+
+class LoaderTest : public testing::Test {
+ public:
+ LoaderTest() {
+ build_settings_.SetBuildDir(SourceDir("//out/Debug/"));
+ }
+ virtual ~LoaderTest() {
+ }
+
+ protected:
+ Scheduler scheduler_;
+ BuildSettings build_settings_;
+ MockInputFileManager mock_ifm_;
+};
+
+} // namespace
+
+// -----------------------------------------------------------------------------
+
+TEST_F(LoaderTest, Foo) {
+ SourceFile build_config("//build/config/BUILDCONFIG.gn");
+ build_settings_.set_build_config_file(build_config);
+
+ scoped_refptr<LoaderImpl> loader(new LoaderImpl(&build_settings_));
+
+ // The default toolchain needs to be set by the build config file.
+ mock_ifm_.AddCannedResponse(build_config,
+ "set_default_toolchain(\"//tc:tc\")");
+
+ loader->set_async_load_file(mock_ifm_.GetCallback());
+
+ // Request the root build file be loaded. This should kick off the default
+ // build config loading.
+ SourceFile root_build("//BUILD.gn");
+ loader->Load(root_build, Label());
+ EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+ // Completing the build config load should kick off the root build file load.
+ mock_ifm_.IssueAllPending();
+ scheduler_.main_loop()->RunUntilIdle();
+ EXPECT_TRUE(mock_ifm_.HasOnePending(root_build));
+
+ // Load the root build file.
+ mock_ifm_.IssueAllPending();
+ scheduler_.main_loop()->RunUntilIdle();
+
+ // Schedule some other file to load in another toolchain.
+ Label second_tc(SourceDir("//tc2/"), "tc2");
+ SourceFile second_file("//foo/BUILD.gn");
+ loader->Load(second_file, second_tc);
+ EXPECT_TRUE(mock_ifm_.HasOnePending(SourceFile("//tc2/BUILD.gn")));
+
+ // Running the toolchain file should schedule the build config file to load
+ // for that toolchain.
+ mock_ifm_.IssueAllPending();
+ scheduler_.main_loop()->RunUntilIdle();
+
+ // We have to tell it we have a toolchain definition now (normally the
+ // builder would do this).
+ const Settings* default_settings = loader->GetToolchainSettings(Label());
+ Toolchain second_tc_object(default_settings, second_tc);
+ loader->ToolchainLoaded(&second_tc_object);
+ EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+ // Scheduling a second file to load in that toolchain should not make it
+ // pending yet (it's waiting for the build config).
+ SourceFile third_file("//bar/BUILD.gn");
+ loader->Load(third_file, second_tc);
+ EXPECT_TRUE(mock_ifm_.HasOnePending(build_config));
+
+ // Running the build config file should make our third file pending.
+ mock_ifm_.IssueAllPending();
+ scheduler_.main_loop()->RunUntilIdle();
+ EXPECT_TRUE(mock_ifm_.HasTwoPending(second_file, third_file));
+
+ EXPECT_FALSE(scheduler_.is_failed());
+}
« no previous file with comments | « tools/gn/loader.cc ('k') | tools/gn/ninja_target_writer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698