summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/extensions
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 06:10:31 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-14 06:10:31 +0000
commitad23b99078f3db28bf5e88821cadc2d5effac52b (patch)
tree0df04a0908e71c383853e71f7586c381cbc4b9c8 /chrome/renderer/extensions
parent0c9366d5f357759e3bd968a267b6eb1100e5835c (diff)
downloadchromium_src-ad23b99078f3db28bf5e88821cadc2d5effac52b.zip
chromium_src-ad23b99078f3db28bf5e88821cadc2d5effac52b.tar.gz
chromium_src-ad23b99078f3db28bf5e88821cadc2d5effac52b.tar.bz2
Add JsonSchema-based validation for the tab APIs.
Arv: can you take json_schema.js and json_schema_test.js. Matt: you take the rest. Review URL: http://codereview.chromium.org/66006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13649 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/extensions')
-rwxr-xr-xchrome/renderer/extensions/extension_api_client_unittest.cc186
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc9
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.h51
-rwxr-xr-xchrome/renderer/extensions/json_schema_unittest.cc84
4 files changed, 302 insertions, 28 deletions
diff --git a/chrome/renderer/extensions/extension_api_client_unittest.cc b/chrome/renderer/extensions/extension_api_client_unittest.cc
new file mode 100755
index 0000000..1c3530f
--- /dev/null
+++ b/chrome/renderer/extensions/extension_api_client_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2009 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/common/render_messages.h"
+#include "chrome/renderer/extensions/extension_process_bindings.h"
+#include "chrome/renderer/extensions/renderer_extension_bindings.h"
+#include "chrome/test/render_view_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ExtensionAPIClientTest : public RenderViewTest {
+ protected:
+ virtual void SetUp() {
+ RenderViewTest::SetUp();
+
+ render_thread_.sink().ClearMessages();
+ LoadHTML("<body></body>");
+ }
+
+ std::string GetConsoleMessage() {
+ const IPC::Message* message =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_AddMessageToConsole::ID);
+ ViewHostMsg_AddMessageToConsole::Param params;
+ if (message) {
+ ViewHostMsg_AddMessageToConsole::Read(message, &params);
+ render_thread_.sink().ClearMessages();
+ return WideToASCII(params.a);
+ } else {
+ return "";
+ }
+ }
+
+ void ExpectJsFail(const std::string& js, const std::string& message) {
+ ExecuteJavaScript(js.c_str());
+ EXPECT_EQ(message, GetConsoleMessage());
+ }
+};
+
+// Tests that callback dispatching works correctly and that JSON is properly
+// deserialized before handing off to the extension code. We use the createTab
+// API here, but we could use any of them since they all dispatch callbacks the
+// same way.
+TEST_F(ExtensionAPIClientTest, CallbackDispatching) {
+ ExecuteJavaScript(
+ "function assert(truth, message) {"
+ " if (!truth) {"
+ " throw new Error(message);"
+ " }"
+ "}"
+ "function callback(result) {"
+ " assert(typeof result == 'object', 'result not object');"
+ " assert(goog.json.serialize(result) == '{\"foo\":\"bar\"}', "
+ " 'incorrect result');"
+ " console.log('pass')"
+ "}"
+ "chromium.tabs.createTab({}, callback);"
+ );
+
+ // Ok, we should have gotten a message to create a tab, grab the callback ID.
+ const IPC::Message* request_msg =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_ExtensionRequest::ID);
+ ASSERT_TRUE(request_msg);
+ ViewHostMsg_ExtensionRequest::Param params;
+ ViewHostMsg_ExtensionRequest::Read(request_msg, &params);
+ int callback_id = params.c;
+ ASSERT_TRUE(callback_id >= 0);
+
+ // Now send the callback a response
+ ExtensionProcessBindings::ExecuteCallbackInFrame(
+ GetMainFrame(), callback_id, "{\"foo\":\"bar\"}");
+
+ // And verify that it worked
+ ASSERT_EQ("pass", GetConsoleMessage());
+}
+
+// The remainder of these tests exercise the client side of the various
+// extension functions. We test both error and success conditions, but do not
+// test errors exhaustively as json schema code is well tested by itself.
+
+TEST_F(ExtensionAPIClientTest, GetTabsForWindow) {
+ ExpectJsFail("chromium.tabs.getTabsForWindow(42, function(){});",
+ "Uncaught Error: Too many arguments.");
+
+ ExecuteJavaScript("chromium.tabs.getTabsForWindow(function(){})");
+ const IPC::Message* request_msg =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_ExtensionRequest::ID);
+ ASSERT_TRUE(request_msg);
+ ViewHostMsg_ExtensionRequest::Param params;
+ ViewHostMsg_ExtensionRequest::Read(request_msg, &params);
+ ASSERT_EQ("GetTabsForWindow", params.a);
+ ASSERT_EQ("null", params.b);
+}
+
+TEST_F(ExtensionAPIClientTest, GetTab) {
+ ExpectJsFail("chromium.tabs.getTab(null, function(){});",
+ "Uncaught Error: Argument 0 is required.");
+
+ ExecuteJavaScript("chromium.tabs.getTab(42)");
+ const IPC::Message* request_msg =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_ExtensionRequest::ID);
+ ASSERT_TRUE(request_msg);
+ ViewHostMsg_ExtensionRequest::Param params;
+ ViewHostMsg_ExtensionRequest::Read(request_msg, &params);
+ ASSERT_EQ("GetTab", params.a);
+ ASSERT_EQ("42", params.b);
+}
+
+TEST_F(ExtensionAPIClientTest, CreateTab) {
+ ExpectJsFail("chromium.tabs.createTab({windowId: 'foo'}, function(){});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'windowId': Expected 'integer' but got 'string'.");
+ ExpectJsFail("chromium.tabs.createTab({url: 42}, function(){});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'url': Expected 'string' but got 'integer'.");
+ ExpectJsFail("chromium.tabs.createTab({selected: null}, function(){});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'selected': Expected 'boolean' but got 'null'.");
+
+ ExecuteJavaScript("chromium.tabs.createTab({"
+ " url:'http://www.google.com/',"
+ " selected:true,"
+ " windowId:4"
+ "})");
+ const IPC::Message* request_msg =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_ExtensionRequest::ID);
+ ASSERT_TRUE(request_msg);
+ ViewHostMsg_ExtensionRequest::Param params;
+ ViewHostMsg_ExtensionRequest::Read(request_msg, &params);
+ ASSERT_EQ("CreateTab", params.a);
+ ASSERT_EQ("{\"url\":\"http://www.google.com/\","
+ "\"selected\":true,"
+ "\"windowId\":4}", params.b);
+}
+
+TEST_F(ExtensionAPIClientTest, UpdateTab) {
+ ExpectJsFail("chromium.tabs.updateTab({id: null});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'id': Expected 'integer' but got 'null'.");
+ ExpectJsFail("chromium.tabs.updateTab({id: 42, windowId: 'foo'});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'windowId': Expected 'integer' but got 'string'.");
+ ExpectJsFail("chromium.tabs.updateTab({id: 42, url: 42});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'url': Expected 'string' but got 'integer'.");
+ ExpectJsFail("chromium.tabs.updateTab({id: 42, selected: null});",
+ "Uncaught Error: Invalid value for argument 0. Property "
+ "'selected': Expected 'boolean' but got 'null'.");
+
+ ExecuteJavaScript("chromium.tabs.updateTab({"
+ " id:42,"
+ " url:'http://www.google.com/',"
+ " selected:true,"
+ " windowId:4"
+ "})");
+ const IPC::Message* request_msg =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_ExtensionRequest::ID);
+ ASSERT_TRUE(request_msg);
+ ViewHostMsg_ExtensionRequest::Param params;
+ ViewHostMsg_ExtensionRequest::Read(request_msg, &params);
+ ASSERT_EQ("UpdateTab", params.a);
+ ASSERT_EQ("{\"id\":42,"
+ "\"url\":\"http://www.google.com/\","
+ "\"selected\":true,"
+ "\"windowId\":4}", params.b);
+}
+
+TEST_F(ExtensionAPIClientTest, RemoveTab) {
+ ExpectJsFail("chromium.tabs.removeTab('foobar', function(){});",
+ "Uncaught Error: Too many arguments.");
+
+ ExecuteJavaScript("chromium.tabs.removeTab(21)");
+ const IPC::Message* request_msg =
+ render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_ExtensionRequest::ID);
+ ASSERT_TRUE(request_msg);
+ ViewHostMsg_ExtensionRequest::Param params;
+ ViewHostMsg_ExtensionRequest::Read(request_msg, &params);
+ ASSERT_EQ("RemoveTab", params.a);
+ ASSERT_EQ("21", params.b);
+}
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
index 2d8f3db..4bc4409 100644
--- a/chrome/renderer/extensions/extension_process_bindings.cc
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -18,14 +18,17 @@ using WebKit::WebString;
namespace {
const char kExtensionName[] = "chrome/ExtensionProcessBindings";
-const char* kExtensionDeps[] = { JsonJsV8Extension::kName };
+const char* kDeps[] = {
+ BaseJsV8Extension::kName,
+ JsonJsV8Extension::kName,
+ JsonSchemaJsV8Extension::kName
+};
class ExtensionImpl : public v8::Extension {
public:
ExtensionImpl() : v8::Extension(
kExtensionName, GetStringResource<IDR_EXTENSION_PROCESS_BINDINGS_JS>(),
- arraysize(kExtensionDeps), kExtensionDeps) {
- }
+ arraysize(kDeps), kDeps) {}
static void SetFunctionNames(const std::vector<std::string>& names) {
function_names_ = new std::set<std::string>();
diff --git a/chrome/renderer/extensions/extension_process_bindings.h b/chrome/renderer/extensions/extension_process_bindings.h
index 8246b4b..01c335b 100644
--- a/chrome/renderer/extensions/extension_process_bindings.h
+++ b/chrome/renderer/extensions/extension_process_bindings.h
@@ -1,25 +1,26 @@
-// Copyright (c) 2009 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.
-
-// Exposes extension APIs into the extension process.
-
-#ifndef CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
-#define CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
-
-#include <string>
-#include <vector>
-
-#include "v8/include/v8.h"
-
-class WebFrame;
-
-class ExtensionProcessBindings {
- public:
- static void SetFunctionNames(const std::vector<std::string>& names);
- static v8::Extension* Get();
- static void ExecuteCallbackInFrame(WebFrame* frame, int callback_id,
- const std::string& response);
-};
-
-#endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
+// Copyright (c) 2009 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.
+
+// Exposes extension APIs into the extension process.
+
+#ifndef CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
+#define CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
+
+#include <string>
+#include <vector>
+
+#include "v8/include/v8.h"
+
+class RenderThreadBase;
+class WebFrame;
+
+class ExtensionProcessBindings {
+ public:
+ static void SetFunctionNames(const std::vector<std::string>& names);
+ static v8::Extension* Get();
+ static void ExecuteCallbackInFrame(WebFrame* frame, int callback_id,
+ const std::string& response);
+};
+
+#endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_PROCESS_BINDINGS_H_
diff --git a/chrome/renderer/extensions/json_schema_unittest.cc b/chrome/renderer/extensions/json_schema_unittest.cc
new file mode 100755
index 0000000..7df624d
--- /dev/null
+++ b/chrome/renderer/extensions/json_schema_unittest.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2009 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 "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/resource_bundle.h"
+#include "chrome/test/v8_unit_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "grit/renderer_resources.h"
+
+// TODO(port)
+#if defined(OS_WIN)
+
+static const char kJsonSchema[] = "json_schema.js";
+static const char kJsonSchemaTest[] = "json_schema_test.js";
+
+class JsonSchemaTest : public V8UnitTest {
+ public:
+ JsonSchemaTest() {}
+
+ virtual void SetUp() {
+ V8UnitTest::SetUp();
+
+ // Add the json schema code to the context.
+ StringPiece js = ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_JSON_SCHEMA_JS);
+ ExecuteScriptInContext(js, kJsonSchema);
+
+ // Add the test functions to the context.
+ std::wstring test_js_file_path;
+ ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_js_file_path));
+ file_util::AppendToPath(&test_js_file_path, L"extensions");
+ file_util::AppendToPath(&test_js_file_path, UTF8ToWide(kJsonSchemaTest));
+ std::string test_js;
+ ASSERT_TRUE(file_util::ReadFileToString(test_js_file_path, &test_js));
+ ExecuteScriptInContext(test_js, kJsonSchemaTest);
+ }
+};
+
+TEST_F(JsonSchemaTest, TestFormatError) {
+ TestFunction("testFormatError");
+}
+
+TEST_F(JsonSchemaTest, TestComplex) {
+ TestFunction("testComplex");
+}
+
+TEST_F(JsonSchemaTest, TestEnum) {
+ TestFunction("testEnum");
+}
+
+TEST_F(JsonSchemaTest, TestExtends) {
+ TestFunction("testExtends");
+}
+
+TEST_F(JsonSchemaTest, TestObject) {
+ TestFunction("testObject");
+}
+
+TEST_F(JsonSchemaTest, TestArrayTuple) {
+ TestFunction("testArrayTuple");
+}
+
+TEST_F(JsonSchemaTest, TestArrayNonTuple) {
+ TestFunction("testArrayNonTuple");
+}
+
+TEST_F(JsonSchemaTest, TestString) {
+ TestFunction("testString");
+}
+
+TEST_F(JsonSchemaTest, TestNumber) {
+ TestFunction("testNumber");
+}
+
+TEST_F(JsonSchemaTest, TestType) {
+ TestFunction("testType");
+}
+
+#endif // #if defined(OSWIN)