/*! * should - test framework agnostic BDD-style assertions * @version v13.2.3 * @author TJ Holowaychuk , Denis Bardadym * @link https://github.com/shouldjs/should.js * @license MIT */ (function () { 'use strict'; var types = { NUMBER: 'number', UNDEFINED: 'undefined', STRING: 'string', BOOLEAN: 'boolean', OBJECT: 'object', FUNCTION: 'function', NULL: 'null', ARRAY: 'array', REGEXP: 'regexp', DATE: 'date', ERROR: 'error', ARGUMENTS: 'arguments', SYMBOL: 'symbol', ARRAY_BUFFER: 'array-buffer', TYPED_ARRAY: 'typed-array', DATA_VIEW: 'data-view', MAP: 'map', SET: 'set', WEAK_SET: 'weak-set', WEAK_MAP: 'weak-map', PROMISE: 'promise', // node buffer BUFFER: 'buffer', // dom html element HTML_ELEMENT: 'html-element', HTML_ELEMENT_TEXT: 'html-element-text', DOCUMENT: 'document', WINDOW: 'window', FILE: 'file', FILE_LIST: 'file-list', BLOB: 'blob', HOST: 'host', XHR: 'xhr', // simd SIMD: 'simd' }; /* * Simple data function to store type information * @param {string} type Usually what is returned from typeof * @param {string} cls Sanitized @Class via Object.prototype.toString * @param {string} sub If type and cls the same, and need to specify somehow * @private * @example * * //for null * new Type('null'); * * //for Date * new Type('object', 'date'); * * //for Uint8Array * * new Type('object', 'typed-array', 'uint8'); */ function Type(type, cls, sub) { if (!type) { throw new Error('Type class must be initialized at least with `type` information'); } this.type = type; this.cls = cls; this.sub = sub; } Type.prototype = { toString: function(sep) { sep = sep || ';'; var str = [this.type]; if (this.cls) { str.push(this.cls); } if (this.sub) { str.push(this.sub); } return str.join(sep); }, toTryTypes: function() { var _types = []; if (this.sub) { _types.push(new Type(this.type, this.cls, this.sub)); } if (this.cls) { _types.push(new Type(this.type, this.cls)); } _types.push(new Type(this.type)); return _types; } }; var toString = Object.prototype.toString; /** * Function to store type checks * @private */ function TypeChecker() { this.checks = []; } TypeChecker.prototype = { add: function(func) { this.checks.push(func); return this; }, addBeforeFirstMatch: function(obj, func) { var match = this.getFirstMatch(obj); if (match) { this.checks.splice(match.index, 0, func); } else { this.add(func); } }, addTypeOf: function(type, res) { return this.add(function(obj, tpeOf) { if (tpeOf === type) { return new Type(res); } }); }, addClass: function(cls, res, sub) { return this.add(function(obj, tpeOf, objCls) { if (objCls === cls) { return new Type(types.OBJECT, res, sub); } }); }, getFirstMatch: function(obj) { var typeOf = typeof obj; var cls = toString.call(obj); for (var i = 0, l = this.checks.length; i < l; i++) { var res = this.checks[i].call(this, obj, typeOf, cls); if (typeof res !== 'undefined') { return { result: res, func: this.checks[i], index: i }; } } }, getType: function(obj) { var match = this.getFirstMatch(obj); return match && match.result; } }; var main = new TypeChecker(); //TODO add iterators main .addTypeOf(types.NUMBER, types.NUMBER) .addTypeOf(types.UNDEFINED, types.UNDEFINED) .addTypeOf(types.STRING, types.STRING) .addTypeOf(types.BOOLEAN, types.BOOLEAN) .addTypeOf(types.FUNCTION, types.FUNCTION) .addTypeOf(types.SYMBOL, types.SYMBOL) .add(function(obj) { if (obj === null) { return new Type(types.NULL); } }) .addClass('[object String]', types.STRING) .addClass('[object Boolean]', types.BOOLEAN) .addClass('[object Number]', types.NUMBER) .addClass('[object Array]', types.ARRAY) .addClass('[object RegExp]', types.REGEXP) .addClass('[object Error]', types.ERROR) .addClass('[object Date]', types.DATE) .addClass('[object Arguments]', types.ARGUMENTS) .addClass('[object ArrayBuffer]', types.ARRAY_BUFFER) .addClass('[object Int8Array]', types.TYPED_ARRAY, 'int8') .addClass('[object Uint8Array]', types.TYPED_ARRAY, 'uint8') .addClass('[object Uint8ClampedArray]', types.TYPED_ARRAY, 'uint8clamped') .addClass('[object Int16Array]', types.TYPED_ARRAY, 'int16') .addClass('[object Uint16Array]', types.TYPED_ARRAY, 'uint16') .addClass('[object Int32Array]', types.TYPED_ARRAY, 'int32') .addClass('[object Uint32Array]', types.TYPED_ARRAY, 'uint32') .addClass('[object Float32Array]', types.TYPED_ARRAY, 'float32') .addClass('[object Float64Array]', types.TYPED_ARRAY, 'float64') .addClass('[object Bool16x8]', types.SIMD, 'bool16x8') .addClass('[object Bool32x4]', types.SIMD, 'bool32x4') .addClass('[object Bool8x16]', types.SIMD, 'bool8x16') .addClass('[object Float32x4]', types.SIMD, 'float32x4') .addClass('[object Int16x8]', types.SIMD, 'int16x8') .addClass('[object Int32x4]', types.SIMD, 'int32x4') .addClass('[object Int8x16]', types.SIMD, 'int8x16') .addClass('[object Uint16x8]', types.SIMD, 'uint16x8') .addClass('[object Uint32x4]', types.SIMD, 'uint32x4') .addClass('[object Uint8x16]', types.SIMD, 'uint8x16') .addClass('[object DataView]', types.DATA_VIEW) .addClass('[object Map]', types.MAP) .addClass('[object WeakMap]', types.WEAK_MAP) .addClass('[object Set]', types.SET) .addClass('[object WeakSet]', types.WEAK_SET) .addClass('[object Promise]', types.PROMISE) .addClass('[object Blob]', types.BLOB) .addClass('[object File]', types.FILE) .addClass('[object FileList]', types.FILE_LIST) .addClass('[object XMLHttpRequest]', types.XHR) .add(function(obj) { if ((typeof Promise === types.FUNCTION && obj instanceof Promise) || (typeof obj.then === types.FUNCTION)) { return new Type(types.OBJECT, types.PROMISE); } }) .add(function(obj) { if (typeof Buffer !== 'undefined' && obj instanceof Buffer) {// eslint-disable-line no-undef return new Type(types.OBJECT, types.BUFFER); } }) .add(function(obj) { if (typeof Node !== 'undefined' && obj instanceof Node) { return new Type(types.OBJECT, types.HTML_ELEMENT, obj.nodeName); } }) .add(function(obj) { // probably at the begginging should be enough these checks if (obj.Boolean === Boolean && obj.Number === Number && obj.String === String && obj.Date === Date) { return new Type(types.OBJECT, types.HOST); } }) .add(function() { return new Type(types.OBJECT); }); /** * Get type information of anything * * @param {any} obj Anything that could require type information * @return {Type} type info * @private */ function getGlobalType(obj) { return main.getType(obj); } getGlobalType.checker = main; getGlobalType.TypeChecker = TypeChecker; getGlobalType.Type = Type; Object.keys(types).forEach(function(typeName) { getGlobalType[typeName] = types[typeName]; }); function format(msg) { var args = arguments; for (var i = 1, l = args.length; i < l; i++) { msg = msg.replace(/%s/, args[i]); } return msg; } var hasOwnProperty = Object.prototype.hasOwnProperty; function EqualityFail(a, b, reason, path) { this.a = a; this.b = b; this.reason = reason; this.path = path; } function typeToString(tp) { return tp.type + (tp.cls ? "(" + tp.cls + (tp.sub ? " " + tp.sub : "") + ")" : ""); } var PLUS_0_AND_MINUS_0 = "+0 is not equal to -0"; var DIFFERENT_TYPES = "A has type %s and B has type %s"; var EQUALITY = "A is not equal to B"; var EQUALITY_PROTOTYPE = "A and B have different prototypes"; var WRAPPED_VALUE = "A wrapped value is not equal to B wrapped value"; var FUNCTION_SOURCES = "function A is not equal to B by source code value (via .toString call)"; var MISSING_KEY = "%s has no key %s"; var SET_MAP_MISSING_KEY = "Set/Map missing key %s"; var DEFAULT_OPTIONS = { checkProtoEql: true, checkSubType: true, plusZeroAndMinusZeroEqual: true, collectAllFails: false }; function setBooleanDefault(property, obj, opts, defaults) { obj[property] = typeof opts[property] !== "boolean" ? defaults[property] : opts[property]; } var METHOD_PREFIX = "_check_"; function EQ(opts, a, b, path) { opts = opts || {}; setBooleanDefault("checkProtoEql", this, opts, DEFAULT_OPTIONS); setBooleanDefault("plusZeroAndMinusZeroEqual", this, opts, DEFAULT_OPTIONS); setBooleanDefault("checkSubType", this, opts, DEFAULT_OPTIONS); setBooleanDefault("collectAllFails", this, opts, DEFAULT_OPTIONS); this.a = a; this.b = b; this._meet = opts._meet || []; this.fails = opts.fails || []; this.path = path || []; } function ShortcutError(fail) { this.name = "ShortcutError"; this.message = "fail fast"; this.fail = fail; } ShortcutError.prototype = Object.create(Error.prototype); EQ.checkStrictEquality = function(a, b) { this.collectFail(a !== b, EQUALITY); }; EQ.add = function add(type, cls, sub, f) { var args = Array.prototype.slice.call(arguments); f = args.pop(); EQ.prototype[METHOD_PREFIX + args.join("_")] = f; }; EQ.prototype = { check: function() { try { this.check0(); } catch (e) { if (e instanceof ShortcutError) { return [e.fail]; } throw e; } return this.fails; }, check0: function() { var a = this.a; var b = this.b; // equal a and b exit early if (a === b) { // check for +0 !== -0; return this.collectFail(a === 0 && 1 / a !== 1 / b && !this.plusZeroAndMinusZeroEqual, PLUS_0_AND_MINUS_0); } var typeA = getGlobalType(a); var typeB = getGlobalType(b); // if objects has different types they are not equal if (typeA.type !== typeB.type || typeA.cls !== typeB.cls || typeA.sub !== typeB.sub) { return this.collectFail(true, format(DIFFERENT_TYPES, typeToString(typeA), typeToString(typeB))); } // as types the same checks type specific things var name1 = typeA.type, name2 = typeA.type; if (typeA.cls) { name1 += "_" + typeA.cls; name2 += "_" + typeA.cls; } if (typeA.sub) { name2 += "_" + typeA.sub; } var f = this[METHOD_PREFIX + name2] || this[METHOD_PREFIX + name1] || this[METHOD_PREFIX + typeA.type] || this.defaultCheck; f.call(this, this.a, this.b); }, collectFail: function(comparison, reason, showReason) { if (comparison) { var res = new EqualityFail(this.a, this.b, reason, this.path); res.showReason = !!showReason; this.fails.push(res); if (!this.collectAllFails) { throw new ShortcutError(res); } } }, checkPlainObjectsEquality: function(a, b) { // compare deep objects and arrays // stacks contain references only // var meet = this._meet; var m = this._meet.length; while (m--) { var st = meet[m]; if (st[0] === a && st[1] === b) { return; } } // add `a` and `b` to the stack of traversed objects meet.push([a, b]); // TODO maybe something else like getOwnPropertyNames var key; for (key in b) { if (hasOwnProperty.call(b, key)) { if (hasOwnProperty.call(a, key)) { this.checkPropertyEquality(key); } else { this.collectFail(true, format(MISSING_KEY, "A", key)); } } } // ensure both objects have the same number of properties for (key in a) { if (hasOwnProperty.call(a, key)) { this.collectFail(!hasOwnProperty.call(b, key), format(MISSING_KEY, "B", key)); } } meet.pop(); if (this.checkProtoEql) { //TODO should i check prototypes for === or use eq? this.collectFail(Object.getPrototypeOf(a) !== Object.getPrototypeOf(b), EQUALITY_PROTOTYPE, true); } }, checkPropertyEquality: function(propertyName) { var _eq = new EQ(this, this.a[propertyName], this.b[propertyName], this.path.concat([propertyName])); _eq.check0(); }, defaultCheck: EQ.checkStrictEquality }; EQ.add(getGlobalType.NUMBER, function(a, b) { this.collectFail((a !== a && b === b) || (b !== b && a === a) || (a !== b && a === a && b === b), EQUALITY); }); [getGlobalType.SYMBOL, getGlobalType.BOOLEAN, getGlobalType.STRING].forEach(function(tp) { EQ.add(tp, EQ.checkStrictEquality); }); EQ.add(getGlobalType.FUNCTION, function(a, b) { // functions are compared by their source code this.collectFail(a.toString() !== b.toString(), FUNCTION_SOURCES); // check user properties this.checkPlainObjectsEquality(a, b); }); EQ.add(getGlobalType.OBJECT, getGlobalType.REGEXP, function(a, b) { // check regexp flags var flags = ["source", "global", "multiline", "lastIndex", "ignoreCase", "sticky", "unicode"]; while (flags.length) { this.checkPropertyEquality(flags.shift()); } // check user properties this.checkPlainObjectsEquality(a, b); }); EQ.add(getGlobalType.OBJECT, getGlobalType.DATE, function(a, b) { //check by timestamp only (using .valueOf) this.collectFail(+a !== +b, EQUALITY); // check user properties this.checkPlainObjectsEquality(a, b); }); [getGlobalType.NUMBER, getGlobalType.BOOLEAN, getGlobalType.STRING].forEach(function(tp) { EQ.add(getGlobalType.OBJECT, tp, function(a, b) { //primitive type wrappers this.collectFail(a.valueOf() !== b.valueOf(), WRAPPED_VALUE); // check user properties this.checkPlainObjectsEquality(a, b); }); }); EQ.add(getGlobalType.OBJECT, function(a, b) { this.checkPlainObjectsEquality(a, b); }); [getGlobalType.ARRAY, getGlobalType.ARGUMENTS, getGlobalType.TYPED_ARRAY].forEach(function(tp) { EQ.add(getGlobalType.OBJECT, tp, function(a, b) { this.checkPropertyEquality("length"); this.checkPlainObjectsEquality(a, b); }); }); EQ.add(getGlobalType.OBJECT, getGlobalType.ARRAY_BUFFER, function(a, b) { this.checkPropertyEquality("byteLength"); this.checkPlainObjectsEquality(a, b); }); EQ.add(getGlobalType.OBJECT, getGlobalType.ERROR, function(a, b) { this.checkPropertyEquality("name"); this.checkPropertyEquality("message"); this.checkPlainObjectsEquality(a, b); }); EQ.add(getGlobalType.OBJECT, getGlobalType.BUFFER, function(a) { this.checkPropertyEquality("length"); var l = a.length; while (l--) { this.checkPropertyEquality(l); } //we do not check for user properties because //node Buffer have some strange hidden properties }); function checkMapByKeys(a, b) { var iteratorA = a.keys(); for (var nextA = iteratorA.next(); !nextA.done; nextA = iteratorA.next()) { var key = nextA.value; var hasKey = b.has(key); this.collectFail(!hasKey, format(SET_MAP_MISSING_KEY, key)); if (hasKey) { var valueB = b.get(key); var valueA = a.get(key); eq(valueA, valueB, this); } } } function checkSetByKeys(a, b) { var iteratorA = a.keys(); for (var nextA = iteratorA.next(); !nextA.done; nextA = iteratorA.next()) { var key = nextA.value; var hasKey = b.has(key); this.collectFail(!hasKey, format(SET_MAP_MISSING_KEY, key)); } } EQ.add(getGlobalType.OBJECT, getGlobalType.MAP, function(a, b) { this._meet.push([a, b]); checkMapByKeys.call(this, a, b); checkMapByKeys.call(this, b, a); this._meet.pop(); this.checkPlainObjectsEquality(a, b); }); EQ.add(getGlobalType.OBJECT, getGlobalType.SET, function(a, b) { this._meet.push([a, b]); checkSetByKeys.call(this, a, b); checkSetByKeys.call(this, b, a); this._meet.pop(); this.checkPlainObjectsEquality(a, b); }); function eq(a, b, opts) { return new EQ(opts, a, b).check(); } eq.EQ = EQ; var _hasOwnProperty = Object.prototype.hasOwnProperty; var _propertyIsEnumerable = Object.prototype.propertyIsEnumerable; function hasOwnProperty$1(obj, key) { return _hasOwnProperty.call(obj, key); } function propertyIsEnumerable(obj, key) { return _propertyIsEnumerable.call(obj, key); } function merge(a, b) { if (a && b) { for (var key in b) { a[key] = b[key]; } } return a; } function isIterator(obj) { if (!obj) { return false; } if (obj.__shouldIterator__) { return true; } return typeof obj.next === 'function' && typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' && typeof obj[Symbol.iterator] === 'function' && obj[Symbol.iterator]() === obj; } //TODO find better way function isGeneratorFunction(f) { return typeof f === 'function' && /^function\s*\*\s*/.test(f.toString()); } // TODO in future add generators instead of forEach and iterator implementation function ObjectIterator(obj) { this._obj = obj; } ObjectIterator.prototype = { __shouldIterator__: true, // special marker next: function() { if (this._done) { throw new Error('Iterator already reached the end'); } if (!this._keys) { this._keys = Object.keys(this._obj); this._index = 0; } var key = this._keys[this._index]; this._done = this._index === this._keys.length; this._index += 1; return { value: this._done ? void 0: [key, this._obj[key]], done: this._done }; } }; if (typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol') { ObjectIterator.prototype[Symbol.iterator] = function() { return this; }; } function TypeAdaptorStorage() { this._typeAdaptors = []; this._iterableTypes = {}; } TypeAdaptorStorage.prototype = { add: function(type, cls, sub, adaptor) { return this.addType(new getGlobalType.Type(type, cls, sub), adaptor); }, addType: function(type, adaptor) { this._typeAdaptors[type.toString()] = adaptor; }, getAdaptor: function(tp, funcName) { var tries = tp.toTryTypes(); while (tries.length) { var toTry = tries.shift(); var ad = this._typeAdaptors[toTry]; if (ad && ad[funcName]) { return ad[funcName]; } } }, requireAdaptor: function(tp, funcName) { var a = this.getAdaptor(tp, funcName); if (!a) { throw new Error('There is no type adaptor `' + funcName + '` for ' + tp.toString()); } return a; }, addIterableType: function(tp) { this._iterableTypes[tp.toString()] = true; }, isIterableType: function(tp) { return !!this._iterableTypes[tp.toString()]; } }; var defaultTypeAdaptorStorage = new TypeAdaptorStorage(); var objectAdaptor = { forEach: function(obj, f, context) { for (var prop in obj) { if (hasOwnProperty$1(obj, prop) && propertyIsEnumerable(obj, prop)) { if (f.call(context, obj[prop], prop, obj) === false) { return; } } } }, has: function(obj, prop) { return hasOwnProperty$1(obj, prop); }, get: function(obj, prop) { return obj[prop]; }, iterator: function(obj) { return new ObjectIterator(obj); } }; // default for objects defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.OBJECT), objectAdaptor); defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.FUNCTION), objectAdaptor); var mapAdaptor = { has: function(obj, key) { return obj.has(key); }, get: function(obj, key) { return obj.get(key); }, forEach: function(obj, f, context) { var iter = obj.entries(); forEach(iter, function(value) { return f.call(context, value[1], value[0], obj); }); }, size: function(obj) { return obj.size; }, isEmpty: function(obj) { return obj.size === 0; }, iterator: function(obj) { return obj.entries(); } }; var setAdaptor = merge({}, mapAdaptor); setAdaptor.get = function(obj, key) { if (obj.has(key)) { return key; } }; setAdaptor.iterator = function(obj) { return obj.values(); }; defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.MAP), mapAdaptor); defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SET), setAdaptor); defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.WEAK_SET), setAdaptor); defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.WEAK_MAP), mapAdaptor); defaultTypeAdaptorStorage.addType(new getGlobalType.Type(getGlobalType.STRING), { isEmpty: function(obj) { return obj === ''; }, size: function(obj) { return obj.length; } }); defaultTypeAdaptorStorage.addIterableType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.ARRAY)); defaultTypeAdaptorStorage.addIterableType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.ARGUMENTS)); defaultTypeAdaptorStorage.addIterableType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SET)); function forEach(obj, f, context) { if (isGeneratorFunction(obj)) { return forEach(obj(), f, context); } else if (isIterator(obj)) { var value = obj.next(); while (!value.done) { if (f.call(context, value.value, 'value', obj) === false) { return; } value = obj.next(); } } else { var type = getGlobalType(obj); var func = defaultTypeAdaptorStorage.requireAdaptor(type, 'forEach'); func(obj, f, context); } } function size(obj) { var type = getGlobalType(obj); var func = defaultTypeAdaptorStorage.getAdaptor(type, 'size'); if (func) { return func(obj); } else { var len = 0; forEach(obj, function() { len += 1; }); return len; } } function isEmpty(obj) { var type = getGlobalType(obj); var func = defaultTypeAdaptorStorage.getAdaptor(type, 'isEmpty'); if (func) { return func(obj); } else { var res = true; forEach(obj, function() { res = false; return false; }); return res; } } // return boolean if obj has such 'key' function has(obj, key) { var type = getGlobalType(obj); var func = defaultTypeAdaptorStorage.requireAdaptor(type, 'has'); return func(obj, key); } // return value for given key function get(obj, key) { var type = getGlobalType(obj); var func = defaultTypeAdaptorStorage.requireAdaptor(type, 'get'); return func(obj, key); } function some(obj, f, context) { var res = false; forEach(obj, function(value, key) { if (f.call(context, value, key, obj)) { res = true; return false; } }, context); return res; } function isIterable(obj) { return defaultTypeAdaptorStorage.isIterableType(getGlobalType(obj)); } function iterator(obj) { return defaultTypeAdaptorStorage.requireAdaptor(getGlobalType(obj), 'iterator')(obj); } function looksLikeANumber(n) { return !!n.match(/\d+/); } function keyCompare(a, b) { var aNum = looksLikeANumber(a); var bNum = looksLikeANumber(b); if (aNum && bNum) { return 1*a - 1*b; } else if (aNum && !bNum) { return -1; } else if (!aNum && bNum) { return 1; } else { return a.localeCompare(b); } } function genKeysFunc(f) { return function(value) { var k = f(value); k.sort(keyCompare); return k; }; } function Formatter(opts) { opts = opts || {}; this.seen = []; var keysFunc; if (typeof opts.keysFunc === 'function') { keysFunc = opts.keysFunc; } else if (opts.keys === false) { keysFunc = Object.getOwnPropertyNames; } else { keysFunc = Object.keys; } this.getKeys = genKeysFunc(keysFunc); this.maxLineLength = typeof opts.maxLineLength === 'number' ? opts.maxLineLength : 60; this.propSep = opts.propSep || ','; this.isUTCdate = !!opts.isUTCdate; } Formatter.prototype = { constructor: Formatter, format: function(value) { var tp = getGlobalType(value); if (this.alreadySeen(value)) { return '[Circular]'; } var tries = tp.toTryTypes(); var f = this.defaultFormat; while (tries.length) { var toTry = tries.shift(); var name = Formatter.formatterFunctionName(toTry); if (this[name]) { f = this[name]; break; } } return f.call(this, value).trim(); }, defaultFormat: function(obj) { return String(obj); }, alreadySeen: function(value) { return this.seen.indexOf(value) >= 0; } }; Formatter.addType = function addType(tp, f) { Formatter.prototype[Formatter.formatterFunctionName(tp)] = f; }; Formatter.formatterFunctionName = function formatterFunctionName(tp) { return '_format_' + tp.toString('_'); }; var EOL = '\n'; function indent(v, indentation) { return v .split(EOL) .map(function(vv) { return indentation + vv; }) .join(EOL); } function pad(str, value, filler) { str = String(str); var isRight = false; if (value < 0) { isRight = true; value = -value; } if (str.length < value) { var padding = new Array(value - str.length + 1).join(filler); return isRight ? str + padding : padding + str; } else { return str; } } function pad0(str, value) { return pad(str, value, '0'); } var functionNameRE = /^\s*function\s*(\S*)\s*\(/; function functionName(f) { if (f.name) { return f.name; } var matches = f.toString().match(functionNameRE); if (matches === null) { // `functionNameRE` doesn't match arrow functions. return ''; } var name = matches[1]; return name; } function constructorName(obj) { while (obj) { var descriptor = Object.getOwnPropertyDescriptor(obj, 'constructor'); if (descriptor !== undefined && typeof descriptor.value === 'function') { var name = functionName(descriptor.value); if (name !== '') { return name; } } obj = Object.getPrototypeOf(obj); } } var INDENT = ' '; function addSpaces(str) { return indent(str, INDENT); } function typeAdaptorForEachFormat(obj, opts) { opts = opts || {}; var filterKey = opts.filterKey || function() { return true; }; var formatKey = opts.formatKey || this.format; var formatValue = opts.formatValue || this.format; var keyValueSep = typeof opts.keyValueSep !== 'undefined' ? opts.keyValueSep : ': '; this.seen.push(obj); var formatLength = 0; var pairs = []; forEach(obj, function(value, key) { if (!filterKey(key)) { return; } var formattedKey = formatKey.call(this, key); var formattedValue = formatValue.call(this, value, key); var pair = formattedKey ? (formattedKey + keyValueSep + formattedValue) : formattedValue; formatLength += pair.length; pairs.push(pair); }, this); this.seen.pop(); (opts.additionalKeys || []).forEach(function(keyValue) { var pair = keyValue[0] + keyValueSep + this.format(keyValue[1]); formatLength += pair.length; pairs.push(pair); }, this); var prefix = opts.prefix || constructorName(obj) || ''; if (prefix.length > 0) { prefix += ' '; } var lbracket, rbracket; if (Array.isArray(opts.brackets)) { lbracket = opts.brackets[0]; rbracket = opts.brackets[1]; } else { lbracket = '{'; rbracket = '}'; } var rootValue = opts.value || ''; if (pairs.length === 0) { return rootValue || (prefix + lbracket + rbracket); } if (formatLength <= this.maxLineLength) { return prefix + lbracket + ' ' + (rootValue ? rootValue + ' ' : '') + pairs.join(this.propSep + ' ') + ' ' + rbracket; } else { return prefix + lbracket + '\n' + (rootValue ? ' ' + rootValue + '\n' : '') + pairs.map(addSpaces).join(this.propSep + '\n') + '\n' + rbracket; } } function formatPlainObjectKey(key) { return typeof key === 'string' && key.match(/^[a-zA-Z_$][a-zA-Z_$0-9]*$/) ? key : this.format(key); } function getPropertyDescriptor(obj, key) { var desc; try { desc = Object.getOwnPropertyDescriptor(obj, key) || { value: obj[key] }; } catch (e) { desc = { value: e }; } return desc; } function formatPlainObjectValue(obj, key) { var desc = getPropertyDescriptor(obj, key); if (desc.get && desc.set) { return '[Getter/Setter]'; } if (desc.get) { return '[Getter]'; } if (desc.set) { return '[Setter]'; } return this.format(desc.value); } function formatPlainObject(obj, opts) { opts = opts || {}; opts.keyValueSep = ': '; opts.formatKey = opts.formatKey || formatPlainObjectKey; opts.formatValue = opts.formatValue || function(value, key) { return formatPlainObjectValue.call(this, obj, key); }; return typeAdaptorForEachFormat.call(this, obj, opts); } function formatWrapper1(value) { return formatPlainObject.call(this, value, { additionalKeys: [['[[PrimitiveValue]]', value.valueOf()]] }); } function formatWrapper2(value) { var realValue = value.valueOf(); return formatPlainObject.call(this, value, { filterKey: function(key) { //skip useless indexed properties return !(key.match(/\d+/) && parseInt(key, 10) < realValue.length); }, additionalKeys: [['[[PrimitiveValue]]', realValue]] }); } function formatRegExp(value) { return formatPlainObject.call(this, value, { value: String(value) }); } function formatFunction(value) { return formatPlainObject.call(this, value, { prefix: 'Function', additionalKeys: [['name', functionName(value)]] }); } function formatArray(value) { return formatPlainObject.call(this, value, { formatKey: function(key) { if (!key.match(/\d+/)) { return formatPlainObjectKey.call(this, key); } }, brackets: ['[', ']'] }); } function formatArguments(value) { return formatPlainObject.call(this, value, { formatKey: function(key) { if (!key.match(/\d+/)) { return formatPlainObjectKey.call(this, key); } }, brackets: ['[', ']'], prefix: 'Arguments' }); } function _formatDate(value, isUTC) { var prefix = isUTC ? 'UTC' : ''; var date = value['get' + prefix + 'FullYear']() + '-' + pad0(value['get' + prefix + 'Month']() + 1, 2) + '-' + pad0(value['get' + prefix + 'Date'](), 2); var time = pad0(value['get' + prefix + 'Hours'](), 2) + ':' + pad0(value['get' + prefix + 'Minutes'](), 2) + ':' + pad0(value['get' + prefix + 'Seconds'](), 2) + '.' + pad0(value['get' + prefix + 'Milliseconds'](), 3); var to = value.getTimezoneOffset(); var absTo = Math.abs(to); var hours = Math.floor(absTo / 60); var minutes = absTo - hours * 60; var tzFormat = (to < 0 ? '+' : '-') + pad0(hours, 2) + pad0(minutes, 2); return date + ' ' + time + (isUTC ? '' : ' ' + tzFormat); } function formatDate(value) { return formatPlainObject.call(this, value, { value: _formatDate(value, this.isUTCdate) }); } function formatError(value) { return formatPlainObject.call(this, value, { prefix: value.name, additionalKeys: [['message', value.message]] }); } function generateFormatForNumberArray(lengthProp, name, padding) { return function(value) { var max = this.byteArrayMaxLength || 50; var length = value[lengthProp]; var formattedValues = []; var len = 0; for (var i = 0; i < max && i < length; i++) { var b = value[i] || 0; var v = pad0(b.toString(16), padding); len += v.length; formattedValues.push(v); } var prefix = value.constructor.name || name || ''; if (prefix) { prefix += ' '; } if (formattedValues.length === 0) { return prefix + '[]'; } if (len <= this.maxLineLength) { return prefix + '[ ' + formattedValues.join(this.propSep + ' ') + ' ' + ']'; } else { return prefix + '[\n' + formattedValues.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; } }; } function formatMap(obj) { return typeAdaptorForEachFormat.call(this, obj, { keyValueSep: ' => ' }); } function formatSet(obj) { return typeAdaptorForEachFormat.call(this, obj, { keyValueSep: '', formatKey: function() { return ''; } }); } function genSimdVectorFormat(constructorName, length) { return function(value) { var Constructor = value.constructor; var extractLane = Constructor.extractLane; var len = 0; var props = []; for (var i = 0; i < length; i ++) { var key = this.format(extractLane(value, i)); len += key.length; props.push(key); } if (len <= this.maxLineLength) { return constructorName + ' [ ' + props.join(this.propSep + ' ') + ' ]'; } else { return constructorName + ' [\n' + props.map(addSpaces).join(this.propSep + '\n') + '\n' + ']'; } }; } function defaultFormat(value, opts) { return new Formatter(opts).format(value); } defaultFormat.Formatter = Formatter; defaultFormat.addSpaces = addSpaces; defaultFormat.pad0 = pad0; defaultFormat.functionName = functionName; defaultFormat.constructorName = constructorName; defaultFormat.formatPlainObjectKey = formatPlainObjectKey; defaultFormat.formatPlainObject = formatPlainObject; defaultFormat.typeAdaptorForEachFormat = typeAdaptorForEachFormat; // adding primitive types Formatter.addType(new getGlobalType.Type(getGlobalType.UNDEFINED), function() { return 'undefined'; }); Formatter.addType(new getGlobalType.Type(getGlobalType.NULL), function() { return 'null'; }); Formatter.addType(new getGlobalType.Type(getGlobalType.BOOLEAN), function(value) { return value ? 'true': 'false'; }); Formatter.addType(new getGlobalType.Type(getGlobalType.SYMBOL), function(value) { return value.toString(); }); Formatter.addType(new getGlobalType.Type(getGlobalType.NUMBER), function(value) { if (value === 0 && 1 / value < 0) { return '-0'; } return String(value); }); Formatter.addType(new getGlobalType.Type(getGlobalType.STRING), function(value) { return '\'' + JSON.stringify(value).replace(/^"|"$/g, '') .replace(/'/g, "\\'") .replace(/\\"/g, '"') + '\''; }); Formatter.addType(new getGlobalType.Type(getGlobalType.FUNCTION), formatFunction); // plain object Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT), formatPlainObject); // type wrappers Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.NUMBER), formatWrapper1); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.BOOLEAN), formatWrapper1); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.STRING), formatWrapper2); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.REGEXP), formatRegExp); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.ARRAY), formatArray); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.ARGUMENTS), formatArguments); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.DATE), formatDate); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.ERROR), formatError); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SET), formatSet); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.MAP), formatMap); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.WEAK_MAP), formatMap); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.WEAK_SET), formatSet); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.BUFFER), generateFormatForNumberArray('length', 'Buffer', 2)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.ARRAY_BUFFER), generateFormatForNumberArray('byteLength', 'ArrayBuffer', 2)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'int8'), generateFormatForNumberArray('length', 'Int8Array', 2)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'uint8'), generateFormatForNumberArray('length', 'Uint8Array', 2)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'uint8clamped'), generateFormatForNumberArray('length', 'Uint8ClampedArray', 2)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'int16'), generateFormatForNumberArray('length', 'Int16Array', 4)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'uint16'), generateFormatForNumberArray('length', 'Uint16Array', 4)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'int32'), generateFormatForNumberArray('length', 'Int32Array', 8)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.TYPED_ARRAY, 'uint32'), generateFormatForNumberArray('length', 'Uint32Array', 8)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'bool16x8'), genSimdVectorFormat('Bool16x8', 8)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'bool32x4'), genSimdVectorFormat('Bool32x4', 4)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'bool8x16'), genSimdVectorFormat('Bool8x16', 16)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'float32x4'), genSimdVectorFormat('Float32x4', 4)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'int16x8'), genSimdVectorFormat('Int16x8', 8)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'int32x4'), genSimdVectorFormat('Int32x4', 4)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'int8x16'), genSimdVectorFormat('Int8x16', 16)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'uint16x8'), genSimdVectorFormat('Uint16x8', 8)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'uint32x4'), genSimdVectorFormat('Uint32x4', 4)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.SIMD, 'uint8x16'), genSimdVectorFormat('Uint8x16', 16)); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.PROMISE), function() { return '[Promise]';//TODO it could be nice to inspect its state and value }); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.XHR), function() { return '[XMLHttpRequest]';//TODO it could be nice to inspect its state }); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.HTML_ELEMENT), function(value) { return value.outerHTML; }); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.HTML_ELEMENT, '#text'), function(value) { return value.nodeValue; }); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.HTML_ELEMENT, '#document'), function(value) { return value.documentElement.outerHTML; }); Formatter.addType(new getGlobalType.Type(getGlobalType.OBJECT, getGlobalType.HOST), function() { return '[Host]'; }); /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function isWrapperType(obj) { return obj instanceof Number || obj instanceof String || obj instanceof Boolean; } // XXX make it more strict: numbers, strings, symbols - and nothing else function convertPropertyName(name) { return typeof name === "symbol" ? name : String(name); } var functionName$1 = defaultFormat.functionName; function isPlainObject(obj) { if (typeof obj == "object" && obj !== null) { var proto = Object.getPrototypeOf(obj); return proto === Object.prototype || proto === null; } return false; } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ var config = { typeAdaptors: defaultTypeAdaptorStorage, getFormatter: function(opts) { return new defaultFormat.Formatter(opts || config); } }; function format$2(value, opts) { return config.getFormatter(opts).format(value); } function formatProp(value) { var formatter = config.getFormatter(); return defaultFormat.formatPlainObjectKey.call(formatter, value); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ /** * should AssertionError * @param {Object} options * @constructor * @memberOf should * @static */ function AssertionError(options) { merge(this, options); if (!options.message) { Object.defineProperty(this, "message", { get: function() { if (!this._message) { this._message = this.generateMessage(); this.generatedMessage = true; } return this._message; }, configurable: true, enumerable: false }); } if (Error.captureStackTrace) { Error.captureStackTrace(this, this.stackStartFunction); } else { // non v8 browsers so we can have a stacktrace var err = new Error(); if (err.stack) { var out = err.stack; if (this.stackStartFunction) { // try to strip useless frames var fn_name = functionName$1(this.stackStartFunction); var idx = out.indexOf("\n" + fn_name); if (idx >= 0) { // once we have located the function frame // we need to strip out everything before it (and its line) var next_line = out.indexOf("\n", idx + 1); out = out.substring(next_line + 1); } } this.stack = out; } } } var indent$1 = " "; function prependIndent(line) { return indent$1 + line; } function indentLines(text) { return text .split("\n") .map(prependIndent) .join("\n"); } // assert.AssertionError instanceof Error AssertionError.prototype = Object.create(Error.prototype, { name: { value: "AssertionError" }, generateMessage: { value: function() { if (!this.operator && this.previous) { return this.previous.message; } var actual = format$2(this.actual); var expected = "expected" in this ? " " + format$2(this.expected) : ""; var details = "details" in this && this.details ? " (" + this.details + ")" : ""; var previous = this.previous ? "\n" + indentLines(this.previous.message) : ""; return ( "expected " + actual + (this.negate ? " not " : " ") + this.operator + expected + details + previous ); } } }); /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ // a bit hacky way how to get error to do not have stack function LightAssertionError(options) { merge(this, options); if (!options.message) { Object.defineProperty(this, "message", { get: function() { if (!this._message) { this._message = this.generateMessage(); this.generatedMessage = true; } return this._message; } }); } } LightAssertionError.prototype = { generateMessage: AssertionError.prototype.generateMessage }; /** * should Assertion * @param {*} obj Given object for assertion * @constructor * @memberOf should * @static */ function Assertion(obj) { this.obj = obj; this.anyOne = false; this.negate = false; this.params = { actual: obj }; } Assertion.prototype = { constructor: Assertion, /** * Base method for assertions. * * Before calling this method need to fill Assertion#params object. This method usually called from other assertion methods. * `Assertion#params` can contain such properties: * * `operator` - required string containing description of this assertion * * `obj` - optional replacement for this.obj, it is useful if you prepare more clear object then given * * `message` - if this property filled with string any others will be ignored and this one used as assertion message * * `expected` - any object used when you need to assert relation between given object and expected. Like given == expected (== is a relation) * * `details` - additional string with details to generated message * * @memberOf Assertion * @category assertion * @param {*} expr Any expression that will be used as a condition for asserting. * @example * * var a = new should.Assertion(42); * * a.params = { * operator: 'to be magic number', * } * * a.assert(false); * //throws AssertionError: expected 42 to be magic number */ assert: function(expr) { if (expr) { return this; } var params = this.params; if ("obj" in params && !("actual" in params)) { params.actual = params.obj; } else if (!("obj" in params) && !("actual" in params)) { params.actual = this.obj; } params.stackStartFunction = params.stackStartFunction || this.assert; params.negate = this.negate; params.assertion = this; if (this.light) { throw new LightAssertionError(params); } else { throw new AssertionError(params); } }, /** * Shortcut for `Assertion#assert(false)`. * * @memberOf Assertion * @category assertion * @example * * var a = new should.Assertion(42); * * a.params = { * operator: 'to be magic number', * } * * a.fail(); * //throws AssertionError: expected 42 to be magic number */ fail: function() { return this.assert(false); }, assertZeroArguments: function(args) { if (args.length !== 0) { throw new TypeError("This assertion does not expect any arguments. You may need to check your code"); } } }; /** * Assertion used to delegate calls of Assertion methods inside of Promise. * It has almost all methods of Assertion.prototype * * @param {Promise} obj */ function PromisedAssertion(/* obj */) { Assertion.apply(this, arguments); } /** * Make PromisedAssertion to look like promise. Delegate resolve and reject to given promise. * * @private * @returns {Promise} */ PromisedAssertion.prototype.then = function(resolve, reject) { return this.obj.then(resolve, reject); }; /** * 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. * * @memberOf Assertion * @static * @param {String} name Name of assertion. It will be used for defining method or getter on Assertion.prototype * @param {Function} func Function that will be called on executing assertion * @example * * Assertion.add('asset', function() { * this.params = { operator: 'to be asset' } * * this.obj.should.have.property('id').which.is.a.Number() * this.obj.should.have.property('path') * }) */ Assertion.add = function(name, func) { Object.defineProperty(Assertion.prototype, name, { enumerable: true, configurable: true, value: function() { var context = new Assertion(this.obj, this, name); context.anyOne = this.anyOne; context.onlyThis = this.onlyThis; // hack context.light = true; try { func.apply(context, arguments); } catch (e) { // check for fail if (e instanceof AssertionError || e instanceof LightAssertionError) { // negative fail if (this.negate) { this.obj = context.obj; this.negate = false; return this; } if (context !== e.assertion) { context.params.previous = e; } // positive fail context.negate = false; // hack context.light = false; context.fail(); } // throw if it is another exception throw e; } // negative pass if (this.negate) { context.negate = true; // because .fail will set negate context.params.details = "false negative fail"; // hack context.light = false; context.fail(); } // positive pass if (!this.params.operator) { this.params = context.params; // shortcut } this.obj = context.obj; this.negate = false; return this; } }); Object.defineProperty(PromisedAssertion.prototype, name, { enumerable: true, configurable: true, value: function() { var args = arguments; this.obj = this.obj.then(function(a) { return a[name].apply(a, args); }); return this; } }); }; /** * Add chaining getter to Assertion like .a, .which etc * * @memberOf Assertion * @static * @param {string} name name of getter * @param {function} [onCall] optional function to call */ Assertion.addChain = function(name, onCall) { onCall = onCall || function() {}; Object.defineProperty(Assertion.prototype, name, { get: function() { onCall.call(this); return this; }, enumerable: true }); Object.defineProperty(PromisedAssertion.prototype, name, { enumerable: true, configurable: true, get: function() { this.obj = this.obj.then(function(a) { return a[name]; }); return this; } }); }; /** * Create alias for some `Assertion` property * * @memberOf Assertion * @static * @param {String} from Name of to map * @param {String} to Name of alias * @example * * Assertion.alias('true', 'True') */ Assertion.alias = function(from, to) { var desc = Object.getOwnPropertyDescriptor(Assertion.prototype, from); if (!desc) { throw new Error("Alias " + from + " -> " + to + " could not be created as " + from + " not defined"); } Object.defineProperty(Assertion.prototype, to, desc); var desc2 = Object.getOwnPropertyDescriptor(PromisedAssertion.prototype, from); if (desc2) { Object.defineProperty(PromisedAssertion.prototype, to, desc2); } }; /** * Negation modifier. Current assertion chain become negated. Each call invert negation on current assertion. * * @name not * @property * @memberOf Assertion * @category assertion */ Assertion.addChain("not", function() { this.negate = !this.negate; }); /** * Any modifier - it affect on execution of sequenced assertion to do not `check all`, but `check any of`. * * @name any * @property * @memberOf Assertion * @category assertion */ Assertion.addChain("any", function() { this.anyOne = true; }); /** * Only modifier - currently used with .keys to check if object contains only exactly this .keys * * @name only * @property * @memberOf Assertion * @category assertion */ Assertion.addChain("only", function() { this.onlyThis = true; }); // implement assert interface using already written peaces of should.js // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 // // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! // // Originally from narwhal.js (http://narwhaljs.org) // Copyright (c) 2009 Thomas Robinson <280north.com> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the 'Software'), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // when used in node, this will actually load the util module we depend on // versus loading the builtin util module as happens otherwise // this is a bug in node module loading as far as I am concerned var pSlice = Array.prototype.slice; // 1. The assert module provides functions that throw // AssertionError's when particular conditions are not met. The // assert module must conform to the following interface. var assert = ok; // 3. All of the following functions must throw an AssertionError // when a corresponding condition is not met, with a message that // may be undefined if not provided. All assertion methods provide // both the actual and expected values to the assertion error for // display purposes. /** * Node.js standard [`assert.fail`](http://nodejs.org/api/assert.html#assert_assert_fail_actual_expected_message_operator). * @static * @memberOf should * @category assertion assert * @param {*} actual Actual object * @param {*} expected Expected object * @param {string} message Message for assertion * @param {string} operator Operator text */ function fail(actual, expected, message, operator, stackStartFunction) { var a = new Assertion(actual); a.params = { operator: operator, expected: expected, message: message, stackStartFunction: stackStartFunction || fail }; a.fail(); } // EXTENSION! allows for well behaved errors defined elsewhere. assert.fail = fail; // 4. Pure assertion tests whether a value is truthy, as determined // by !!guard. // assert.ok(guard, message_opt); // This statement is equivalent to assert.equal(true, !!guard, // message_opt);. To test strictly for the value true, use // assert.strictEqual(true, guard, message_opt);. /** * Node.js standard [`assert.ok`](http://nodejs.org/api/assert.html#assert_assert_value_message_assert_ok_value_message). * @static * @memberOf should * @category assertion assert * @param {*} value * @param {string} [message] */ function ok(value, message) { if (!value) { fail(value, true, message, "==", assert.ok); } } assert.ok = ok; // 5. The equality assertion tests shallow, coercive equality with // ==. // assert.equal(actual, expected, message_opt); /** * Node.js standard [`assert.equal`](http://nodejs.org/api/assert.html#assert_assert_equal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.equal = function equal(actual, expected, message) { if (actual != expected) { fail(actual, expected, message, "==", assert.equal); } }; // 6. The non-equality assertion tests for whether two objects are not equal // with != assert.notEqual(actual, expected, message_opt); /** * Node.js standard [`assert.notEqual`](http://nodejs.org/api/assert.html#assert_assert_notequal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.notEqual = function notEqual(actual, expected, message) { if (actual == expected) { fail(actual, expected, message, "!=", assert.notEqual); } }; // 7. The equivalence assertion tests a deep equality relation. // assert.deepEqual(actual, expected, message_opt); /** * Node.js standard [`assert.deepEqual`](http://nodejs.org/api/assert.html#assert_assert_deepequal_actual_expected_message). * But uses should.js .eql implementation instead of Node.js own deepEqual. * * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.deepEqual = function deepEqual(actual, expected, message) { if (eq(actual, expected).length !== 0) { fail(actual, expected, message, "deepEqual", assert.deepEqual); } }; // 8. The non-equivalence assertion tests for any deep inequality. // assert.notDeepEqual(actual, expected, message_opt); /** * Node.js standard [`assert.notDeepEqual`](http://nodejs.org/api/assert.html#assert_assert_notdeepequal_actual_expected_message). * But uses should.js .eql implementation instead of Node.js own deepEqual. * * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.notDeepEqual = function notDeepEqual(actual, expected, message) { if (eq(actual, expected).result) { fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual); } }; // 9. The strict equality assertion tests strict equality, as determined by ===. // assert.strictEqual(actual, expected, message_opt); /** * Node.js standard [`assert.strictEqual`](http://nodejs.org/api/assert.html#assert_assert_strictequal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.strictEqual = function strictEqual(actual, expected, message) { if (actual !== expected) { fail(actual, expected, message, "===", assert.strictEqual); } }; // 10. The strict non-equality assertion tests for strict inequality, as // determined by !==. assert.notStrictEqual(actual, expected, message_opt); /** * Node.js standard [`assert.notStrictEqual`](http://nodejs.org/api/assert.html#assert_assert_notstrictequal_actual_expected_message). * @static * @memberOf should * @category assertion assert * @param {*} actual * @param {*} expected * @param {string} [message] */ assert.notStrictEqual = function notStrictEqual(actual, expected, message) { if (actual === expected) { fail(actual, expected, message, "!==", assert.notStrictEqual); } }; function expectedException(actual, expected) { if (!actual || !expected) { return false; } if (Object.prototype.toString.call(expected) == "[object RegExp]") { return expected.test(actual); } else if (actual instanceof expected) { return true; } else if (expected.call({}, actual) === true) { return true; } return false; } function _throws(shouldThrow, block, expected, message) { var actual; if (typeof expected == "string") { message = expected; expected = null; } try { block(); } catch (e) { actual = e; } message = (expected && expected.name ? " (" + expected.name + ")" : ".") + (message ? " " + message : "."); if (shouldThrow && !actual) { fail(actual, expected, "Missing expected exception" + message); } if (!shouldThrow && expectedException(actual, expected)) { fail(actual, expected, "Got unwanted exception" + message); } if ( (shouldThrow && actual && expected && !expectedException(actual, expected)) || (!shouldThrow && actual) ) { throw actual; } } // 11. Expected to throw an error: // assert.throws(block, Error_opt, message_opt); /** * Node.js standard [`assert.throws`](http://nodejs.org/api/assert.html#assert_assert_throws_block_error_message). * @static * @memberOf should * @category assertion assert * @param {Function} block * @param {Function} [error] * @param {String} [message] */ assert.throws = function(/*block, error, message*/) { _throws.apply(this, [true].concat(pSlice.call(arguments))); }; // EXTENSION! This is annoying to write outside this module. /** * Node.js standard [`assert.doesNotThrow`](http://nodejs.org/api/assert.html#assert_assert_doesnotthrow_block_message). * @static * @memberOf should * @category assertion assert * @param {Function} block * @param {String} [message] */ assert.doesNotThrow = function(/*block, message*/) { _throws.apply(this, [false].concat(pSlice.call(arguments))); }; /** * Node.js standard [`assert.ifError`](http://nodejs.org/api/assert.html#assert_assert_iferror_value). * @static * @memberOf should * @category assertion assert * @param {Error} err */ assert.ifError = function(err) { if (err) { throw err; } }; /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function assertExtensions(should) { var i = should.format; /* * Expose assert to should * * This allows you to do things like below * without require()ing the assert module. * * should.equal(foo.bar, undefined); * */ merge(should, assert); /** * Assert _obj_ exists, with optional message. * * @static * @memberOf should * @category assertion assert * @alias should.exists * @param {*} obj * @param {String} [msg] * @example * * should.exist(1); * should.exist(new Date()); */ should.exist = should.exists = function(obj, msg) { if (null == obj) { throw new AssertionError({ message: msg || "expected " + i(obj) + " to exist", stackStartFunction: should.exist }); } }; should.not = {}; /** * Asserts _obj_ does not exist, with optional message. * * @name not.exist * @static * @memberOf should * @category assertion assert * @alias should.not.exists * @param {*} obj * @param {String} [msg] * @example * * should.not.exist(null); * should.not.exist(void 0); */ should.not.exist = should.not.exists = function(obj, msg) { if (null != obj) { throw new AssertionError({ message: msg || "expected " + i(obj) + " to not exist", stackStartFunction: should.not.exist }); } }; } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function chainAssertions(should, Assertion) { /** * Simple chaining to improve readability. Does nothing. * * @memberOf Assertion * @name be * @property {should.Assertion} be * @alias Assertion#an * @alias Assertion#of * @alias Assertion#a * @alias Assertion#and * @alias Assertion#been * @alias Assertion#have * @alias Assertion#has * @alias Assertion#with * @alias Assertion#is * @alias Assertion#which * @alias Assertion#the * @alias Assertion#it * @category assertion chaining */ [ "an", "of", "a", "and", "be", "been", "has", "have", "with", "is", "which", "the", "it" ].forEach(function(name) { Assertion.addChain(name); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function booleanAssertions(should, Assertion) { /** * Assert given object is exactly `true`. * * @name true * @memberOf Assertion * @category assertion bool * @alias Assertion#True * @param {string} [message] Optional message * @example * * (true).should.be.true(); * false.should.not.be.true(); * * ({ a: 10}).should.not.be.true(); */ Assertion.add("true", function(message) { this.is.exactly(true, message); }); Assertion.alias("true", "True"); /** * Assert given object is exactly `false`. * * @name false * @memberOf Assertion * @category assertion bool * @alias Assertion#False * @param {string} [message] Optional message * @example * * (true).should.not.be.false(); * false.should.be.false(); */ Assertion.add("false", function(message) { this.is.exactly(false, message); }); Assertion.alias("false", "False"); /** * Assert given object is truthy according javascript type conversions. * * @name ok * @memberOf Assertion * @category assertion bool * @example * * (true).should.be.ok(); * ''.should.not.be.ok(); * should(null).not.be.ok(); * should(void 0).not.be.ok(); * * (10).should.be.ok(); * (0).should.not.be.ok(); */ Assertion.add("ok", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be truthy" }; this.assert(this.obj); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function numberAssertions(should, Assertion) { /** * Assert given object is NaN * @name NaN * @memberOf Assertion * @category assertion numbers * @example * * (10).should.not.be.NaN(); * NaN.should.be.NaN(); */ Assertion.add("NaN", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be NaN" }; this.assert(this.obj !== this.obj); }); /** * Assert given object is not finite (positive or negative) * * @name Infinity * @memberOf Assertion * @category assertion numbers * @example * * (10).should.not.be.Infinity(); * NaN.should.not.be.Infinity(); */ Assertion.add("Infinity", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be Infinity" }; this.is.a .Number() .and.not.a.NaN() .and.assert(!isFinite(this.obj)); }); /** * Assert given number between `start` and `finish` or equal one of them. * * @name within * @memberOf Assertion * @category assertion numbers * @param {number} start Start number * @param {number} finish Finish number * @param {string} [description] Optional message * @example * * (10).should.be.within(0, 20); */ Assertion.add("within", function(start, finish, description) { this.params = { operator: "to be within " + start + ".." + finish, message: description }; this.assert(this.obj >= start && this.obj <= finish); }); /** * Assert given number near some other `value` within `delta` * * @name approximately * @memberOf Assertion * @category assertion numbers * @param {number} value Center number * @param {number} delta Radius * @param {string} [description] Optional message * @example * * (9.99).should.be.approximately(10, 0.1); */ Assertion.add("approximately", function(value, delta, description) { this.params = { operator: "to be approximately " + value + " ±" + delta, message: description }; this.assert(Math.abs(this.obj - value) <= delta); }); /** * Assert given number above `n`. * * @name above * @alias Assertion#greaterThan * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (10).should.be.above(0); */ Assertion.add("above", function(n, description) { this.params = { operator: "to be above " + n, message: description }; this.assert(this.obj > n); }); /** * Assert given number below `n`. * * @name below * @alias Assertion#lessThan * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (0).should.be.below(10); */ Assertion.add("below", function(n, description) { this.params = { operator: "to be below " + n, message: description }; this.assert(this.obj < n); }); Assertion.alias("above", "greaterThan"); Assertion.alias("below", "lessThan"); /** * Assert given number above `n`. * * @name aboveOrEqual * @alias Assertion#greaterThanOrEqual * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (10).should.be.aboveOrEqual(0); * (10).should.be.aboveOrEqual(10); */ Assertion.add("aboveOrEqual", function(n, description) { this.params = { operator: "to be above or equal " + n, message: description }; this.assert(this.obj >= n); }); /** * Assert given number below `n`. * * @name belowOrEqual * @alias Assertion#lessThanOrEqual * @memberOf Assertion * @category assertion numbers * @param {number} n Margin number * @param {string} [description] Optional message * @example * * (0).should.be.belowOrEqual(10); * (0).should.be.belowOrEqual(0); */ Assertion.add("belowOrEqual", function(n, description) { this.params = { operator: "to be below or equal " + n, message: description }; this.assert(this.obj <= n); }); Assertion.alias("aboveOrEqual", "greaterThanOrEqual"); Assertion.alias("belowOrEqual", "lessThanOrEqual"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function typeAssertions(should, Assertion) { /** * Assert given object is number * @name Number * @memberOf Assertion * @category assertion types */ Assertion.add("Number", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a number" }; this.have.type("number"); }); /** * Assert given object is arguments * @name arguments * @alias Assertion#Arguments * @memberOf Assertion * @category assertion types */ Assertion.add("arguments", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be arguments" }; this.have.class("Arguments"); }); Assertion.alias("arguments", "Arguments"); /** * Assert given object has some type using `typeof` * @name type * @memberOf Assertion * @param {string} type Type name * @param {string} [description] Optional message * @category assertion types */ Assertion.add("type", function(type, description) { this.params = { operator: "to have type " + type, message: description }; should(typeof this.obj).be.exactly(type); }); /** * Assert given object is instance of `constructor` * @name instanceof * @alias Assertion#instanceOf * @memberOf Assertion * @param {Function} constructor Constructor function * @param {string} [description] Optional message * @category assertion types */ Assertion.add("instanceof", function(constructor, description) { this.params = { operator: "to be an instance of " + functionName$1(constructor), message: description }; this.assert(Object(this.obj) instanceof constructor); }); Assertion.alias("instanceof", "instanceOf"); /** * Assert given object is function * @name Function * @memberOf Assertion * @category assertion types */ Assertion.add("Function", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a function" }; this.have.type("function"); }); /** * Assert given object is object * @name Object * @memberOf Assertion * @category assertion types */ Assertion.add("Object", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be an object" }; this.is.not.null().and.have.type("object"); }); /** * Assert given object is string * @name String * @memberOf Assertion * @category assertion types */ Assertion.add("String", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a string" }; this.have.type("string"); }); /** * Assert given object is array * @name Array * @memberOf Assertion * @category assertion types */ Assertion.add("Array", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be an array" }; this.have.class("Array"); }); /** * Assert given object is boolean * @name Boolean * @memberOf Assertion * @category assertion types */ Assertion.add("Boolean", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a boolean" }; this.have.type("boolean"); }); /** * Assert given object is error * @name Error * @memberOf Assertion * @category assertion types */ Assertion.add("Error", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be an error" }; this.have.instanceOf(Error); }); /** * Assert given object is a date * @name Date * @memberOf Assertion * @category assertion types */ Assertion.add("Date", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be a date" }; this.have.instanceOf(Date); }); /** * Assert given object is null * @name null * @alias Assertion#Null * @memberOf Assertion * @category assertion types */ Assertion.add("null", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be null" }; this.assert(this.obj === null); }); Assertion.alias("null", "Null"); /** * Assert given object has some internal [[Class]], via Object.prototype.toString call * @name class * @alias Assertion#Class * @memberOf Assertion * @category assertion types */ Assertion.add("class", function(cls) { this.params = { operator: "to have [[Class]] " + cls }; this.assert(Object.prototype.toString.call(this.obj) === "[object " + cls + "]"); }); Assertion.alias("class", "Class"); /** * Assert given object is undefined * @name undefined * @alias Assertion#Undefined * @memberOf Assertion * @category assertion types */ Assertion.add("undefined", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be undefined" }; this.assert(this.obj === void 0); }); Assertion.alias("undefined", "Undefined"); /** * Assert given object supports es6 iterable protocol (just check * that object has property Symbol.iterator, which is a function) * @name iterable * @memberOf Assertion * @category assertion es6 */ Assertion.add("iterable", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be iterable" }; should(this.obj) .have.property(Symbol.iterator) .which.is.a.Function(); }); /** * Assert given object supports es6 iterator protocol (just check * that object has property next, which is a function) * @name iterator * @memberOf Assertion * @category assertion es6 */ Assertion.add("iterator", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be iterator" }; should(this.obj) .have.property("next") .which.is.a.Function(); }); /** * Assert given object is a generator object * @name generator * @memberOf Assertion * @category assertion es6 */ Assertion.add("generator", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be generator" }; should(this.obj).be.iterable.and.iterator.and.it.is.equal(this.obj[Symbol.iterator]()); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function formatEqlResult(r, a, b) { return ((r.path.length > 0 ? "at " + r.path.map(formatProp).join(" -> ") : "") + (r.a === a ? "" : ", A has " + format$2(r.a)) + (r.b === b ? "" : " and B has " + format$2(r.b)) + (r.showReason ? " because " + r.reason : "")).trim(); } function equalityAssertions(should, Assertion) { /** * Deep object equality comparison. For full spec see [`should-equal tests`](https://github.com/shouldjs/equal/blob/master/test.js). * * @name eql * @memberOf Assertion * @category assertion equality * @alias Assertion#eqls * @alias Assertion#deepEqual * @param {*} val Expected value * @param {string} [description] Optional message * @example * * (10).should.be.eql(10); * ('10').should.not.be.eql(10); * (-0).should.not.be.eql(+0); * * NaN.should.be.eql(NaN); * * ({ a: 10}).should.be.eql({ a: 10 }); * [ 'a' ].should.not.be.eql({ '0': 'a' }); */ Assertion.add("eql", function(val, description) { this.params = { operator: "to equal", expected: val, message: description }; var obj = this.obj; var fails = eq(this.obj, val, should.config); this.params.details = fails .map(function(fail) { return formatEqlResult(fail, obj, val); }) .join(", "); this.params.showDiff = eq(getGlobalType(obj), getGlobalType(val)).length === 0; this.assert(fails.length === 0); }); /** * Exact comparison using ===. * * @name equal * @memberOf Assertion * @category assertion equality * @alias Assertion#equals * @alias Assertion#exactly * @param {*} val Expected value * @param {string} [description] Optional message * @example * * 10.should.be.equal(10); * 'a'.should.be.exactly('a'); * * should(null).be.exactly(null); */ Assertion.add("equal", function(val, description) { this.params = { operator: "to be", expected: val, message: description }; this.params.showDiff = eq(getGlobalType(this.obj), getGlobalType(val)).length === 0; this.assert(val === this.obj); }); Assertion.alias("equal", "equals"); Assertion.alias("equal", "exactly"); Assertion.alias("eql", "eqls"); Assertion.alias("eql", "deepEqual"); function addOneOf(name, message, method) { Assertion.add(name, function(vals) { if (arguments.length !== 1) { vals = Array.prototype.slice.call(arguments); } else { should(vals).be.Array(); } this.params = { operator: message, expected: vals }; var obj = this.obj; var found = false; forEach(vals, function(val) { try { should(val)[method](obj); found = true; return false; } catch (e) { if (e instanceof should.AssertionError) { return; //do nothing } throw e; } }); this.assert(found); }); } /** * Exact comparison using === to be one of supplied objects. * * @name equalOneOf * @memberOf Assertion * @category assertion equality * @param {Array|*} vals Expected values * @example * * 'ab'.should.be.equalOneOf('a', 10, 'ab'); * 'ab'.should.be.equalOneOf(['a', 10, 'ab']); */ addOneOf("equalOneOf", "to be equals one of", "equal"); /** * Exact comparison using .eql to be one of supplied objects. * * @name oneOf * @memberOf Assertion * @category assertion equality * @param {Array|*} vals Expected values * @example * * ({a: 10}).should.be.oneOf('a', 10, 'ab', {a: 10}); * ({a: 10}).should.be.oneOf(['a', 10, 'ab', {a: 10}]); */ addOneOf("oneOf", "to be one of", "eql"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function promiseAssertions(should, Assertion$$1) { /** * Assert given object is a Promise * * @name Promise * @memberOf Assertion * @category assertion promises * @example * * promise.should.be.Promise() * (new Promise(function(resolve, reject) { resolve(10); })).should.be.a.Promise() * (10).should.not.be.a.Promise() */ Assertion$$1.add("Promise", function() { this.assertZeroArguments(arguments); this.params = { operator: "to be promise" }; var obj = this.obj; should(obj) .have.property("then") .which.is.a.Function(); }); /** * Assert given promise will be fulfilled. Result of assertion is still .thenable and should be handled accordingly. * * @name fulfilled * @memberOf Assertion * @alias Assertion#resolved * @returns {Promise} * @category assertion promises * @example * * // don't forget to handle async nature * (new Promise(function(resolve, reject) { resolve(10); })).should.be.fulfilled(); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise(resolve => resolve(10)) * .should.be.fulfilled(); * }); */ Assertion$$1.prototype.fulfilled = function Assertion$fulfilled() { this.assertZeroArguments(arguments); this.params = { operator: "to be fulfilled" }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function next$onResolve(value) { if (that.negate) { that.fail(); } return value; }, function next$onReject(err) { if (!that.negate) { that.params.operator += ", but it was rejected with " + should.format(err); that.fail(); } return err; } ); }; Assertion$$1.prototype.resolved = Assertion$$1.prototype.fulfilled; /** * Assert given promise will be rejected. Result of assertion is still .thenable and should be handled accordingly. * * @name rejected * @memberOf Assertion * @category assertion promises * @returns {Promise} * @example * * // don't forget to handle async nature * (new Promise(function(resolve, reject) { resolve(10); })) * .should.not.be.rejected(); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise((resolve, reject) => reject(new Error('boom'))) * .should.be.rejected(); * }); */ Assertion$$1.prototype.rejected = function() { this.assertZeroArguments(arguments); this.params = { operator: "to be rejected" }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function(value) { if (!that.negate) { that.params.operator += ", but it was fulfilled"; if (arguments.length != 0) { that.params.operator += " with " + should.format(value); } that.fail(); } return value; }, function next$onError(err) { if (that.negate) { that.fail(); } return err; } ); }; /** * Assert given promise will be fulfilled with some expected value (value compared using .eql). * Result of assertion is still .thenable and should be handled accordingly. * * @name fulfilledWith * @memberOf Assertion * @alias Assertion#resolvedWith * @category assertion promises * @returns {Promise} * @example * * // don't forget to handle async nature * (new Promise(function(resolve, reject) { resolve(10); })) * .should.be.fulfilledWith(10); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise((resolve, reject) => resolve(10)) * .should.be.fulfilledWith(10); * }); */ Assertion$$1.prototype.fulfilledWith = function(expectedValue) { this.params = { operator: "to be fulfilled with " + should.format(expectedValue) }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function(value) { if (that.negate) { that.fail(); } should(value).eql(expectedValue); return value; }, function next$onError(err) { if (!that.negate) { that.params.operator += ", but it was rejected with " + should.format(err); that.fail(); } return err; } ); }; Assertion$$1.prototype.resolvedWith = Assertion$$1.prototype.fulfilledWith; /** * Assert given promise will be rejected with some sort of error. Arguments is the same for Assertion#throw. * Result of assertion is still .thenable and should be handled accordingly. * * @name rejectedWith * @memberOf Assertion * @category assertion promises * @returns {Promise} * @example * * function failedPromise() { * return new Promise(function(resolve, reject) { * reject(new Error('boom')) * }) * } * failedPromise().should.be.rejectedWith(Error); * failedPromise().should.be.rejectedWith('boom'); * failedPromise().should.be.rejectedWith(/boom/); * failedPromise().should.be.rejectedWith(Error, { message: 'boom' }); * failedPromise().should.be.rejectedWith({ message: 'boom' }); * * // test example with mocha it is possible to return promise * it('is async', () => { * return failedPromise().should.be.rejectedWith({ message: 'boom' }); * }); */ Assertion$$1.prototype.rejectedWith = function(message, properties) { this.params = { operator: "to be rejected" }; should(this.obj).be.a.Promise(); var that = this; return this.obj.then( function(value) { if (!that.negate) { that.fail(); } return value; }, function next$onError(err) { if (that.negate) { that.fail(); } var errorMatched = true; var errorInfo = ""; if ("string" === typeof message) { errorMatched = message === err.message; } else if (message instanceof RegExp) { errorMatched = message.test(err.message); } else if ("function" === typeof message) { errorMatched = err instanceof message; } else if (message !== null && typeof message === "object") { try { should(err).match(message); } catch (e) { if (e instanceof should.AssertionError) { errorInfo = ": " + e.message; errorMatched = false; } else { throw e; } } } if (!errorMatched) { if (typeof message === "string" || message instanceof RegExp) { errorInfo = " with a message matching " + should.format(message) + ", but got '" + err.message + "'"; } else if ("function" === typeof message) { errorInfo = " of type " + functionName$1(message) + ", but got " + functionName$1(err.constructor); } } else if ("function" === typeof message && properties) { try { should(err).match(properties); } catch (e) { if (e instanceof should.AssertionError) { errorInfo = ": " + e.message; errorMatched = false; } else { throw e; } } } that.params.operator += errorInfo; that.assert(errorMatched); return err; } ); }; /** * Assert given object is promise and wrap it in PromisedAssertion, which has all properties of Assertion. * That means you can chain as with usual Assertion. * Result of assertion is still .thenable and should be handled accordingly. * * @name finally * @memberOf Assertion * @alias Assertion#eventually * @category assertion promises * @returns {PromisedAssertion} Like Assertion, but .then this.obj in Assertion * @example * * (new Promise(function(resolve, reject) { resolve(10); })) * .should.be.eventually.equal(10); * * // test example with mocha it is possible to return promise * it('is async', () => { * return new Promise(resolve => resolve(10)) * .should.be.finally.equal(10); * }); */ Object.defineProperty(Assertion$$1.prototype, "finally", { get: function() { should(this.obj).be.a.Promise(); var that = this; return new PromisedAssertion( this.obj.then(function(obj) { var a = should(obj); a.negate = that.negate; a.anyOne = that.anyOne; return a; }) ); } }); Assertion$$1.alias("finally", "eventually"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function stringAssertions(should, Assertion) { /** * Assert given string starts with prefix * @name startWith * @memberOf Assertion * @category assertion strings * @param {string} str Prefix * @param {string} [description] Optional message * @example * * 'abc'.should.startWith('a'); */ Assertion.add("startWith", function(str, description) { this.params = { operator: "to start with " + should.format(str), message: description }; this.assert(0 === this.obj.indexOf(str)); }); /** * Assert given string ends with prefix * @name endWith * @memberOf Assertion * @category assertion strings * @param {string} str Prefix * @param {string} [description] Optional message * @example * * 'abca'.should.endWith('a'); */ Assertion.add("endWith", function(str, description) { this.params = { operator: "to end with " + should.format(str), message: description }; this.assert(this.obj.indexOf(str, this.obj.length - str.length) >= 0); }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function containAssertions(should, Assertion) { var i = should.format; /** * 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; if (typeof obj == "string") { this.assert(obj.indexOf(String(other)) >= 0); } else if (isIterable(obj)) { this.assert( some(obj, function(v) { return eq(v, other).length === 0; }) ); } else { forEach( other, function(value, key) { should(obj).have.value(key, value); }, this ); } }); /** * 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) * 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 ]]); * * ({ 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 (typeof obj == "string") { // expect other to be string this.is.equal(String(other)); } else if (isIterable(obj) && isIterable(other)) { var objIterator = iterator(obj); var otherIterator = iterator(other); var nextObj = objIterator.next(); var nextOther = otherIterator.next(); while (!nextObj.done && !nextOther.done) { try { should(nextObj.value[1]).containDeepOrdered(nextOther.value[1]); nextOther = otherIterator.next(); } catch (e) { if (!(e instanceof should.AssertionError)) { throw e; } } nextObj = objIterator.next(); } this.assert(nextOther.done); } else if (obj != null && typeof obj == "object" && other != null && typeof other == "object") { //TODO compare types object contains object case 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 (isEmpty(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" && typeof other === "string") { // expect other to be string this.is.equal(String(other)); } else if (isIterable(obj) && isIterable(other)) { var usedKeys = {}; forEach( other, function(otherItem) { this.assert( 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 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 (isEmpty(other)) { this.eql(other); } } else { this.eql(other); } }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ var aSlice = Array.prototype.slice; function propertyAssertions(should, Assertion) { var i = should.format; /** * Asserts given object has some descriptor. **On success it change given object to be value of property**. * * @name propertyWithDescriptor * @memberOf Assertion * @category assertion property * @param {string} name Name of property * @param {Object} desc Descriptor like used in Object.defineProperty (not required to add all properties) * @example * * ({ a: 10 }).should.have.propertyWithDescriptor('a', { enumerable: true }); */ Assertion.add("propertyWithDescriptor", function(name, desc) { this.params = { actual: this.obj, operator: "to have own property with descriptor " + i(desc) }; var obj = this.obj; this.have.ownProperty(name); should(Object.getOwnPropertyDescriptor(Object(obj), name)).have.properties(desc); }); /** * Asserts given object has property with optionally value. **On success it change given object to be value of property**. * * @name property * @memberOf Assertion * @category assertion property * @param {string} name Name of property * @param {*} [val] Optional property value to check * @example * * ({ a: 10 }).should.have.property('a'); */ Assertion.add("property", function(name, val) { name = convertPropertyName(name); if (arguments.length > 1) { var p = {}; p[name] = val; this.have.properties(p); } else { this.have.properties(name); } this.obj = this.obj[name]; }); /** * Asserts given object has properties. On this method affect .any modifier, which allow to check not all properties. * * @name properties * @memberOf Assertion * @category assertion property * @param {Array|...string|Object} names Names of property * @example * * ({ a: 10 }).should.have.properties('a'); * ({ a: 10, b: 20 }).should.have.properties([ 'a' ]); * ({ a: 10, b: 20 }).should.have.properties({ b: 20 }); */ Assertion.add("properties", function(names) { var values = {}; if (arguments.length > 1) { names = aSlice.call(arguments); } else if (!Array.isArray(names)) { if (typeof names == "string" || typeof names == "symbol") { 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(formatProp(name)); } }); var props = missingProperties; if (props.length === 0) { props = names.map(formatProp); } else if (this.anyOne) { props = names .filter(function(name) { return missingProperties.indexOf(formatProp(name)) < 0; }) .map(formatProp); } var operator = (props.length === 1 ? "to have property " : "to have " + (this.anyOne ? "any of " : "") + "properties ") + props.join(", "); this.params = { obj: this.obj, operator: operator }; //check that all properties presented //or if we request one of them that at least one them presented this.assert( missingProperties.length === 0 || (this.anyOne && missingProperties.length != names.length) ); // 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 (eq(obj[name], value).length !== 0) { wrongValues.push(formatProp(name) + " of " + i(value) + " (got " + i(obj[name]) + ")"); } else { props.push(formatProp(name) + " of " + i(value)); } }); if ((wrongValues.length !== 0 && !this.anyOne) || (this.anyOne && props.length === 0)) { props = wrongValues; } operator = (props.length === 1 ? "to have property " : "to have " + (this.anyOne ? "any of " : "") + "properties ") + props.join(", "); this.params = { obj: this.obj, operator: operator }; //if there is no not matched values //or there is at least one matched this.assert( wrongValues.length === 0 || (this.anyOne && wrongValues.length != valueCheckNames.length) ); } }); /** * Asserts given object has property `length` with given value `n` * * @name length * @alias Assertion#lengthOf * @memberOf Assertion * @category assertion property * @param {number} n Expected length * @param {string} [description] Optional message * @example * * [1, 2].should.have.length(2); */ Assertion.add("length", function(n, description) { this.have.property("length", n, description); }); Assertion.alias("length", "lengthOf"); /** * Asserts given object has own property. **On success it change given object to be value of property**. * * @name ownProperty * @alias Assertion#hasOwnProperty * @memberOf Assertion * @category assertion property * @param {string} name Name of property * @param {string} [description] Optional message * @example * * ({ a: 10 }).should.have.ownProperty('a'); */ Assertion.add("ownProperty", function(name, description) { name = convertPropertyName(name); this.params = { actual: this.obj, operator: "to have own property " + formatProp(name), message: description }; this.assert(hasOwnProperty$1(this.obj, name)); this.obj = this.obj[name]; }); Assertion.alias("ownProperty", "hasOwnProperty"); /** * Asserts given object is empty. For strings, arrays and arguments it checks .length property, for objects it checks keys. * * @name empty * @memberOf Assertion * @category assertion property * @example * * ''.should.be.empty(); * [].should.be.empty(); * ({}).should.be.empty(); */ Assertion.add( "empty", function() { this.params = { operator: "to be empty" }; this.assert(isEmpty(this.obj)); }, true ); /** * Asserts given object has such keys. Compared to `properties`, `keys` does not accept Object as a argument. * When calling via .key current object in assertion changed to value of this key * * @name keys * @alias Assertion#key * @memberOf Assertion * @category assertion property * @param {...*} keys Keys to check * @example * * ({ a: 10 }).should.have.keys('a'); * ({ a: 10, b: 20 }).should.have.keys('a', 'b'); * (new Map([[1, 2]])).should.have.key(1); * * json.should.have.only.keys('type', 'version') */ Assertion.add("keys", function(keys) { keys = aSlice.call(arguments); var obj = Object(this.obj); // first check if some keys are missing var missingKeys = keys.filter(function(key) { return !has(obj, key); }); var verb = "to have " + (this.onlyThis ? "only " : "") + (keys.length === 1 ? "key " : "keys "); this.params = { operator: verb + keys.join(", ") }; if (missingKeys.length > 0) { this.params.operator += "\n\tmissing keys: " + missingKeys.join(", "); } this.assert(missingKeys.length === 0); if (this.onlyThis) { should(obj).have.size(keys.length); } }); Assertion.add("key", function(key) { this.have.keys(key); this.obj = get(this.obj, key); }); /** * Asserts given object has such value for given key * * @name value * @memberOf Assertion * @category assertion property * @param {*} key Key to check * @param {*} value Value to check * @example * * ({ a: 10 }).should.have.value('a', 10); * (new Map([[1, 2]])).should.have.value(1, 2); */ Assertion.add("value", function(key, value) { this.have.key(key).which.is.eql(value); }); /** * Asserts given object has such size. * * @name size * @memberOf Assertion * @category assertion property * @param {number} s Size to check * @example * * ({ a: 10 }).should.have.size(1); * (new Map([[1, 2]])).should.have.size(1); */ Assertion.add("size", function(s) { this.params = { operator: "to have size " + s }; should(size(this.obj)).be.exactly(s); }); /** * Asserts given object has nested property in depth by path. **On success it change given object to be value of final property**. * * @name propertyByPath * @memberOf Assertion * @category assertion property * @param {Array|...string} properties Properties path to search * @example * * ({ a: {b: 10}}).should.have.propertyByPath('a', 'b').eql(10); */ Assertion.add("propertyByPath", function(properties) { properties = aSlice.call(arguments); var allProps = properties.map(formatProp); properties = properties.map(convertPropertyName); var obj = should(Object(this.obj)); var foundProperties = []; var currentProperty; while (properties.length) { currentProperty = properties.shift(); this.params = { operator: "to have property by path " + allProps.join(", ") + " - failed on " + formatProp(currentProperty) }; obj = obj.have.property(currentProperty); foundProperties.push(currentProperty); } this.params = { obj: this.obj, operator: "to have property by path " + allProps.join(", ") }; this.obj = obj.obj; }); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function errorAssertions(should, Assertion) { var i = should.format; /** * Assert given function throws error with such message. * * @name throw * @memberOf Assertion * @category assertion errors * @alias Assertion#throwError * @param {string|RegExp|Function|Object|GeneratorFunction|GeneratorObject} [message] Message to match or properties * @param {Object} [properties] Optional properties that will be matched to thrown error * @example * * (function(){ throw new Error('fail') }).should.throw(); * (function(){ throw new Error('fail') }).should.throw('fail'); * (function(){ throw new Error('fail') }).should.throw(/fail/); * * (function(){ throw new Error('fail') }).should.throw(Error); * var error = new Error(); * error.a = 10; * (function(){ throw error; }).should.throw(Error, { a: 10 }); * (function(){ throw error; }).should.throw({ a: 10 }); * (function*() { * yield throwError(); * }).should.throw(); */ Assertion.add("throw", function(message, properties) { var fn = this.obj; var err = {}; var errorInfo = ""; var thrown = false; if (isGeneratorFunction(fn)) { return should(fn()).throw(message, properties); } else if (isIterator(fn)) { return should(fn.next.bind(fn)).throw(message, properties); } this.is.a.Function(); var errorMatched = true; try { fn(); } catch (e) { thrown = true; err = e; } if (thrown) { if (message) { if ("string" == typeof message) { errorMatched = message == err.message; } else if (message instanceof RegExp) { errorMatched = message.test(err.message); } else if ("function" == typeof message) { errorMatched = err instanceof message; } else if (null != message) { try { should(err).match(message); } catch (e) { if (e instanceof should.AssertionError) { errorInfo = ": " + e.message; errorMatched = false; } else { throw e; } } } if (!errorMatched) { if ("string" == typeof message || message instanceof RegExp) { errorInfo = " with a message matching " + i(message) + ", but got '" + err.message + "'"; } else if ("function" == typeof message) { errorInfo = " of type " + functionName$1(message) + ", but got " + functionName$1(err.constructor); } } else if ("function" == typeof message && properties) { try { should(err).match(properties); } catch (e) { if (e instanceof should.AssertionError) { errorInfo = ": " + e.message; errorMatched = false; } else { throw e; } } } } else { errorInfo = " (got " + i(err) + ")"; } } this.params = { operator: "to throw exception" + errorInfo }; this.assert(thrown); this.assert(errorMatched); }); Assertion.alias("throw", "throwError"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ function matchingAssertions(should, Assertion) { var i = should.format; /** * Asserts if given object match `other` object, using some assumptions: * First object matched if they are equal, * If `other` is a regexp and given object is a string check on matching with regexp * If `other` is a regexp and given object is an array check if all elements matched regexp * If `other` is a regexp and given object is an object check values on matching regexp * If `other` is a function check if this function throws AssertionError on given object or return false - it will be assumed as not matched * If `other` is an object check if the same keys matched with above rules * All other cases failed. * * Usually it is right idea to add pre type assertions, like `.String()` or `.Object()` to be sure assertions will do what you are expecting. * Object iteration happen by keys (properties with enumerable: true), thus some objects can cause small pain. Typical example is js * Error - it by default has 2 properties `name` and `message`, but they both non-enumerable. In this case make sure you specify checking props (see examples). * * @name match * @memberOf Assertion * @category assertion matching * @param {*} other Object to match * @param {string} [description] Optional message * @example * 'foobar'.should.match(/^foo/); * 'foobar'.should.not.match(/^bar/); * * ({ a: 'foo', c: 'barfoo' }).should.match(/foo$/); * * ['a', 'b', 'c'].should.match(/[a-z]/); * * (5).should.not.match(function(n) { * return n < 0; * }); * (5).should.not.match(function(it) { * it.should.be.an.Array(); * }); * ({ a: 10, b: 'abc', c: { d: 10 }, d: 0 }).should * .match({ a: 10, b: /c$/, c: function(it) { * return it.should.have.property('d', 10); * }}); * * [10, 'abc', { d: 10 }, 0].should * .match({ '0': 10, '1': /c$/, '2': function(it) { * return it.should.have.property('d', 10); * }}); * * var myString = 'abc'; * * myString.should.be.a.String().and.match(/abc/); * * myString = {}; * * myString.should.match(/abc/); //yes this will pass * //better to do * myString.should.be.an.Object().and.not.empty().and.match(/abc/);//fixed * * (new Error('boom')).should.match(/abc/);//passed because no keys * (new Error('boom')).should.not.match({ message: /abc/ });//check specified property */ Assertion.add("match", function(other, description) { this.params = { operator: "to match " + i(other), message: description }; if (eq(this.obj, other).length !== 0) { if (other instanceof RegExp) { // something - regex if (typeof this.obj == "string") { this.assert(other.exec(this.obj)); } else if (null != this.obj && typeof this.obj == "object") { var notMatchedProps = [], matchedProps = []; forEach( this.obj, function(value, name) { if (other.exec(value)) { matchedProps.push(formatProp(name)); } else { notMatchedProps.push(formatProp(name) + " (" + i(value) + ")"); } }, this ); if (notMatchedProps.length) { this.params.operator += "\n not matched properties: " + notMatchedProps.join(", "); } if (matchedProps.length) { this.params.operator += "\n matched properties: " + matchedProps.join(", "); } this.assert(notMatchedProps.length === 0); } else { // should we try to convert to String and exec? this.assert(false); } } else if (typeof other == "function") { var res; res = other(this.obj); //if we throw exception ok - it is used .should inside if (typeof res == "boolean") { this.assert(res); // if it is just boolean function assert on it } } else if (typeof this.obj == "object" && this.obj != null && (isPlainObject(other) || Array.isArray(other))) { // try to match properties (for Object and Array) notMatchedProps = []; matchedProps = []; forEach( other, function(value, key) { try { should(this.obj) .have.property(key) .which.match(value); matchedProps.push(formatProp(key)); } catch (e) { if (e instanceof should.AssertionError) { notMatchedProps.push(formatProp(key) + " (" + i(this.obj[key]) + ")"); } else { throw e; } } }, this ); if (notMatchedProps.length) { this.params.operator += "\n not matched properties: " + notMatchedProps.join(", "); } if (matchedProps.length) { this.params.operator += "\n matched properties: " + matchedProps.join(", "); } this.assert(notMatchedProps.length === 0); } else { this.assert(false); } } }); /** * Asserts if given object values or array elements all match `other` object, using some assumptions: * First object matched if they are equal, * If `other` is a regexp - matching with regexp * If `other` is a function check if this function throws AssertionError on given object or return false - it will be assumed as not matched * All other cases check if this `other` equal to each element * * @name matchEach * @memberOf Assertion * @category assertion matching * @alias Assertion#matchEvery * @param {*} other Object to match * @param {string} [description] Optional message * @example * [ 'a', 'b', 'c'].should.matchEach(/\w+/); * [ 'a', 'a', 'a'].should.matchEach('a'); * * [ 'a', 'a', 'a'].should.matchEach(function(value) { value.should.be.eql('a') }); * * { a: 'a', b: 'a', c: 'a' }.should.matchEach(function(value) { value.should.be.eql('a') }); */ Assertion.add("matchEach", function(other, description) { this.params = { operator: "to match each " + i(other), message: description }; forEach( this.obj, function(value) { should(value).match(other); }, this ); }); /** * Asserts if any of given object values or array elements match `other` object, using some assumptions: * First object matched if they are equal, * If `other` is a regexp - matching with regexp * If `other` is a function check if this function throws AssertionError on given object or return false - it will be assumed as not matched * All other cases check if this `other` equal to each element * * @name matchAny * @memberOf Assertion * @category assertion matching * @param {*} other Object to match * @alias Assertion#matchSome * @param {string} [description] Optional message * @example * [ 'a', 'b', 'c'].should.matchAny(/\w+/); * [ 'a', 'b', 'c'].should.matchAny('a'); * * [ 'a', 'b', 'c'].should.matchAny(function(value) { value.should.be.eql('a') }); * * { a: 'a', b: 'b', c: 'c' }.should.matchAny(function(value) { value.should.be.eql('a') }); */ Assertion.add("matchAny", function(other, description) { this.params = { operator: "to match any " + i(other), message: description }; this.assert( some(this.obj, function(value) { try { should(value).match(other); return true; } catch (e) { if (e instanceof should.AssertionError) { // Caught an AssertionError, return false to the iterator return false; } throw e; } }) ); }); Assertion.alias("matchAny", "matchSome"); Assertion.alias("matchEach", "matchEvery"); } /* * should.js - assertion library * Copyright(c) 2010-2013 TJ Holowaychuk * Copyright(c) 2013-2017 Denis Bardadym * MIT Licensed */ /** * Our function should * * @param {*} obj Object to assert * @returns {should.Assertion} Returns new Assertion for beginning assertion chain * @example * * var should = require('should'); * should('abc').be.a.String(); */ function should$1(obj) { return new Assertion(obj); } should$1.AssertionError = AssertionError; should$1.Assertion = Assertion; // exposing modules dirty way should$1.modules = { format: defaultFormat, type: getGlobalType, equal: eq }; should$1.format = format$2; /** * Object with configuration. * It contains such properties: * * `checkProtoEql` boolean - Affect if `.eql` will check objects prototypes * * `plusZeroAndMinusZeroEqual` boolean - Affect if `.eql` will treat +0 and -0 as equal * Also it can contain options for should-format. * * @type {Object} * @memberOf should * @static * @example * * var a = { a: 10 }, b = Object.create(null); * b.a = 10; * * a.should.be.eql(b); * //not throws * * should.config.checkProtoEql = true; * a.should.be.eql(b); * //throws AssertionError: expected { a: 10 } to equal { a: 10 } (because A and B have different prototypes) */ should$1.config = config; /** * Allow to extend given prototype with should property using given name. This getter will **unwrap** all standard wrappers like `Number`, `Boolean`, `String`. * Using `should(obj)` is the equivalent of using `obj.should` with known issues (like nulls and method calls etc). * * To add new assertions, need to use Assertion.add method. * * @param {string} [propertyName] Name of property to add. Default is `'should'`. * @param {Object} [proto] Prototype to extend with. Default is `Object.prototype`. * @memberOf should * @returns {{ name: string, descriptor: Object, proto: Object }} Descriptor enough to return all back * @static * @example * * var prev = should.extend('must', Object.prototype); * * 'abc'.must.startWith('a'); * * var should = should.noConflict(prev); * should.not.exist(Object.prototype.must); */ should$1.extend = function(propertyName, proto) { propertyName = propertyName || "should"; proto = proto || Object.prototype; var prevDescriptor = Object.getOwnPropertyDescriptor(proto, propertyName); Object.defineProperty(proto, propertyName, { set: function() {}, get: function() { return should$1(isWrapperType(this) ? this.valueOf() : this); }, configurable: true }); return { name: propertyName, descriptor: prevDescriptor, proto: proto }; }; /** * Delete previous extension. If `desc` missing it will remove default extension. * * @param {{ name: string, descriptor: Object, proto: Object }} [desc] Returned from `should.extend` object * @memberOf should * @returns {Function} Returns should function * @static * @example * * var should = require('should').noConflict(); * * should(Object.prototype).not.have.property('should'); * * var prev = should.extend('must', Object.prototype); * 'abc'.must.startWith('a'); * should.noConflict(prev); * * should(Object.prototype).not.have.property('must'); */ should$1.noConflict = function(desc) { desc = desc || should$1._prevShould; if (desc) { delete desc.proto[desc.name]; if (desc.descriptor) { Object.defineProperty(desc.proto, desc.name, desc.descriptor); } } return should$1; }; /** * Simple utility function for a bit more easier should assertion extension * @param {Function} f So called plugin function. It should accept 2 arguments: `should` function and `Assertion` constructor * @memberOf should * @returns {Function} Returns `should` function * @static * @example * * should.use(function(should, Assertion) { * Assertion.add('asset', function() { * this.params = { operator: 'to be asset' }; * * this.obj.should.have.property('id').which.is.a.Number(); * this.obj.should.have.property('path'); * }) * }) */ should$1.use = function(f) { f(should$1, should$1.Assertion); return this; }; should$1 .use(assertExtensions) .use(chainAssertions) .use(booleanAssertions) .use(numberAssertions) .use(equalityAssertions) .use(typeAssertions) .use(stringAssertions) .use(propertyAssertions) .use(errorAssertions) .use(matchingAssertions) .use(containAssertions) .use(promiseAssertions); var defaultProto = Object.prototype; var defaultProperty = "should"; var freeGlobal = typeof global == "object" && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == "object" && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function("return this")(); //Expose api via `Object#should`. try { var prevShould = should$1.extend(defaultProperty, defaultProto); should$1._prevShould = prevShould; Object.defineProperty(root, "should", { enumerable: false, configurable: true, value: should$1 }); } catch (e) { //ignore errors } if (typeof define === "function" && define.amd) { define([], function() { return should$1; }); } else if (typeof module === "object" && module.exports) { module.exports = should$1; } }());