|  | // 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 "base/strings/stringprintf.h" | 
|  | #include "extensions/renderer/module_system_test.h" | 
|  | #include "grit/extensions_renderer_resources.h" | 
|  |  | 
|  | namespace extensions { | 
|  | namespace { | 
|  |  | 
|  | class MessagingUtilsUnittest : public ModuleSystemTest { | 
|  | protected: | 
|  | void RegisterTestModule(const char* code) { | 
|  | env()->RegisterModule( | 
|  | "test", | 
|  | base::StringPrintf( | 
|  | "var assert = requireNative('assert');\n" | 
|  | "var AssertTrue = assert.AssertTrue;\n" | 
|  | "var AssertFalse = assert.AssertFalse;\n" | 
|  | "var messagingUtils = require('messaging_utils');\n" | 
|  | "%s", | 
|  | code)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | void SetUp() override { | 
|  | ModuleSystemTest::SetUp(); | 
|  |  | 
|  | env()->RegisterModule("messaging_utils", IDR_MESSAGING_UTILS_JS); | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, TestNothing) { | 
|  | ExpectNoAssertionsMade(); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, NoArguments) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments();\n" | 
|  | "AssertTrue(args === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, ZeroArguments) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments([]);" | 
|  | "AssertTrue(args === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, TooManyArgumentsNoOptions) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments(\n" | 
|  | "    ['a', 'b', 'c', 'd']);\n" | 
|  | "AssertTrue(args === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, TooManyArgumentsWithOptions) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments(\n" | 
|  | "    ['a', 'b', 'c', 'd', 'e'], true);\n" | 
|  | "AssertTrue(args === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, FinalArgumentIsNotAFunctionNoOptions) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments(\n" | 
|  | "    ['a', 'b', 'c']);\n" | 
|  | "AssertTrue(args === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, FinalArgumentIsNotAFunctionWithOptions) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments(\n" | 
|  | "    ['a', 'b', 'c', 'd'], true);\n" | 
|  | "AssertTrue(args === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, OneStringArgument) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | // Because the request argument is required, a single argument must get | 
|  | // mapped to it rather than to the optional targetId argument. | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments(['a']);\n" | 
|  | "AssertTrue(args.length == 3);\n" | 
|  | "AssertTrue(args[0] === null);\n" | 
|  | "AssertTrue(args[1] == 'a');\n" | 
|  | "AssertTrue(args[2] === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, OneStringAndOneNullArgument) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | // Explicitly specifying null as the request is allowed. | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments(['a', null]);\n" | 
|  | "AssertTrue(args.length == 3);\n" | 
|  | "AssertTrue(args[0] == 'a');\n" | 
|  | "AssertTrue(args[1] === null);\n" | 
|  | "AssertTrue(args[2] === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, OneNullAndOneStringArgument) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | RegisterTestModule( | 
|  | "var args = messagingUtils.alignSendMessageArguments([null, 'a']);\n" | 
|  | "AssertTrue(args.length == 3);\n" | 
|  | "AssertTrue(args[0] === null);\n" | 
|  | "AssertTrue(args[1] == 'a');\n" | 
|  | "AssertTrue(args[2] === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, OneStringAndOneFunctionArgument) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | // When the arguments are a string and a function, the function is | 
|  | // unambiguously the responseCallback. Because the request argument is | 
|  | // required, the remaining argument must get mapped to it rather than to the | 
|  | // optional targetId argument. | 
|  | RegisterTestModule( | 
|  | "var cb = function() {};\n" | 
|  | "var args = messagingUtils.alignSendMessageArguments(['a', cb]);\n" | 
|  | "AssertTrue(args.length == 3);\n" | 
|  | "AssertTrue(args[0] === null);\n" | 
|  | "AssertTrue(args[1] == 'a');\n" | 
|  | "AssertTrue(args[2] == cb);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, OneStringAndOneObjectArgument) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | // This tests an ambiguous set of arguments when options are present: | 
|  | // chrome.runtime.sendMessage('target', {'msg': 'this is a message'}); | 
|  | // vs. | 
|  | // chrome.runtime.sendMessage('request', {'includeTlsChannelId': true}); | 
|  | // | 
|  | // The question is whether the string should map to the target and the | 
|  | // dictionary to the message, or whether the string should map to the message | 
|  | // and the dictionary to the options. Because the target and message arguments | 
|  | // predate the options argument, we bind the string in this case to the | 
|  | // targetId. | 
|  | RegisterTestModule( | 
|  | "var obj = {'b': true};\n" | 
|  | "var args = messagingUtils.alignSendMessageArguments(['a', obj], true);\n" | 
|  | "AssertTrue(args.length == 4);\n" | 
|  | "AssertTrue(args[0] == 'a');\n" | 
|  | "AssertTrue(args[1] == obj);\n" | 
|  | "AssertTrue(args[2] === null);\n" | 
|  | "AssertTrue(args[3] === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | TEST_F(MessagingUtilsUnittest, TwoObjectArguments) { | 
|  | ModuleSystem::NativesEnabledScope natives_enabled_scope( | 
|  | env()->module_system()); | 
|  | // When two non-string arguments are provided and options are present, the | 
|  | // two arguments must match request and options, respectively, because | 
|  | // targetId must be a string. | 
|  | RegisterTestModule( | 
|  | "var obj1 = {'a': 'foo'};\n" | 
|  | "var obj2 = {'b': 'bar'};\n" | 
|  | "var args = messagingUtils.alignSendMessageArguments(\n" | 
|  | "    [obj1, obj2], true);\n" | 
|  | "AssertTrue(args.length == 4);\n" | 
|  | "AssertTrue(args[0] === null);\n" | 
|  | "AssertTrue(args[1] == obj1);\n" | 
|  | "AssertTrue(args[2] == obj2);\n" | 
|  | "AssertTrue(args[3] === null);"); | 
|  | env()->module_system()->Require("test"); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace extensions |