-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create CustomError to refactor other Error classes
- Loading branch information
Rémi Becheras
committed
Jan 2, 2017
1 parent
aab7947
commit d8b2e66
Showing
2 changed files
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
'use strict' | ||
|
||
var path = require('path') | ||
var PrivateMethodError = require('./PrivateMethodError') | ||
|
||
module.exports = CustomError | ||
|
||
/** | ||
* CustomError | ||
* @class | ||
* @mixin | ||
* @property {String} message The error message | ||
* @property {String} stack The error stack trace | ||
* | ||
* @constructor | ||
* @param {String} [msg] The error message | ||
*/ | ||
function CustomError (msg) { | ||
// Error.call(this, msg) | ||
if (msg && typeof msg === 'string') { | ||
this.message = msg | ||
} else if (this.constructor.name !== 'CustomError') { | ||
this.message = global[this.constructor.name].DEFAULT_ERROR_MESSAGE | ||
} else { | ||
this.message = undefined | ||
} | ||
this.createStackTrace() | ||
} | ||
|
||
CustomError.prototype = Object.create(Error.prototype) | ||
CustomError.prototype.constructor = CustomError | ||
CustomError.prototype.createStackTrace = createStackTrace | ||
CustomError.prototype.protect = protect | ||
CustomError.prototype.privatize = privatize | ||
|
||
/** | ||
* Set the the correct stack trace for this error | ||
* @method | ||
* @returns {undefined} | ||
* @throws {PrivateMethodError} | ||
*/ | ||
function createStackTrace () { | ||
privatize() | ||
var stack = new Error().stack | ||
var splited = stack.split('\n') | ||
var modifiedStack = splited[0].concat('\n', splited.splice(3).join('\n')) | ||
this.stack = modifiedStack | ||
} | ||
|
||
/** | ||
* Throws a PrivateMethodError if the caller is not CustomError | ||
* @function | ||
* @inner | ||
* @returns {undefined} | ||
* @throws {PrivateMethodError} | ||
*/ | ||
function privatize () { | ||
var trace = new Error().stack | ||
var here = getFileCall(trace, 1) | ||
var caller = getFileCall(trace, 3) | ||
if (here !== caller) { | ||
throw new PrivateMethodError() | ||
} | ||
} | ||
|
||
/** | ||
* Throws a ProtectedMethodError if the caller is not a child class of CustomError | ||
* @method | ||
* @returns {undefined} | ||
* @throws {ProtectedMethodError} | ||
*/ | ||
function protect (sourcePath) { | ||
var trace = new Error().stack | ||
var caller = getFileCall(trace, 3) | ||
if (sourcePath !== caller) { | ||
// throw new ProtectedMethodError() | ||
throw new Error() | ||
} | ||
} | ||
|
||
/** | ||
* Get the file path of the caller at a given stack level | ||
* @function | ||
* @inner | ||
* @param {String} trace A given stack trace | ||
* @param {Number} level A given stack level to get the file path at this level | ||
* @returns {String} The file path for this level | ||
*/ | ||
function getFileCall (trace, level) { | ||
var firstLineOfStack = trace.split('\n')[level] | ||
var splitted = firstLineOfStack.split('(') | ||
firstLineOfStack = splitted.splice(1).join('') | ||
splitted = firstLineOfStack.split(')') | ||
firstLineOfStack = splitted.join('') | ||
splitted = firstLineOfStack.split(':') | ||
firstLineOfStack = splitted.slice(0, -2).join('') | ||
return firstLineOfStack | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
'use strict' | ||
|
||
var path = require('path') | ||
var chai = require('chai') | ||
var CustomError = require(path.resolve('./lib/errors/CustomError')) | ||
|
||
var describe = global.describe | ||
var it = global.it | ||
var expect = chai.expect | ||
|
||
describe('CustomError', function () { | ||
it('should be a function', function () { | ||
expect(CustomError).to.be.a('function') | ||
}) | ||
|
||
it("should not have a 'DEFAULT_ERROR_MESSAGE' static constant property (child classes should have one)", function () { | ||
expect(CustomError).to.not.have.a.property('DEFAULT_ERROR_MESSAGE') | ||
}) | ||
|
||
describe('.prototype', function () { | ||
it('should be a function', function () { | ||
expect(CustomError.prototype).to.be.a('OBJECT') | ||
}) | ||
|
||
it('should be an instance of Error', function () { | ||
expect(CustomError.prototype).to.be.an.instanceof(Error) | ||
}) | ||
|
||
describe('.constructor()', function () { | ||
it('should be an instance of CustomError', function () { | ||
var err = new CustomError() | ||
expect(CustomError.prototype).to.be.an.instanceof(Error) | ||
expect(err).to.be.an.instanceof(CustomError) | ||
}) | ||
|
||
it("should have a 'name' property of type 'String'", function () { | ||
var msg = "'arg' is missing" | ||
var err = new CustomError(msg) | ||
expect(err).to.be.a.property('name') | ||
expect(err.message).to.be.a('String') | ||
}) | ||
|
||
it("should have a 'message' property of type 'String'", function () { | ||
var msg = "'arg' is missing" | ||
var err = new CustomError(msg) | ||
expect(err).to.be.a.property('message') | ||
expect(err.message).to.be.a('String') | ||
expect(err.message).to.equal(msg) | ||
}) | ||
|
||
it("should have a 'stack' property of type 'String'", function () { | ||
var msg = "'arg' is missing" | ||
var err = new CustomError(msg) | ||
expect(err).to.be.a.property('stack') | ||
expect(err.stack).to.be.a('String') | ||
}) | ||
|
||
it("should have a 'createStackTrace' property of type 'function'", function () { | ||
var err = new CustomError('yo') | ||
expect(err).to.have.a.property('createStackTrace') | ||
expect(err.createStackTrace).to.be.a('function') | ||
}) | ||
|
||
it("should have a 'privatize' property of type 'function'", function () { | ||
var err = new CustomError() | ||
expect(err).to.be.a.property('privatize') | ||
expect(err.privatize).to.be.a('function') | ||
}) | ||
|
||
it("should have a 'protect' property of type 'function'", function () { | ||
var err = new CustomError() | ||
expect(err).to.be.a.property('protect') | ||
expect(err.protect).to.be.a('function') | ||
}) | ||
|
||
it('should not fail if an bad type is given instead of a string as first argument', function () { | ||
var err | ||
var func = function () { err = new CustomError(func) } | ||
var obj = function () { err = new CustomError({ foo: 'bar' }) } | ||
var arr = function () { err = new CustomError([ 'foo', 'baz' ]) } | ||
|
||
expect(func).to.not.throw('TypeError') | ||
expect(obj).to.not.throw('TypeError') | ||
expect(arr).to.not.throw('TypeError') | ||
}) | ||
|
||
it('should fails if we call the private createStackTrace method', function () { | ||
var func = function () { | ||
var err = new CustomError(func) | ||
var t = err.createStackTrace() | ||
console.log(t) | ||
} | ||
expect(func).to.throw(Error) | ||
}) | ||
|
||
it('should fails if a child class call the protected createStackTrace method', function () { | ||
var func = function () { | ||
var err = new CustomError(func) | ||
var t = err.createStackTrace() | ||
console.log(t) | ||
} | ||
expect(func).to.throw(Error) | ||
}) | ||
|
||
it('should not have a default error message if no argument is given (child class should have)', function () { | ||
var err = new CustomError() | ||
expect(err.message).to.not.be.a('String') | ||
expect(err.message).to.be.undefined | ||
}) | ||
}) | ||
}) | ||
}) |