4 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
12 var util = require('sys')
13 , assert = require('assert')
14 , AssertionError = assert.AssertionError
15 , eql = require('./eql')
19 * Expose assert as should.
21 * This allows you to do things like below
22 * without require()ing the assert module.
24 * should.equal(foo.bar, undefined);
28 exports = module.exports = assert;
34 exports.version = '0.0.4';
37 * Expose api via `Object#should`.
42 Object.defineProperty(Object.prototype, 'should', {
45 return new Assertion(this);
50 * Initialize a new `Assertion` with the given _obj_.
56 var Assertion = exports.Assertion = function Assertion(obj) {
64 Assertion.prototype = {
67 * HACK: prevents double require() from failing.
73 * Assert _expr_ with the given _msg_ and _negatedMsg_.
75 * @param {Boolean} expr
77 * @param {String} negatedMsg
81 assert: function(expr, msg, negatedMsg){
82 var msg = this.negate ? negatedMsg : msg
83 , ok = this.negate ? !expr : expr;
85 throw new AssertionError({
87 , stackStartFunction: this.assert
143 * Inclusion modifier.
149 this.includes = true;
165 * Get object inspection string.
176 * Assert instanceof `Arguments`.
183 '[object Arguments]' == Object.prototype.toString.call(this.obj)
184 , 'expected ' + this.inspect + ' to be arguments'
185 , 'expected ' + this.inspect + ' to not be arguments');
190 * Assert that an object is empty aka length of 0.
196 this.obj.should.have.property('length');
198 0 === this.obj.length
199 , 'expected ' + this.inspect + ' to be empty'
200 , 'expected ' + this.inspect + ' not to be empty');
213 , 'expected ' + this.inspect + ' to be truthy'
214 , 'expected ' + this.inspect + ' to be falsey');
227 , 'expected ' + this.inspect + ' to be true'
228 , 'expected ' + this.inspect + ' not to be true');
241 , 'expected ' + this.inspect + ' to be false'
242 , 'expected ' + this.inspect + ' not to be false');
256 , 'expected ' + this.inspect + ' to equal ' + i(val)
257 , 'expected ' + this.inspect + ' to not equal ' + i(val));
262 * Assert strict equal.
268 equal: function(val){
271 , 'expected ' + this.inspect + ' to equal ' + i(val)
272 , 'expected ' + this.inspect + ' to not equal ' + i(val));
277 * Assert within start to finish (inclusive).
279 * @param {Number} start
280 * @param {Number} finish
284 within: function(start, finish){
285 var range = start + '..' + finish;
287 this.obj >= start && this.obj <= finish
288 , 'expected ' + this.inspect + ' to be within ' + range
289 , 'expected ' + this.inspect + ' to not be within ' + range);
301 type == typeof this.obj
302 , 'expected ' + this.inspect + ' to be a ' + type
303 , 'expected ' + this.inspect + ' not to be a ' + type);
313 instanceof: function(constructor){
314 var name = constructor.name;
316 this.obj instanceof constructor
317 , 'expected ' + this.inspect + ' to be an instance of ' + name
318 , 'expected ' + this.inspect + ' not to be an instance of ' + name);
323 * Assert numeric value above _n_.
332 , 'expected ' + this.inspect + ' to be above ' + n
333 , 'expected ' + this.inspect + ' to be below ' + n);
338 * Assert numeric value below _n_.
347 , 'expected ' + this.inspect + ' to be below ' + n
348 , 'expected ' + this.inspect + ' to be above ' + n);
353 * Assert string value matches _regexp_.
355 * @param {RegExp} regexp
359 match: function(regexp){
361 regexp.exec(this.obj)
362 , 'expected ' + this.inspect + ' to match ' + regexp
363 , 'expected ' + this.inspect + ' not to match ' + regexp);
368 * Assert property "length" exists and has value of _n_.
375 this.obj.should.have.property('length');
376 var len = this.obj.length;
379 , 'expected ' + this.inspect + ' to have a length of ' + n + ' but got ' + len
380 , 'expected ' + this.inspect + ' to not have a length of ' + len);
387 * @param {String} str
391 string: function(str){
392 this.obj.should.be.a('string');
394 ~this.obj.indexOf(str)
395 , 'expected ' + this.inspect + ' to include ' + i(str)
396 , 'expected ' + this.inspect + ' to not include ' + i(str));
401 * Assert property _name_ exists, with optional _val_.
403 * @param {String} name
408 property: function(name, val){
409 if (this.negate && undefined !== val) {
410 if (undefined === this.obj[name]) {
411 throw new Error(this.inspect + ' has no property ' + i(name));
415 undefined !== this.obj[name]
416 , 'expected ' + this.inspect + ' to have a property ' + i(name)
417 , 'expected ' + this.inspect + ' to not have a property ' + i(name));
420 if (undefined !== val) {
422 val === this.obj[name]
423 , 'expected ' + this.inspect + ' to have a property ' + i(name)
424 + ' of ' + i(val) + ', but got ' + i(this.obj[name])
425 , 'expected ' + this.inspect + ' to not have a property ' + i(name) + ' of ' + i(val));
428 this.obj = this.obj[name];
433 * Assert own property _name_ exists.
435 * @param {String} name
439 ownProperty: function(name){
441 this.obj.hasOwnProperty(name)
442 , 'expected ' + this.inspect + ' to have own property ' + i(name)
443 , 'expected ' + this.inspect + ' to not have own property ' + i(name));
448 * Assert that the array contains _obj_.
454 contain: function(obj){
455 this.obj.should.be.an.instanceof(Array);
457 ~this.obj.indexOf(obj)
458 , 'expected ' + this.inspect + ' to contain ' + i(obj)
459 , 'expected ' + this.inspect + ' to not contain ' + i(obj));
464 * Assert exact keys or inclusion of keys by using
465 * the `.include` modifier.
467 * @param {Array|String ...} keys
471 keys: function(keys){
475 keys = keys instanceof Array
477 : Array.prototype.slice.call(arguments);
479 if (!keys.length) throw new Error('keys required');
481 var actual = Object.keys(this.obj)
485 ok = keys.every(function(key){
486 return ~actual.indexOf(key);
490 if (!this.negate && !this.includes) {
491 ok = ok && keys.length == actual.length;
496 keys = keys.map(function(key){
499 var last = keys.pop();
500 str = keys.join(', ') + ', and ' + last;
506 str = (len > 1 ? 'keys ' : 'key ') + str;
509 str = (this.includes ? 'include ' : 'have ') + str;
514 , 'expected ' + this.inspect + ' to ' + str
515 , 'expected ' + this.inspect + ' to not ' + str);
521 * Assert that _method_ is a function.
523 * @param {String} method
527 respondTo: function(method){
529 'function' == typeof this.obj[method]
530 , 'expected ' + this.inspect + ' to respond to ' + method + '()'
531 , 'expected ' + this.inspect + ' to not respond to ' + method + '()');
540 (function alias(name, as){
541 Assertion.prototype[as] = Assertion.prototype[name];
544 ('length', 'lengthOf')
546 ('ownProperty', 'haveOwnProperty')
547 ('above', 'greaterThan')
548 ('below', 'lessThan');