1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file. 4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <map> 6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <utility> 7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <vector> 8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/bind.h" 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/memory/linked_ptr.h" 11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/message_loop/message_loop.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/build_settings.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/err.h" 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/loader.h" 16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/parse_tree.h" 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/parser.h" 18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/scheduler.h" 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "tools/gn/tokenizer.h" 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace { 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class MockInputFileManager { 24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typedef base::Callback<void(const ParseNode*)> Callback; 26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MockInputFileManager() { 28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LoaderImpl::AsyncLoadFileCallback GetCallback(); 31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Sets a given response for a given source file. 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void AddCannedResponse(const SourceFile& source_file, 34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& source); 35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Returns true if there is/are pending load(s) matching the given file(s). 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool HasOnePending(const SourceFile& f) const; 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool HasTwoPending(const SourceFile& f1, const SourceFile& f2) const; 39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) void IssueAllPending(); 41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private: 43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) struct CannedResult { 44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<InputFile> input_file; 45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::vector<Token> tokens; 46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<ParseNode> root; 47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) }; 48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool AsyncLoadFile(const LocationRange& origin, 50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const BuildSettings* build_settings, 51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SourceFile& file_name, 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const Callback& callback, 53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Err* err) { 54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) pending_.push_back(std::make_pair(file_name, callback)); 55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Owning pointers. 59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) typedef std::map<SourceFile, linked_ptr<CannedResult> > CannedResponseMap; 60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CannedResponseMap canned_responses_; 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::vector< std::pair<SourceFile, Callback> > pending_; 63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 64f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 65f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)LoaderImpl::AsyncLoadFileCallback MockInputFileManager::GetCallback() { 66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return base::Bind(&MockInputFileManager::AsyncLoadFile, 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Unretained(this)); 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Sets a given response for a given source file. 71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MockInputFileManager::AddCannedResponse(const SourceFile& source_file, 72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& source) { 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CannedResult* canned = new CannedResult; 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canned->input_file.reset(new InputFile(source_file)); 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canned->input_file->SetContents(source); 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Tokenize. 78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Err err; 79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canned->tokens = Tokenizer::Tokenize(canned->input_file.get(), &err); 80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_FALSE(err.has_error()); 81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Parse. 83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canned->root = Parser::Parse(canned->tokens, &err).Pass(); 84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_FALSE(err.has_error()); 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canned_responses_[source_file] = linked_ptr<CannedResult>(canned); 87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool MockInputFileManager::HasOnePending(const SourceFile& f) const { 90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return pending_.size() == 1u && pending_[0].first == f; 91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool MockInputFileManager::HasTwoPending(const SourceFile& f1, 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const SourceFile& f2) const { 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (pending_.size() != 2u) 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return pending_[0].first == f1 && pending_[1].first == f2; 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void MockInputFileManager::IssueAllPending() { 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BlockNode block(false); // Default response. 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for (size_t i = 0; i < pending_.size(); i++) { 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) CannedResponseMap::const_iterator found = 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) canned_responses_.find(pending_[i].first); 106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (found == canned_responses_.end()) 107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) pending_[i].second.Run(&block); 108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) else 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) pending_[i].second.Run(found->second->root.get()); 110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) pending_.clear(); 112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// LoaderTest ------------------------------------------------------------------ 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class LoaderTest : public testing::Test { 117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public: 118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) LoaderTest() { 119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) build_settings_.SetBuildDir(SourceDir("//out/Debug/")); 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~LoaderTest() { 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) protected: 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Scheduler scheduler_; 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) BuildSettings build_settings_; 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) MockInputFileManager mock_ifm_; 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}; 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} // namespace 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// ----------------------------------------------------------------------------- 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)TEST_F(LoaderTest, Foo) { 135f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SourceFile build_config("//build/config/BUILDCONFIG.gn"); 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) build_settings_.set_build_config_file(build_config); 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_refptr<LoaderImpl> loader(new LoaderImpl(&build_settings_)); 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // The default toolchain needs to be set by the build config file. 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mock_ifm_.AddCannedResponse(build_config, 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) "set_default_toolchain(\"//tc:tc\")"); 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) loader->set_async_load_file(mock_ifm_.GetCallback()); 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Request the root build file be loaded. This should kick off the default 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // build config loading. 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SourceFile root_build("//BUILD.gn"); 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) loader->Load(root_build, LocationRange(), Label()); 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(mock_ifm_.HasOnePending(build_config)); 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Completing the build config load should kick off the root build file load. 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mock_ifm_.IssueAllPending(); 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scheduler_.main_loop()->RunUntilIdle(); 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(mock_ifm_.HasOnePending(root_build)); 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Load the root build file. 158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mock_ifm_.IssueAllPending(); 159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scheduler_.main_loop()->RunUntilIdle(); 160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Schedule some other file to load in another toolchain. 162f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Label second_tc(SourceDir("//tc2/"), "tc2"); 163f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SourceFile second_file("//foo/BUILD.gn"); 164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) loader->Load(second_file, LocationRange(), second_tc); 165f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(mock_ifm_.HasOnePending(SourceFile("//tc2/BUILD.gn"))); 166f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 167f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Running the toolchain file should schedule the build config file to load 168f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // for that toolchain. 169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mock_ifm_.IssueAllPending(); 170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scheduler_.main_loop()->RunUntilIdle(); 171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // We have to tell it we have a toolchain definition now (normally the 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // builder would do this). 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const Settings* default_settings = loader->GetToolchainSettings(Label()); 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Toolchain second_tc_object(default_settings, second_tc); 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) loader->ToolchainLoaded(&second_tc_object); 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(mock_ifm_.HasOnePending(build_config)); 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Scheduling a second file to load in that toolchain should not make it 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // pending yet (it's waiting for the build config). 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) SourceFile third_file("//bar/BUILD.gn"); 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) loader->Load(third_file, LocationRange(), second_tc); 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(mock_ifm_.HasOnePending(build_config)); 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Running the build config file should make our third file pending. 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) mock_ifm_.IssueAllPending(); 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scheduler_.main_loop()->RunUntilIdle(); 188f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_TRUE(mock_ifm_.HasTwoPending(second_file, third_file)); 189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 190f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) EXPECT_FALSE(scheduler_.is_failed()); 191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 192