| // 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/common/extension_urls.h" |
| #include "extensions/renderer/module_system_test.h" |
| #include "grit/extensions_renderer_resources.h" |
| |
| namespace extensions { |
| namespace { |
| |
| class EventUnittest : public ModuleSystemTest { |
| void SetUp() override { |
| ModuleSystemTest::SetUp(); |
| |
| env()->RegisterModule(kEventBindings, IDR_EVENT_BINDINGS_JS); |
| env()->RegisterModule("json_schema", IDR_JSON_SCHEMA_JS); |
| env()->RegisterModule(kSchemaUtils, IDR_SCHEMA_UTILS_JS); |
| env()->RegisterModule("uncaught_exception_handler", |
| IDR_UNCAUGHT_EXCEPTION_HANDLER_JS); |
| env()->RegisterModule("unload_event", IDR_UNLOAD_EVENT_JS); |
| env()->RegisterModule("utils", IDR_UTILS_JS); |
| |
| // Mock out the native handler for event_bindings. These mocks will fail if |
| // any invariants maintained by the real event_bindings are broken. |
| env()->OverrideNativeHandler( |
| "event_natives", |
| "var assert = requireNative('assert');" |
| "var attachedListeners = exports.attachedListeners = {};" |
| "var attachedFilteredListeners = " |
| " exports.attachedFilteredListeners = {};" |
| "var nextId = 0;" |
| "var idToName = {};" |
| "exports.AttachEvent = function(eventName) {" |
| " assert.AssertFalse(!!attachedListeners[eventName]);" |
| " attachedListeners[eventName] = 1;" |
| "};" |
| "exports.DetachEvent = function(eventName) {" |
| " assert.AssertTrue(!!attachedListeners[eventName]);" |
| " delete attachedListeners[eventName];" |
| "};" |
| "exports.IsEventAttached = function(eventName) {" |
| " return !!attachedListeners[eventName];" |
| "};" |
| "exports.AttachFilteredEvent = function(name, filters) {" |
| " var id = nextId++;" |
| " idToName[id] = name;" |
| " attachedFilteredListeners[name] =" |
| " attachedFilteredListeners[name] || [];" |
| " attachedFilteredListeners[name][id] = filters;" |
| " return id;" |
| "};" |
| "exports.DetachFilteredEvent = function(id, manual) {" |
| " var i = attachedFilteredListeners[idToName[id]].indexOf(id);" |
| " attachedFilteredListeners[idToName[id]].splice(i, 1);" |
| "};" |
| "exports.HasFilteredListener = function(name) {" |
| " return attachedFilteredListeners[name].length;" |
| "};"); |
| env()->OverrideNativeHandler("sendRequest", |
| "exports.sendRequest = function() {};"); |
| env()->OverrideNativeHandler( |
| "apiDefinitions", |
| "exports.GetExtensionAPIDefinitionsForTest = function() {};"); |
| env()->OverrideNativeHandler("logging", "exports.DCHECK = function() {};"); |
| env()->OverrideNativeHandler("schema_registry", |
| "exports.GetSchema = function() {};"); |
| } |
| }; |
| |
| TEST_F(EventUnittest, TestNothing) { |
| ExpectNoAssertionsMade(); |
| } |
| |
| TEST_F(EventUnittest, AddRemoveTwoListeners) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var assert = requireNative('assert');" |
| "var Event = require('event_bindings').Event;" |
| "var eventNatives = requireNative('event_natives');" |
| "var myEvent = new Event('named-event');" |
| "var cb1 = function() {};" |
| "var cb2 = function() {};" |
| "myEvent.addListener(cb1);" |
| "myEvent.addListener(cb2);" |
| "myEvent.removeListener(cb1);" |
| "assert.AssertTrue(!!eventNatives.attachedListeners['named-event']);" |
| "myEvent.removeListener(cb2);" |
| "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, OnUnloadDetachesAllListeners) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var assert = requireNative('assert');" |
| "var Event = require('event_bindings').Event;" |
| "var eventNatives = requireNative('event_natives');" |
| "var myEvent = new Event('named-event');" |
| "var cb1 = function() {};" |
| "var cb2 = function() {};" |
| "myEvent.addListener(cb1);" |
| "myEvent.addListener(cb2);" |
| "require('unload_event').dispatch();" |
| "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, OnUnloadDetachesAllListenersEvenDupes) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var assert = requireNative('assert');" |
| "var Event = require('event_bindings').Event;" |
| "var eventNatives = requireNative('event_natives');" |
| "var myEvent = new Event('named-event');" |
| "var cb1 = function() {};" |
| "myEvent.addListener(cb1);" |
| "myEvent.addListener(cb1);" |
| "require('unload_event').dispatch();" |
| "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, EventsThatSupportRulesMustHaveAName) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var eventOpts = {supportsRules: true};" |
| "var assert = requireNative('assert');" |
| "var caught = false;" |
| "try {" |
| " var myEvent = new Event(undefined, undefined, eventOpts);" |
| "} catch (e) {" |
| " caught = true;" |
| "}" |
| "assert.AssertTrue(caught);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, NamedEventDispatch) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var dispatchEvent = require('event_bindings').dispatchEvent;" |
| "var assert = requireNative('assert');" |
| "var e = new Event('myevent');" |
| "var called = false;" |
| "e.addListener(function() { called = true; });" |
| "dispatchEvent('myevent', []);" |
| "assert.AssertTrue(called);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, AddListenerWithFiltersThrowsErrorByDefault) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule("test", |
| "var Event = require('event_bindings').Event;" |
| "var assert = requireNative('assert');" |
| "var e = new Event('myevent');" |
| "var filter = [{" |
| " url: {hostSuffix: 'google.com'}," |
| "}];" |
| "var caught = false;" |
| "try {" |
| " e.addListener(function() {}, filter);" |
| "} catch (e) {" |
| " caught = true;" |
| "}" |
| "assert.AssertTrue(caught);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, FilteredEventsAttachment) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var assert = requireNative('assert');" |
| "var bindings = requireNative('event_natives');" |
| "var eventOpts = {supportsListeners: true, supportsFilters: true};" |
| "var e = new Event('myevent', undefined, eventOpts);" |
| "var cb = function() {};" |
| "var filters = {url: [{hostSuffix: 'google.com'}]};" |
| "e.addListener(cb, filters);" |
| "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" |
| "e.removeListener(cb);" |
| "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, DetachFilteredEvent) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var assert = requireNative('assert');" |
| "var bindings = requireNative('event_natives');" |
| "var eventOpts = {supportsListeners: true, supportsFilters: true};" |
| "var e = new Event('myevent', undefined, eventOpts);" |
| "var cb1 = function() {};" |
| "var cb2 = function() {};" |
| "var filters = {url: [{hostSuffix: 'google.com'}]};" |
| "e.addListener(cb1, filters);" |
| "e.addListener(cb2, filters);" |
| "privates(e).impl.detach_();" |
| "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, AttachAndRemoveSameFilteredEventListener) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var assert = requireNative('assert');" |
| "var bindings = requireNative('event_natives');" |
| "var eventOpts = {supportsListeners: true, supportsFilters: true};" |
| "var e = new Event('myevent', undefined, eventOpts);" |
| "var cb = function() {};" |
| "var filters = {url: [{hostSuffix: 'google.com'}]};" |
| "e.addListener(cb, filters);" |
| "e.addListener(cb, filters);" |
| "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" |
| "e.removeListener(cb);" |
| "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" |
| "e.removeListener(cb);" |
| "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, AddingFilterWithUrlFieldNotAListThrowsException) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var assert = requireNative('assert');" |
| "var eventOpts = {supportsListeners: true, supportsFilters: true};" |
| "var e = new Event('myevent', undefined, eventOpts);" |
| "var cb = function() {};" |
| "var filters = {url: {hostSuffix: 'google.com'}};" |
| "var caught = false;" |
| "try {" |
| " e.addListener(cb, filters);" |
| "} catch (e) {" |
| " caught = true;" |
| "}" |
| "assert.AssertTrue(caught);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| TEST_F(EventUnittest, MaxListeners) { |
| ModuleSystem::NativesEnabledScope natives_enabled_scope( |
| env()->module_system()); |
| env()->RegisterModule( |
| "test", |
| "var Event = require('event_bindings').Event;" |
| "var assert = requireNative('assert');" |
| "var eventOpts = {supportsListeners: true, maxListeners: 1};" |
| "var e = new Event('myevent', undefined, eventOpts);" |
| "var cb = function() {};" |
| "var caught = false;" |
| "try {" |
| " e.addListener(cb);" |
| "} catch (e) {" |
| " caught = true;" |
| "}" |
| "assert.AssertTrue(!caught);" |
| "try {" |
| " e.addListener(cb);" |
| "} catch (e) {" |
| " caught = true;" |
| "}" |
| "assert.AssertTrue(caught);"); |
| env()->module_system()->Require("test"); |
| } |
| |
| } // namespace |
| } // namespace extensions |