Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logging: rethrowAsync facility #2597

Merged
merged 1 commit into from
Mar 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 44 additions & 22 deletions src/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,37 +186,20 @@ export class Log {
if (this.level_ >= LogLevel.ERROR) {
this.msg_(tag, 'ERROR', Array.prototype.slice.call(arguments, 1));
} else {
let error = null;
let message = '';
for (let i = 1; i < arguments.length; i++) {
const arg = arguments[i];
if (arg instanceof Error && !error) {
error = arg;
} else {
if (message) {
message += ' ';
}
message += arg;
}
}
if (!error) {
error = new Error(message);
} else if (message) {
error.message = message + ': ' + error.message;
}
const error = createErrorVargs.apply(null,
Array.prototype.slice.call(arguments, 1));
this.prepareError_(error);
this.win.setTimeout(() => {throw error;});
}
}

/**
* Creates an error object.
* @param {string|!Error} errorOrMessage
* @param {...*} var_args
* @return {!Error}
*/
createError(errorOrMessage) {
const error = typeof errorOrMessage == 'string' ?
new Error(errorOrMessage) : errorOrMessage;
createError(var_args) {
const error = createErrorVargs.apply(null, arguments);
this.prepareError_(error);
return error;
}
Expand Down Expand Up @@ -331,6 +314,45 @@ function pushIfNonEmpty(array, val) {
}


/**
* @param {...*} var_args
* @return {!Error}
* @private
*/
function createErrorVargs(var_args) {
let error = null;
let message = '';
for (let i = 0; i < arguments.length; i++) {
const arg = arguments[i];
if (arg instanceof Error && !error) {
error = arg;
} else {
if (message) {
message += ' ';
}
message += arg;
}
}
if (!error) {
error = new Error(message);
} else if (message) {
error.message = message + ': ' + error.message;
}
return error;
}


/**
* Rethrows the error without terminating the current context. This preserves
* whether the original error designation is a user error or a dev error.
* @param {...*} var_args
*/
export function rethrowAsync(var_args) {
const error = createErrorVargs.apply(null, arguments);
setTimeout(() => {throw error;});
}


/**
* @deprecated Use either publog or devlog
* TODO(dvoytenko, #2527): Remove this constant.
Expand Down
68 changes: 68 additions & 0 deletions test/functional/test-log.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
USER_ERROR_SENTINEL,
dev,
isUserErrorMessage,
rethrowAsync,
user,
} from '../../src/log';
import {setModeForTesting} from '../../src/mode';
Expand Down Expand Up @@ -445,4 +446,71 @@ describe('Logging', () => {
.to.throw('Unknown enum value: "VALUE1"');
});
});


describe('rethrowAsync', () => {
let clock;

beforeEach(() => {
clock = sandbox.useFakeTimers();
});

it('should rethrow error with single message', () => {
rethrowAsync('intended');
expect(() => {
clock.tick(1);
}).to.throw(Error, /^intended$/);
});

it('should rethrow a single error', () => {
const orig = new Error('intended');
rethrowAsync(orig);
let error;
try {
clock.tick(1);
} catch (e) {
error = e;
}
expect(error).to.equal(orig);
expect(error.message).to.equal('intended');
});

it('should rethrow error with many messages', () => {
rethrowAsync('first', 'second', 'third');
let error;
try {
clock.tick(1);
} catch (e) {
error = e;
}
expect(error.message).to.equal('first second third');
});

it('should rethrow error with original error and messages', () => {
const orig = new Error('intended');
rethrowAsync('first', orig, 'second', 'third');
let error;
try {
clock.tick(1);
} catch (e) {
error = e;
}
expect(error).to.equal(orig);
expect(error.message).to.equal('first second third: intended');
});

it('should preserve error suffix', () => {
const orig = user.createError('intended');
expect(isUserErrorMessage(orig.message)).to.be.true;
rethrowAsync('first', orig, 'second');
let error;
try {
clock.tick(1);
} catch (e) {
error = e;
}
expect(error).to.equal(orig);
expect(isUserErrorMessage(error.message)).to.be.true;
});
});
});