summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorsammc@chromium.org <sammc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-26 19:48:04 +0000
committersammc@chromium.org <sammc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-26 19:48:04 +0000
commitf80685c31c04410dc90bc45f492f4adc73ace117 (patch)
tree10bc5ea060c8538b846ff79a44beb0ab18947904 /extensions
parent5f2d097e8e839a4ab180cc8f63a5ddec4378e408 (diff)
downloadchromium_src-f80685c31c04410dc90bc45f492f4adc73ace117.zip
chromium_src-f80685c31c04410dc90bc45f492f4adc73ace117.tar.gz
chromium_src-f80685c31c04410dc90bc45f492f4adc73ace117.tar.bz2
Add support for writing unit tests for Mojo-backed apps/extensions APIs.
This change adds the infrastructure for unit testing the JS parts of apps and extensions APIs implemented on top of Mojo services. The test environment provides a partial implementation of the JS test API provided to browser tests. A TestServiceProvider implementation is used to provide test implementations of the appropriate Mojo services to the JS code. BUG=389016 Review URL: https://codereview.chromium.org/399363002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285792 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions')
-rw-r--r--extensions/DEPS2
-rw-r--r--extensions/extensions.gyp12
-rw-r--r--extensions/renderer/DEPS1
-rw-r--r--extensions/renderer/api_test_base.cc221
-rw-r--r--extensions/renderer/api_test_base.h94
-rw-r--r--extensions/renderer/api_test_base_unittest.cc34
-rw-r--r--extensions/renderer/dispatcher.cc265
-rw-r--r--extensions/renderer/dispatcher.h10
-rw-r--r--extensions/renderer/module_system.cc5
-rw-r--r--extensions/renderer/module_system_test.cc2
-rw-r--r--extensions/renderer/resources/browser_test_environment_specific_bindings.js15
-rw-r--r--extensions/renderer/resources/extensions_renderer_resources.grd1
-rw-r--r--extensions/renderer/resources/test_custom_bindings.js11
-rw-r--r--extensions/renderer/script_context.cc2
-rw-r--r--extensions/test/DEPS3
-rw-r--r--extensions/test/data/api_test_base_unittest.js65
-rw-r--r--extensions/test/data/unit_test_environment_specific_bindings.js50
-rw-r--r--extensions/test/extensions_unittests_main.cc2
-rw-r--r--extensions/test/test_extensions_client.cc52
19 files changed, 724 insertions, 123 deletions
diff --git a/extensions/DEPS b/extensions/DEPS
index f544c73..f0606ba 100644
--- a/extensions/DEPS
+++ b/extensions/DEPS
@@ -5,8 +5,10 @@ include_rules = [
"+content/public/common",
"+content/public/test",
"+crypto",
+ "+grit/content_resources.h",
"+grit/extensions_renderer_resources.h",
"+grit/extensions_resources.h",
+ "+mojo/public",
"+testing",
"+ui",
diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp
index 7faa191..ece9476 100644
--- a/extensions/extensions.gyp
+++ b/extensions/extensions.gyp
@@ -535,7 +535,9 @@
'dependencies': [
'extensions_resources.gyp:extensions_resources',
'../chrome/chrome_resources.gyp:chrome_resources',
+ '../content/content_resources.gyp:content_resources',
'../gin/gin.gyp:gin',
+ '../mojo/mojo.gyp:mojo_js_bindings',
'../third_party/WebKit/public/blink.gyp:blink',
],
'include_dirs': [
@@ -733,6 +735,7 @@
'target_name': 'extensions_pak',
'type': 'none',
'dependencies': [
+ '../content/content_resources.gyp:content_resources',
'../ui/strings/ui_strings.gyp:ui_strings',
'extensions_resources.gyp:extensions_resources',
],
@@ -741,6 +744,7 @@
'action_name': 'repack_extensions_pak',
'variables': {
'pak_inputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_renderer_resources.pak',
'<(SHARED_INTERMEDIATE_DIR)/ui/strings/app_locale_settings_en-US.pak',
@@ -763,6 +767,11 @@
'../base/base.gyp:base',
'../base/base.gyp:test_support_base',
'../content/content_shell_and_tests.gyp:test_support_content',
+ '../device/serial/serial.gyp:device_serial',
+ '../mojo/mojo.gyp:mojo_environment_chromium',
+ '../mojo/mojo.gyp:mojo_cpp_bindings',
+ '../mojo/mojo.gyp:mojo_js_bindings_lib',
+ '../mojo/mojo.gyp:mojo_system_impl',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
'extensions_common',
@@ -781,6 +790,9 @@
'common/one_shot_event_unittest.cc',
'common/permissions/manifest_permission_set_unittest.cc',
'common/user_script_unittest.cc',
+ 'renderer/api_test_base.cc',
+ 'renderer/api_test_base.h',
+ 'renderer/api_test_base_unittest.cc',
'renderer/event_unittest.cc',
'renderer/json_schema_unittest.cc',
'renderer/messaging_utils_unittest.cc',
diff --git a/extensions/renderer/DEPS b/extensions/renderer/DEPS
index ab21030..2b18364 100644
--- a/extensions/renderer/DEPS
+++ b/extensions/renderer/DEPS
@@ -2,6 +2,7 @@ include_rules = [
"+content/public/renderer",
"+gin",
+ "+mojo/bindings/js",
"+third_party/skia/include/core",
diff --git a/extensions/renderer/api_test_base.cc b/extensions/renderer/api_test_base.cc
new file mode 100644
index 0000000..f0943c9
--- /dev/null
+++ b/extensions/renderer/api_test_base.cc
@@ -0,0 +1,221 @@
+// Copyright 2014 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 "extensions/renderer/api_test_base.h"
+
+#include <vector>
+
+#include "base/run_loop.h"
+#include "extensions/common/extension_urls.h"
+#include "extensions/renderer/dispatcher.h"
+#include "extensions/renderer/process_info_native_handler.h"
+#include "gin/converter.h"
+#include "gin/dictionary.h"
+#include "mojo/bindings/js/core.h"
+#include "mojo/bindings/js/handle.h"
+#include "mojo/bindings/js/support.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace extensions {
+namespace {
+
+// Natives for the implementation of the unit test version of chrome.test. Calls
+// the provided |quit_closure| when either notifyPass or notifyFail is called.
+class TestNatives : public gin::Wrappable<TestNatives> {
+ public:
+ static gin::Handle<TestNatives> Create(v8::Isolate* isolate,
+ const base::Closure& quit_closure) {
+ return gin::CreateHandle(isolate, new TestNatives(quit_closure));
+ }
+
+ virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE {
+ return Wrappable<TestNatives>::GetObjectTemplateBuilder(isolate)
+ .SetMethod("Log", &TestNatives::Log)
+ .SetMethod("NotifyPass", &TestNatives::NotifyPass)
+ .SetMethod("NotifyFail", &TestNatives::NotifyFail);
+ }
+
+ void Log(const std::string& value) { logs_ += value + "\n"; }
+ void NotifyPass() { FinishTesting(); }
+
+ void NotifyFail(const std::string& message) {
+ FinishTesting();
+ FAIL() << logs_ << message;
+ }
+
+ void FinishTesting() {
+ base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
+ }
+
+ static gin::WrapperInfo kWrapperInfo;
+
+ private:
+ explicit TestNatives(const base::Closure& quit_closure)
+ : quit_closure_(quit_closure) {}
+
+ const base::Closure quit_closure_;
+ std::string logs_;
+};
+
+gin::WrapperInfo TestNatives::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+} // namespace
+
+gin::WrapperInfo TestServiceProvider::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+gin::Handle<TestServiceProvider> TestServiceProvider::Create(
+ v8::Isolate* isolate) {
+ return gin::CreateHandle(isolate, new TestServiceProvider());
+}
+
+TestServiceProvider::~TestServiceProvider() {
+}
+
+gin::ObjectTemplateBuilder TestServiceProvider::GetObjectTemplateBuilder(
+ v8::Isolate* isolate) {
+ return Wrappable<TestServiceProvider>::GetObjectTemplateBuilder(isolate)
+ .SetMethod("connectToService", &TestServiceProvider::ConnectToService);
+}
+
+mojo::Handle TestServiceProvider::ConnectToService(
+ const std::string& service_name) {
+ EXPECT_EQ(1u, service_factories_.count(service_name))
+ << "Unregistered service " << service_name << " requested.";
+ mojo::MessagePipe pipe;
+ std::map<std::string,
+ base::Callback<void(mojo::ScopedMessagePipeHandle)> >::iterator it =
+ service_factories_.find(service_name);
+ if (it != service_factories_.end())
+ it->second.Run(pipe.handle0.Pass());
+ return pipe.handle1.release();
+}
+
+TestServiceProvider::TestServiceProvider() {
+}
+
+ApiTestBase::ApiTestBase() {
+}
+ApiTestBase::~ApiTestBase() {
+}
+
+void ApiTestBase::SetUp() {
+ ModuleSystemTest::SetUp();
+ InitializeEnvironment();
+ RegisterModules();
+}
+
+void ApiTestBase::RegisterModules() {
+ v8_schema_registry_.reset(new V8SchemaRegistry);
+ const std::vector<std::pair<std::string, int> > resources =
+ Dispatcher::GetJsResources();
+ for (std::vector<std::pair<std::string, int> >::const_iterator resource =
+ resources.begin();
+ resource != resources.end();
+ ++resource) {
+ if (resource->first != "test_environment_specific_bindings")
+ env()->RegisterModule(resource->first, resource->second);
+ }
+ Dispatcher::RegisterNativeHandlers(env()->module_system(),
+ env()->context(),
+ NULL,
+ NULL,
+ v8_schema_registry_.get());
+ env()->module_system()->RegisterNativeHandler(
+ "process",
+ scoped_ptr<NativeHandler>(new ProcessInfoNativeHandler(
+ env()->context(),
+ env()->context()->GetExtensionID(),
+ env()->context()->GetContextTypeDescription(),
+ false,
+ 2,
+ false)));
+ env()->RegisterTestFile("test_environment_specific_bindings",
+ "unit_test_environment_specific_bindings.js");
+
+ env()->OverrideNativeHandler("activityLogger",
+ "exports.LogAPICall = function() {};");
+ env()->OverrideNativeHandler(
+ "apiDefinitions",
+ "exports.GetExtensionAPIDefinitionsForTest = function() { return [] };");
+ env()->OverrideNativeHandler(
+ "event_natives",
+ "exports.AttachEvent = function() {};"
+ "exports.DetachEvent = function() {};"
+ "exports.AttachFilteredEvent = function() {};"
+ "exports.AttachFilteredEvent = function() {};"
+ "exports.MatchAgainstEventFilter = function() { return [] };");
+
+ gin::ModuleRegistry::From(env()->context()->v8_context())
+ ->AddBuiltinModule(env()->isolate(),
+ mojo::js::Core::kModuleName,
+ mojo::js::Core::GetModule(env()->isolate()));
+ gin::ModuleRegistry::From(env()->context()->v8_context())
+ ->AddBuiltinModule(env()->isolate(),
+ mojo::js::Support::kModuleName,
+ mojo::js::Support::GetModule(env()->isolate()));
+ gin::Handle<TestServiceProvider> service_provider =
+ TestServiceProvider::Create(env()->isolate());
+ service_provider_ = service_provider.get();
+ gin::ModuleRegistry::From(env()->context()->v8_context())
+ ->AddBuiltinModule(env()->isolate(),
+ "content/public/renderer/service_provider",
+ service_provider.ToV8());
+}
+
+void ApiTestBase::InitializeEnvironment() {
+ gin::Dictionary global(env()->isolate(),
+ env()->context()->v8_context()->Global());
+ gin::Dictionary navigator(gin::Dictionary::CreateEmpty(env()->isolate()));
+ navigator.Set("appVersion", base::StringPiece(""));
+ global.Set("navigator", navigator);
+ gin::Dictionary chrome(gin::Dictionary::CreateEmpty(env()->isolate()));
+ global.Set("chrome", chrome);
+ gin::Dictionary extension(gin::Dictionary::CreateEmpty(env()->isolate()));
+ chrome.Set("extension", extension);
+ gin::Dictionary runtime(gin::Dictionary::CreateEmpty(env()->isolate()));
+ chrome.Set("runtime", runtime);
+}
+
+void ApiTestBase::RunTest(const std::string& file_name,
+ const std::string& test_name) {
+ env()->RegisterTestFile("testBody", file_name);
+ ExpectNoAssertionsMade();
+ base::RunLoop run_loop;
+ gin::ModuleRegistry::From(env()->context()->v8_context())->AddBuiltinModule(
+ env()->isolate(),
+ "testNatives",
+ TestNatives::Create(env()->isolate(), run_loop.QuitClosure()).ToV8());
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::Bind(&ApiTestBase::RunTestInner,
+ base::Unretained(this),
+ test_name,
+ run_loop.QuitClosure()));
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&ApiTestBase::RunPromisesAgain, base::Unretained(this)));
+ run_loop.Run();
+}
+
+void ApiTestBase::RunTestInner(const std::string& test_name,
+ const base::Closure& quit_closure) {
+ v8::HandleScope scope(env()->isolate());
+ ModuleSystem::NativesEnabledScope natives_enabled(env()->module_system());
+ v8::Handle<v8::Value> result =
+ env()->module_system()->CallModuleMethod("testBody", test_name);
+ if (!result->IsTrue()) {
+ base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure);
+ FAIL() << "Failed to run test \"" << test_name << "\"";
+ }
+}
+
+void ApiTestBase::RunPromisesAgain() {
+ RunResolvedPromises();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&ApiTestBase::RunPromisesAgain, base::Unretained(this)));
+}
+
+} // namespace extensions
diff --git a/extensions/renderer/api_test_base.h b/extensions/renderer/api_test_base.h
new file mode 100644
index 0000000..4d74995
--- /dev/null
+++ b/extensions/renderer/api_test_base.h
@@ -0,0 +1,94 @@
+// Copyright 2014 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 EXTENSIONS_RENDERER_API_TEST_BASE_H_
+#define EXTENSIONS_RENDERER_API_TEST_BASE_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "extensions/renderer/module_system_test.h"
+#include "extensions/renderer/v8_schema_registry.h"
+#include "gin/handle.h"
+#include "gin/modules/module_registry.h"
+#include "gin/object_template_builder.h"
+#include "gin/wrappable.h"
+#include "mojo/bindings/js/handle.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/core.h"
+
+namespace extensions {
+
+class V8SchemaRegistry;
+
+// A ServiceProvider that provides access from JS modules to services registered
+// by AddService() calls.
+class TestServiceProvider : public gin::Wrappable<TestServiceProvider> {
+ public:
+ static gin::Handle<TestServiceProvider> Create(v8::Isolate* isolate);
+ virtual ~TestServiceProvider();
+
+ virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) OVERRIDE;
+
+ template <typename Interface>
+ void AddService(const base::Callback<void(mojo::InterfaceRequest<Interface>)>
+ service_factory) {
+ service_factories_.insert(std::make_pair(
+ Interface::Name_,
+ base::Bind(ForwardToServiceFactory<Interface>, service_factory)));
+ }
+
+ static gin::WrapperInfo kWrapperInfo;
+
+ private:
+ TestServiceProvider();
+
+ mojo::Handle ConnectToService(const std::string& service_name);
+
+ template <typename Interface>
+ static void ForwardToServiceFactory(
+ const base::Callback<void(mojo::InterfaceRequest<Interface>)>
+ service_factory,
+ mojo::ScopedMessagePipeHandle handle) {
+ service_factory.Run(mojo::MakeRequest<Interface>(handle.Pass()));
+ }
+ std::map<std::string, base::Callback<void(mojo::ScopedMessagePipeHandle)> >
+ service_factories_;
+};
+
+// A base class for unit testing apps/extensions API custom bindings implemented
+// on Mojo services. To use:
+// 1. Register test Mojo service implementations on service_provider().
+// 2. Write JS tests in extensions/test/data/test_file.js.
+// 3. Write one C++ test function for each JS test containing
+// RunTest("test_file.js", "testFunctionName").
+// See extensions/renderer/api_test_base_unittest.cc and
+// extensions/test/data/api_test_base_unittest.js for sample usage.
+class ApiTestBase : public ModuleSystemTest {
+ protected:
+ ApiTestBase();
+ virtual ~ApiTestBase();
+ virtual void SetUp() OVERRIDE;
+ void RunTest(const std::string& file_name, const std::string& test_name);
+ TestServiceProvider* service_provider() { return service_provider_; }
+
+ private:
+ void RegisterModules();
+ void InitializeEnvironment();
+ void RunTestInner(const std::string& test_name,
+ const base::Closure& quit_closure);
+ void RunPromisesAgain();
+
+ base::MessageLoop message_loop_;
+ TestServiceProvider* service_provider_;
+ scoped_ptr<V8SchemaRegistry> v8_schema_registry_;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_RENDERER_API_TEST_BASE_H_
diff --git a/extensions/renderer/api_test_base_unittest.cc b/extensions/renderer/api_test_base_unittest.cc
new file mode 100644
index 0000000..953d7b5
--- /dev/null
+++ b/extensions/renderer/api_test_base_unittest.cc
@@ -0,0 +1,34 @@
+// Copyright 2014 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 "extensions/renderer/api_test_base.h"
+
+namespace extensions {
+
+class ApiTestBaseTest : public ApiTestBase {
+ public:
+ virtual void SetUp() OVERRIDE { ApiTestBase::SetUp(); }
+};
+
+TEST_F(ApiTestBaseTest, TestEnvironment) {
+ RunTest("api_test_base_unittest.js", "testEnvironment");
+}
+
+TEST_F(ApiTestBaseTest, TestPromisesRun) {
+ RunTest("api_test_base_unittest.js", "testPromisesRun");
+}
+
+TEST_F(ApiTestBaseTest, TestCommonModulesAreAvailable) {
+ RunTest("api_test_base_unittest.js", "testCommonModulesAreAvailable");
+}
+
+TEST_F(ApiTestBaseTest, TestMojoModulesAreAvailable) {
+ RunTest("api_test_base_unittest.js", "testMojoModulesAreAvailable");
+}
+
+TEST_F(ApiTestBaseTest, TestTestBindings) {
+ RunTest("api_test_base_unittest.js", "testTestBindings");
+}
+
+} // namespace extensions
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index be09e31..a00e7d6 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -75,7 +75,9 @@
#include "extensions/renderer/user_gestures_native_handler.h"
#include "extensions/renderer/utils_native_handler.h"
#include "extensions/renderer/v8_context_native_handler.h"
+#include "grit/content_resources.h"
#include "grit/extensions_renderer_resources.h"
+#include "mojo/public/js/bindings/constants.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebCustomElement.h"
@@ -457,6 +459,149 @@ void Dispatcher::ClearPortData(int port_id) {
port_to_tab_id_map_.erase(port_id);
}
+// static
+std::vector<std::pair<std::string, int> > Dispatcher::GetJsResources() {
+ std::vector<std::pair<std::string, int> > resources;
+
+ // Libraries.
+ resources.push_back(std::make_pair("entryIdManager", IDR_ENTRY_ID_MANAGER));
+ resources.push_back(std::make_pair(kEventBindings, IDR_EVENT_BINDINGS_JS));
+ resources.push_back(std::make_pair("imageUtil", IDR_IMAGE_UTIL_JS));
+ resources.push_back(std::make_pair("json_schema", IDR_JSON_SCHEMA_JS));
+ resources.push_back(std::make_pair("lastError", IDR_LAST_ERROR_JS));
+ resources.push_back(std::make_pair("messaging", IDR_MESSAGING_JS));
+ resources.push_back(
+ std::make_pair("messaging_utils", IDR_MESSAGING_UTILS_JS));
+ resources.push_back(std::make_pair(kSchemaUtils, IDR_SCHEMA_UTILS_JS));
+ resources.push_back(std::make_pair("sendRequest", IDR_SEND_REQUEST_JS));
+ resources.push_back(std::make_pair("setIcon", IDR_SET_ICON_JS));
+ resources.push_back(std::make_pair("test", IDR_TEST_CUSTOM_BINDINGS_JS));
+ resources.push_back(
+ std::make_pair("test_environment_specific_bindings",
+ IDR_BROWSER_TEST_ENVIRONMENT_SPECIFIC_BINDINGS_JS));
+ resources.push_back(std::make_pair("uncaught_exception_handler",
+ IDR_UNCAUGHT_EXCEPTION_HANDLER_JS));
+ resources.push_back(std::make_pair("unload_event", IDR_UNLOAD_EVENT_JS));
+ resources.push_back(std::make_pair("utils", IDR_UTILS_JS));
+ resources.push_back(
+ std::make_pair(mojo::kBufferModuleName, IDR_MOJO_BUFFER_JS));
+ resources.push_back(
+ std::make_pair(mojo::kCodecModuleName, IDR_MOJO_CODEC_JS));
+ resources.push_back(
+ std::make_pair(mojo::kConnectionModuleName, IDR_MOJO_CONNECTION_JS));
+ resources.push_back(
+ std::make_pair(mojo::kConnectorModuleName, IDR_MOJO_CONNECTOR_JS));
+ resources.push_back(
+ std::make_pair(mojo::kRouterModuleName, IDR_MOJO_ROUTER_JS));
+ resources.push_back(
+ std::make_pair(mojo::kUnicodeModuleName, IDR_MOJO_UNICODE_JS));
+
+ // Custom bindings.
+ resources.push_back(
+ std::make_pair("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS));
+ resources.push_back(
+ std::make_pair("contextMenus", IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS));
+ resources.push_back(
+ std::make_pair("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS));
+ resources.push_back(std::make_pair("i18n", IDR_I18N_CUSTOM_BINDINGS_JS));
+ resources.push_back(
+ std::make_pair("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS));
+ resources.push_back(
+ std::make_pair("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS));
+ resources.push_back(std::make_pair("binding", IDR_BINDING_JS));
+
+ // Custom types sources.
+ resources.push_back(std::make_pair("StorageArea", IDR_STORAGE_AREA_JS));
+
+ // Platform app sources that are not API-specific..
+ resources.push_back(std::make_pair("platformApp", IDR_PLATFORM_APP_JS));
+
+ return resources;
+}
+
+// NOTE: please use the naming convention "foo_natives" for these.
+// static
+void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
+ ScriptContext* context,
+ Dispatcher* dispatcher,
+ RequestSender* request_sender,
+ V8SchemaRegistry* v8_schema_registry) {
+ module_system->RegisterNativeHandler(
+ "chrome", scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "lazy_background_page",
+ scoped_ptr<NativeHandler>(new LazyBackgroundPageNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "logging", scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
+ module_system->RegisterNativeHandler("schema_registry",
+ v8_schema_registry->AsNativeHandler());
+ module_system->RegisterNativeHandler(
+ "print", scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "test_features",
+ scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "user_gestures",
+ scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "utils", scoped_ptr<NativeHandler>(new UtilsNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "v8_context",
+ scoped_ptr<NativeHandler>(
+ new V8ContextNativeHandler(context, dispatcher)));
+ module_system->RegisterNativeHandler(
+ "event_natives",
+ scoped_ptr<NativeHandler>(new EventBindings(dispatcher, context)));
+ module_system->RegisterNativeHandler(
+ "messaging_natives",
+ scoped_ptr<NativeHandler>(MessagingBindings::Get(dispatcher, context)));
+ module_system->RegisterNativeHandler(
+ "apiDefinitions",
+ scoped_ptr<NativeHandler>(
+ new ApiDefinitionsNatives(dispatcher, context)));
+ module_system->RegisterNativeHandler(
+ "sendRequest",
+ scoped_ptr<NativeHandler>(
+ new SendRequestNatives(request_sender, context)));
+ module_system->RegisterNativeHandler(
+ "setIcon",
+ scoped_ptr<NativeHandler>(new SetIconNatives(request_sender, context)));
+ module_system->RegisterNativeHandler(
+ "activityLogger",
+ scoped_ptr<NativeHandler>(new APIActivityLogger(context)));
+ module_system->RegisterNativeHandler(
+ "renderViewObserverNatives",
+ scoped_ptr<NativeHandler>(new RenderViewObserverNatives(context)));
+
+ // Natives used by multiple APIs.
+ module_system->RegisterNativeHandler(
+ "file_system_natives",
+ scoped_ptr<NativeHandler>(new FileSystemNatives(context)));
+
+ // Custom bindings.
+ module_system->RegisterNativeHandler(
+ "app_runtime",
+ scoped_ptr<NativeHandler>(new AppRuntimeCustomBindings(context)));
+ module_system->RegisterNativeHandler(
+ "blob_natives",
+ scoped_ptr<NativeHandler>(new BlobNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "context_menus",
+ scoped_ptr<NativeHandler>(new ContextMenusCustomBindings(context)));
+ module_system->RegisterNativeHandler(
+ "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context)));
+ module_system->RegisterNativeHandler(
+ "document_natives",
+ scoped_ptr<NativeHandler>(new DocumentCustomBindings(context)));
+ module_system->RegisterNativeHandler(
+ "i18n", scoped_ptr<NativeHandler>(new I18NCustomBindings(context)));
+ module_system->RegisterNativeHandler(
+ "id_generator",
+ scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(context)));
+ module_system->RegisterNativeHandler(
+ "runtime", scoped_ptr<NativeHandler>(new RuntimeCustomBindings(context)));
+}
+
bool Dispatcher::OnControlMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(Dispatcher, message)
@@ -962,29 +1107,11 @@ void Dispatcher::RegisterBinding(const std::string& api_name,
// NOTE: please use the naming convention "foo_natives" for these.
void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
ScriptContext* context) {
- module_system->RegisterNativeHandler(
- "chrome", scoped_ptr<NativeHandler>(new ChromeNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "lazy_background_page",
- scoped_ptr<NativeHandler>(new LazyBackgroundPageNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "logging", scoped_ptr<NativeHandler>(new LoggingNativeHandler(context)));
- module_system->RegisterNativeHandler("schema_registry",
- v8_schema_registry_->AsNativeHandler());
- module_system->RegisterNativeHandler(
- "print", scoped_ptr<NativeHandler>(new PrintNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "test_features",
- scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "user_gestures",
- scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "utils", scoped_ptr<NativeHandler>(new UtilsNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "v8_context",
- scoped_ptr<NativeHandler>(new V8ContextNativeHandler(context, this)));
-
+ RegisterNativeHandlers(module_system,
+ context,
+ this,
+ request_sender_.get(),
+ v8_schema_registry_.get());
const Extension* extension = context->extension();
int manifest_version = extension ? extension->manifest_version() : 1;
bool send_request_disabled =
@@ -1000,95 +1127,17 @@ void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
manifest_version,
send_request_disabled)));
- module_system->RegisterNativeHandler(
- "event_natives",
- scoped_ptr<NativeHandler>(new EventBindings(this, context)));
- module_system->RegisterNativeHandler(
- "messaging_natives",
- scoped_ptr<NativeHandler>(MessagingBindings::Get(this, context)));
- module_system->RegisterNativeHandler(
- "apiDefinitions",
- scoped_ptr<NativeHandler>(new ApiDefinitionsNatives(this, context)));
- module_system->RegisterNativeHandler(
- "sendRequest",
- scoped_ptr<NativeHandler>(
- new SendRequestNatives(request_sender_.get(), context)));
- module_system->RegisterNativeHandler(
- "setIcon",
- scoped_ptr<NativeHandler>(
- new SetIconNatives(request_sender_.get(), context)));
- module_system->RegisterNativeHandler(
- "activityLogger",
- scoped_ptr<NativeHandler>(new APIActivityLogger(context)));
- module_system->RegisterNativeHandler(
- "renderViewObserverNatives",
- scoped_ptr<NativeHandler>(new RenderViewObserverNatives(context)));
-
- // Natives used by multiple APIs.
- module_system->RegisterNativeHandler(
- "file_system_natives",
- scoped_ptr<NativeHandler>(new FileSystemNatives(context)));
-
- // Custom bindings.
- module_system->RegisterNativeHandler(
- "app_runtime",
- scoped_ptr<NativeHandler>(new AppRuntimeCustomBindings(context)));
- module_system->RegisterNativeHandler(
- "blob_natives",
- scoped_ptr<NativeHandler>(new BlobNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "context_menus",
- scoped_ptr<NativeHandler>(new ContextMenusCustomBindings(context)));
- module_system->RegisterNativeHandler(
- "css_natives", scoped_ptr<NativeHandler>(new CssNativeHandler(context)));
- module_system->RegisterNativeHandler(
- "document_natives",
- scoped_ptr<NativeHandler>(new DocumentCustomBindings(context)));
- module_system->RegisterNativeHandler(
- "i18n", scoped_ptr<NativeHandler>(new I18NCustomBindings(context)));
- module_system->RegisterNativeHandler(
- "id_generator",
- scoped_ptr<NativeHandler>(new IdGeneratorCustomBindings(context)));
- module_system->RegisterNativeHandler(
- "runtime", scoped_ptr<NativeHandler>(new RuntimeCustomBindings(context)));
-
delegate_->RegisterNativeHandlers(this, module_system, context);
}
void Dispatcher::PopulateSourceMap() {
- // Libraries.
- source_map_.RegisterSource("entryIdManager", IDR_ENTRY_ID_MANAGER);
- source_map_.RegisterSource(kEventBindings, IDR_EVENT_BINDINGS_JS);
- source_map_.RegisterSource("imageUtil", IDR_IMAGE_UTIL_JS);
- source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
- source_map_.RegisterSource("lastError", IDR_LAST_ERROR_JS);
- source_map_.RegisterSource("messaging", IDR_MESSAGING_JS);
- source_map_.RegisterSource("messaging_utils", IDR_MESSAGING_UTILS_JS);
- source_map_.RegisterSource(kSchemaUtils, IDR_SCHEMA_UTILS_JS);
- source_map_.RegisterSource("sendRequest", IDR_SEND_REQUEST_JS);
- source_map_.RegisterSource("setIcon", IDR_SET_ICON_JS);
- source_map_.RegisterSource("test", IDR_TEST_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("uncaught_exception_handler",
- IDR_UNCAUGHT_EXCEPTION_HANDLER_JS);
- source_map_.RegisterSource("unload_event", IDR_UNLOAD_EVENT_JS);
- source_map_.RegisterSource("utils", IDR_UTILS_JS);
-
- // Custom bindings.
- source_map_.RegisterSource("app.runtime", IDR_APP_RUNTIME_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("contextMenus",
- IDR_CONTEXT_MENUS_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("extension", IDR_EXTENSION_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("i18n", IDR_I18N_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("permissions", IDR_PERMISSIONS_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS);
- source_map_.RegisterSource("binding", IDR_BINDING_JS);
-
- // Custom types sources.
- source_map_.RegisterSource("StorageArea", IDR_STORAGE_AREA_JS);
-
- // Platform app sources that are not API-specific..
- source_map_.RegisterSource("platformApp", IDR_PLATFORM_APP_JS);
-
+ const std::vector<std::pair<std::string, int> > resources = GetJsResources();
+ for (std::vector<std::pair<std::string, int> >::const_iterator resource =
+ resources.begin();
+ resource != resources.end();
+ ++resource) {
+ source_map_.RegisterSource(resource->first, resource->second);
+ }
delegate_->PopulateSourceMap(&source_map_);
}
diff --git a/extensions/renderer/dispatcher.h b/extensions/renderer/dispatcher.h
index b6a630d..a0308a1 100644
--- a/extensions/renderer/dispatcher.h
+++ b/extensions/renderer/dispatcher.h
@@ -8,6 +8,7 @@
#include <map>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "base/scoped_observer.h"
@@ -136,6 +137,15 @@ class Dispatcher : public content::RenderProcessObserver,
void ClearPortData(int port_id);
+ // Returns a list of (module name, resource id) pairs for the JS modules to
+ // add to the source map.
+ static std::vector<std::pair<std::string, int> > GetJsResources();
+ static void RegisterNativeHandlers(ModuleSystem* module_system,
+ ScriptContext* context,
+ Dispatcher* dispatcher,
+ RequestSender* request_sender,
+ V8SchemaRegistry* v8_schema_registry);
+
private:
friend class ::ChromeRenderViewTest;
FRIEND_TEST_ALL_PREFIXES(RendererPermissionsPolicyDelegateTest,
diff --git a/extensions/renderer/module_system.cc b/extensions/renderer/module_system.cc
index ab265fa..1f33764 100644
--- a/extensions/renderer/module_system.cc
+++ b/extensions/renderer/module_system.cc
@@ -230,9 +230,10 @@ v8::Local<v8::Value> ModuleSystem::RequireForJsInner(
v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
const std::string& module_name,
const std::string& method_name) {
- v8::HandleScope handle_scope(GetIsolate());
+ v8::EscapableHandleScope handle_scope(GetIsolate());
v8::Handle<v8::Value> no_args;
- return CallModuleMethod(module_name, method_name, 0, &no_args);
+ return handle_scope.Escape(
+ CallModuleMethod(module_name, method_name, 0, &no_args));
}
v8::Local<v8::Value> ModuleSystem::CallModuleMethod(
diff --git a/extensions/renderer/module_system_test.cc b/extensions/renderer/module_system_test.cc
index 72f1dbb..4f4675e 100644
--- a/extensions/renderer/module_system_test.cc
+++ b/extensions/renderer/module_system_test.cc
@@ -131,7 +131,7 @@ ModuleSystemTestEnvironment::ModuleSystemTestEnvironment(v8::Isolate* isolate)
context_.reset(new ScriptContext(context_holder_->context(),
NULL, // WebFrame
NULL, // Extension
- Feature::UNSPECIFIED_CONTEXT));
+ Feature::BLESSED_EXTENSION_CONTEXT));
context_->v8_context()->Enter();
assert_natives_ = new AssertNatives(context_.get());
diff --git a/extensions/renderer/resources/browser_test_environment_specific_bindings.js b/extensions/renderer/resources/browser_test_environment_specific_bindings.js
new file mode 100644
index 0000000..f540862
--- /dev/null
+++ b/extensions/renderer/resources/browser_test_environment_specific_bindings.js
@@ -0,0 +1,15 @@
+// Copyright 2014 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.
+
+function registerHooks(api) {
+}
+
+function testDone(runNextTest) {
+ // Use setTimeout here to allow previous test contexts to be
+ // eligible for garbage collection.
+ setTimeout(runNextTest, 0);
+}
+
+exports.registerHooks = registerHooks;
+exports.testDone = testDone;
diff --git a/extensions/renderer/resources/extensions_renderer_resources.grd b/extensions/renderer/resources/extensions_renderer_resources.grd
index 1b5742e..a2c0283 100644
--- a/extensions/renderer/resources/extensions_renderer_resources.grd
+++ b/extensions/renderer/resources/extensions_renderer_resources.grd
@@ -19,6 +19,7 @@
<include name="IDR_SCHEMA_UTILS_JS" file="schema_utils.js" type="BINDATA" />
<include name="IDR_SEND_REQUEST_JS" file="send_request.js" type="BINDATA" />
<include name="IDR_SET_ICON_JS" file="set_icon.js" type="BINDATA" />
+ <include name="IDR_BROWSER_TEST_ENVIRONMENT_SPECIFIC_BINDINGS_JS" file="browser_test_environment_specific_bindings.js" type="BINDATA" />
<include name="IDR_TEST_CUSTOM_BINDINGS_JS" file="test_custom_bindings.js" type="BINDATA" />
<include name="IDR_UNCAUGHT_EXCEPTION_HANDLER_JS" file="uncaught_exception_handler.js" type="BINDATA" />
<include name="IDR_UNLOAD_EVENT_JS" file="unload_event.js" type="BINDATA" />
diff --git a/extensions/renderer/resources/test_custom_bindings.js b/extensions/renderer/resources/test_custom_bindings.js
index 5fd4549..188a9c8 100644
--- a/extensions/renderer/resources/test_custom_bindings.js
+++ b/extensions/renderer/resources/test_custom_bindings.js
@@ -7,10 +7,9 @@
var binding = require('binding').Binding.create('test');
-var chrome = requireNative('chrome').GetChrome();
+var environmentSpecificBindings = require('test_environment_specific_bindings');
var GetExtensionAPIDefinitionsForTest =
requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest;
-var GetAvailability = requireNative('v8_context').GetAvailability;
var GetAPIFeatures = requireNative('test_features').GetAPIFeatures;
var uncaughtExceptionHandler = require('uncaught_exception_handler');
var userGestures = requireNative('user_gestures');
@@ -37,9 +36,7 @@ binding.registerCustomHook(function(api) {
}
function testDone() {
- // Use setTimeout here to allow previous test contexts to be
- // eligible for garbage collection.
- setTimeout(chromeTest.runNextTest, 0);
+ environmentSpecificBindings.testDone(chromeTest.runNextTest);
}
function allTestsDone() {
@@ -60,7 +57,7 @@ binding.registerCustomHook(function(api) {
return function() {
if (called != null) {
var redundantPrefix = 'Error\n';
- chrome.test.fail(
+ chromeTest.fail(
'Callback has already been run. ' +
'First call:\n' +
$String.slice(called, redundantPrefix.length) + '\n' +
@@ -355,6 +352,8 @@ binding.registerCustomHook(function(api) {
chromeTest.assertEq(typeof(callback), 'function');
uncaughtExceptionHandler.setHandler(callback);
});
+
+ environmentSpecificBindings.registerHooks(api);
});
exports.binding = binding.generate();
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index 0f40f9a..97e6c76 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -121,6 +121,8 @@ void ScriptContext::DispatchEvent(const char* event_name,
}
void ScriptContext::DispatchOnUnloadEvent() {
+ v8::HandleScope handle_scope(isolate());
+ v8::Context::Scope context_scope(v8_context());
module_system_->CallModuleMethod("unload_event", "dispatch");
}
diff --git a/extensions/test/DEPS b/extensions/test/DEPS
new file mode 100644
index 0000000..26b3ad9b
--- /dev/null
+++ b/extensions/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+mojo/embedder",
+]
diff --git a/extensions/test/data/api_test_base_unittest.js b/extensions/test/data/api_test_base_unittest.js
new file mode 100644
index 0000000..c402d59
--- /dev/null
+++ b/extensions/test/data/api_test_base_unittest.js
@@ -0,0 +1,65 @@
+// Copyright 2014 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.
+
+var test = require('test').binding;
+var unittestBindings = require('test_environment_specific_bindings');
+
+unittestBindings.exportTests([
+ function testEnvironment() {
+ test.assertTrue(!!$Array);
+ test.assertTrue(!!$Function);
+ test.assertTrue(!!$JSON);
+ test.assertTrue(!!$Object);
+ test.assertTrue(!!$RegExp);
+ test.assertTrue(!!$String);
+ test.assertTrue(!!privates);
+ test.assertTrue(!!define);
+ test.assertTrue(!!require);
+ test.assertTrue(!!requireNative);
+ test.assertTrue(!!requireAsync);
+ test.assertEq(undefined, chrome.runtime.lastError);
+ test.assertEq(undefined, chrome.extension.lastError);
+ test.succeed();
+ },
+ function testPromisesRun() {
+ Promise.resolve().then(test.callbackPass());
+ },
+ function testCommonModulesAreAvailable() {
+ var binding = require('binding');
+ var sendRequest = require('sendRequest');
+ var lastError = require('lastError');
+ test.assertTrue(!!binding);
+ test.assertTrue(!!sendRequest);
+ test.assertTrue(!!lastError);
+ test.succeed();
+ },
+ function testMojoModulesAreAvailable() {
+ Promise.all([
+ requireAsync('mojo/public/js/bindings/connection'),
+ requireAsync('mojo/public/js/bindings/core'),
+ requireAsync('content/public/renderer/service_provider'),
+ ]).then(test.callback(function(modules) {
+ var connection = modules[0];
+ var core = modules[1];
+ var serviceProvider = modules[2];
+ test.assertTrue(!!connection.Connection);
+ test.assertTrue(!!core.createMessagePipe);
+ test.assertTrue(!!serviceProvider.connectToService);
+ }));
+ },
+ function testTestBindings() {
+ var counter = 0;
+ function increment() {
+ counter++;
+ }
+ test.runWithUserGesture(increment);
+ test.runWithoutUserGesture(increment);
+ test.runWithModuleSystem(increment);
+ test.assertEq(3, counter);
+ test.assertFalse(test.isProcessingUserGesture());
+ test.assertTrue(!!test.getApiFeatures());
+ test.assertEq(0, test.getApiDefinitions().length);
+ test.succeed();
+ }
+], test.runTests, exports);
diff --git a/extensions/test/data/unit_test_environment_specific_bindings.js b/extensions/test/data/unit_test_environment_specific_bindings.js
new file mode 100644
index 0000000..245d050
--- /dev/null
+++ b/extensions/test/data/unit_test_environment_specific_bindings.js
@@ -0,0 +1,50 @@
+// Copyright 2014 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.
+
+var nativesPromise = requireAsync('testNatives');
+
+function registerHooks(api) {
+ var chromeTest = api.compiledApi;
+ var apiFunctions = api.apiFunctions;
+
+ apiFunctions.setHandleRequest('notifyPass', function() {
+ nativesPromise.then(function(natives) {
+ natives.NotifyPass();
+ });
+ });
+
+ apiFunctions.setHandleRequest('notifyFail', function(message) {
+ nativesPromise.then(function(natives) {
+ natives.NotifyFail(message);
+ });
+ });
+
+ apiFunctions.setHandleRequest('log', function() {
+ nativesPromise.then(function(natives) {
+ natives.Log($Array.join(arguments, ' '));
+ });
+ });
+
+}
+
+function testDone(runNextTest) {
+ // Use a promise here to allow previous test contexts to be eligible for
+ // garbage collection.
+ Promise.resolve().then(function() {
+ runNextTest();
+ });
+}
+
+function exportTests(tests, runTests, exports) {
+ $Array.forEach(tests, function(test) {
+ exports[test.name] = function() {
+ runTests([test]);
+ return true;
+ }
+ });
+}
+
+exports.registerHooks = registerHooks;
+exports.testDone = testDone;
+exports.exportTests = exportTests;
diff --git a/extensions/test/extensions_unittests_main.cc b/extensions/test/extensions_unittests_main.cc
index b13ce80..be46e85 100644
--- a/extensions/test/extensions_unittests_main.cc
+++ b/extensions/test/extensions_unittests_main.cc
@@ -13,6 +13,7 @@
#include "extensions/common/constants.h"
#include "extensions/common/extension_paths.h"
#include "extensions/test/test_extensions_client.h"
+#include "mojo/embedder/embedder.h"
#include "ui/base/resource/resource_bundle.h"
namespace {
@@ -96,6 +97,7 @@ void ExtensionsTestSuite::Shutdown() {
int main(int argc, char** argv) {
content::UnitTestTestSuite test_suite(new ExtensionsTestSuite(argc, argv));
+ mojo::embedder::Init();
return base::LaunchUnitTests(argc,
argv,
base::Bind(&content::UnitTestTestSuite::Run,
diff --git a/extensions/test/test_extensions_client.cc b/extensions/test/test_extensions_client.cc
index 8cee49a..47a6a47 100644
--- a/extensions/test/test_extensions_client.cc
+++ b/extensions/test/test_extensions_client.cc
@@ -4,15 +4,30 @@
#include "extensions/test/test_extensions_client.h"
+#include "extensions/common/api/generated_schemas.h"
#include "extensions/common/common_manifest_handlers.h"
+#include "extensions/common/features/api_feature.h"
+#include "extensions/common/features/base_feature_provider.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/features/json_feature_provider_source.h"
+#include "extensions/common/features/manifest_feature.h"
+#include "extensions/common/features/permission_feature.h"
#include "extensions/common/manifest_handler.h"
#include "extensions/common/url_pattern_set.h"
#include "extensions/test/test_permission_message_provider.h"
+#include "grit/extensions_resources.h"
namespace extensions {
+namespace {
+
+template <class FeatureClass>
+SimpleFeature* CreateFeature() {
+ return new FeatureClass;
+}
+
+} // namespace
+
TestExtensionsClient::TestExtensionsClient() {
}
@@ -34,17 +49,42 @@ TestExtensionsClient::GetPermissionMessageProvider() const {
return provider;
}
-// TODO(yoz): Implement something reasonable here.
scoped_ptr<FeatureProvider> TestExtensionsClient::CreateFeatureProvider(
const std::string& name) const {
- return scoped_ptr<FeatureProvider>();
+ scoped_ptr<FeatureProvider> provider;
+ scoped_ptr<JSONFeatureProviderSource> source(
+ CreateFeatureProviderSource(name));
+ if (name == "api") {
+ provider.reset(new BaseFeatureProvider(source->dictionary(),
+ CreateFeature<APIFeature>));
+ } else if (name == "manifest") {
+ provider.reset(new BaseFeatureProvider(source->dictionary(),
+ CreateFeature<ManifestFeature>));
+ } else if (name == "permission") {
+ provider.reset(new BaseFeatureProvider(source->dictionary(),
+ CreateFeature<PermissionFeature>));
+ } else {
+ NOTREACHED();
+ }
+ return provider.Pass();
}
-// TODO(yoz): Implement something reasonable here.
scoped_ptr<JSONFeatureProviderSource>
TestExtensionsClient::CreateFeatureProviderSource(
const std::string& name) const {
- return scoped_ptr<JSONFeatureProviderSource>();
+ scoped_ptr<JSONFeatureProviderSource> source(
+ new JSONFeatureProviderSource(name));
+ if (name == "api") {
+ source->LoadJSON(IDR_EXTENSION_API_FEATURES);
+ } else if (name == "manifest") {
+ source->LoadJSON(IDR_EXTENSION_MANIFEST_FEATURES);
+ } else if (name == "permission") {
+ source->LoadJSON(IDR_EXTENSION_PERMISSION_FEATURES);
+ } else {
+ NOTREACHED();
+ source.reset();
+ }
+ return source.Pass();
}
void TestExtensionsClient::FilterHostPermissions(
@@ -77,12 +117,12 @@ bool TestExtensionsClient::IsScriptableURL(const GURL& url,
bool TestExtensionsClient::IsAPISchemaGenerated(
const std::string& name) const {
- return false;
+ return core_api::GeneratedSchemas::IsGenerated(name);
}
base::StringPiece TestExtensionsClient::GetAPISchema(
const std::string& name) const {
- return base::StringPiece();
+ return core_api::GeneratedSchemas::Get(name);
}
void TestExtensionsClient::RegisterAPISchemaResources(ExtensionAPI* api) const {