// Copyright (c) 2012 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 "chrome/browser/extensions/extension_function_test_utils.h" #include #include "base/files/file_path.h" #include "base/json/json_reader.h" #include "base/macros.h" #include "base/values.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "components/crx_file/id_util.h" #include "extensions/browser/api_test_utils.h" #include "extensions/browser/extension_function.h" #include "extensions/browser/extension_function_dispatcher.h" #include "extensions/common/extension.h" #include "testing/gtest/include/gtest/gtest.h" using content::WebContents; using extensions::Extension; using extensions::Manifest; namespace keys = extensions::tabs_constants; namespace { class TestFunctionDispatcherDelegate : public extensions::ExtensionFunctionDispatcher::Delegate { public: explicit TestFunctionDispatcherDelegate(Browser* browser) : browser_(browser) {} ~TestFunctionDispatcherDelegate() override {} private: extensions::WindowController* GetExtensionWindowController() const override { return browser_->extension_window_controller(); } WebContents* GetAssociatedWebContents() const override { return NULL; } Browser* browser_; }; } // namespace namespace extension_function_test_utils { base::ListValue* ParseList(const std::string& data) { scoped_ptr result = base::JSONReader::Read(data); base::ListValue* list = NULL; result->GetAsList(&list); ignore_result(result.release()); return list; } base::DictionaryValue* ToDictionary(base::Value* val) { EXPECT_TRUE(val); EXPECT_EQ(base::Value::TYPE_DICTIONARY, val->GetType()); return static_cast(val); } base::ListValue* ToList(base::Value* val) { EXPECT_TRUE(val); EXPECT_EQ(base::Value::TYPE_LIST, val->GetType()); return static_cast(val); } bool HasPrivacySensitiveFields(base::DictionaryValue* val) { std::string result; if (val->GetString(keys::kUrlKey, &result) || val->GetString(keys::kTitleKey, &result) || val->GetString(keys::kFaviconUrlKey, &result)) return true; return false; } std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, const std::string& args, Browser* browser) { return RunFunctionAndReturnError(function, args, browser, NONE); } std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, const std::string& args, Browser* browser, RunFunctionFlags flags) { scoped_refptr function_owner(function); // Without a callback the function will not generate a result. function->set_has_callback(true); RunFunction(function, args, browser, flags); EXPECT_FALSE(function->GetResultList()) << "Did not expect a result"; return function->GetError(); } base::Value* RunFunctionAndReturnSingleResult( UIThreadExtensionFunction* function, const std::string& args, Browser* browser) { return RunFunctionAndReturnSingleResult(function, args, browser, NONE); } base::Value* RunFunctionAndReturnSingleResult( UIThreadExtensionFunction* function, const std::string& args, Browser* browser, RunFunctionFlags flags) { scoped_refptr function_owner(function); // Without a callback the function will not generate a result. function->set_has_callback(true); RunFunction(function, args, browser, flags); EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: " << function->GetError(); const base::Value* single_result = NULL; if (function->GetResultList() != NULL && function->GetResultList()->Get(0, &single_result)) { return single_result->DeepCopy(); } return NULL; } // This helps us be able to wait until an UIThreadExtensionFunction calls // SendResponse. class SendResponseDelegate : public UIThreadExtensionFunction::DelegateForTests { public: SendResponseDelegate() : should_post_quit_(false) {} virtual ~SendResponseDelegate() {} void set_should_post_quit(bool should_quit) { should_post_quit_ = should_quit; } bool HasResponse() { return response_.get() != NULL; } bool GetResponse() { EXPECT_TRUE(HasResponse()); return *response_.get(); } void OnSendResponse(UIThreadExtensionFunction* function, bool success, bool bad_message) override { ASSERT_FALSE(bad_message); ASSERT_FALSE(HasResponse()); response_.reset(new bool); *response_ = success; if (should_post_quit_) { base::MessageLoopForUI::current()->QuitWhenIdle(); } } private: scoped_ptr response_; bool should_post_quit_; }; bool RunFunction(UIThreadExtensionFunction* function, const std::string& args, Browser* browser, RunFunctionFlags flags) { scoped_ptr parsed_args(ParseList(args)); EXPECT_TRUE(parsed_args.get()) << "Could not parse extension function arguments: " << args; return RunFunction(function, parsed_args.Pass(), browser, flags); } bool RunFunction(UIThreadExtensionFunction* function, scoped_ptr args, Browser* browser, RunFunctionFlags flags) { TestFunctionDispatcherDelegate dispatcher_delegate(browser); scoped_ptr dispatcher( new extensions::ExtensionFunctionDispatcher(browser->profile())); dispatcher->set_delegate(&dispatcher_delegate); // TODO(yoz): The cast is a hack; these flags should be defined in // only one place. See crbug.com/394840. return extensions::api_test_utils::RunFunction( function, args.Pass(), browser->profile(), dispatcher.Pass(), static_cast(flags)); } } // namespace extension_function_test_utils