2011-12-07 05:26:47 +00:00
|
|
|
|
2011-12-14 20:56:56 +00:00
|
|
|
var AssertionError = require('./error')
|
2011-12-15 10:31:35 +00:00
|
|
|
, eql = require('./utils/eql')
|
|
|
|
, inspect = require('./utils/inspect');
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
module.exports = Assertion;
|
|
|
|
|
|
|
|
function Assertion (obj, msg) {
|
|
|
|
this.obj = obj;
|
|
|
|
this.msg = msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
Assertion.prototype.assert = function (expr, msg, negateMsg) {
|
|
|
|
var msg = (this.msg ? this.msg + ': ' : '') + (this.negate ? negateMsg : msg)
|
|
|
|
, ok = this.negate ? !expr : expr;
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
throw new AssertionError({
|
|
|
|
message: msg,
|
|
|
|
startStackFunction: this.assert
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('inspect', function () {
|
|
|
|
return inspect(this.obj);
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('to', function () {
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('be', function () {
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('an', function () {
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('is', function () {
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('and', function () {
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('have', function () {
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('include', function () {
|
2011-12-15 10:33:25 +00:00
|
|
|
this.includes = true;
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('with', function () {
|
2011-12-07 05:26:47 +00:00
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('not', function () {
|
|
|
|
this.negate = true;
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('ok', function () {
|
|
|
|
this.assert(
|
|
|
|
this.obj
|
|
|
|
, 'expected ' + this.inspect + ' to be truthy'
|
|
|
|
, 'expected ' + this.inspect + ' to be falsey');
|
|
|
|
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('true', function () {
|
|
|
|
this.assert(
|
|
|
|
true === this.obj
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to be true'
|
|
|
|
, 'expected ' + this.inspect + ' to be false');
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('false', function () {
|
|
|
|
this.assert(
|
|
|
|
false === this.obj
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to be false'
|
|
|
|
, 'expected ' + this.inspect + ' to be true');
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('exist', function () {
|
|
|
|
this.assert(
|
2011-12-07 06:50:28 +00:00
|
|
|
null != this.obj
|
2011-12-07 05:26:47 +00:00
|
|
|
, 'expected ' + this.inspect + ' to exist'
|
|
|
|
, 'expected ' + this.inspect + ' to not exist');
|
|
|
|
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.__defineGetter__('empty', function () {
|
|
|
|
new Assertion(this.obj).to.have.property('length');
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
0 === this.obj.length
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to be empty'
|
|
|
|
, 'expected ' + this.inspect + ' not to be empty');
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
});
|
|
|
|
|
|
|
|
Assertion.prototype.equal = function (val) {
|
|
|
|
this.assert(
|
|
|
|
val === this.obj
|
|
|
|
, 'expected ' + this.inspect + ' to equal ' + inspect(val)
|
|
|
|
, 'expected ' + this.inspect + ' to not equal ' + inspect(val));
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-07 06:50:28 +00:00
|
|
|
Assertion.prototype.eql = function (obj) {
|
2011-12-14 20:56:56 +00:00
|
|
|
this.assert(
|
|
|
|
eql(obj, this.obj)
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to equal ' + inspect(obj)
|
|
|
|
, 'expected ' + this.inspect + ' to not equal ' + inspect(obj));
|
2011-12-07 06:50:28 +00:00
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-07 05:26:47 +00:00
|
|
|
Assertion.prototype.above = function (val) {
|
|
|
|
this.assert(
|
|
|
|
this.obj > val
|
|
|
|
, 'expected ' + this.inspect + ' to be above ' + val
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to be below ' + val);
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.below = function (val) {
|
|
|
|
this.assert(
|
|
|
|
this.obj < val
|
|
|
|
, 'expected ' + this.inspect + ' to be below ' + val
|
|
|
|
, 'expected ' + this.inspect + ' to be above ' + val);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.a = function (type) {
|
|
|
|
this.assert(
|
|
|
|
type == typeof this.obj
|
|
|
|
, 'expected ' + this.inspect + ' to be a ' + type
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' not to be a ' + type);
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.instanceof = function (constructor) {
|
|
|
|
var name = constructor.name;
|
|
|
|
this.assert(
|
|
|
|
this.obj instanceof constructor
|
|
|
|
, 'expected ' + this.inspect + ' to be an instance of ' + name
|
|
|
|
, 'expected ' + this.inspect + ' to not be an instance of ' + name);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-15 10:32:09 +00:00
|
|
|
Assertion.prototype.respondTo = function (method) {
|
|
|
|
this.assert(
|
|
|
|
'function' == typeof this.obj[method]
|
|
|
|
, 'expected ' + this.inspect + ' to respond to ' + method + '()'
|
|
|
|
, 'expected ' + this.inspect + ' to not respond to ' + method + '()');
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2011-12-14 20:57:52 +00:00
|
|
|
Assertion.prototype.property = function (name, val) {
|
2011-12-15 10:34:06 +00:00
|
|
|
if (this.negate && undefined !== val) {
|
|
|
|
if (undefined === this.obj[name]) {
|
|
|
|
throw new Error(this.inspect + ' has no property ' + inspect(name));
|
|
|
|
}
|
2011-12-14 20:57:52 +00:00
|
|
|
} else {
|
|
|
|
this.assert(
|
|
|
|
undefined !== this.obj[name]
|
2011-12-15 10:34:06 +00:00
|
|
|
, 'expected ' + this.inspect + ' to have a property ' + inspect(name)
|
|
|
|
, 'expected ' + this.inspect + ' to not have property ' + inspect(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (undefined !== val) {
|
|
|
|
this.assert(
|
|
|
|
val === this.obj[name]
|
|
|
|
, 'expected ' + this.inspect + ' to have a property ' + inspect(name) + ' of ' +
|
|
|
|
inspect(val) + ', but got ' + inspect(this.obj[name])
|
|
|
|
, 'expected ' + this.inspect + ' to not have a property ' + inspect(name) + ' of ' + inspect(val));
|
2011-12-14 20:57:52 +00:00
|
|
|
}
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
this.obj = this.obj[name];
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-15 10:34:06 +00:00
|
|
|
Assertion.prototype.ownProperty = function (name) {
|
|
|
|
this.assert(
|
|
|
|
this.obj.hasOwnProperty(name)
|
|
|
|
, 'expected ' + this.inspect + ' to have own property ' + inspect(name)
|
|
|
|
, 'expected ' + this.inspect + ' to not have own property ' + inspect(name));
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-07 05:26:47 +00:00
|
|
|
Assertion.prototype.length = function (n) {
|
|
|
|
new Assertion(this.obj).to.have.property('length');
|
|
|
|
var len = this.obj.length;
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
len == n
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to have a length of ' + n + ' but got ' + len
|
2011-12-07 05:26:47 +00:00
|
|
|
, 'expected ' + this.inspect + ' to not have a length of ' + len);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.match = function (re) {
|
|
|
|
this.assert(
|
|
|
|
re.exec(this.obj)
|
|
|
|
, 'expected ' + this.inspect + ' to match ' + re
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' not to match ' + re);
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.contain = function (obj) {
|
|
|
|
new Assertion(this.obj).to.be.an.instanceof(Array);
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
~this.obj.indexOf(obj)
|
|
|
|
, 'expected ' + this.inspect + ' to contain ' + inspect(obj)
|
|
|
|
, 'expected ' + this.inspect + ' to not contain ' + inspect(obj));
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-15 10:34:58 +00:00
|
|
|
Assertion.prototype.within = function (start, finish) {
|
|
|
|
var range = start + '..' + finish;
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
this.obj >= start && this.obj <= finish
|
|
|
|
, 'expected ' + this.inspect + ' to be within ' + range
|
|
|
|
, 'expected ' + this.inspect + ' to not be within ' + range);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
Assertion.prototype.greaterThan = function (val) {
|
|
|
|
this.assert(
|
|
|
|
this.obj > val
|
|
|
|
, 'expected ' + this.inspect + ' to be greater than ' + inspect(val)
|
|
|
|
, 'expected ' + this.inspect + ' to not be greater than ' + inspect(val));
|
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-07 05:26:47 +00:00
|
|
|
Assertion.prototype.string = function (str) {
|
|
|
|
new Assertion(this.obj).is.a('string');
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
~this.obj.indexOf(str)
|
2011-12-15 10:33:25 +00:00
|
|
|
, 'expected ' + this.inspect + ' to include ' + inspect(str)
|
|
|
|
, 'expected ' + this.inspect + ' to not include ' + inspect(str));
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2011-12-15 10:34:58 +00:00
|
|
|
Assertion.prototype.object = function(obj){
|
|
|
|
new Assertion(this.obj).is.a('object');
|
|
|
|
|
|
|
|
var included = true;
|
|
|
|
|
|
|
|
for (var key in obj) {
|
|
|
|
if (obj.hasOwnProperty(key) && !eql(obj[key], this.obj[key])) {
|
|
|
|
included = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
included
|
|
|
|
, 'expected ' + this.inspect + ' to include ' + inspect(obj)
|
|
|
|
, 'expected ' + this.inspect + ' to not include ' + inspect(obj));
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Assertion.prototype.keys = function(keys) {
|
|
|
|
var str
|
|
|
|
, ok = true;
|
|
|
|
|
|
|
|
keys = keys instanceof Array
|
|
|
|
? keys
|
|
|
|
: Array.prototype.slice.call(arguments);
|
|
|
|
|
|
|
|
if (!keys.length) throw new Error('keys required');
|
|
|
|
|
|
|
|
var actual = Object.keys(this.obj)
|
|
|
|
, len = keys.length;
|
|
|
|
|
|
|
|
// Inclusion
|
|
|
|
ok = keys.every(function(key){
|
|
|
|
return ~actual.indexOf(key);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Strict
|
|
|
|
if (!this.negate && !this.includes) {
|
|
|
|
ok = ok && keys.length == actual.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Key string
|
|
|
|
if (len > 1) {
|
|
|
|
keys = keys.map(function(key){
|
|
|
|
return inspect(key);
|
|
|
|
});
|
|
|
|
var last = keys.pop();
|
|
|
|
str = keys.join(', ') + ', and ' + last;
|
|
|
|
} else {
|
|
|
|
str = inspect(keys[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Form
|
|
|
|
str = (len > 1 ? 'keys ' : 'key ') + str;
|
|
|
|
|
|
|
|
// Have / include
|
|
|
|
str = (this.includes ? 'include ' : 'have ') + str;
|
|
|
|
|
|
|
|
// Assertion
|
|
|
|
this.assert(
|
|
|
|
ok
|
|
|
|
, 'expected ' + this.inspect + ' to ' + str
|
|
|
|
, 'expected ' + this.inspect + ' to not ' + str);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2011-12-07 05:26:47 +00:00
|
|
|
Assertion.prototype.throw = function (constructor) {
|
2011-12-07 06:10:44 +00:00
|
|
|
new Assertion(this.obj).is.a('function');
|
2011-12-07 05:26:47 +00:00
|
|
|
|
|
|
|
constructor = constructor || Error;
|
|
|
|
var name = constructor.name
|
|
|
|
, thrown = false;
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.obj();
|
|
|
|
} catch (err) {
|
|
|
|
thrown = true;
|
|
|
|
this.assert(
|
|
|
|
err instanceof constructor
|
|
|
|
, 'expected ' + this.inspect + ' to throw ' + name
|
|
|
|
, 'expected ' + this.inspect + ' to not throw ' + name);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.assert(
|
|
|
|
thrown === true
|
|
|
|
, 'expected ' + this.inspect + ' to throw ' + name
|
|
|
|
, 'expected ' + this.inspect + ' to not throw ' + name);
|
2011-12-15 10:34:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Aliases.
|
|
|
|
*/
|
|
|
|
|
|
|
|
(function alias(name, as){
|
|
|
|
Assertion.prototype[as] = Assertion.prototype[name];
|
|
|
|
return alias;
|
|
|
|
})
|
|
|
|
('length', 'lengthOf')
|
|
|
|
('keys', 'key')
|
|
|
|
('ownProperty', 'haveOwnProperty')
|
|
|
|
('above', 'greaterThan')
|
|
|
|
('below', 'lessThan');
|