Files
hudozka/node_modules/should/lib/ext/property.js
T
2014-02-12 12:36:59 +04:00

215 lines
5.9 KiB
JavaScript

/*!
* Should
* Copyright(c) 2010-2014 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
var util = require('../util'),
eql = require('../eql');
var aSlice = Array.prototype.slice;
module.exports = function(should, Assertion) {
var i = should.format;
Assertion.add('property', function(name, val) {
if(arguments.length > 1) {
var p = {};
p[name] = val;
this.have.properties(p);
} else {
this.have.properties(name);
}
this.obj = this.obj[name];
});
Assertion.add('properties', function(names) {
var values = {};
if(arguments.length > 1) {
names = aSlice.call(arguments);
} else if(!Array.isArray(names)) {
if(util.isString(names)) {
names = [names];
} else {
values = names;
names = Object.keys(names);
}
}
var obj = Object(this.obj), missingProperties = [];
//just enumerate properties and check if they all present
names.forEach(function(name) {
if(!(name in obj)) missingProperties.push(i(name));
});
var props = missingProperties;
if(props.length === 0) {
props = names.map(i);
}
var operator = (props.length === 1 ?
'to have property ' : 'to have properties ') + props.join(', ');
this.params = { operator: operator };
this.assert(missingProperties.length === 0);
// check if values in object matched expected
var valueCheckNames = Object.keys(values);
if(valueCheckNames.length) {
var wrongValues = [];
props = [];
// now check values, as there we have all properties
valueCheckNames.forEach(function(name) {
var value = values[name];
if(!eql(obj[name], value)) {
wrongValues.push(i(name) + ' of ' + i(value) + ' (got ' + i(obj[name]) + ')');
} else {
props.push(i(name) + ' of ' + i(value));
}
});
if(wrongValues.length > 0) {
props = wrongValues;
}
operator = (props.length === 1 ?
'to have property ' : 'to have properties ') + props.join(', ');
this.params = { operator: operator };
this.assert(wrongValues.length === 0);
}
});
Assertion.add('length', function(n, description) {
this.have.property('length', n, description);
});
Assertion.alias('length', 'lengthOf');
var hasOwnProperty = Object.prototype.hasOwnProperty;
Assertion.add('ownProperty', function(name, description) {
this.params = { operator: 'to have own property ' + i(name), message: description };
this.assert(hasOwnProperty.call(this.obj, name));
this.obj = this.obj[name];
});
Assertion.alias('hasOwnProperty', 'ownProperty');
Assertion.add('empty', function() {
this.params = { operator: 'to be empty' };
if(util.isString(this.obj) || Array.isArray(this.obj) || util.isArguments(this.obj)) {
this.have.property('length', 0);
} else {
var obj = Object(this.obj); // wrap to reference for booleans and numbers
for(var prop in obj) {
this.have.not.ownProperty(prop);
}
}
}, true);
Assertion.add('keys', function(keys) {
if(arguments.length > 1) keys = aSlice.call(arguments);
else if(arguments.length === 1 && util.isString(keys)) keys = [ keys ];
else if(arguments.length === 0) keys = [];
var obj = Object(this.obj);
// first check if some keys are missing
var missingKeys = [];
keys.forEach(function(key) {
if(!hasOwnProperty.call(this.obj, key))
missingKeys.push(i(key));
}, this);
// second check for extra keys
var extraKeys = [];
Object.keys(obj).forEach(function(key) {
if(keys.indexOf(key) < 0) {
extraKeys.push(i(key));
}
});
var verb = keys.length === 0 ? 'to be empty' :
'to have ' + (keys.length === 1 ? 'key ' : 'keys ');
this.params = { operator: verb + keys.map(i).join(', ')};
if(missingKeys.length > 0)
this.params.operator += '\n\tmissing keys: ' + missingKeys.join(', ');
if(extraKeys.length > 0)
this.params.operator += '\n\textra keys: ' + extraKeys.join(', ');
this.assert(missingKeys.length === 0 && extraKeys.length === 0);
});
Assertion.alias("keys", "key");
Assertion.add('containEql', function(other) {
this.params = { operator: 'to contain ' + i(other) };
var obj = this.obj;
if(Array.isArray(obj)) {
this.assert(obj.some(function(item) {
return eql(item, other);
}));
} else if(util.isString(obj)) {
// expect obj to be string
this.assert(obj.indexOf(String(other)) >= 0);
} else if(util.isObject(obj)) {
// object contains object case
util.forOwn(other, function(value, key) {
obj[key].should.eql(value);
});
} else {
//other uncovered cases
this.assert(false);
}
});
Assertion.add('containDeep', function(other) {
this.params = { operator: 'to contain ' + i(other) };
var obj = this.obj;
if(Array.isArray(obj)) {
if(Array.isArray(other)) {
var otherIdx = 0;
obj.forEach(function(item) {
try {
should(item).not.be.null.and.containDeep(other[otherIdx]);
otherIdx++;
} catch(e) {
if(e instanceof should.AssertionError) {
return;
}
throw e;
}
});
this.assert(otherIdx == other.length);
//search array contain other as sub sequence
} else {
this.assert(false);
}
} else if(util.isString(obj)) {// expect other to be string
this.assert(obj.indexOf(String(other)) >= 0);
} else if(util.isObject(obj)) {// object contains object case
if(util.isObject(other)) {
util.forOwn(other, function(value, key) {
should(obj[key]).not.be.null.and.containDeep(value);
});
} else {//one of the properties contain value
this.assert(false);
}
} else {
this.eql(other);
}
});
};