diff options
-rw-r--r-- | chrome/browser/extensions/extension_function.cc | 6 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function.h | 9 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_dispatcher.cc | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_test_utils.cc | 108 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_function_test_utils.h | 82 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tabs_test.cc | 113 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_webrequest_api.cc | 4 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 3 |
8 files changed, 320 insertions, 7 deletions
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc index 0374dd0..998b1b0 100644 --- a/chrome/browser/extensions/extension_function.cc +++ b/chrome/browser/extensions/extension_function.cc @@ -43,7 +43,7 @@ void UIThreadExtensionFunction::RenderViewHostTracker::Observe( ExtensionFunction::ExtensionFunction() : request_id_(-1), - profile_(NULL), + profile_id_(NULL), has_callback_(false), include_incognito_(false), user_gesture_(false), @@ -75,6 +75,10 @@ const std::string ExtensionFunction::GetResult() { return json; } +Value* ExtensionFunction::GetResultValue() { + return result_.get(); +} + const std::string ExtensionFunction::GetError() { return error_; } diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h index f0bef3a..b006fd8 100644 --- a/chrome/browser/extensions/extension_function.h +++ b/chrome/browser/extensions/extension_function.h @@ -91,6 +91,9 @@ class ExtensionFunction // be empty). virtual const std::string GetResult(); + // Retrieves the results of the function as a Value. + base::Value* GetResultValue(); + // Retrieves any error string from the function. virtual const std::string GetError(); @@ -98,8 +101,8 @@ class ExtensionFunction void set_name(const std::string& name) { name_ = name; } const std::string& name() const { return name_; } - void set_profile(void* profile) { profile_ = profile; } - void* profile() const { return profile_; } + void set_profile_id(void* profile_id) { profile_id_ = profile_id; } + void* profile_id() const { return profile_id_; } void set_extension(const Extension* extension) { extension_ = extension; } const Extension* GetExtension() const { return extension_.get(); } @@ -155,7 +158,7 @@ class ExtensionFunction int request_id_; // The Profile of this function's extension. - void* profile_; + void* profile_id_; // The extension that called this function. scoped_refptr<const Extension> extension_; diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index 0a53fbe..91c470e 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -670,7 +670,7 @@ ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( function->set_has_callback(params.has_callback); function->set_user_gesture(params.user_gesture); function->set_extension(extension); - function->set_profile(profile); + function->set_profile_id(profile); return function; } diff --git a/chrome/browser/extensions/extension_function_test_utils.cc b/chrome/browser/extensions/extension_function_test_utils.cc new file mode 100644 index 0000000..4f5b8ae --- /dev/null +++ b/chrome/browser/extensions/extension_function_test_utils.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2011 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 <string> + +#include "base/json/json_reader.h" +#include "base/values.h" +#include "chrome/browser/ui/browser.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extension_function_test_utils { + +base::Value* ParseJSON(const std::string& data) { + const bool kAllowTrailingComma = false; + return base::JSONReader::Read(data, kAllowTrailingComma); +} + +base::ListValue* ParseList(const std::string& data) { + scoped_ptr<base::Value> result(ParseJSON(data)); + if (result.get() && result->IsType(base::Value::TYPE_LIST)) + return static_cast<base::ListValue*>(result.release()); + else + return NULL; +} + +base::DictionaryValue* ParseDictionary( + const std::string& data) { + scoped_ptr<base::Value> result(ParseJSON(data)); + if (result.get() && result->IsType(base::Value::TYPE_DICTIONARY)) + return static_cast<base::DictionaryValue*>(result.release()); + else + return NULL; +} + +bool GetBoolean(base::DictionaryValue* val, const std::string& key) { + bool result = false; + if (!val->GetBoolean(key, &result)) + ADD_FAILURE() << key << " does not exist or is not a boolean."; + return result; +} + +int GetInteger(base::DictionaryValue* val, const std::string& key) { + int result = 0; + if (!val->GetInteger(key, &result)) + ADD_FAILURE() << key << " does not exist or is not an integer."; + return result; +} + +std::string GetString(base::DictionaryValue* val, const std::string& key) { + std::string result; + if (!val->GetString(key, &result)) + ADD_FAILURE() << key << " does not exist or is not a string."; + return result; +} + +base::DictionaryValue* ToDictionary(base::Value* val) { + if (!val || !val->IsType(base::Value::TYPE_DICTIONARY)) + ADD_FAILURE() << "value is null or not a dictionary."; + return static_cast<base::DictionaryValue*>(val); +} + +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<ExtensionFunction> function_owner(function); + RunFunction(function, args, browser, flags); + if (function->GetResultValue()) + ADD_FAILURE() << function->GetResult(); + return function->GetError(); +} + +base::Value* RunFunctionAndReturnResult(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser) { + return RunFunctionAndReturnResult(function, args, browser, NONE); +} +base::Value* RunFunctionAndReturnResult(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser, + RunFunctionFlags flags) { + scoped_refptr<ExtensionFunction> function_owner(function); + RunFunction(function, args, browser, flags); + if (!function->GetError().empty()) + ADD_FAILURE() << function->GetError(); + return function->GetResultValue()->DeepCopy(); +} + +void RunFunction(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser, + RunFunctionFlags flags) { + scoped_ptr<base::ListValue> parsed_args(ParseList(args)); + function->SetArgs(parsed_args.get()); + function->set_profile(browser->profile()); + function->set_include_incognito(flags & INCLUDE_INCOGNITO); + function->Run(); +} + +} // namespace extension_function_test_utils diff --git a/chrome/browser/extensions/extension_function_test_utils.h b/chrome/browser/extensions/extension_function_test_utils.h new file mode 100644 index 0000000..acdabda --- /dev/null +++ b/chrome/browser/extensions/extension_function_test_utils.h @@ -0,0 +1,82 @@ +// Copyright (c) 2011 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_TEST_UTILS_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_TEST_UTILS_H_ +#pragma once + +#include <string> + +#include "base/memory/ref_counted.h" +#include "chrome/browser/extensions/extension_function.h" + +namespace base { +class Value; +class DictionaryValue; +class ListValue; +} + +namespace extension_function_test_utils { + +// Parse JSON and return as the specified type, or NULL if the JSON is invalid +// or not the specified type. +base::Value* ParseJSON(const std::string& data); +base::ListValue* ParseList(const std::string& data); +base::DictionaryValue* ParseDictionary(const std::string& data); + +// Get |key| from |val| as the specified type. If |key| does not exist, or is +// not of the specified type, adds a failure to the current test and returns +// false, 0, empty string, etc. +bool GetBoolean(base::DictionaryValue* val, const std::string& key); +int GetInteger(base::DictionaryValue* val, const std::string& key); +std::string GetString(base::DictionaryValue* val, const std::string& key); + +// If |val| is a dictionary, return it as one, otherwise NULL. +base::DictionaryValue* ToDictionary(base::Value* val); + +enum RunFunctionFlags { + NONE = 0, + INCLUDE_INCOGNITO = 1 << 0 +}; + +// Run |function| with |args| and return the resulting error. Adds an error to +// the current test if |function| returns a result. The caller releases +// ownership of |function|. +std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser, + RunFunctionFlags flags); +std::string RunFunctionAndReturnError(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser); + +// Run |function| with |args| and return the result. Adds an error to the +// current test if |function| returns an error. The caller releases ownership of +// |function|. the caller takes ownership of the result. +base::Value* RunFunctionAndReturnResult(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser, + RunFunctionFlags flags); +base::Value* RunFunctionAndReturnResult(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser); + +// Create and run |function| with |args|. The caller retains ownership of +// |function|. +// +// TODO(aa): It would be nice if |args| could be validated against the schema +// that |function| expects. That way, we know that we are testing something +// close to what the bindings would actually send. +// +// TODO(aa): I'm concerned that this style won't scale to all the bits and bobs +// we're going to need to frob for all the different extension functions. But we +// can refactor when we see what is needed. +void RunFunction(UIThreadExtensionFunction* function, + const std::string& args, + Browser* browser, + RunFunctionFlags flags); + +} // namespace extension_function_test_utils + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_TEST_UTILS_H_ diff --git a/chrome/browser/extensions/extension_tabs_test.cc b/chrome/browser/extensions/extension_tabs_test.cc new file mode 100644 index 0000000..a3f0282 --- /dev/null +++ b/chrome/browser/extensions/extension_tabs_test.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2011 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_tabs_module.h" + +#include <string> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/stringprintf.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" +#include "chrome/browser/extensions/extension_tab_util.h" +#include "chrome/browser/extensions/extension_tabs_module_constants.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "ui/gfx/rect.h" + +using namespace extension_function_test_utils; + +namespace { + +class ExtensionTabsTest : public InProcessBrowserTest { +}; + +} + +IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { + int window_id = ExtensionTabUtil::GetWindowId(browser()); + + // Invalid window ID error. + EXPECT_TRUE(MatchPattern( + RunFunctionAndReturnError( + new GetWindowFunction(), + base::StringPrintf("[%u]", window_id + 1), + browser()), + extension_tabs_module_constants::kWindowNotFoundError)); + + // Basic window details. + // Need GetRestoredBound instead of GetBounds. + // See crbug.com/98759. + gfx::Rect bounds = browser()->window()->GetRestoredBounds(); + + scoped_ptr<base::DictionaryValue> result(ToDictionary( + RunFunctionAndReturnResult( + new GetWindowFunction(), + base::StringPrintf("[%u]", window_id), + browser()))); + EXPECT_EQ(window_id, GetInteger(result.get(), "id")); + EXPECT_FALSE(GetBoolean(result.get(), "incognito")); + EXPECT_EQ("normal", GetString(result.get(), "type")); + EXPECT_EQ(bounds.x(), GetInteger(result.get(), "left")); + EXPECT_EQ(bounds.y(), GetInteger(result.get(), "top")); + EXPECT_EQ(bounds.width(), GetInteger(result.get(), "width")); + EXPECT_EQ(bounds.height(), GetInteger(result.get(), "height")); + + // TODO(aa): Can't assume window is focused. On mac, calling Activate() from a + // browser test doesn't seem to do anything, so can't test the opposite + // either. + EXPECT_EQ(browser()->window()->IsActive(), + GetBoolean(result.get(), "focused")); + + // TODO(aa): Minimized and maximized dimensions. Is there a way to set + // minimize/maximize programmatically? + + // Popup. + Browser* popup_browser = + Browser::CreateForType(Browser::TYPE_POPUP, browser()->profile()); + result.reset(ToDictionary( + RunFunctionAndReturnResult( + new GetWindowFunction(), + base::StringPrintf( + "[%u]", ExtensionTabUtil::GetWindowId(popup_browser)), + browser()))); + EXPECT_EQ("popup", GetString(result.get(), "type")); + + // Panel. + Browser* panel_browser = + Browser::CreateForType(Browser::TYPE_PANEL, browser()->profile()); + result.reset(ToDictionary( + RunFunctionAndReturnResult( + new GetWindowFunction(), + base::StringPrintf( + "[%u]", ExtensionTabUtil::GetWindowId(panel_browser)), + browser()))); + EXPECT_EQ("panel", GetString(result.get(), "type")); + + // Incognito. + Browser* incognito_browser = CreateIncognitoBrowser(); + int incognito_window_id = ExtensionTabUtil::GetWindowId(incognito_browser); + + // Without "include_incognito". + EXPECT_TRUE(MatchPattern( + RunFunctionAndReturnError( + new GetWindowFunction(), + base::StringPrintf("[%u]", incognito_window_id), + browser()), + extension_tabs_module_constants::kWindowNotFoundError)); + + // With "include_incognito". + result.reset(ToDictionary( + RunFunctionAndReturnResult( + new GetWindowFunction(), + base::StringPrintf("[%u]", incognito_window_id), + browser(), + INCLUDE_INCOGNITO))); + EXPECT_TRUE(GetBoolean(result.get(), "incognito")); + +} diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc index 7e7bea0..43c2007 100644 --- a/chrome/browser/extensions/extension_webrequest_api.cc +++ b/chrome/browser/extensions/extension_webrequest_api.cc @@ -1362,7 +1362,7 @@ bool WebRequestAddEventListener::RunImpl() { std::string extension_name = extension ? extension->name() : extension_id(); ExtensionWebRequestEventRouter::GetInstance()->AddEventListener( - profile(), extension_id(), extension_name, + profile_id(), extension_id(), extension_name, event_name, sub_event_name, filter, extra_info_spec, ipc_sender_weak()); @@ -1440,7 +1440,7 @@ bool WebRequestEventHandled::RunImpl() { } ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled( - profile(), extension_id(), event_name, sub_event_name, request_id, + profile_id(), extension_id(), event_name, sub_event_name, request_id, response.release()); return true; diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 7b66eb8..691e8c6 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2315,6 +2315,8 @@ 'browser/extensions/extension_downloads_apitest.cc', 'browser/extensions/extension_file_browser_private_apitest.cc', 'browser/extensions/extension_fileapi_apitest.cc', + 'browser/extensions/extension_function_test_utils.cc', + 'browser/extensions/extension_function_test_utils.h', 'browser/extensions/extension_gallery_install_apitest.cc', 'browser/extensions/extension_geolocation_apitest.cc', 'browser/extensions/extension_get_views_apitest.cc', @@ -2352,6 +2354,7 @@ 'browser/extensions/extension_startup_browsertest.cc', 'browser/extensions/extension_storage_apitest.cc', 'browser/extensions/extension_tabs_apitest.cc', + 'browser/extensions/extension_tabs_test.cc', 'browser/extensions/extension_test_message_listener.cc', 'browser/extensions/extension_test_message_listener.h', 'browser/extensions/extension_toolbar_model_browsertest.cc', |