170 lines
3.4 KiB
JavaScript
170 lines
3.4 KiB
JavaScript
/*!
|
|
* Should
|
|
* Copyright(c) 2010-2014 TJ Holowaychuk <tj@vision-media.ca>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
|
|
var util = require('./util')
|
|
, AssertionError = util.AssertionError
|
|
, inspect = util.inspect;
|
|
|
|
/**
|
|
* Our function should
|
|
* @param obj
|
|
* @returns {Assertion}
|
|
*/
|
|
var should = function(obj) {
|
|
return new Assertion(util.isWrapperType(obj) ? obj.valueOf(): obj);
|
|
};
|
|
|
|
/**
|
|
* Initialize a new `Assertion` with the given _obj_.
|
|
*
|
|
* @param {*} obj
|
|
* @api private
|
|
*/
|
|
|
|
var Assertion = should.Assertion = function Assertion(obj) {
|
|
this.obj = obj;
|
|
};
|
|
|
|
|
|
/**
|
|
Way to extend Assertion function. It uses some logic
|
|
to define only positive assertions and itself rule with negative assertion.
|
|
|
|
All actions happen in subcontext and this method take care about negation.
|
|
Potentially we can add some more modifiers that does not depends from state of assertion.
|
|
*/
|
|
Assertion.add = function(name, f, isGetter) {
|
|
var prop = {};
|
|
prop[isGetter ? 'get' : 'value'] = function() {
|
|
var context = new Assertion(this.obj);
|
|
context.copy = context.copyIfMissing;
|
|
|
|
try {
|
|
f.apply(context, arguments);
|
|
} catch(e) {
|
|
//copy data from sub context to this
|
|
this.copy(context);
|
|
|
|
//check for fail
|
|
if(e instanceof should.AssertionError) {
|
|
//negative fail
|
|
if(this.negate) {
|
|
this.obj = context.obj;
|
|
this.negate = false;
|
|
return this;
|
|
}
|
|
this.assert(false);
|
|
}
|
|
// throw if it is another exception
|
|
throw e;
|
|
}
|
|
//copy data from sub context to this
|
|
this.copy(context);
|
|
if(this.negate) {
|
|
this.assert(false);
|
|
}
|
|
|
|
this.obj = context.obj;
|
|
this.negate = false;
|
|
return this;
|
|
};
|
|
|
|
Object.defineProperty(Assertion.prototype, name, prop);
|
|
};
|
|
|
|
Assertion.alias = function(from, to) {
|
|
Assertion.prototype[to] = Assertion.prototype[from]
|
|
};
|
|
|
|
should.AssertionError = AssertionError;
|
|
var i = should.format = function i(value) {
|
|
if(util.isDate(value) && typeof value.inspect !== 'function') return value.toISOString(); //show millis in dates
|
|
return inspect(value, { depth: null });
|
|
};
|
|
|
|
should.use = function(f) {
|
|
f(this, Assertion);
|
|
return this;
|
|
};
|
|
|
|
|
|
/**
|
|
* Expose should to external world.
|
|
*/
|
|
exports = module.exports = should;
|
|
|
|
|
|
/**
|
|
* Expose api via `Object#should`.
|
|
*
|
|
* @api public
|
|
*/
|
|
|
|
Object.defineProperty(Object.prototype, 'should', {
|
|
set: function(){},
|
|
get: function(){
|
|
return should(this);
|
|
},
|
|
configurable: true
|
|
});
|
|
|
|
|
|
Assertion.prototype = {
|
|
constructor: Assertion,
|
|
|
|
assert: function(expr) {
|
|
if(expr) return;
|
|
|
|
var params = this.params;
|
|
|
|
var msg = params.message, generatedMessage = false;
|
|
if(!msg) {
|
|
msg = this.getMessage();
|
|
generatedMessage = true;
|
|
}
|
|
|
|
var err = new AssertionError({
|
|
message: msg
|
|
, actual: this.obj
|
|
, expected: params.expected
|
|
, stackStartFunction: this.assert
|
|
});
|
|
|
|
err.showDiff = params.showDiff;
|
|
err.operator = params.operator;
|
|
err.generatedMessage = generatedMessage;
|
|
|
|
throw err;
|
|
},
|
|
|
|
getMessage: function() {
|
|
return 'expected ' + i(this.obj) + (this.negate ? ' not ': ' ') +
|
|
this.params.operator + ('expected' in this.params ? ' ' + i(this.params.expected) : '');
|
|
},
|
|
|
|
copy: function(other) {
|
|
this.params = other.params;
|
|
},
|
|
|
|
copyIfMissing: function(other) {
|
|
if(!this.params) this.params = other.params;
|
|
},
|
|
|
|
|
|
/**
|
|
* Negation modifier.
|
|
*
|
|
* @api public
|
|
*/
|
|
|
|
get not() {
|
|
this.negate = !this.negate;
|
|
return this;
|
|
}
|
|
};
|
|
|