123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- // Copyright 2008 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.
- goog.provide('goog.DisposableTest');
- goog.setTestOnly('goog.DisposableTest');
- goog.require('goog.Disposable');
- goog.require('goog.testing.jsunit');
- goog.require('goog.testing.recordFunction');
- var d1, d2;
- // Sample subclass of goog.Disposable.
- function DisposableTest() {
- goog.Disposable.call(this);
- this.element = document.getElementById('someElement');
- }
- goog.inherits(DisposableTest, goog.Disposable);
- DisposableTest.prototype.disposeInternal = function() {
- DisposableTest.superClass_.disposeInternal.call(this);
- delete this.element;
- };
- // Class that doesn't inherit from goog.Disposable, but implements the
- // disposable interface via duck typing.
- function DisposableDuck() {
- this.element = document.getElementById('someElement');
- }
- DisposableDuck.prototype.dispose = function() {
- delete this.element;
- };
- // Class which calls dispose recursively.
- function RecursiveDisposable() {
- this.disposedCount = 0;
- }
- goog.inherits(RecursiveDisposable, goog.Disposable);
- RecursiveDisposable.prototype.disposeInternal = function() {
- ++this.disposedCount;
- assertEquals('Disposed too many times', 1, this.disposedCount);
- this.dispose();
- };
- // Test methods.
- function setUp() {
- d1 = new goog.Disposable();
- d2 = new DisposableTest();
- }
- function tearDown() {
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.OFF;
- goog.Disposable.INCLUDE_STACK_ON_CREATION = true;
- goog.Disposable.instances_ = {};
- d1.dispose();
- d2.dispose();
- }
- function testConstructor() {
- assertFalse(d1.isDisposed());
- assertFalse(d2.isDisposed());
- assertEquals(document.getElementById('someElement'), d2.element);
- }
- function testDispose() {
- assertFalse(d1.isDisposed());
- d1.dispose();
- assertTrue(
- 'goog.Disposable instance should have been disposed of', d1.isDisposed());
- assertFalse(d2.isDisposed());
- d2.dispose();
- assertTrue(
- 'goog.DisposableTest instance should have been disposed of',
- d2.isDisposed());
- }
- function testDisposeInternal() {
- assertNotUndefined(d2.element);
- d2.dispose();
- assertUndefined(
- 'goog.DisposableTest.prototype.disposeInternal should ' +
- 'have deleted the element reference',
- d2.element);
- }
- function testDisposeAgain() {
- d2.dispose();
- assertUndefined(
- 'goog.DisposableTest.prototype.disposeInternal should ' +
- 'have deleted the element reference',
- d2.element);
- // Manually reset the element to a non-null value, and call dispose().
- // Because the object is already marked disposed, disposeInternal won't
- // be called again.
- d2.element = document.getElementById('someElement');
- d2.dispose();
- assertNotUndefined(
- 'disposeInternal should not be called again if the ' +
- 'object has already been marked disposed',
- d2.element);
- }
- function testDisposeWorksRecursively() {
- new RecursiveDisposable().dispose();
- }
- function testStaticDispose() {
- assertFalse(d1.isDisposed());
- goog.dispose(d1);
- assertTrue(
- 'goog.Disposable instance should have been disposed of', d1.isDisposed());
- assertFalse(d2.isDisposed());
- goog.dispose(d2);
- assertTrue(
- 'goog.DisposableTest instance should have been disposed of',
- d2.isDisposed());
- var duck = new DisposableDuck();
- assertNotUndefined(duck.element);
- goog.dispose(duck);
- assertUndefined(
- 'goog.dispose should have disposed of object that ' +
- 'implements the disposable interface',
- duck.element);
- }
- function testStaticDisposeOnNonDisposableType() {
- // Call goog.dispose() with various types and make sure no errors are
- // thrown.
- goog.dispose(true);
- goog.dispose(false);
- goog.dispose(null);
- goog.dispose(undefined);
- goog.dispose('');
- goog.dispose([]);
- goog.dispose({});
- function A() {}
- goog.dispose(new A());
- }
- function testMonitoringFailure() {
- function BadDisposable(){};
- goog.inherits(BadDisposable, goog.Disposable);
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.PERMANENT;
- var badDisposable = new BadDisposable;
- assertArrayEquals(
- 'no disposable objects registered', [],
- goog.Disposable.getUndisposedObjects());
- assertThrows(
- 'the base ctor should have been called',
- goog.bind(badDisposable.dispose, badDisposable));
- }
- function testGetUndisposedObjects() {
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.PERMANENT;
- var d1 = new DisposableTest();
- var d2 = new DisposableTest();
- assertSameElements(
- 'the undisposed instances', [d1, d2],
- goog.Disposable.getUndisposedObjects());
- d1.dispose();
- assertSameElements(
- '1 undisposed instance left', [d2],
- goog.Disposable.getUndisposedObjects());
- d1.dispose();
- assertSameElements(
- 'second disposal of the same object is no-op', [d2],
- goog.Disposable.getUndisposedObjects());
- d2.dispose();
- assertSameElements(
- 'all objects have been disposed of', [],
- goog.Disposable.getUndisposedObjects());
- }
- function testClearUndisposedObjects() {
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.PERMANENT;
- var d1 = new DisposableTest();
- var d2 = new DisposableTest();
- d2.dispose();
- goog.Disposable.clearUndisposedObjects();
- assertSameElements(
- 'no undisposed object in the registry', [],
- goog.Disposable.getUndisposedObjects());
- assertThrows(
- 'disposal after clearUndisposedObjects()', function() { d1.dispose(); });
- // d2 is already disposed of, the redisposal shouldn't throw error.
- d2.dispose();
- }
- function testRegisterDisposable() {
- var d1 = new DisposableTest();
- var d2 = new DisposableTest();
- d1.registerDisposable(d2);
- d1.dispose();
- assertTrue('d2 should be disposed when d1 is disposed', d2.isDisposed());
- }
- function testDisposeAll() {
- var d1 = new DisposableTest();
- var d2 = new DisposableTest();
- goog.disposeAll(d1, d2);
- assertTrue('d1 should be disposed', d1.isDisposed());
- assertTrue('d2 should be disposed', d2.isDisposed());
- }
- function testDisposeAllRecursive() {
- var d1 = new DisposableTest();
- var d2 = new DisposableTest();
- var d3 = new DisposableTest();
- var d4 = new DisposableTest();
- goog.disposeAll(d1, [[d2], d3, d4]);
- assertTrue('d1 should be disposed', d1.isDisposed());
- assertTrue('d2 should be disposed', d2.isDisposed());
- assertTrue('d3 should be disposed', d3.isDisposed());
- assertTrue('d4 should be disposed', d4.isDisposed());
- }
- function testCreationStack() {
- if (!new Error().stack) return;
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.PERMANENT;
- var disposableStack = new DisposableTest().creationStack;
- // Check that the name of this test function occurs in the stack trace.
- assertNotEquals(-1, disposableStack.indexOf('testCreationStack'));
- }
- function testMonitoredWithoutCreationStack() {
- if (!new Error().stack) return;
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.PERMANENT;
- goog.Disposable.INCLUDE_STACK_ON_CREATION = false;
- var d1 = new DisposableTest();
- // Check that it is tracked, but not with a creation stack.
- assertUndefined(d1.creationStack);
- assertSameElements(
- 'the undisposed instance', [d1], goog.Disposable.getUndisposedObjects());
- }
- function testOnDisposeCallback() {
- var callback = goog.testing.recordFunction();
- d1.addOnDisposeCallback(callback);
- assertEquals('callback called too early', 0, callback.getCallCount());
- d1.dispose();
- assertEquals(
- 'callback should be called once on dispose', 1, callback.getCallCount());
- }
- function testOnDisposeCallbackOrder() {
- var invocations = [];
- var callback = function(str) { invocations.push(str); };
- d1.addOnDisposeCallback(goog.partial(callback, 'a'));
- d1.addOnDisposeCallback(goog.partial(callback, 'b'));
- goog.dispose(d1);
- assertArrayEquals(
- 'callbacks should be called in chronological order', ['a', 'b'],
- invocations);
- }
- function testAddOnDisposeCallbackAfterDispose() {
- var callback = goog.testing.recordFunction();
- var scope = {};
- goog.dispose(d1);
- d1.addOnDisposeCallback(callback, scope);
- assertEquals(
- 'Callback should be immediately called if already disposed', 1,
- callback.getCallCount());
- assertEquals(
- 'Callback scope should be respected', scope,
- callback.getLastCall().getThis());
- }
- function testInteractiveMonitoring() {
- var d1 = new DisposableTest();
- goog.Disposable.MONITORING_MODE = goog.Disposable.MonitoringMode.INTERACTIVE;
- var d2 = new DisposableTest();
- assertSameElements(
- 'only 1 undisposed instance tracked', [d2],
- goog.Disposable.getUndisposedObjects());
- // No errors should be thrown.
- d1.dispose();
- assertSameElements(
- '1 undisposed instance left', [d2],
- goog.Disposable.getUndisposedObjects());
- d2.dispose();
- assertSameElements(
- 'all disposed', [], goog.Disposable.getUndisposedObjects());
- }
|