1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/common/extension_urls.h" 6#include "extensions/renderer/module_system_test.h" 7#include "grit/extensions_renderer_resources.h" 8 9namespace extensions { 10namespace { 11 12class EventUnittest : public ModuleSystemTest { 13 virtual void SetUp() OVERRIDE { 14 ModuleSystemTest::SetUp(); 15 16 env()->RegisterModule(kEventBindings, IDR_EVENT_BINDINGS_JS); 17 env()->RegisterModule("json_schema", IDR_JSON_SCHEMA_JS); 18 env()->RegisterModule(kSchemaUtils, IDR_SCHEMA_UTILS_JS); 19 env()->RegisterModule("uncaught_exception_handler", 20 IDR_UNCAUGHT_EXCEPTION_HANDLER_JS); 21 env()->RegisterModule("unload_event", IDR_UNLOAD_EVENT_JS); 22 env()->RegisterModule("utils", IDR_UTILS_JS); 23 24 // Mock out the native handler for event_bindings. These mocks will fail if 25 // any invariants maintained by the real event_bindings are broken. 26 env()->OverrideNativeHandler( 27 "event_natives", 28 "var assert = requireNative('assert');" 29 "var attachedListeners = exports.attachedListeners = {};" 30 "var attachedFilteredListeners = " 31 " exports.attachedFilteredListeners = {};" 32 "var nextId = 0;" 33 "var idToName = {};" 34 "exports.AttachEvent = function(eventName) {" 35 " assert.AssertFalse(!!attachedListeners[eventName]);" 36 " attachedListeners[eventName] = 1;" 37 "};" 38 "exports.DetachEvent = function(eventName) {" 39 " assert.AssertTrue(!!attachedListeners[eventName]);" 40 " delete attachedListeners[eventName];" 41 "};" 42 "exports.IsEventAttached = function(eventName) {" 43 " return !!attachedListeners[eventName];" 44 "};" 45 "exports.AttachFilteredEvent = function(name, filters) {" 46 " var id = nextId++;" 47 " idToName[id] = name;" 48 " attachedFilteredListeners[name] =" 49 " attachedFilteredListeners[name] || [];" 50 " attachedFilteredListeners[name][id] = filters;" 51 " return id;" 52 "};" 53 "exports.DetachFilteredEvent = function(id, manual) {" 54 " var i = attachedFilteredListeners[idToName[id]].indexOf(id);" 55 " attachedFilteredListeners[idToName[id]].splice(i, 1);" 56 "};" 57 "exports.HasFilteredListener = function(name) {" 58 " return attachedFilteredListeners[name].length;" 59 "};"); 60 env()->OverrideNativeHandler("sendRequest", 61 "exports.sendRequest = function() {};"); 62 env()->OverrideNativeHandler( 63 "apiDefinitions", 64 "exports.GetExtensionAPIDefinitionsForTest = function() {};"); 65 env()->OverrideNativeHandler("logging", "exports.DCHECK = function() {};"); 66 env()->OverrideNativeHandler("schema_registry", 67 "exports.GetSchema = function() {};"); 68 } 69}; 70 71TEST_F(EventUnittest, TestNothing) { 72 ExpectNoAssertionsMade(); 73} 74 75TEST_F(EventUnittest, AddRemoveTwoListeners) { 76 ModuleSystem::NativesEnabledScope natives_enabled_scope( 77 env()->module_system()); 78 env()->RegisterModule( 79 "test", 80 "var assert = requireNative('assert');" 81 "var Event = require('event_bindings').Event;" 82 "var eventNatives = requireNative('event_natives');" 83 "var myEvent = new Event('named-event');" 84 "var cb1 = function() {};" 85 "var cb2 = function() {};" 86 "myEvent.addListener(cb1);" 87 "myEvent.addListener(cb2);" 88 "myEvent.removeListener(cb1);" 89 "assert.AssertTrue(!!eventNatives.attachedListeners['named-event']);" 90 "myEvent.removeListener(cb2);" 91 "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); 92 env()->module_system()->Require("test"); 93} 94 95TEST_F(EventUnittest, OnUnloadDetachesAllListeners) { 96 ModuleSystem::NativesEnabledScope natives_enabled_scope( 97 env()->module_system()); 98 env()->RegisterModule( 99 "test", 100 "var assert = requireNative('assert');" 101 "var Event = require('event_bindings').Event;" 102 "var eventNatives = requireNative('event_natives');" 103 "var myEvent = new Event('named-event');" 104 "var cb1 = function() {};" 105 "var cb2 = function() {};" 106 "myEvent.addListener(cb1);" 107 "myEvent.addListener(cb2);" 108 "require('unload_event').dispatch();" 109 "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); 110 env()->module_system()->Require("test"); 111} 112 113TEST_F(EventUnittest, OnUnloadDetachesAllListenersEvenDupes) { 114 ModuleSystem::NativesEnabledScope natives_enabled_scope( 115 env()->module_system()); 116 env()->RegisterModule( 117 "test", 118 "var assert = requireNative('assert');" 119 "var Event = require('event_bindings').Event;" 120 "var eventNatives = requireNative('event_natives');" 121 "var myEvent = new Event('named-event');" 122 "var cb1 = function() {};" 123 "myEvent.addListener(cb1);" 124 "myEvent.addListener(cb1);" 125 "require('unload_event').dispatch();" 126 "assert.AssertFalse(!!eventNatives.attachedListeners['named-event']);"); 127 env()->module_system()->Require("test"); 128} 129 130TEST_F(EventUnittest, EventsThatSupportRulesMustHaveAName) { 131 ModuleSystem::NativesEnabledScope natives_enabled_scope( 132 env()->module_system()); 133 env()->RegisterModule( 134 "test", 135 "var Event = require('event_bindings').Event;" 136 "var eventOpts = {supportsRules: true};" 137 "var assert = requireNative('assert');" 138 "var caught = false;" 139 "try {" 140 " var myEvent = new Event(undefined, undefined, eventOpts);" 141 "} catch (e) {" 142 " caught = true;" 143 "}" 144 "assert.AssertTrue(caught);"); 145 env()->module_system()->Require("test"); 146} 147 148TEST_F(EventUnittest, NamedEventDispatch) { 149 ModuleSystem::NativesEnabledScope natives_enabled_scope( 150 env()->module_system()); 151 env()->RegisterModule( 152 "test", 153 "var Event = require('event_bindings').Event;" 154 "var dispatchEvent = require('event_bindings').dispatchEvent;" 155 "var assert = requireNative('assert');" 156 "var e = new Event('myevent');" 157 "var called = false;" 158 "e.addListener(function() { called = true; });" 159 "dispatchEvent('myevent', []);" 160 "assert.AssertTrue(called);"); 161 env()->module_system()->Require("test"); 162} 163 164TEST_F(EventUnittest, AddListenerWithFiltersThrowsErrorByDefault) { 165 ModuleSystem::NativesEnabledScope natives_enabled_scope( 166 env()->module_system()); 167 env()->RegisterModule("test", 168 "var Event = require('event_bindings').Event;" 169 "var assert = requireNative('assert');" 170 "var e = new Event('myevent');" 171 "var filter = [{" 172 " url: {hostSuffix: 'google.com'}," 173 "}];" 174 "var caught = false;" 175 "try {" 176 " e.addListener(function() {}, filter);" 177 "} catch (e) {" 178 " caught = true;" 179 "}" 180 "assert.AssertTrue(caught);"); 181 env()->module_system()->Require("test"); 182} 183 184TEST_F(EventUnittest, FilteredEventsAttachment) { 185 ModuleSystem::NativesEnabledScope natives_enabled_scope( 186 env()->module_system()); 187 env()->RegisterModule( 188 "test", 189 "var Event = require('event_bindings').Event;" 190 "var assert = requireNative('assert');" 191 "var bindings = requireNative('event_natives');" 192 "var eventOpts = {supportsListeners: true, supportsFilters: true};" 193 "var e = new Event('myevent', undefined, eventOpts);" 194 "var cb = function() {};" 195 "var filters = {url: [{hostSuffix: 'google.com'}]};" 196 "e.addListener(cb, filters);" 197 "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" 198 "e.removeListener(cb);" 199 "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); 200 env()->module_system()->Require("test"); 201} 202 203TEST_F(EventUnittest, DetachFilteredEvent) { 204 ModuleSystem::NativesEnabledScope natives_enabled_scope( 205 env()->module_system()); 206 env()->RegisterModule( 207 "test", 208 "var Event = require('event_bindings').Event;" 209 "var assert = requireNative('assert');" 210 "var bindings = requireNative('event_natives');" 211 "var eventOpts = {supportsListeners: true, supportsFilters: true};" 212 "var e = new Event('myevent', undefined, eventOpts);" 213 "var cb1 = function() {};" 214 "var cb2 = function() {};" 215 "var filters = {url: [{hostSuffix: 'google.com'}]};" 216 "e.addListener(cb1, filters);" 217 "e.addListener(cb2, filters);" 218 "privates(e).impl.detach_();" 219 "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); 220 env()->module_system()->Require("test"); 221} 222 223TEST_F(EventUnittest, AttachAndRemoveSameFilteredEventListener) { 224 ModuleSystem::NativesEnabledScope natives_enabled_scope( 225 env()->module_system()); 226 env()->RegisterModule( 227 "test", 228 "var Event = require('event_bindings').Event;" 229 "var assert = requireNative('assert');" 230 "var bindings = requireNative('event_natives');" 231 "var eventOpts = {supportsListeners: true, supportsFilters: true};" 232 "var e = new Event('myevent', undefined, eventOpts);" 233 "var cb = function() {};" 234 "var filters = {url: [{hostSuffix: 'google.com'}]};" 235 "e.addListener(cb, filters);" 236 "e.addListener(cb, filters);" 237 "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" 238 "e.removeListener(cb);" 239 "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" 240 "e.removeListener(cb);" 241 "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); 242 env()->module_system()->Require("test"); 243} 244 245TEST_F(EventUnittest, AddingFilterWithUrlFieldNotAListThrowsException) { 246 ModuleSystem::NativesEnabledScope natives_enabled_scope( 247 env()->module_system()); 248 env()->RegisterModule( 249 "test", 250 "var Event = require('event_bindings').Event;" 251 "var assert = requireNative('assert');" 252 "var eventOpts = {supportsListeners: true, supportsFilters: true};" 253 "var e = new Event('myevent', undefined, eventOpts);" 254 "var cb = function() {};" 255 "var filters = {url: {hostSuffix: 'google.com'}};" 256 "var caught = false;" 257 "try {" 258 " e.addListener(cb, filters);" 259 "} catch (e) {" 260 " caught = true;" 261 "}" 262 "assert.AssertTrue(caught);"); 263 env()->module_system()->Require("test"); 264} 265 266TEST_F(EventUnittest, MaxListeners) { 267 ModuleSystem::NativesEnabledScope natives_enabled_scope( 268 env()->module_system()); 269 env()->RegisterModule( 270 "test", 271 "var Event = require('event_bindings').Event;" 272 "var assert = requireNative('assert');" 273 "var eventOpts = {supportsListeners: true, maxListeners: 1};" 274 "var e = new Event('myevent', undefined, eventOpts);" 275 "var cb = function() {};" 276 "var caught = false;" 277 "try {" 278 " e.addListener(cb);" 279 "} catch (e) {" 280 " caught = true;" 281 "}" 282 "assert.AssertTrue(!caught);" 283 "try {" 284 " e.addListener(cb);" 285 "} catch (e) {" 286 " caught = true;" 287 "}" 288 "assert.AssertTrue(caught);"); 289 env()->module_system()->Require("test"); 290} 291 292} // namespace 293} // namespace extensions 294