// Copyright (c) 2010 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/json/json_reader.h" #include "base/json/json_writer.h" #include "base/path_service.h" #include "base/string_util.h" #include "chrome/common/chrome_paths.h" #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" // Make failures easier to locate by using SCOPED_TRACE() to print out the line // number of a failing call to ExtensionAPIClientTest::ExpectJs(Pass|Fail) . // Sadly, a #define is the only reasonable way to get the line number. #define ExpectJsFail(js, expected_failure_message) { \ SCOPED_TRACE(js); \ ExpectJsFailInternal(js, expected_failure_message); \ } #define ExpectJsPass(js, function, arg1) { \ SCOPED_TRACE(js); \ ExpectJsPassInternal(js, function, arg1); \ } class ExtensionAPIClientTest : public RenderViewTest { protected: virtual void SetUp() { RenderViewTest::SetUp(); render_thread_.SetExtensionProcess(true); render_thread_.sink().ClearMessages(); LoadHTML(""); } std::string GetConsoleMessage() { const IPC::Message* message = render_thread_.sink().GetUniqueMessageMatching( ViewHostMsg_AddMessageToConsole::ID); ViewHostMsg_AddMessageToConsole::Param params; if (message) { ViewHostMsg_AddMessageToConsole::Read(message, ¶ms); render_thread_.sink().ClearMessages(); return WideToASCII(params.a); } else { return ""; } } // Don't call this directly. Use the macro ExpectJsFail. void ExpectJsFailInternal(const std::string& js, const std::string& message) { ExecuteJavaScript(js.c_str()); EXPECT_EQ(message, GetConsoleMessage()); render_thread_.sink().ClearMessages(); } // Don't call this directly. Use the macro ExpectJsPass. void ExpectJsPassInternal(const std::string& js, const std::string& function, const std::string& arg1) { ExecuteJavaScript(js.c_str()); const IPC::Message* request_msg = render_thread_.sink().GetUniqueMessageMatching( ViewHostMsg_ExtensionRequest::ID); ASSERT_EQ("", GetConsoleMessage()) << js; ASSERT_TRUE(request_msg) << js; ViewHostMsg_ExtensionRequest::Param params; ViewHostMsg_ExtensionRequest::Read(request_msg, ¶ms); ASSERT_EQ(function.c_str(), params.a) << js; ASSERT_TRUE(params.b.IsType(Value::TYPE_LIST)); ListValue* args = ¶ms.b; base::JSONReader reader; scoped_ptr arg1_value(reader.JsonToValue(arg1, false, false)); ASSERT_TRUE(arg1_value.get()) << "Failed to parse expected result as JSON: " << arg1; std::string args_as_string; base::JSONWriter::Write(args, false, &args_as_string); ASSERT_TRUE(args->Equals(arg1_value.get())) << js << "\n Expected "<< arg1 << "\n Actual: "<< args_as_string; render_thread_.sink().ClearMessages(); } }; // 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(JSON.stringify(result) == '{\"id\":1,\"index\":1,\"windowId\":1," "\"selected\":true,\"incognito\":false," "\"url\":\"http://www.google.com/\"}'," " 'incorrect result');" " console.log('pass')" "}" "chrome.tabs.create({}, callback);" ); EXPECT_EQ("", GetConsoleMessage()); // 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, ¶ms); int callback_id = params.d; ASSERT_GE(callback_id, 0); // Now send the callback a response ExtensionProcessBindings::HandleResponse( callback_id, true, "{\"id\":1,\"index\":1,\"windowId\":1,\"selected\":true," "\"incognito\":false,\"url\":\"http://www.google.com/\"}", ""); // 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. // Window API tests TEST_F(ExtensionAPIClientTest, GetWindow) { ExpectJsFail("chrome.windows.get(32, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.windows.get(32);", "Uncaught Error: Parameter 1 is required."); ExpectJsFail("chrome.windows.get('abc', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.get(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsPass("chrome.windows.get(2, function(){})", "windows.get", "[2]"); } // This test flakily crashes (http://crbug.com/22248) TEST_F(ExtensionAPIClientTest, DISABLED_GetCurrentWindow) { ExpectJsFail("chrome.windows.getCurrent(function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.windows.getCurrent();", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.windows.getCurrent('abc');", "Uncaught Error: Invalid value for argument 0. " "Expected 'function' but got 'string'."); ExpectJsPass("chrome.windows.getCurrent(function(){})", "windows.getCurrent", "null"); } // This test flakily crashes (http://crbug.com/22248) TEST_F(ExtensionAPIClientTest, DISABLED_GetLastFocusedWindow) { ExpectJsFail("chrome.windows.getLastFocused(function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.windows.getLastFocused();", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.windows.getLastFocused('abc');", "Uncaught Error: Invalid value for argument 0. " "Expected 'function' but got 'string'."); ExpectJsPass("chrome.windows.getLastFocused(function(){})", "windows.getLastFocused", "null"); } // This test flakily crashes (http://crbug.com/22248) TEST_F(ExtensionAPIClientTest, DISABLED_GetAllWindows) { ExpectJsFail("chrome.windows.getAll({populate: true}, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.windows.getAll(1, function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'object' but got 'integer'."); ExpectJsPass("chrome.windows.getAll({populate:true}, function(){})", "windows.getAll", "{\"populate\":true}"); ExpectJsPass("chrome.windows.getAll(null, function(){})", "windows.getAll", "null"); ExpectJsPass("chrome.windows.getAll({}, function(){})", "windows.getAll", "{}"); ExpectJsPass("chrome.windows.getAll(undefined, function(){})", "windows.getAll", "null"); } // Flaky on Windows. http://crosbug.com/46217 #if defined(OS_WIN) #define MAYBE_CreateWindow FLAKY_CreateWindow #else #define MAYBE_CreateWindow CreateWindow #endif TEST_F(ExtensionAPIClientTest, MAYBE_CreateWindow) { ExpectJsFail("chrome.windows.create({url: 1}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'url': Expected 'string' but got 'integer'."); ExpectJsFail("chrome.windows.create({left: 'foo'}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'left': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.create({top: 'foo'}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'top': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.create({width: 'foo'}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'width': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.create({height: 'foo'}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'height': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.create({foo: 42}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'foo': Unexpected property."); ExpectJsPass("chrome.windows.create({" " url:'http://www.google.com/'," " left:0," " top: 10," " width:100," " height:200" "})", "windows.create", "[{\"url\":\"http://www.google.com/\"," "\"left\":0," "\"top\":10," "\"width\":100," "\"height\":200}]"); } TEST_F(ExtensionAPIClientTest, UpdateWindow) { ExpectJsFail("chrome.windows.update(null);", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.windows.update(42, {left: 'foo'});", "Uncaught Error: Invalid value for argument 1. Property " "'left': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.update(42, {top: 'foo'});", "Uncaught Error: Invalid value for argument 1. Property " "'top': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.update(42, {height: false});", "Uncaught Error: Invalid value for argument 1. Property " "'height': Expected 'integer' but got 'boolean'."); ExpectJsFail("chrome.windows.update(42, {width: false});", "Uncaught Error: Invalid value for argument 1. Property " "'width': Expected 'integer' but got 'boolean'."); ExpectJsFail("chrome.windows.update(42, {foo: false});", "Uncaught Error: Invalid value for argument 1. Property " "'foo': Unexpected property."); ExpectJsPass("chrome.windows.update(42, {" " width:100," " height:200" "})", "windows.update", "[42," "{\"width\":100," "\"height\":200}]"); } TEST_F(ExtensionAPIClientTest, RemoveWindow) { ExpectJsFail("chrome.windows.remove(32, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.windows.remove('abc', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.windows.remove(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsPass("chrome.windows.remove(2, function(){})", "windows.remove", "[2]"); ExpectJsPass("chrome.windows.remove(2)", "windows.remove", "[2]"); } // Tab API tests TEST_F(ExtensionAPIClientTest, GetTab) { ExpectJsFail("chrome.tabs.get(32, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.tabs.get(32);", "Uncaught Error: Parameter 1 is required."); ExpectJsFail("chrome.tabs.get('abc', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.tabs.get(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsPass("chrome.tabs.get(2, function(){})", "tabs.get", "[2]"); } TEST_F(ExtensionAPIClientTest, GetCurrentTab) { ExpectJsFail("chrome.tabs.getCurrent(function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.tabs.getCurrent();", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.tabs.getCurrent('abc');", "Uncaught Error: Invalid value for argument 0. " "Expected 'function' but got 'string'."); ExpectJsPass("chrome.tabs.getCurrent(function(){})", "tabs.getCurrent", "[]"); } TEST_F(ExtensionAPIClientTest, DetectTabLanguage) { ExpectJsFail("chrome.tabs.detectLanguage(32, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.tabs.detectLanguage('abc', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.tabs.detectLanguage(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsPass("chrome.tabs.detectLanguage(null, function(){})", "tabs.detectLanguage", "[null]"); } TEST_F(ExtensionAPIClientTest, GetSelectedTab) { ExpectJsFail("chrome.tabs.getSelected(32, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.tabs.getSelected(32);", "Uncaught Error: Parameter 1 is required."); ExpectJsFail("chrome.tabs.getSelected('abc', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.tabs.getSelected(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsPass("chrome.tabs.getSelected(2, function(){})", "tabs.getSelected", "[2]"); ExpectJsPass("chrome.tabs.getSelected(null, function(){})", "tabs.getSelected", "[null]"); } TEST_F(ExtensionAPIClientTest, GetAllTabsInWindow) { ExpectJsFail("chrome.tabs.getAllInWindow(42, function(){}, 'asd');", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.tabs.getAllInWindow(32);", "Uncaught Error: Parameter 1 is required."); ExpectJsFail("chrome.tabs.getAllInWindow(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsFail("chrome.tabs.getAllInWindow('asd', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsPass("chrome.tabs.getAllInWindow(32, function(){})", "tabs.getAllInWindow", "[32]"); ExpectJsPass("chrome.tabs.getAllInWindow(undefined, function(){})", "tabs.getAllInWindow", "[null]"); } TEST_F(ExtensionAPIClientTest, CreateTab) { ExpectJsFail("chrome.tabs.create({windowId: 'foo'}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'windowId': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.tabs.create({url: 42}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'url': Expected 'string' but got 'integer'."); ExpectJsFail("chrome.tabs.create({foo: 42}, function(){});", "Uncaught Error: Invalid value for argument 0. Property " "'foo': Unexpected property."); ExpectJsPass("chrome.tabs.create({" " url:'http://www.google.com/'," " selected:true," " index: 2," " windowId:4" "})", "tabs.create", "[{\"url\":\"http://www.google.com/\"," "\"selected\":true," "\"index\":2," "\"windowId\":4}]"); } TEST_F(ExtensionAPIClientTest, UpdateTab) { ExpectJsFail("chrome.tabs.update(null);", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.tabs.update(42, {selected: 'foo'});", "Uncaught Error: Invalid value for argument 1. Property " "'selected': Expected 'boolean' but got 'string'."); ExpectJsFail("chrome.tabs.update(42, {url: 42});", "Uncaught Error: Invalid value for argument 1. Property " "'url': Expected 'string' but got 'integer'."); ExpectJsPass("chrome.tabs.update(42, {" " url:'http://www.google.com/'," " selected:true" "})", "tabs.update", "[42," "{\"url\":\"http://www.google.com/\"," "\"selected\":true}]"); } TEST_F(ExtensionAPIClientTest, MoveTab) { ExpectJsFail("chrome.tabs.move(null);", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.tabs.move(42, {index: 'foo'});", "Uncaught Error: Invalid value for argument 1. Property " "'index': Expected 'integer' but got 'string'."); ExpectJsFail("chrome.tabs.move(42, {index: 3, windowId: 'foo'});", "Uncaught Error: Invalid value for argument 1. Property " "'windowId': Expected 'integer' but got 'string'."); ExpectJsPass("chrome.tabs.move(42, {" " index:3," " windowId:21" "})", "tabs.move", "[42," "{\"index\":3," "\"windowId\":21}]"); } TEST_F(ExtensionAPIClientTest, RemoveTab) { ExpectJsFail("chrome.tabs.remove(32, function(){}, 20);", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.tabs.remove('abc', function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.tabs.remove(1, 1);", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); ExpectJsPass("chrome.tabs.remove(2, function(){})", "tabs.remove", "[2]"); ExpectJsPass("chrome.tabs.remove(2)", "tabs.remove", "[2]"); } TEST_F(ExtensionAPIClientTest, CaptureVisibleTab) { ExpectJsFail("chrome.tabs.captureVisibleTab(0);", "Uncaught Error: Parameter 2 is required."); ExpectJsFail("chrome.tabs.captureVisibleTab(0, null);", "Uncaught Error: Parameter 2 is required."); ExpectJsFail("chrome.tabs.captureVisibleTab(null, {});", "Uncaught Error: Parameter 2 is required."); ExpectJsFail("chrome.tabs.captureVisibleTab(function(){}, 0)", "Uncaught Error: Invalid value for argument 0. " "Expected 'integer' but got 'function'."); // Use old signiture. Check that a null value of the options paramenter // is added. ExpectJsPass("chrome.tabs.captureVisibleTab(null, function(img){});", "tabs.captureVisibleTab", "[null, null]"); ExpectJsPass("chrome.tabs.captureVisibleTab(1, function(img){});", "tabs.captureVisibleTab", "[1, null]"); ExpectJsPass("chrome.tabs.captureVisibleTab(null, null, function(img){});", "tabs.captureVisibleTab", "[null, null]"); ExpectJsPass("chrome.tabs.captureVisibleTab(" "null, undefined, function(img){});", "tabs.captureVisibleTab", "[null, null]"); ExpectJsPass("chrome.tabs.captureVisibleTab(null, {}, function(img){});", "tabs.captureVisibleTab", "[null, {}]"); ExpectJsFail("chrome.tabs.captureVisibleTab(null, 42, function(img){});", "Uncaught Error: Invalid value for argument 1. " "Expected 'object' but got 'integer'."); ExpectJsPass("chrome.tabs.captureVisibleTab(" "null, {\"format\": \"jpeg\"}, function(img){});", "tabs.captureVisibleTab", "[null, {\"format\": \"jpeg\"}]"); ExpectJsPass("chrome.tabs.captureVisibleTab(" "null, {\"quality\": 100}, function(img){});", "tabs.captureVisibleTab", "[null, {\"quality\": 100}]"); ExpectJsFail("chrome.tabs.captureVisibleTab(" "null, {\"quality\": 101}, function(img){});", "Uncaught Error: Invalid value for argument 1. " "Property 'quality': Value must not be greater than 100."); ExpectJsFail("chrome.tabs.captureVisibleTab(" "null, {'not_a_param': 'jpeg'}, function(img){});", "Uncaught Error: Invalid value for argument 1. " "Property 'not_a_param': Unexpected property."); ExpectJsFail("chrome.tabs.captureVisibleTab(" "null, {'format': 'invalid'}, function(img){});", "Uncaught Error: Invalid value for argument 1. " "Property 'format': Value must be one of: [jpeg, png]."); ExpectJsFail("chrome.tabs.captureVisibleTab(" "null, {'format': 42}, function(img){});", "Uncaught Error: Invalid value for argument 1. " "Property 'format': Value must be one of: [jpeg, png]."); } // Bookmark API tests // TODO(erikkay) add more variations here TEST_F(ExtensionAPIClientTest, CreateBookmark) { ExpectJsFail( "chrome.bookmarks.create({parentId:0, title:0}, function(){})", "Uncaught Error: Invalid value for argument 0. " "Property 'parentId': Expected 'string' but got 'integer', " "Property 'title': Expected 'string' but got 'integer'."); ExpectJsPass( "chrome.bookmarks.create({parentId:'0', title:'x'}, function(){})", "bookmarks.create", "[{\"parentId\":\"0\",\"title\":\"x\"}]"); } TEST_F(ExtensionAPIClientTest, GetBookmarks) { ExpectJsPass("chrome.bookmarks.get('0', function(){});", "bookmarks.get", "[\"0\"]"); ExpectJsPass("chrome.bookmarks.get(['0','1','2','3'], function(){});", "bookmarks.get", "[[\"0\",\"1\",\"2\",\"3\"]]"); ExpectJsFail("chrome.bookmarks.get(null, function(){});", "Uncaught Error: Parameter 0 is required."); // TODO(erikkay) This is succeeding, when it should fail. // BUG=13719 #if 0 ExpectJsFail("chrome.bookmarks.get({}, function(){});", "Uncaught Error: Invalid value for argument 0. " "Expected 'array' but got 'object'."); #endif } TEST_F(ExtensionAPIClientTest, GetBookmarkChildren) { ExpectJsPass("chrome.bookmarks.getChildren('42', function(){});", "bookmarks.getChildren", "[\"42\"]"); } TEST_F(ExtensionAPIClientTest, GetBookmarkRecent) { ExpectJsPass("chrome.bookmarks.getRecent(5, function(){});", "bookmarks.getRecent", "[5]"); } TEST_F(ExtensionAPIClientTest, GetBookmarkTree) { ExpectJsPass("chrome.bookmarks.getTree(function(){});", "bookmarks.getTree", "[]"); } TEST_F(ExtensionAPIClientTest, SearchBookmarks) { ExpectJsPass("chrome.bookmarks.search('hello',function(){});", "bookmarks.search", "[\"hello\"]"); } TEST_F(ExtensionAPIClientTest, RemoveBookmark) { ExpectJsPass("chrome.bookmarks.remove('42');", "bookmarks.remove", "[\"42\"]"); } TEST_F(ExtensionAPIClientTest, RemoveBookmarkTree) { ExpectJsPass("chrome.bookmarks.removeTree('42');", "bookmarks.removeTree", "[\"42\"]"); } TEST_F(ExtensionAPIClientTest, MoveBookmark) { ExpectJsPass("chrome.bookmarks.move('42',{parentId:'1',index:0});", "bookmarks.move", "[\"42\",{\"parentId\":\"1\",\"index\":0}]"); } TEST_F(ExtensionAPIClientTest, SetBookmarkTitle) { ExpectJsPass("chrome.bookmarks.update('42',{title:'x'});", "bookmarks.update", "[\"42\",{\"title\":\"x\"}]"); } TEST_F(ExtensionAPIClientTest, EnablePageAction) { // Basic old-school enablePageAction call. ExpectJsPass("chrome.pageActions.enableForTab(" "'dummy', {tabId: 0, url: 'http://foo/'});", "pageActions.enableForTab", "[\"dummy\",{\"tabId\":0,\"url\":\"http://foo/\"}]"); // Try both optional parameters (title and iconId). ExpectJsPass("chrome.pageActions.enableForTab(" "'dummy', {tabId: 0, url: 'http://foo/'," "title: 'a', iconId: 0});", "pageActions.enableForTab", "[\"dummy\",{\"tabId\":0,\"url\":\"http://foo/\"," "\"title\":\"a\",\"iconId\":0}]"); // Now try disablePageAction. ExpectJsPass("chrome.pageActions.disableForTab(" "'dummy', {tabId: 0, url: 'http://foo/'});", "pageActions.disableForTab", "[\"dummy\",{\"tabId\":0,\"url\":\"http://foo/\"}]"); } TEST_F(ExtensionAPIClientTest, ExpandToolstrip) { ExpectJsPass("chrome.toolstrip.expand({height:100, url:'http://foo/'})", "toolstrip.expand", "[{\"height\":100,\"url\":\"http://foo/\"}]"); ExpectJsPass("chrome.toolstrip.expand({height:100}, null)", "toolstrip.expand", "[{\"height\":100}]"); ExpectJsPass("chrome.toolstrip.expand({height:100,url:'http://foo/'}, " "function(){})", "toolstrip.expand", "[{\"height\":100,\"url\":\"http://foo/\"}]"); ExpectJsFail("chrome.toolstrip.expand()", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.toolstrip.expand(1)", "Uncaught Error: Invalid value for argument 0. " "Expected 'object' but got 'integer'."); ExpectJsFail("chrome.toolstrip.expand({height:'100', url:'http://foo/'})", "Uncaught Error: Invalid value for argument 0. " "Property 'height': " "Expected 'integer' but got 'string'."); ExpectJsFail("chrome.toolstrip.expand({height:100,url:100})", "Uncaught Error: Invalid value for argument 0. Property 'url': " "Expected 'string' but got 'integer'."); ExpectJsFail("chrome.toolstrip.expand({height:100,'url':'http://foo/'}, 32)", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); } TEST_F(ExtensionAPIClientTest, CollapseToolstrip) { ExpectJsPass("chrome.toolstrip.collapse({url:'http://foo/'})", "toolstrip.collapse", "[{\"url\":\"http://foo/\"}]"); ExpectJsPass("chrome.toolstrip.collapse(null)", "toolstrip.collapse", "[null]"); ExpectJsPass("chrome.toolstrip.collapse({url:'http://foo/'}, function(){})", "toolstrip.collapse", "[{\"url\":\"http://foo/\"}]"); ExpectJsFail("chrome.toolstrip.collapse(1)", "Uncaught Error: Invalid value for argument 0. " "Expected 'object' but got 'integer'."); ExpectJsFail("chrome.toolstrip.collapse(100)", "Uncaught Error: Invalid value for argument 0. " "Expected 'object' but got 'integer'."); ExpectJsFail("chrome.toolstrip.collapse({url:'http://foo/'}, 32)", "Uncaught Error: Invalid value for argument 1. " "Expected 'function' but got 'integer'."); } // I18N API TEST_F(ExtensionAPIClientTest, GetAcceptLanguages) { ExpectJsFail("chrome.i18n.getAcceptLanguages(32, function(){})", "Uncaught Error: Too many arguments."); ExpectJsFail("chrome.i18n.getAcceptLanguages()", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.i18n.getAcceptLanguages('abc')", "Uncaught Error: Invalid value for argument 0. " "Expected 'function' but got 'string'."); ExpectJsPass("chrome.i18n.getAcceptLanguages(function(){})", "i18n.getAcceptLanguages", "[]"); } // TODO(cira): re-enable when we get validation going for // renderer_process_bindings.js TEST_F(ExtensionAPIClientTest, DISABLED_GetL10nMessage) { ExpectJsFail("chrome.i18n.getMessage()", "Uncaught Error: Parameter 0 is required."); ExpectJsFail("chrome.i18n.getMessage(1)", "Uncaught Error: Invalid value for argument 0. " "Expected 'string' but got 'integer'."); ExpectJsFail("chrome.i18n.getMessage('name', [])", "Uncaught Error: Invalid value for argument 1. Value does not " "match any valid type choices."); ExpectJsFail("chrome.i18n.getMessage('name', ['p1', 'p2', 'p3', 'p4', 'p5', " "'p6', 'p7', 'p8', 'p9', 'p10'])", "Uncaught Error: Invalid value for argument 1. Value does not " "match any valid type choices."); }