blob: f5bd41bffa2f13d07b36d9fbdbf62c9111dc85c9 [file] [log] [blame]
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview goog.events.EventTarget tester.
* @author chrishenry@google.com (Chris Henry)
*/
goog.provide('goog.events.eventTargetTester');
goog.setTestOnly('goog.events.eventTargetTester');
goog.provide('goog.events.eventTargetTester.KeyType');
goog.setTestOnly('goog.events.eventTargetTester.KeyType');
goog.provide('goog.events.eventTargetTester.UnlistenReturnType');
goog.setTestOnly('goog.events.eventTargetTester.UnlistenReturnType');
goog.require('goog.array');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.events.EventTarget');
goog.require('goog.testing.asserts');
goog.require('goog.testing.recordFunction');
/**
* Setup step for the test functions. This needs to be called from the
* test setUp.
* @param {function():!goog.events.Listenable} listenableFactoryFn Function
* that will return a new Listenable instance each time it is called.
* @param {Function} listenFn Function that, given the same signature
* as goog.events.listen, will add listener to the given event
* target.
* @param {Function} unlistenFn Function that, given the same
* signature as goog.events.unlisten, will remove listener from
* the given event target.
* @param {Function} unlistenByKeyFn Function that, given 2
* parameters: src and key, will remove the corresponding
* listener.
* @param {Function} listenOnceFn Function that, given the same
* signature as goog.events.listenOnce, will add a one-time
* listener to the given event target.
* @param {Function} dispatchEventFn Function that, given the same
* signature as goog.events.dispatchEvent, will dispatch the event
* on the given event target.
* @param {Function} removeAllFn Function that, given the same
* signature as goog.events.removeAll, will remove all listeners
* according to the contract of goog.events.removeAll.
* @param {Function} getListenersFn Function that, given the same
* signature as goog.events.getListeners, will retrieve listeners.
* @param {Function} getListenerFn Function that, given the same
* signature as goog.events.getListener, will retrieve the
* listener object.
* @param {Function} hasListenerFn Function that, given the same
* signature as goog.events.hasListener, will determine whether
* listeners exist.
* @param {goog.events.eventTargetTester.KeyType} listenKeyType The
* key type returned by listen call.
* @param {goog.events.eventTargetTester.UnlistenReturnType}
* unlistenFnReturnType
* Whether we should check return value from
* unlisten call. If unlisten does not return a value, this should
* be set to false.
* @param {boolean} objectListenerSupported Whether listener of type
* Object is supported.
*/
goog.events.eventTargetTester.setUp = function(
listenableFactoryFn,
listenFn, unlistenFn, unlistenByKeyFn, listenOnceFn,
dispatchEventFn, removeAllFn,
getListenersFn, getListenerFn, hasListenerFn,
listenKeyType, unlistenFnReturnType, objectListenerSupported) {
listenableFactory = listenableFactoryFn;
listen = listenFn;
unlisten = unlistenFn;
unlistenByKey = unlistenByKeyFn;
listenOnce = listenOnceFn;
dispatchEvent = dispatchEventFn;
removeAll = removeAllFn;
getListeners = getListenersFn;
getListener = getListenerFn;
hasListener = hasListenerFn;
keyType = listenKeyType;
unlistenReturnType = unlistenFnReturnType;
objectTypeListenerSupported = objectListenerSupported;
listeners = [];
for (var i = 0; i < goog.events.eventTargetTester.MAX_; i++) {
listeners[i] = createListener();
}
eventTargets = [];
for (i = 0; i < goog.events.eventTargetTester.MAX_; i++) {
eventTargets[i] = listenableFactory();
}
};
/**
* Teardown step for the test functions. This needs to be called from
* test teardown.
*/
goog.events.eventTargetTester.tearDown = function() {
for (var i = 0; i < goog.events.eventTargetTester.MAX_; i++) {
goog.dispose(eventTargets[i]);
}
};
/**
* The type of key returned by key-returning functions (listen).
* @enum {number}
*/
goog.events.eventTargetTester.KeyType = {
/**
* Returns number for key.
*/
NUMBER: 0,
/**
* Returns undefined (no return value).
*/
UNDEFINED: 1
};
/**
* The type of unlisten function's return value.
*/
goog.events.eventTargetTester.UnlistenReturnType = {
/**
* Returns boolean indicating whether unlisten is successful.
*/
BOOLEAN: 0,
/**
* Returns undefind (no return value).
*/
UNDEFINED: 1
};
/**
* Expando property used on "listener" function to determine if a
* listener has already been checked. This is what allows us to
* implement assertNoOtherListenerIsCalled.
* @type {string}
*/
goog.events.eventTargetTester.ALREADY_CHECKED_PROP = '__alreadyChecked';
/**
* Expando property used on "listener" function to record the number
* of times it has been called the last time assertListenerIsCalled is
* done. This allows us to verify that it has not been called more
* times in assertNoOtherListenerIsCalled.
*/
goog.events.eventTargetTester.NUM_CALLED_PROP = '__numCalled';
/**
* The maximum number of initialized event targets (in eventTargets
* array) and listeners (in listeners array).
* @type {number}
* @private
*/
goog.events.eventTargetTester.MAX_ = 10;
/**
* Contains test event types.
* @enum {string}
*/
var EventType = {
A: goog.events.getUniqueId('a'),
B: goog.events.getUniqueId('b'),
C: goog.events.getUniqueId('c')
};
var listenableFactory, listen, unlisten, unlistenByKey, listenOnce;
var dispatchEvent, removeAll, getListeners, getListener, hasListener;
var keyType, unlistenReturnType, objectTypeListenerSupported;
var eventTargets, listeners;
/**
* Custom event object for testing.
* @constructor
* @extends {goog.events.Event}
* @final
*/
var TestEvent = function() {
TestEvent.base(this, 'constructor', EventType.A);
};
goog.inherits(TestEvent, goog.events.Event);
/**
* Creates a listener that executes the given function (optional).
* @param {!Function=} opt_listenerFn The optional function to execute.
* @return {!Function} The listener function.
*/
function createListener(opt_listenerFn) {
return goog.testing.recordFunction(opt_listenerFn);
}
/**
* Asserts that the given listener is called numCount number of times.
* @param {!Function} listener The listener to check.
* @param {number} numCount The number of times. See also the times()
* function below.
*/
function assertListenerIsCalled(listener, numCount) {
assertEquals('Listeners is not called the correct number of times.',
numCount, listener.getCallCount());
listener[goog.events.eventTargetTester.ALREADY_CHECKED_PROP] = true;
listener[goog.events.eventTargetTester.NUM_CALLED_PROP] = numCount;
}
/**
* Asserts that no other listeners, other than those verified via
* assertListenerIsCalled, have been called since the last
* resetListeners().
*/
function assertNoOtherListenerIsCalled() {
goog.array.forEach(listeners, function(l, index) {
if (!l[goog.events.eventTargetTester.ALREADY_CHECKED_PROP]) {
assertEquals(
'Listeners ' + index + ' is unexpectedly called.',
0, l.getCallCount());
} else {
assertEquals(
'Listeners ' + index + ' is unexpectedly called.',
l[goog.events.eventTargetTester.NUM_CALLED_PROP], l.getCallCount());
}
});
}
/**
* Resets all listeners call count to 0.
*/
function resetListeners() {
goog.array.forEach(listeners, function(l) {
l.reset();
l[goog.events.eventTargetTester.ALREADY_CHECKED_PROP] = false;
});
}
/**
* The number of times a listener should have been executed. This
* exists to make assertListenerIsCalled more readable. This is used
* like so: assertListenerIsCalled(listener, times(2));
* @param {number} n The number of times a listener should have been
* executed.
* @return {number} The number n.
*/
function times(n) {
return n;
}
function testNoListener() {
dispatchEvent(eventTargets[0], EventType.A);
assertNoOtherListenerIsCalled();
}
function testOneListener() {
listen(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertNoOtherListenerIsCalled();
resetListeners();
dispatchEvent(eventTargets[0], EventType.B);
dispatchEvent(eventTargets[0], EventType.C);
assertNoOtherListenerIsCalled();
}
function testTwoListenersOfSameType() {
var key1 = listen(eventTargets[0], EventType.A, listeners[0]);
var key2 = listen(eventTargets[0], EventType.A, listeners[1]);
if (keyType == goog.events.eventTargetTester.KeyType.NUMBER) {
assertNotEquals(key1, key2);
} else {
assertUndefined(key1);
assertUndefined(key2);
}
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertNoOtherListenerIsCalled();
}
function testInstallingSameListeners() {
var key1 = listen(eventTargets[0], EventType.A, listeners[0]);
var key2 = listen(eventTargets[0], EventType.A, listeners[0]);
var key3 = listen(eventTargets[0], EventType.B, listeners[0]);
if (keyType == goog.events.eventTargetTester.KeyType.NUMBER) {
assertEquals(key1, key2);
assertNotEquals(key1, key3);
} else {
assertUndefined(key1);
assertUndefined(key2);
assertUndefined(key3);
}
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
dispatchEvent(eventTargets[0], EventType.B);
assertListenerIsCalled(listeners[0], times(2));
assertNoOtherListenerIsCalled();
}
function testScope() {
listeners[0] = createListener(function(e) {
assertEquals('Wrong scope with undefined scope', eventTargets[0], this);
});
listeners[1] = createListener(function(e) {
assertEquals('Wrong scope with null scope', eventTargets[0], this);
});
var scope = {};
listeners[2] = createListener(function(e) {
assertEquals('Wrong scope with specific scope object', scope, this);
});
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1], false, null);
listen(eventTargets[0], EventType.A, listeners[2], false, scope);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(1));
}
function testDispatchEventDoesNotThrowWithDisposedEventTarget() {
goog.dispose(eventTargets[0]);
assertTrue(dispatchEvent(eventTargets[0], EventType.A));
}
function testDispatchEventWithObjectLiteral() {
listen(eventTargets[0], EventType.A, listeners[0]);
assertTrue(dispatchEvent(eventTargets[0], {type: EventType.A}));
assertListenerIsCalled(listeners[0], times(1));
assertNoOtherListenerIsCalled();
}
function testDispatchEventWithCustomEventObject() {
listen(eventTargets[0], EventType.A, listeners[0]);
var e = new TestEvent();
assertTrue(dispatchEvent(eventTargets[0], e));
assertListenerIsCalled(listeners[0], times(1));
assertNoOtherListenerIsCalled();
var actualEvent = listeners[0].getLastCall().getArgument(0);
assertEquals(e, actualEvent);
assertEquals(eventTargets[0], actualEvent.target);
}
function testDisposingEventTargetRemovesListeners() {
if (!(listenableFactory() instanceof goog.events.EventTarget)) {
return;
}
listen(eventTargets[0], EventType.A, listeners[0]);
goog.dispose(eventTargets[0]);
dispatchEvent(eventTargets[0], EventType.A);
assertNoOtherListenerIsCalled();
}
/**
* Unlisten/unlistenByKey should still work after disposal. There are
* many circumstances when this is actually necessary. For example, a
* user may have listened to an event target and stored the key
* (e.g. in a goog.events.EventHandler) and only unlisten after the
* target has been disposed.
*/
function testUnlistenWorksAfterDisposal() {
var key = listen(eventTargets[0], EventType.A, listeners[0]);
goog.dispose(eventTargets[0]);
unlisten(eventTargets[0], EventType.A, listeners[1]);
if (unlistenByKey) {
unlistenByKey(eventTargets[0], key);
}
}
function testRemovingListener() {
var ret1 = unlisten(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[0]);
var ret2 = unlisten(eventTargets[0], EventType.A, listeners[1]);
var ret3 = unlisten(eventTargets[0], EventType.B, listeners[0]);
var ret4 = unlisten(eventTargets[1], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
var ret5 = unlisten(eventTargets[0], EventType.A, listeners[0]);
var ret6 = unlisten(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertNoOtherListenerIsCalled();
if (unlistenReturnType ==
goog.events.eventTargetTester.UnlistenReturnType.BOOLEAN) {
assertFalse(ret1);
assertFalse(ret2);
assertFalse(ret3);
assertFalse(ret4);
assertTrue(ret5);
assertFalse(ret6);
} else {
assertUndefined(ret1);
assertUndefined(ret2);
assertUndefined(ret3);
assertUndefined(ret4);
assertUndefined(ret5);
assertUndefined(ret6);
}
}
function testCapture() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
eventTargets[9].setParentEventTarget(eventTargets[0]);
var ordering = 0;
listeners[0] = createListener(
function(e) {
assertEquals(eventTargets[2], e.currentTarget);
assertEquals(eventTargets[0], e.target);
assertEquals('First capture listener is not called first', 0, ordering);
ordering++;
});
listeners[1] = createListener(
function(e) {
assertEquals(eventTargets[1], e.currentTarget);
assertEquals(eventTargets[0], e.target);
assertEquals('2nd capture listener is not called 2nd', 1, ordering);
ordering++;
});
listeners[2] = createListener(
function(e) {
assertEquals(eventTargets[0], e.currentTarget);
assertEquals(eventTargets[0], e.target);
assertEquals('3rd capture listener is not called 3rd', 2, ordering);
ordering++;
});
listen(eventTargets[2], EventType.A, listeners[0], true);
listen(eventTargets[1], EventType.A, listeners[1], true);
listen(eventTargets[0], EventType.A, listeners[2], true);
// These should not be called.
listen(eventTargets[3], EventType.A, listeners[3], true);
listen(eventTargets[0], EventType.B, listeners[4], true);
listen(eventTargets[0], EventType.C, listeners[5], true);
listen(eventTargets[1], EventType.B, listeners[6], true);
listen(eventTargets[1], EventType.C, listeners[7], true);
listen(eventTargets[2], EventType.B, listeners[8], true);
listen(eventTargets[2], EventType.C, listeners[9], true);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(1));
assertNoOtherListenerIsCalled();
}
function testBubble() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
eventTargets[9].setParentEventTarget(eventTargets[0]);
var ordering = 0;
listeners[0] = createListener(
function(e) {
assertEquals(eventTargets[0], e.currentTarget);
assertEquals(eventTargets[0], e.target);
assertEquals('First bubble listener is not called first', 0, ordering);
ordering++;
});
listeners[1] = createListener(
function(e) {
assertEquals(eventTargets[1], e.currentTarget);
assertEquals(eventTargets[0], e.target);
assertEquals('2nd bubble listener is not called 2nd', 1, ordering);
ordering++;
});
listeners[2] = createListener(
function(e) {
assertEquals(eventTargets[2], e.currentTarget);
assertEquals(eventTargets[0], e.target);
assertEquals('3rd bubble listener is not called 3rd', 2, ordering);
ordering++;
});
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[1], EventType.A, listeners[1]);
listen(eventTargets[2], EventType.A, listeners[2]);
// These should not be called.
listen(eventTargets[3], EventType.A, listeners[3]);
listen(eventTargets[0], EventType.B, listeners[4]);
listen(eventTargets[0], EventType.C, listeners[5]);
listen(eventTargets[1], EventType.B, listeners[6]);
listen(eventTargets[1], EventType.C, listeners[7]);
listen(eventTargets[2], EventType.B, listeners[8]);
listen(eventTargets[2], EventType.C, listeners[9]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(1));
assertNoOtherListenerIsCalled();
}
function testCaptureAndBubble() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
listen(eventTargets[0], EventType.A, listeners[0], true);
listen(eventTargets[1], EventType.A, listeners[1], true);
listen(eventTargets[2], EventType.A, listeners[2], true);
listen(eventTargets[0], EventType.A, listeners[3]);
listen(eventTargets[1], EventType.A, listeners[4]);
listen(eventTargets[2], EventType.A, listeners[5]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(1));
assertListenerIsCalled(listeners[3], times(1));
assertListenerIsCalled(listeners[4], times(1));
assertListenerIsCalled(listeners[5], times(1));
assertNoOtherListenerIsCalled();
}
function testPreventDefaultByReturningFalse() {
listeners[0] = createListener(function(e) { return false; });
listeners[1] = createListener(function(e) { return true; });
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1]);
var result = dispatchEvent(eventTargets[0], EventType.A);
assertFalse(result);
}
function testPreventDefault() {
listeners[0] = createListener(function(e) { e.preventDefault(); });
listeners[1] = createListener(function(e) { return true; });
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1]);
var result = dispatchEvent(eventTargets[0], EventType.A);
assertFalse(result);
}
function testPreventDefaultAtCapture() {
listeners[0] = createListener(function(e) { e.preventDefault(); });
listeners[1] = createListener(function(e) { return true; });
listen(eventTargets[0], EventType.A, listeners[0], true);
listen(eventTargets[0], EventType.A, listeners[1], true);
var result = dispatchEvent(eventTargets[0], EventType.A);
assertFalse(result);
}
function testStopPropagation() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
listeners[0] = createListener(function(e) { e.stopPropagation(); });
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1]);
listen(eventTargets[1], EventType.A, listeners[2]);
listen(eventTargets[2], EventType.A, listeners[3]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertNoOtherListenerIsCalled();
}
function testStopPropagation2() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
listeners[1] = createListener(function(e) { e.stopPropagation(); });
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1]);
listen(eventTargets[1], EventType.A, listeners[2]);
listen(eventTargets[2], EventType.A, listeners[3]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertNoOtherListenerIsCalled();
}
function testStopPropagation3() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
listeners[2] = createListener(function(e) { e.stopPropagation(); });
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1]);
listen(eventTargets[1], EventType.A, listeners[2]);
listen(eventTargets[2], EventType.A, listeners[3]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(1));
assertNoOtherListenerIsCalled();
}
function testStopPropagationAtCapture() {
eventTargets[0].setParentEventTarget(eventTargets[1]);
eventTargets[1].setParentEventTarget(eventTargets[2]);
listeners[0] = createListener(function(e) { e.stopPropagation(); });
listen(eventTargets[2], EventType.A, listeners[0], true);
listen(eventTargets[1], EventType.A, listeners[1], true);
listen(eventTargets[0], EventType.A, listeners[2], true);
listen(eventTargets[0], EventType.A, listeners[3]);
listen(eventTargets[1], EventType.A, listeners[4]);
listen(eventTargets[2], EventType.A, listeners[5]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertNoOtherListenerIsCalled();
}
function testHandleEvent() {
if (!objectTypeListenerSupported) {
return;
}
var obj = {};
obj.handleEvent = goog.testing.recordFunction();
listen(eventTargets[0], EventType.A, obj);
dispatchEvent(eventTargets[0], EventType.A);
assertEquals(1, obj.handleEvent.getCallCount());
}
function testListenOnce() {
if (!listenOnce) {
return;
}
listenOnce(eventTargets[0], EventType.A, listeners[0], true);
listenOnce(eventTargets[0], EventType.A, listeners[1]);
listenOnce(eventTargets[0], EventType.B, listeners[2]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(0));
assertNoOtherListenerIsCalled();
resetListeners();
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(0));
assertListenerIsCalled(listeners[1], times(0));
assertListenerIsCalled(listeners[2], times(0));
dispatchEvent(eventTargets[0], EventType.B);
assertListenerIsCalled(listeners[2], times(1));
assertNoOtherListenerIsCalled();
}
function testUnlistenInListen() {
listeners[1] = createListener(
function(e) {
unlisten(eventTargets[0], EventType.A, listeners[1]);
unlisten(eventTargets[0], EventType.A, listeners[2]);
});
listen(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[1]);
listen(eventTargets[0], EventType.A, listeners[2]);
listen(eventTargets[0], EventType.A, listeners[3]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(0));
assertListenerIsCalled(listeners[3], times(1));
assertNoOtherListenerIsCalled();
resetListeners();
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(0));
assertListenerIsCalled(listeners[2], times(0));
assertListenerIsCalled(listeners[3], times(1));
assertNoOtherListenerIsCalled();
}
function testUnlistenByKeyInListen() {
if (!unlistenByKey) {
return;
}
var key1, key2;
listeners[1] = createListener(
function(e) {
unlistenByKey(eventTargets[0], key1);
unlistenByKey(eventTargets[0], key2);
});
listen(eventTargets[0], EventType.A, listeners[0]);
key1 = listen(eventTargets[0], EventType.A, listeners[1]);
key2 = listen(eventTargets[0], EventType.A, listeners[2]);
listen(eventTargets[0], EventType.A, listeners[3]);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(0));
assertListenerIsCalled(listeners[3], times(1));
assertNoOtherListenerIsCalled();
resetListeners();
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(0));
assertListenerIsCalled(listeners[2], times(0));
assertListenerIsCalled(listeners[3], times(1));
assertNoOtherListenerIsCalled();
}
function testSetParentEventTarget() {
assertNull(eventTargets[0].getParentEventTarget());
eventTargets[0].setParentEventTarget(eventTargets[1]);
assertEquals(eventTargets[1], eventTargets[0].getParentEventTarget());
assertNull(eventTargets[1].getParentEventTarget());
eventTargets[0].setParentEventTarget(null);
assertNull(eventTargets[0].getParentEventTarget());
}
function testListenOnceAfterListenDoesNotChangeExistingListener() {
if (!listenOnce) {
return;
}
listen(eventTargets[0], EventType.A, listeners[0]);
listenOnce(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(3));
assertNoOtherListenerIsCalled();
}
function testListenOnceAfterListenOnceDoesNotChangeExistingListener() {
if (!listenOnce) {
return;
}
listenOnce(eventTargets[0], EventType.A, listeners[0]);
listenOnce(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(1));
assertNoOtherListenerIsCalled();
}
function testListenAfterListenOnceRemoveOnceness() {
if (!listenOnce) {
return;
}
listenOnce(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.A);
assertListenerIsCalled(listeners[0], times(3));
assertNoOtherListenerIsCalled();
}
function testUnlistenAfterListenOnce() {
if (!listenOnce) {
return;
}
listenOnce(eventTargets[0], EventType.A, listeners[0]);
unlisten(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
listen(eventTargets[0], EventType.A, listeners[0]);
listenOnce(eventTargets[0], EventType.A, listeners[0]);
unlisten(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
listenOnce(eventTargets[0], EventType.A, listeners[0]);
listen(eventTargets[0], EventType.A, listeners[0]);
unlisten(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
listenOnce(eventTargets[0], EventType.A, listeners[0]);
listenOnce(eventTargets[0], EventType.A, listeners[0]);
unlisten(eventTargets[0], EventType.A, listeners[0]);
dispatchEvent(eventTargets[0], EventType.A);
assertNoOtherListenerIsCalled();
}
function testRemoveAllWithType() {
if (!removeAll) {
return;
}
listen(eventTargets[0], EventType.A, listeners[0], true);
listen(eventTargets[0], EventType.A, listeners[1]);
listen(eventTargets[0], EventType.C, listeners[2], true);
listen(eventTargets[0], EventType.C, listeners[3]);
listen(eventTargets[0], EventType.B, listeners[4], true);
listen(eventTargets[0], EventType.B, listeners[5], true);
listen(eventTargets[0], EventType.B, listeners[6]);
listen(eventTargets[0], EventType.B, listeners[7]);
assertEquals(4, removeAll(eventTargets[0], EventType.B));
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.B);
dispatchEvent(eventTargets[0], EventType.C);
assertListenerIsCalled(listeners[0], times(1));
assertListenerIsCalled(listeners[1], times(1));
assertListenerIsCalled(listeners[2], times(1));
assertListenerIsCalled(listeners[3], times(1));
assertNoOtherListenerIsCalled();
}
function testRemoveAll() {
if (!removeAll) {
return;
}
listen(eventTargets[0], EventType.A, listeners[0], true);
listen(eventTargets[0], EventType.A, listeners[1]);
listen(eventTargets[0], EventType.C, listeners[2], true);
listen(eventTargets[0], EventType.C, listeners[3]);
listen(eventTargets[0], EventType.B, listeners[4], true);
listen(eventTargets[0], EventType.B, listeners[5], true);
listen(eventTargets[0], EventType.B, listeners[6]);
listen(eventTargets[0], EventType.B, listeners[7]);
assertEquals(8, removeAll(eventTargets[0]));
dispatchEvent(eventTargets[0], EventType.A);
dispatchEvent(eventTargets[0], EventType.B);
dispatchEvent(eventTargets[0], EventType.C);
assertNoOtherListenerIsCalled();
}
function testRemoveAllCallsMarkAsRemoved() {
if (!removeAll) {
return;
}
var key0 = listen(eventTargets[0], EventType.A, listeners[0]);
var key1 = listen(eventTargets[1], EventType.A, listeners[1]);
assertNotNullNorUndefined(key0.listener);
assertFalse(key0.removed);
assertNotNullNorUndefined(key1.listener);
assertFalse(key1.removed);
assertEquals(1, removeAll(eventTargets[0]));
assertNull(key0.listener);
assertTrue(key0.removed);
assertNotNullNorUndefined(key1.listener);
assertFalse(key1.removed);
assertEquals(1, removeAll(eventTargets[1]));
assertNull(key1.listener);
assertTrue(key1.removed);
}
function testGetListeners() {
if (!getListeners) {
return;
}
listen(eventTargets[0], EventType.A, listeners[0], true);
listen(eventTargets[0], EventType.A, listeners[1], true);
listen(eventTargets[0], EventType.A, listeners[2]);
listen(eventTargets[0], EventType.A, listeners[3]);
var l = getListeners(eventTargets[0], EventType.A, true);
assertEquals(2, l.length);
assertEquals(listeners[0], l[0].listener);
assertEquals(listeners[1], l[1].listener);
l = getListeners(eventTargets[0], EventType.A, false);
assertEquals(2, l.length);
assertEquals(listeners[2], l[0].listener);
assertEquals(listeners[3], l[1].listener);
l = getListeners(eventTargets[0], EventType.B, true);
assertEquals(0, l.length);
}
function testGetListener() {
if (!getListener) {
return;
}
listen(eventTargets[0], EventType.A, listeners[0], true);
assertNotNull(getListener(eventTargets[0], EventType.A, listeners[0], true));
assertNull(
getListener(eventTargets[0], EventType.A, listeners[0], true, {}));
assertNull(getListener(eventTargets[1], EventType.A, listeners[0], true));
assertNull(getListener(eventTargets[0], EventType.B, listeners[0], true));
assertNull(getListener(eventTargets[0], EventType.A, listeners[1], true));
}
function testHasListener() {
if (!hasListener) {
return;
}
assertFalse(hasListener(eventTargets[0]));
listen(eventTargets[0], EventType.A, listeners[0], true);
assertTrue(hasListener(eventTargets[0]));
assertTrue(hasListener(eventTargets[0], EventType.A));
assertTrue(hasListener(eventTargets[0], EventType.A, true));
assertTrue(hasListener(eventTargets[0], undefined, true));
assertFalse(hasListener(eventTargets[0], EventType.A, false));
assertFalse(hasListener(eventTargets[0], undefined, false));
assertFalse(hasListener(eventTargets[0], EventType.B));
assertFalse(hasListener(eventTargets[0], EventType.B, true));
assertFalse(hasListener(eventTargets[1]));
}
function testFiringEventBeforeDisposeInternalWorks() {
/**
* @extends {goog.events.EventTarget}
* @constructor
* @final
*/
var MockTarget = function() {
MockTarget.base(this, 'constructor');
};
goog.inherits(MockTarget, goog.events.EventTarget);
MockTarget.prototype.disposeInternal = function() {
dispatchEvent(this, EventType.A);
MockTarget.base(this, 'disposeInternal');
};
var t = new MockTarget();
try {
listen(t, EventType.A, listeners[0]);
t.dispose();
assertListenerIsCalled(listeners[0], times(1));
} catch (e) {
goog.dispose(t);
}
}
function testLoopDetection() {
var target = listenableFactory();
target.setParentEventTarget(target);
try {
target.dispatchEvent('string');
fail('expected error');
} catch (e) {
assertContains('infinite', e.message);
}
}