// 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