summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/extension_function.cc6
-rw-r--r--chrome/browser/extensions/extension_function.h9
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc2
-rw-r--r--chrome/browser/extensions/extension_function_test_utils.cc108
-rw-r--r--chrome/browser/extensions/extension_function_test_utils.h82
-rw-r--r--chrome/browser/extensions/extension_tabs_test.cc113
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.cc4
-rw-r--r--chrome/chrome_tests.gypi3
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',