/*! * Should * Copyright(c) 2010-2014 TJ Holowaychuk * 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; } };