123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- // 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.debug.ErrorHandlerTest');
- goog.setTestOnly('goog.debug.ErrorHandlerTest');
- goog.require('goog.debug.ErrorHandler');
- goog.require('goog.testing.MockControl');
- goog.require('goog.testing.jsunit');
- var oldGetObjectByName;
- // provide our own window that implements our instrumented and
- // immediate-call versions of setTimeout and setInterval
- var fakeWin = {};
- var errorHandler;
- var mockControl;
- function badTimer() {
- arguments.callee.called = true;
- throw 'die die die';
- }
- function setUp() {
- mockControl = new goog.testing.MockControl();
- // On IE, globalEval happens async. So make it synchronous.
- goog.globalEval = function(str) { eval(str); };
- oldGetObjectByName = goog.getObjectByName;
- goog.getObjectByName = function(name) {
- if (name == 'window') {
- return fakeWin;
- } else {
- return oldGetObjectByName(name);
- }
- };
- fakeWin.setTimeout = function(fn, time) {
- fakeWin.setTimeout.called = true;
- fakeWin.setTimeout.that = this;
- if (goog.isString(fn)) {
- eval(fn);
- } else {
- fn.apply(this, Array.prototype.slice.call(arguments, 2));
- }
- };
- fakeWin.setInterval = function(fn, time) {
- fakeWin.setInterval.called = true;
- fakeWin.setInterval.that = this;
- if (goog.isString(fn)) {
- eval(fn);
- } else {
- fn.apply(this, Array.prototype.slice.call(arguments, 2));
- }
- };
- fakeWin.requestAnimationFrame = function(fn) {
- fakeWin.requestAnimationFrame.called = true;
- fakeWin.requestAnimationFrame.that = this;
- fn();
- };
- // just record the exception in the error handler when it happens
- errorHandler = new goog.debug.ErrorHandler(function(ex) { this.ex = ex; });
- }
- function tearDown() {
- mockControl.$tearDown();
- goog.dispose(errorHandler);
- errorHandler = null;
- goog.getObjectByName = oldGetObjectByName;
- delete badTimer['__protected__'];
- }
- function testWrapSetTimeout() {
- errorHandler.protectWindowSetTimeout();
- var caught;
- try {
- fakeWin.setTimeout(badTimer, 3);
- } catch (ex) {
- caught = ex;
- }
- assertSetTimeoutError(caught);
- }
- function testWrapSetTimeoutWithoutException() {
- errorHandler.protectWindowSetTimeout();
- fakeWin.setTimeout(function(x, y) {
- assertEquals('test', x);
- assertEquals(7, y);
- }, 3, 'test', 7);
- }
- function testWrapSetTimeoutWithString() {
- errorHandler.protectWindowSetTimeout();
- var caught;
- try {
- fakeWin.setTimeout('badTimer()', 3);
- } catch (ex) {
- caught = ex;
- }
- assertSetTimeoutError(caught);
- }
- function testWrapSetInterval() {
- errorHandler.protectWindowSetInterval();
- var caught;
- try {
- fakeWin.setInterval(badTimer, 3);
- } catch (ex) {
- caught = ex;
- }
- assertSetIntervalError(caught);
- }
- function testWrapSetIntervalWithoutException() {
- errorHandler.protectWindowSetInterval();
- fakeWin.setInterval(function(x, y) {
- assertEquals('test', x);
- assertEquals(7, y);
- }, 3, 'test', 7);
- }
- function testWrapSetIntervalWithString() {
- errorHandler.protectWindowSetInterval();
- var caught;
- try {
- fakeWin.setInterval('badTimer()', 3);
- } catch (ex) {
- caught = ex;
- }
- assertSetIntervalError(caught);
- }
- function testWrapRequestAnimationFrame() {
- errorHandler.protectWindowRequestAnimationFrame();
- var caught;
- try {
- fakeWin.requestAnimationFrame(badTimer);
- } catch (ex) {
- caught = ex;
- }
- assertRequestAnimationFrameError(caught);
- }
- function testDisposal() {
- fakeWin = goog.getObjectByName('window');
- var originalSetTimeout = fakeWin.setTimeout;
- var originalSetInterval = fakeWin.setInterval;
- errorHandler.protectWindowSetTimeout();
- errorHandler.protectWindowSetInterval();
- assertNotEquals(originalSetTimeout, fakeWin.setTimeout);
- assertNotEquals(originalSetInterval, fakeWin.setInterval);
- errorHandler.dispose();
- assertEquals(originalSetTimeout, fakeWin.setTimeout);
- assertEquals(originalSetInterval, fakeWin.setInterval);
- }
- function testUnwrap() {
- var fn = function() {};
- var wrappedFn = errorHandler.wrap(fn);
- assertNotEquals(wrappedFn, fn);
- assertEquals(fn, errorHandler.unwrap(fn));
- assertEquals(fn, errorHandler.unwrap(wrappedFn));
- }
- function testStackPreserved() {
- var e;
- var hasStacks;
- function specialFunctionName() {
- var e = Error();
- hasStacks = !!e.stack;
- throw e;
- }
- var wrappedFn = errorHandler.wrap(specialFunctionName);
- try {
- wrappedFn();
- } catch (exception) {
- e = exception;
- }
- assertTrue(!!e);
- if (hasStacks) {
- assertContains('specialFunctionName', e.stack);
- }
- }
- function testGetProtectedFunction() {
- var fn = function() { throw new Error('Foo'); };
- var protectedFn = errorHandler.getProtectedFunction(fn);
- var e = assertThrows(protectedFn);
- assertTrue(e instanceof goog.debug.ErrorHandler.ProtectedFunctionError);
- assertEquals('Foo', e.cause.message);
- }
- function testGetProtectedFunctionNullError() {
- var fn = function() { throw null; };
- var protectedFn = errorHandler.getProtectedFunction(fn);
- var e = assertThrows(protectedFn);
- assertTrue(e instanceof goog.debug.ErrorHandler.ProtectedFunctionError);
- assertNull(e.cause);
- }
- function testGetProtectedFunction_withoutWrappedErrors() {
- var shouldCallErrorLog = !!Error.captureStackTrace;
- if (shouldCallErrorLog) {
- mockControl.createMethodMock(goog.global.console, 'error');
- }
- errorHandler.setWrapErrors(false);
- var fn = function() {
- var e = new Error('Foo');
- e.stack = 'STACK';
- throw e;
- };
- var protectedFn = errorHandler.getProtectedFunction(fn);
- if (shouldCallErrorLog) {
- goog.global.console.error('Foo', 'STACK');
- }
- mockControl.$replayAll();
- var e = assertThrows(protectedFn);
- mockControl.$verifyAll();
- assertTrue(e instanceof Error);
- assertEquals('Foo', e.message);
- assertEquals(e.stack, 'STACK');
- }
- function testGetProtectedFunction_withoutWrappedErrorsWithMessagePrefix() {
- errorHandler.setWrapErrors(false);
- errorHandler.setPrefixErrorMessages(true);
- var fn = function() { throw new Error('Foo'); };
- var protectedFn = errorHandler.getProtectedFunction(fn);
- var e = assertThrows(protectedFn);
- assertTrue(e instanceof Error);
- assertEquals(
- goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX + 'Foo',
- e.message);
- var stringError = function() { throw 'String'; };
- protectedFn = errorHandler.getProtectedFunction(stringError);
- e = assertThrows(protectedFn);
- assertEquals('string', typeof e);
- assertEquals(
- goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX + 'String',
- e);
- }
- function testProtectedFunction_infiniteLoop() {
- var numErrors = 0;
- var errorHandler = new goog.debug.ErrorHandler(function(ex) { numErrors++; });
- errorHandler.protectWindowSetTimeout();
- fakeWin.setTimeout(function() { fakeWin.setTimeout(badTimer, 3); }, 3);
- assertEquals(
- 'Error handler should only have been executed once.', 1, numErrors);
- }
- function assertSetTimeoutError(caught) {
- assertMethodCalledHelper('setTimeout', caught);
- }
- function assertSetIntervalError(caught) {
- assertMethodCalledHelper('setInterval', caught);
- }
- function assertRequestAnimationFrameError(caught) {
- assertMethodCalledHelper('requestAnimationFrame', caught);
- }
- function assertMethodCalledHelper(method, caught) {
- assertTrue('exception not thrown', !!caught);
- assertEquals(
- 'exception not caught by error handler', caught.cause, errorHandler.ex);
- assertTrue('fake ' + method + ' not called', !!fakeWin[method].called);
- assertTrue(
- '"this" not passed to original ' + method,
- fakeWin[method].that === fakeWin);
- }
|