cloudboost-tv
Version:
Database Service that does Storage, Search, Real-time and a whole lot more.
164 lines (148 loc) • 5.69 kB
JavaScript
/*!
* Should
* Copyright(c) 2010-2014 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
var util = require('../util');
var eql = require('should-equal');
module.exports = function(should, Assertion) {
var i = should.format;
var type = should.type;
/**
* Assert that given object contain something that equal to `other`. It uses `should-equal` for equality checks.
* If given object is array it search that one of elements was equal to `other`.
* If given object is string it checks if `other` is a substring - expected that `other` is a string.
* If given object is Object it checks that `other` is a subobject - expected that `other` is a object.
*
* @name containEql
* @memberOf Assertion
* @category assertion contain
* @param {*} other Nested object
* @example
*
* [1, 2, 3].should.containEql(1);
* [{ a: 1 }, 'a', 10].should.containEql({ a: 1 });
*
* 'abc'.should.containEql('b');
* 'ab1c'.should.containEql(1);
*
* ({ a: 10, c: { d: 10 }}).should.containEql({ a: 10 });
* ({ a: 10, c: { d: 10 }}).should.containEql({ c: { d: 10 }});
* ({ a: 10, c: { d: 10 }}).should.containEql({ b: 10 });
* // throws AssertionError: expected { a: 10, c: { d: 10 } } to contain { b: 10 }
* // expected { a: 10, c: { d: 10 } } to have property b
*/
Assertion.add('containEql', function(other) {
this.params = {operator: 'to contain ' + i(other)};
this.is.not.null.and.not.undefined;
var obj = this.obj;
var tpe = should.type(obj);
if(tpe == should.type.STRING) {
this.assert(obj.indexOf(String(other)) >= 0);
} else if(util.isIndexable(obj)) {
this.assert(util.some(obj, function(v) {
return eql(v, other).result;
}));
} else {
this.have.properties(other);
}
});
/**
* Assert that given object is contain equally structured object on the same depth level.
* If given object is an array and `other` is an array it checks that the eql elements is going in the same sequence in given array (recursive)
* For string it is working as `Assertion#containEql
* If given object is an object it checks that the same keys contain deep equal values (recursive)
* On other cases it try to check with `.eql`
*
* @name containDeepOrdered
* @memberOf Assertion
* @category assertion contain
* @param {*} other Nested object
* @example
*
* [ 1, 2, 3].should.containDeepOrdered([1, 2]);
* [ 1, 2, [ 1, 2, 3 ]].should.containDeepOrdered([ 1, [ 2, 3 ]]);
*
* '123'.should.containDeepOrdered('1')
*
* ({ a: 10, b: { c: 10, d: [1, 2, 3] }}).should.containDeepOrdered({a: 10});
* ({ a: 10, b: { c: 10, d: [1, 2, 3] }}).should.containDeepOrdered({b: {c: 10}});
* ({ a: 10, b: { c: 10, d: [1, 2, 3] }}).should.containDeepOrdered({b: {d: [1, 3]}});
*/
Assertion.add('containDeepOrdered', function(other) {
this.params = {operator: 'to contain ' + i(other)};
var obj = this.obj;
if(type(obj) == type.STRING) {// expect other to be string
this.assert(obj.indexOf(String(other)) >= 0);
} else if(util.isIndexable(obj) && util.isIndexable(other)) {
for(var objIdx = 0, otherIdx = 0, objLength = util.length(obj), otherLength = util.length(other); objIdx < objLength && otherIdx < otherLength; objIdx++) {
try {
should(obj[objIdx]).containDeepOrdered(other[otherIdx]);
otherIdx++;
} catch(e) {
if(e instanceof should.AssertionError) {
continue;
}
throw e;
}
}
this.assert(otherIdx == otherLength);
} else if(obj != null && other != null && typeof obj == 'object' && typeof other == 'object') {// object contains object case
util.forEach(other, function(value, key) {
should(obj[key]).containDeepOrdered(value);
});
// if both objects is empty means we finish traversing - and we need to compare for hidden values
if(util.isEmptyObject(other)) {
this.eql(other);
}
} else {
this.eql(other);
}
});
/**
* The same like `Assertion#containDeepOrdered` but all checks on arrays without order.
*
* @name containDeep
* @memberOf Assertion
* @category assertion contain
* @param {*} other Nested object
* @example
*
* [ 1, 2, 3].should.containDeep([2, 1]);
* [ 1, 2, [ 1, 2, 3 ]].should.containDeep([ 1, [ 3, 1 ]]);
*/
Assertion.add('containDeep', function(other) {
this.params = {operator: 'to contain ' + i(other)};
var obj = this.obj;
if(typeof obj == 'string') {// expect other to be string
this.assert(obj.indexOf(String(other)) >= 0);
} else if(util.isIndexable(obj) && util.isIndexable(other)) {
var usedKeys = {};
util.forEach(other, function(otherItem) {
this.assert(util.some(obj, function(item, index) {
if(index in usedKeys) return false;
try {
should(item).containDeep(otherItem);
usedKeys[index] = true;
return true;
} catch(e) {
if(e instanceof should.AssertionError) {
return false;
}
throw e;
}
}));
}, this);
} else if(obj != null && other != null && typeof obj == 'object' && typeof other == 'object') {// object contains object case
util.forEach(other, function(value, key) {
should(obj[key]).containDeep(value);
});
// if both objects is empty means we finish traversing - and we need to compare for hidden values
if(util.isEmptyObject(other)) {
this.eql(other);
}
} else {
this.eql(other);
}
});
};