From 9211a80d0ebe792e30907ae588632601242dfff9 Mon Sep 17 00:00:00 2001 From: Andrew Carreiro Date: Thu, 19 Nov 2015 23:15:19 -0500 Subject: [PATCH] Added tests, modified resemble to add error state for loaded images --- resemble.js | 13 + tests/chai-3.4.2.js | 6019 +++++++++++++++++++++++++++++++++++++++++++ tests/main_spec.js | 70 + tests/test.html | 12 + 4 files changed, 6114 insertions(+) create mode 100644 tests/chai-3.4.2.js create mode 100644 tests/main_spec.js create mode 100644 tests/test.html diff --git a/resemble.js b/resemble.js index 815a5bc..195dec2 100644 --- a/resemble.js +++ b/resemble.js @@ -148,7 +148,14 @@ URL: https://github.com/Huddle/Resemble.js hiddenImage.setAttribute('crossorigin', 'anonymous'); } + hiddenImage.onerror = function () { + hiddenImage.onerror = null; //fixes pollution between calls + images.push({ error : "Image load error."}); + callback(); + }; + hiddenImage.onload = function() { + hiddenImage.onload = null; //fixes pollution between calls var hiddenCanvas = document.createElement('canvas'); var imageData; @@ -531,6 +538,12 @@ URL: https://github.com/Huddle/Resemble.js var width; var height; if(images.length === 2){ + if( images[0].error || images[1].error ){ + data = {}; + data.error = images[0].error ? images[0].error : images[1].error; + triggerDataUpdate(); + return; + } width = images[0].width > images[1].width ? images[0].width : images[1].width; height = images[0].height > images[1].height ? images[0].height : images[1].height; diff --git a/tests/chai-3.4.2.js b/tests/chai-3.4.2.js new file mode 100644 index 0000000..c467073 --- /dev/null +++ b/tests/chai-3.4.2.js @@ -0,0 +1,6019 @@ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.chai = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * MIT Licensed + */ + +var used = [] + , exports = module.exports = {}; + +/*! + * Chai version + */ + +exports.version = '3.4.2'; + +/*! + * Assertion Error + */ + +exports.AssertionError = require('assertion-error'); + +/*! + * Utils for plugins (not exported) + */ + +var util = require('./chai/utils'); + +/** + * # .use(function) + * + * Provides a way to extend the internals of Chai + * + * @param {Function} + * @returns {this} for chaining + * @api public + */ + +exports.use = function (fn) { + if (!~used.indexOf(fn)) { + fn(this, util); + used.push(fn); + } + + return this; +}; + +/*! + * Utility Functions + */ + +exports.util = util; + +/*! + * Configuration + */ + +var config = require('./chai/config'); +exports.config = config; + +/*! + * Primary `Assertion` prototype + */ + +var assertion = require('./chai/assertion'); +exports.use(assertion); + +/*! + * Core Assertions + */ + +var core = require('./chai/core/assertions'); +exports.use(core); + +/*! + * Expect interface + */ + +var expect = require('./chai/interface/expect'); +exports.use(expect); + +/*! + * Should interface + */ + +var should = require('./chai/interface/should'); +exports.use(should); + +/*! + * Assert interface + */ + +var assert = require('./chai/interface/assert'); +exports.use(assert); + +},{"./chai/assertion":3,"./chai/config":4,"./chai/core/assertions":5,"./chai/interface/assert":6,"./chai/interface/expect":7,"./chai/interface/should":8,"./chai/utils":22,"assertion-error":30}],3:[function(require,module,exports){ +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +var config = require('./config'); + +module.exports = function (_chai, util) { + /*! + * Module dependencies. + */ + + var AssertionError = _chai.AssertionError + , flag = util.flag; + + /*! + * Module export. + */ + + _chai.Assertion = Assertion; + + /*! + * Assertion Constructor + * + * Creates object for chaining. + * + * @api private + */ + + function Assertion (obj, msg, stack) { + flag(this, 'ssfi', stack || arguments.callee); + flag(this, 'object', obj); + flag(this, 'message', msg); + } + + Object.defineProperty(Assertion, 'includeStack', { + get: function() { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + return config.includeStack; + }, + set: function(value) { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + config.includeStack = value; + } + }); + + Object.defineProperty(Assertion, 'showDiff', { + get: function() { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + return config.showDiff; + }, + set: function(value) { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + config.showDiff = value; + } + }); + + Assertion.addProperty = function (name, fn) { + util.addProperty(this.prototype, name, fn); + }; + + Assertion.addMethod = function (name, fn) { + util.addMethod(this.prototype, name, fn); + }; + + Assertion.addChainableMethod = function (name, fn, chainingBehavior) { + util.addChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + Assertion.overwriteProperty = function (name, fn) { + util.overwriteProperty(this.prototype, name, fn); + }; + + Assertion.overwriteMethod = function (name, fn) { + util.overwriteMethod(this.prototype, name, fn); + }; + + Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { + util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + /** + * ### .assert(expression, message, negateMessage, expected, actual, showDiff) + * + * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. + * + * @name assert + * @param {Philosophical} expression to be tested + * @param {String|Function} message or function that returns message to display if expression fails + * @param {String|Function} negatedMessage or function that returns negatedMessage to display if negated expression fails + * @param {Mixed} expected value (remember to check for negation) + * @param {Mixed} actual (optional) will default to `this.obj` + * @param {Boolean} showDiff (optional) when set to `true`, assert will display a diff in addition to the message if expression fails + * @api private + */ + + Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { + var ok = util.test(this, arguments); + if (true !== showDiff) showDiff = false; + if (true !== config.showDiff) showDiff = false; + + if (!ok) { + var msg = util.getMessage(this, arguments) + , actual = util.getActual(this, arguments); + throw new AssertionError(msg, { + actual: actual + , expected: expected + , showDiff: showDiff + }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); + } + }; + + /*! + * ### ._obj + * + * Quick reference to stored `actual` value for plugin developers. + * + * @api private + */ + + Object.defineProperty(Assertion.prototype, '_obj', + { get: function () { + return flag(this, 'object'); + } + , set: function (val) { + flag(this, 'object', val); + } + }); +}; + +},{"./config":4}],4:[function(require,module,exports){ +module.exports = { + + /** + * ### config.includeStack + * + * User configurable property, influences whether stack trace + * is included in Assertion error message. Default of false + * suppresses stack trace in the error message. + * + * chai.config.includeStack = true; // enable stack on error + * + * @param {Boolean} + * @api public + */ + + includeStack: false, + + /** + * ### config.showDiff + * + * User configurable property, influences whether or not + * the `showDiff` flag should be included in the thrown + * AssertionErrors. `false` will always be `false`; `true` + * will be true when the assertion has requested a diff + * be shown. + * + * @param {Boolean} + * @api public + */ + + showDiff: true, + + /** + * ### config.truncateThreshold + * + * User configurable property, sets length threshold for actual and + * expected values in assertion errors. If this threshold is exceeded, for + * example for large data structures, the value is replaced with something + * like `[ Array(3) ]` or `{ Object (prop1, prop2) }`. + * + * Set it to zero if you want to disable truncating altogether. + * + * This is especially userful when doing assertions on arrays: having this + * set to a reasonable large value makes the failure messages readily + * inspectable. + * + * chai.config.truncateThreshold = 0; // disable truncating + * + * @param {Number} + * @api public + */ + + truncateThreshold: 40 + +}; + +},{}],5:[function(require,module,exports){ +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, _) { + var Assertion = chai.Assertion + , toString = Object.prototype.toString + , flag = _.flag; + + /** + * ### Language Chains + * + * The following are provided as chainable getters to + * improve the readability of your assertions. They + * do not provide testing capabilities unless they + * have been overwritten by a plugin. + * + * **Chains** + * + * - to + * - be + * - been + * - is + * - that + * - which + * - and + * - has + * - have + * - with + * - at + * - of + * - same + * + * @name language chains + * @namespace BDD + * @api public + */ + + [ 'to', 'be', 'been' + , 'is', 'and', 'has', 'have' + , 'with', 'that', 'which', 'at' + , 'of', 'same' ].forEach(function (chain) { + Assertion.addProperty(chain, function () { + return this; + }); + }); + + /** + * ### .not + * + * Negates any of assertions following in the chain. + * + * expect(foo).to.not.equal('bar'); + * expect(goodFn).to.not.throw(Error); + * expect({ foo: 'baz' }).to.have.property('foo') + * .and.not.equal('bar'); + * + * @name not + * @namespace BDD + * @api public + */ + + Assertion.addProperty('not', function () { + flag(this, 'negate', true); + }); + + /** + * ### .deep + * + * Sets the `deep` flag, later used by the `equal` and + * `property` assertions. + * + * expect(foo).to.deep.equal({ bar: 'baz' }); + * expect({ foo: { bar: { baz: 'quux' } } }) + * .to.have.deep.property('foo.bar.baz', 'quux'); + * + * `.deep.property` special characters can be escaped + * by adding two slashes before the `.` or `[]`. + * + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * + * @name deep + * @namespace BDD + * @api public + */ + + Assertion.addProperty('deep', function () { + flag(this, 'deep', true); + }); + + /** + * ### .any + * + * Sets the `any` flag, (opposite of the `all` flag) + * later used in the `keys` assertion. + * + * expect(foo).to.have.any.keys('bar', 'baz'); + * + * @name any + * @namespace BDD + * @api public + */ + + Assertion.addProperty('any', function () { + flag(this, 'any', true); + flag(this, 'all', false) + }); + + + /** + * ### .all + * + * Sets the `all` flag (opposite of the `any` flag) + * later used by the `keys` assertion. + * + * expect(foo).to.have.all.keys('bar', 'baz'); + * + * @name all + * @namespace BDD + * @api public + */ + + Assertion.addProperty('all', function () { + flag(this, 'all', true); + flag(this, 'any', false); + }); + + /** + * ### .a(type) + * + * The `a` and `an` assertions are aliases that can be + * used either as language chains or to assert a value's + * type. + * + * // typeof + * expect('test').to.be.a('string'); + * expect({ foo: 'bar' }).to.be.an('object'); + * expect(null).to.be.a('null'); + * expect(undefined).to.be.an('undefined'); + * expect(new Error).to.be.an('error'); + * expect(new Promise).to.be.a('promise'); + * expect(new Float32Array()).to.be.a('float32array'); + * expect(Symbol()).to.be.a('symbol'); + * + * // es6 overrides + * expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo'); + * + * // language chain + * expect(foo).to.be.an.instanceof(Foo); + * + * @name a + * @alias an + * @param {String} type + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function an (type, msg) { + if (msg) flag(this, 'message', msg); + type = type.toLowerCase(); + var obj = flag(this, 'object') + , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; + + this.assert( + type === _.type(obj) + , 'expected #{this} to be ' + article + type + , 'expected #{this} not to be ' + article + type + ); + } + + Assertion.addChainableMethod('an', an); + Assertion.addChainableMethod('a', an); + + /** + * ### .include(value) + * + * The `include` and `contain` assertions can be used as either property + * based language chains or as methods to assert the inclusion of an object + * in an array or a substring in a string. When used as language chains, + * they toggle the `contains` flag for the `keys` assertion. + * + * expect([1,2,3]).to.include(2); + * expect('foobar').to.contain('foo'); + * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); + * + * @name include + * @alias contain + * @alias includes + * @alias contains + * @param {Object|String|Number} obj + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function includeChainingBehavior () { + flag(this, 'contains', true); + } + + function include (val, msg) { + _.expectTypes(this, ['array', 'object', 'string']); + + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var expected = false; + + if (_.type(obj) === 'array' && _.type(val) === 'object') { + for (var i in obj) { + if (_.eql(obj[i], val)) { + expected = true; + break; + } + } + } else if (_.type(val) === 'object') { + if (!flag(this, 'negate')) { + for (var k in val) new Assertion(obj).property(k, val[k]); + return; + } + var subset = {}; + for (var k in val) subset[k] = obj[k]; + expected = _.eql(subset, val); + } else { + expected = (obj != undefined) && ~obj.indexOf(val); + } + this.assert( + expected + , 'expected #{this} to include ' + _.inspect(val) + , 'expected #{this} to not include ' + _.inspect(val)); + } + + Assertion.addChainableMethod('include', include, includeChainingBehavior); + Assertion.addChainableMethod('contain', include, includeChainingBehavior); + Assertion.addChainableMethod('contains', include, includeChainingBehavior); + Assertion.addChainableMethod('includes', include, includeChainingBehavior); + + /** + * ### .ok + * + * Asserts that the target is truthy. + * + * expect('everything').to.be.ok; + * expect(1).to.be.ok; + * expect(false).to.not.be.ok; + * expect(undefined).to.not.be.ok; + * expect(null).to.not.be.ok; + * + * @name ok + * @namespace BDD + * @api public + */ + + Assertion.addProperty('ok', function () { + this.assert( + flag(this, 'object') + , 'expected #{this} to be truthy' + , 'expected #{this} to be falsy'); + }); + + /** + * ### .true + * + * Asserts that the target is `true`. + * + * expect(true).to.be.true; + * expect(1).to.not.be.true; + * + * @name true + * @namespace BDD + * @api public + */ + + Assertion.addProperty('true', function () { + this.assert( + true === flag(this, 'object') + , 'expected #{this} to be true' + , 'expected #{this} to be false' + , this.negate ? false : true + ); + }); + + /** + * ### .false + * + * Asserts that the target is `false`. + * + * expect(false).to.be.false; + * expect(0).to.not.be.false; + * + * @name false + * @namespace BDD + * @api public + */ + + Assertion.addProperty('false', function () { + this.assert( + false === flag(this, 'object') + , 'expected #{this} to be false' + , 'expected #{this} to be true' + , this.negate ? true : false + ); + }); + + /** + * ### .null + * + * Asserts that the target is `null`. + * + * expect(null).to.be.null; + * expect(undefined).to.not.be.null; + * + * @name null + * @namespace BDD + * @api public + */ + + Assertion.addProperty('null', function () { + this.assert( + null === flag(this, 'object') + , 'expected #{this} to be null' + , 'expected #{this} not to be null' + ); + }); + + /** + * ### .undefined + * + * Asserts that the target is `undefined`. + * + * expect(undefined).to.be.undefined; + * expect(null).to.not.be.undefined; + * + * @name undefined + * @namespace BDD + * @api public + */ + + Assertion.addProperty('undefined', function () { + this.assert( + undefined === flag(this, 'object') + , 'expected #{this} to be undefined' + , 'expected #{this} not to be undefined' + ); + }); + + /** + * ### .NaN + * Asserts that the target is `NaN`. + * + * expect('foo').to.be.NaN; + * expect(4).not.to.be.NaN; + * + * @name NaN + * @namespace BDD + * @api public + */ + + Assertion.addProperty('NaN', function () { + this.assert( + isNaN(flag(this, 'object')) + , 'expected #{this} to be NaN' + , 'expected #{this} not to be NaN' + ); + }); + + /** + * ### .exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi' + * , bar = null + * , baz; + * + * expect(foo).to.exist; + * expect(bar).to.not.exist; + * expect(baz).to.not.exist; + * + * @name exist + * @namespace BDD + * @api public + */ + + Assertion.addProperty('exist', function () { + this.assert( + null != flag(this, 'object') + , 'expected #{this} to exist' + , 'expected #{this} to not exist' + ); + }); + + + /** + * ### .empty + * + * Asserts that the target's length is `0`. For arrays and strings, it checks + * the `length` property. For objects, it gets the count of + * enumerable keys. + * + * expect([]).to.be.empty; + * expect('').to.be.empty; + * expect({}).to.be.empty; + * + * @name empty + * @namespace BDD + * @api public + */ + + Assertion.addProperty('empty', function () { + var obj = flag(this, 'object') + , expected = obj; + + if (Array.isArray(obj) || 'string' === typeof object) { + expected = obj.length; + } else if (typeof obj === 'object') { + expected = Object.keys(obj).length; + } + + this.assert( + !expected + , 'expected #{this} to be empty' + , 'expected #{this} not to be empty' + ); + }); + + /** + * ### .arguments + * + * Asserts that the target is an arguments object. + * + * function test () { + * expect(arguments).to.be.arguments; + * } + * + * @name arguments + * @alias Arguments + * @namespace BDD + * @api public + */ + + function checkArguments () { + var obj = flag(this, 'object') + , type = Object.prototype.toString.call(obj); + this.assert( + '[object Arguments]' === type + , 'expected #{this} to be arguments but got ' + type + , 'expected #{this} to not be arguments' + ); + } + + Assertion.addProperty('arguments', checkArguments); + Assertion.addProperty('Arguments', checkArguments); + + /** + * ### .equal(value) + * + * Asserts that the target is strictly equal (`===`) to `value`. + * Alternately, if the `deep` flag is set, asserts that + * the target is deeply equal to `value`. + * + * expect('hello').to.equal('hello'); + * expect(42).to.equal(42); + * expect(1).to.not.equal(true); + * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); + * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); + * + * @name equal + * @alias equals + * @alias eq + * @alias deep.equal + * @param {Mixed} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertEqual (val, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'deep')) { + return this.eql(val); + } else { + this.assert( + val === obj + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{exp}' + , val + , this._obj + , true + ); + } + } + + Assertion.addMethod('equal', assertEqual); + Assertion.addMethod('equals', assertEqual); + Assertion.addMethod('eq', assertEqual); + + /** + * ### .eql(value) + * + * Asserts that the target is deeply equal to `value`. + * + * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); + * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); + * + * @name eql + * @alias eqls + * @param {Mixed} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertEql(obj, msg) { + if (msg) flag(this, 'message', msg); + this.assert( + _.eql(obj, flag(this, 'object')) + , 'expected #{this} to deeply equal #{exp}' + , 'expected #{this} to not deeply equal #{exp}' + , obj + , this._obj + , true + ); + } + + Assertion.addMethod('eql', assertEql); + Assertion.addMethod('eqls', assertEql); + + /** + * ### .above(value) + * + * Asserts that the target is greater than `value`. + * + * expect(10).to.be.above(5); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * + * @name above + * @alias gt + * @alias greaterThan + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertAbove (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len > n + , 'expected #{this} to have a length above #{exp} but got #{act}' + , 'expected #{this} to not have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj > n + , 'expected #{this} to be above ' + n + , 'expected #{this} to be at most ' + n + ); + } + } + + Assertion.addMethod('above', assertAbove); + Assertion.addMethod('gt', assertAbove); + Assertion.addMethod('greaterThan', assertAbove); + + /** + * ### .least(value) + * + * Asserts that the target is greater than or equal to `value`. + * + * expect(10).to.be.at.least(10); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.least(2); + * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); + * + * @name least + * @alias gte + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertLeast (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= n + , 'expected #{this} to have a length at least #{exp} but got #{act}' + , 'expected #{this} to have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj >= n + , 'expected #{this} to be at least ' + n + , 'expected #{this} to be below ' + n + ); + } + } + + Assertion.addMethod('least', assertLeast); + Assertion.addMethod('gte', assertLeast); + + /** + * ### .below(value) + * + * Asserts that the target is less than `value`. + * + * expect(5).to.be.below(10); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * + * @name below + * @alias lt + * @alias lessThan + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertBelow (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len < n + , 'expected #{this} to have a length below #{exp} but got #{act}' + , 'expected #{this} to not have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj < n + , 'expected #{this} to be below ' + n + , 'expected #{this} to be at least ' + n + ); + } + } + + Assertion.addMethod('below', assertBelow); + Assertion.addMethod('lt', assertBelow); + Assertion.addMethod('lessThan', assertBelow); + + /** + * ### .most(value) + * + * Asserts that the target is less than or equal to `value`. + * + * expect(5).to.be.at.most(5); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.most(4); + * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); + * + * @name most + * @alias lte + * @param {Number} value + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertMost (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len <= n + , 'expected #{this} to have a length at most #{exp} but got #{act}' + , 'expected #{this} to have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj <= n + , 'expected #{this} to be at most ' + n + , 'expected #{this} to be above ' + n + ); + } + } + + Assertion.addMethod('most', assertMost); + Assertion.addMethod('lte', assertMost); + + /** + * ### .within(start, finish) + * + * Asserts that the target is within a range. + * + * expect(7).to.be.within(5,10); + * + * Can also be used in conjunction with `length` to + * assert a length range. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name within + * @param {Number} start lowerbound inclusive + * @param {Number} finish upperbound inclusive + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + Assertion.addMethod('within', function (start, finish, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , range = start + '..' + finish; + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= start && len <= finish + , 'expected #{this} to have a length within ' + range + , 'expected #{this} to not have a length within ' + range + ); + } else { + this.assert( + obj >= start && obj <= finish + , 'expected #{this} to be within ' + range + , 'expected #{this} to not be within ' + range + ); + } + }); + + /** + * ### .instanceof(constructor) + * + * Asserts that the target is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , Chai = new Tea('chai'); + * + * expect(Chai).to.be.an.instanceof(Tea); + * expect([ 1, 2, 3 ]).to.be.instanceof(Array); + * + * @name instanceof + * @param {Constructor} constructor + * @param {String} message _optional_ + * @alias instanceOf + * @namespace BDD + * @api public + */ + + function assertInstanceOf (constructor, msg) { + if (msg) flag(this, 'message', msg); + var name = _.getName(constructor); + this.assert( + flag(this, 'object') instanceof constructor + , 'expected #{this} to be an instance of ' + name + , 'expected #{this} to not be an instance of ' + name + ); + }; + + Assertion.addMethod('instanceof', assertInstanceOf); + Assertion.addMethod('instanceOf', assertInstanceOf); + + /** + * ### .property(name, [value]) + * + * Asserts that the target has a property `name`, optionally asserting that + * the value of that property is strictly equal to `value`. + * If the `deep` flag is set, you can use dot- and bracket-notation for deep + * references into objects and arrays. + * + * // simple referencing + * var obj = { foo: 'bar' }; + * expect(obj).to.have.property('foo'); + * expect(obj).to.have.property('foo', 'bar'); + * + * // deep referencing + * var deepObj = { + * green: { tea: 'matcha' } + * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] + * }; + * + * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); + * + * You can also use an array as the starting point of a `deep.property` + * assertion, or traverse nested arrays. + * + * var arr = [ + * [ 'chai', 'matcha', 'konacha' ] + * , [ { tea: 'chai' } + * , { tea: 'matcha' } + * , { tea: 'konacha' } ] + * ]; + * + * expect(arr).to.have.deep.property('[0][1]', 'matcha'); + * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); + * + * Furthermore, `property` changes the subject of the assertion + * to be the value of that property from the original object. This + * permits for further chainable assertions on that property. + * + * expect(obj).to.have.property('foo') + * .that.is.a('string'); + * expect(deepObj).to.have.property('green') + * .that.is.an('object') + * .that.deep.equals({ tea: 'matcha' }); + * expect(deepObj).to.have.property('teas') + * .that.is.an('array') + * .with.deep.property('[2]') + * .that.deep.equals({ tea: 'konacha' }); + * + * Note that dots and bracket in `name` must be backslash-escaped when + * the `deep` flag is set, while they must NOT be escaped when the `deep` + * flag is not set. + * + * // simple referencing + * var css = { '.link[target]': 42 }; + * expect(css).to.have.property('.link[target]', 42); + * + * // deep referencing + * var deepCss = { '.link': { '[target]': 42 }}; + * expect(deepCss).to.have.deep.property('\\.link.\\[target\\]', 42); + * + * @name property + * @alias deep.property + * @param {String} name + * @param {Mixed} value (optional) + * @param {String} message _optional_ + * @returns value of property for chaining + * @namespace BDD + * @api public + */ + + Assertion.addMethod('property', function (name, val, msg) { + if (msg) flag(this, 'message', msg); + + var isDeep = !!flag(this, 'deep') + , descriptor = isDeep ? 'deep property ' : 'property ' + , negate = flag(this, 'negate') + , obj = flag(this, 'object') + , pathInfo = isDeep ? _.getPathInfo(name, obj) : null + , hasProperty = isDeep + ? pathInfo.exists + : _.hasProperty(name, obj) + , value = isDeep + ? pathInfo.value + : obj[name]; + + if (negate && arguments.length > 1) { + if (undefined === value) { + msg = (msg != null) ? msg + ': ' : ''; + throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); + } + } else { + this.assert( + hasProperty + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + , 'expected #{this} to not have ' + descriptor + _.inspect(name)); + } + + if (arguments.length > 1) { + this.assert( + val === value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' + , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' + , val + , value + ); + } + + flag(this, 'object', value); + }); + + + /** + * ### .ownProperty(name) + * + * Asserts that the target has an own property `name`. + * + * expect('test').to.have.ownProperty('length'); + * + * @name ownProperty + * @alias haveOwnProperty + * @param {String} name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertOwnProperty (name, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + obj.hasOwnProperty(name) + , 'expected #{this} to have own property ' + _.inspect(name) + , 'expected #{this} to not have own property ' + _.inspect(name) + ); + } + + Assertion.addMethod('ownProperty', assertOwnProperty); + Assertion.addMethod('haveOwnProperty', assertOwnProperty); + + /** + * ### .ownPropertyDescriptor(name[, descriptor[, message]]) + * + * Asserts that the target has an own property descriptor `name`, that optionally matches `descriptor`. + * + * expect('test').to.have.ownPropertyDescriptor('length'); + * expect('test').to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 4 }); + * expect('test').not.to.have.ownPropertyDescriptor('length', { enumerable: false, configurable: false, writable: false, value: 3 }); + * expect('test').ownPropertyDescriptor('length').to.have.property('enumerable', false); + * expect('test').ownPropertyDescriptor('length').to.have.keys('value'); + * + * @name ownPropertyDescriptor + * @alias haveOwnPropertyDescriptor + * @param {String} name + * @param {Object} descriptor _optional_ + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertOwnPropertyDescriptor (name, descriptor, msg) { + if (typeof descriptor === 'string') { + msg = descriptor; + descriptor = null; + } + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var actualDescriptor = Object.getOwnPropertyDescriptor(Object(obj), name); + if (actualDescriptor && descriptor) { + this.assert( + _.eql(descriptor, actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to match ' + _.inspect(descriptor) + ', got ' + _.inspect(actualDescriptor) + , 'expected the own property descriptor for ' + _.inspect(name) + ' on #{this} to not match ' + _.inspect(descriptor) + , descriptor + , actualDescriptor + , true + ); + } else { + this.assert( + actualDescriptor + , 'expected #{this} to have an own property descriptor for ' + _.inspect(name) + , 'expected #{this} to not have an own property descriptor for ' + _.inspect(name) + ); + } + flag(this, 'object', actualDescriptor); + } + + Assertion.addMethod('ownPropertyDescriptor', assertOwnPropertyDescriptor); + Assertion.addMethod('haveOwnPropertyDescriptor', assertOwnPropertyDescriptor); + + /** + * ### .length + * + * Sets the `doLength` flag later used as a chain precursor to a value + * comparison for the `length` property. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * *Deprecation notice:* Using `length` as an assertion will be deprecated + * in version 2.4.0 and removed in 3.0.0. Code using the old style of + * asserting for `length` property value using `length(value)` should be + * switched to use `lengthOf(value)` instead. + * + * @name length + * @namespace BDD + * @api public + */ + + /** + * ### .lengthOf(value[, message]) + * + * Asserts that the target's `length` property has + * the expected value. + * + * expect([ 1, 2, 3]).to.have.lengthOf(3); + * expect('foobar').to.have.lengthOf(6); + * + * @name lengthOf + * @param {Number} length + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertLengthChain () { + flag(this, 'doLength', true); + } + + function assertLength (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + + this.assert( + len == n + , 'expected #{this} to have a length of #{exp} but got #{act}' + , 'expected #{this} to not have a length of #{act}' + , n + , len + ); + } + + Assertion.addChainableMethod('length', assertLength, assertLengthChain); + Assertion.addMethod('lengthOf', assertLength); + + /** + * ### .match(regexp) + * + * Asserts that the target matches a regular expression. + * + * expect('foobar').to.match(/^foo/); + * + * @name match + * @alias matches + * @param {RegExp} RegularExpression + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + function assertMatch(re, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + re.exec(obj) + , 'expected #{this} to match ' + re + , 'expected #{this} not to match ' + re + ); + } + + Assertion.addMethod('match', assertMatch); + Assertion.addMethod('matches', assertMatch); + + /** + * ### .string(string) + * + * Asserts that the string target contains another string. + * + * expect('foobar').to.have.string('bar'); + * + * @name string + * @param {String} string + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + Assertion.addMethod('string', function (str, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('string'); + + this.assert( + ~obj.indexOf(str) + , 'expected #{this} to contain ' + _.inspect(str) + , 'expected #{this} to not contain ' + _.inspect(str) + ); + }); + + + /** + * ### .keys(key1, [key2], [...]) + * + * Asserts that the target contains any or all of the passed-in keys. + * Use in combination with `any`, `all`, `contains`, or `have` will affect + * what will pass. + * + * When used in conjunction with `any`, at least one key that is passed + * in must exist in the target object. This is regardless whether or not + * the `have` or `contain` qualifiers are used. Note, either `any` or `all` + * should be used in the assertion. If neither are used, the assertion is + * defaulted to `all`. + * + * When both `all` and `contain` are used, the target object must have at + * least all of the passed-in keys but may have more keys not listed. + * + * When both `all` and `have` are used, the target object must both contain + * all of the passed-in keys AND the number of keys in the target object must + * match the number of keys passed in (in other words, a target object must + * have all and only all of the passed-in keys). + * + * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo', 'baz'); + * expect({ foo: 1, bar: 2 }).to.have.any.keys('foo'); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys('bar', 'baz'); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys(['foo']); + * expect({ foo: 1, bar: 2 }).to.contain.any.keys({'foo': 6}); + * expect({ foo: 1, bar: 2 }).to.have.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2 }).to.have.all.keys({'bar': 6, 'foo': 7}); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys(['bar', 'foo']); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.all.keys({'bar': 6}); + * + * + * @name keys + * @alias key + * @param {...String|Array|Object} keys + * @namespace BDD + * @api public + */ + + function assertKeys (keys) { + var obj = flag(this, 'object') + , str + , ok = true + , mixedArgsMsg = 'keys must be given single argument of Array|Object|String, or multiple String arguments'; + + switch (_.type(keys)) { + case "array": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + break; + case "object": + if (arguments.length > 1) throw (new Error(mixedArgsMsg)); + keys = Object.keys(keys); + break; + default: + keys = Array.prototype.slice.call(arguments); + } + + if (!keys.length) throw new Error('keys required'); + + var actual = Object.keys(obj) + , expected = keys + , len = keys.length + , any = flag(this, 'any') + , all = flag(this, 'all'); + + if (!any && !all) { + all = true; + } + + // Has any + if (any) { + var intersection = expected.filter(function(key) { + return ~actual.indexOf(key); + }); + ok = intersection.length > 0; + } + + // Has all + if (all) { + ok = keys.every(function(key){ + return ~actual.indexOf(key); + }); + if (!flag(this, 'negate') && !flag(this, 'contains')) { + ok = ok && keys.length == actual.length; + } + } + + // Key string + if (len > 1) { + keys = keys.map(function(key){ + return _.inspect(key); + }); + var last = keys.pop(); + if (all) { + str = keys.join(', ') + ', and ' + last; + } + if (any) { + str = keys.join(', ') + ', or ' + last; + } + } else { + str = _.inspect(keys[0]); + } + + // Form + str = (len > 1 ? 'keys ' : 'key ') + str; + + // Have / include + str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; + + // Assertion + this.assert( + ok + , 'expected #{this} to ' + str + , 'expected #{this} to not ' + str + , expected.slice(0).sort() + , actual.sort() + , true + ); + } + + Assertion.addMethod('keys', assertKeys); + Assertion.addMethod('key', assertKeys); + + /** + * ### .throw(constructor) + * + * Asserts that the function target will throw a specific error, or specific type of error + * (as determined using `instanceof`), optionally with a RegExp or string inclusion test + * for the error's message. + * + * var err = new ReferenceError('This is a bad function.'); + * var fn = function () { throw err; } + * expect(fn).to.throw(ReferenceError); + * expect(fn).to.throw(Error); + * expect(fn).to.throw(/bad function/); + * expect(fn).to.not.throw('good function'); + * expect(fn).to.throw(ReferenceError, /bad function/); + * expect(fn).to.throw(err); + * + * Please note that when a throw expectation is negated, it will check each + * parameter independently, starting with error constructor type. The appropriate way + * to check for the existence of a type of error but for a message that does not match + * is to use `and`. + * + * expect(fn).to.throw(ReferenceError) + * .and.not.throw(/good function/); + * + * @name throw + * @alias throws + * @alias Throw + * @param {ErrorConstructor} constructor + * @param {String|RegExp} expected error message + * @param {String} message _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @returns error for chaining (null if no error) + * @namespace BDD + * @api public + */ + + function assertThrows (constructor, errMsg, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('function'); + + var thrown = false + , desiredError = null + , name = null + , thrownError = null; + + if (arguments.length === 0) { + errMsg = null; + constructor = null; + } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { + errMsg = constructor; + constructor = null; + } else if (constructor && constructor instanceof Error) { + desiredError = constructor; + constructor = null; + errMsg = null; + } else if (typeof constructor === 'function') { + name = constructor.prototype.name; + if (!name || (name === 'Error' && constructor !== Error)) { + name = constructor.name || (new constructor()).name; + } + } else { + constructor = null; + } + + try { + obj(); + } catch (err) { + // first, check desired error + if (desiredError) { + this.assert( + err === desiredError + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (err instanceof Error ? err.toString() : err) + ); + + flag(this, 'object', err); + return this; + } + + // next, check constructor + if (constructor) { + this.assert( + err instanceof constructor + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp} but #{act} was thrown' + , name + , (err instanceof Error ? err.toString() : err) + ); + + if (!errMsg) { + flag(this, 'object', err); + return this; + } + } + + // next, check message + var message = 'error' === _.type(err) && "message" in err + ? err.message + : '' + err; + + if ((message != null) && errMsg && errMsg instanceof RegExp) { + this.assert( + errMsg.exec(message) + , 'expected #{this} to throw error matching #{exp} but got #{act}' + , 'expected #{this} to throw error not matching #{exp}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else if ((message != null) && errMsg && 'string' === typeof errMsg) { + this.assert( + ~message.indexOf(errMsg) + , 'expected #{this} to throw error including #{exp} but got #{act}' + , 'expected #{this} to throw error not including #{act}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else { + thrown = true; + thrownError = err; + } + } + + var actuallyGot = '' + , expectedThrown = name !== null + ? name + : desiredError + ? '#{exp}' //_.inspect(desiredError) + : 'an error'; + + if (thrown) { + actuallyGot = ' but #{act} was thrown' + } + + this.assert( + thrown === true + , 'expected #{this} to throw ' + expectedThrown + actuallyGot + , 'expected #{this} to not throw ' + expectedThrown + actuallyGot + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (thrownError instanceof Error ? thrownError.toString() : thrownError) + ); + + flag(this, 'object', thrownError); + }; + + Assertion.addMethod('throw', assertThrows); + Assertion.addMethod('throws', assertThrows); + Assertion.addMethod('Throw', assertThrows); + + /** + * ### .respondTo(method) + * + * Asserts that the object or class target will respond to a method. + * + * Klass.prototype.bar = function(){}; + * expect(Klass).to.respondTo('bar'); + * expect(obj).to.respondTo('bar'); + * + * To check if a constructor will respond to a static function, + * set the `itself` flag. + * + * Klass.baz = function(){}; + * expect(Klass).itself.to.respondTo('baz'); + * + * @name respondTo + * @alias respondsTo + * @param {String} method + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function respondTo (method, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , itself = flag(this, 'itself') + , context = ('function' === _.type(obj) && !itself) + ? obj.prototype[method] + : obj[method]; + + this.assert( + 'function' === typeof context + , 'expected #{this} to respond to ' + _.inspect(method) + , 'expected #{this} to not respond to ' + _.inspect(method) + ); + } + + Assertion.addMethod('respondTo', respondTo); + Assertion.addMethod('respondsTo', respondTo); + + /** + * ### .itself + * + * Sets the `itself` flag, later used by the `respondTo` assertion. + * + * function Foo() {} + * Foo.bar = function() {} + * Foo.prototype.baz = function() {} + * + * expect(Foo).itself.to.respondTo('bar'); + * expect(Foo).itself.not.to.respondTo('baz'); + * + * @name itself + * @namespace BDD + * @api public + */ + + Assertion.addProperty('itself', function () { + flag(this, 'itself', true); + }); + + /** + * ### .satisfy(method) + * + * Asserts that the target passes a given truth test. + * + * expect(1).to.satisfy(function(num) { return num > 0; }); + * + * @name satisfy + * @alias satisfies + * @param {Function} matcher + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function satisfy (matcher, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var result = matcher(obj); + this.assert( + result + , 'expected #{this} to satisfy ' + _.objDisplay(matcher) + , 'expected #{this} to not satisfy' + _.objDisplay(matcher) + , this.negate ? false : true + , result + ); + } + + Assertion.addMethod('satisfy', satisfy); + Assertion.addMethod('satisfies', satisfy); + + /** + * ### .closeTo(expected, delta) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * expect(1.5).to.be.closeTo(1, 0.5); + * + * @name closeTo + * @alias approximately + * @param {Number} expected + * @param {Number} delta + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function closeTo(expected, delta, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj, msg).is.a('number'); + if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { + throw new Error('the arguments to closeTo or approximately must be numbers'); + } + + this.assert( + Math.abs(obj - expected) <= delta + , 'expected #{this} to be close to ' + expected + ' +/- ' + delta + , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta + ); + } + + Assertion.addMethod('closeTo', closeTo); + Assertion.addMethod('approximately', closeTo); + + function isSubsetOf(subset, superset, cmp) { + return subset.every(function(elem) { + if (!cmp) return superset.indexOf(elem) !== -1; + + return superset.some(function(elem2) { + return cmp(elem, elem2); + }); + }) + } + + /** + * ### .members(set) + * + * Asserts that the target is a superset of `set`, + * or that the target and `set` have the same strictly-equal (===) members. + * Alternately, if the `deep` flag is set, set members are compared for deep + * equality. + * + * expect([1, 2, 3]).to.include.members([3, 2]); + * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); + * + * expect([4, 2]).to.have.members([2, 4]); + * expect([5, 2]).to.not.have.members([5, 2, 1]); + * + * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); + * + * @name members + * @param {Array} set + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + Assertion.addMethod('members', function (subset, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj).to.be.an('array'); + new Assertion(subset).to.be.an('array'); + + var cmp = flag(this, 'deep') ? _.eql : undefined; + + if (flag(this, 'contains')) { + return this.assert( + isSubsetOf(subset, obj, cmp) + , 'expected #{this} to be a superset of #{act}' + , 'expected #{this} to not be a superset of #{act}' + , obj + , subset + ); + } + + this.assert( + isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) + , 'expected #{this} to have the same members as #{act}' + , 'expected #{this} to not have the same members as #{act}' + , obj + , subset + ); + }); + + /** + * ### .oneOf(list) + * + * Assert that a value appears somewhere in the top level of array `list`. + * + * expect('a').to.be.oneOf(['a', 'b', 'c']); + * expect(9).to.not.be.oneOf(['z']); + * expect([3]).to.not.be.oneOf([1, 2, [3]]); + * + * var three = [3]; + * // for object-types, contents are not compared + * expect(three).to.not.be.oneOf([1, 2, [3]]); + * // comparing references works + * expect(three).to.be.oneOf([1, 2, three]); + * + * @name oneOf + * @param {Array<*>} list + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function oneOf (list, msg) { + if (msg) flag(this, 'message', msg); + var expected = flag(this, 'object'); + new Assertion(list).to.be.an('array'); + + this.assert( + list.indexOf(expected) > -1 + , 'expected #{this} to be one of #{exp}' + , 'expected #{this} to not be one of #{exp}' + , list + , expected + ); + } + + Assertion.addMethod('oneOf', oneOf); + + + /** + * ### .change(function) + * + * Asserts that a function changes an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val += 3 }; + * var noChangeFn = function() { return 'foo' + 'bar'; } + * expect(fn).to.change(obj, 'val'); + * expect(noChangFn).to.not.change(obj, 'val') + * + * @name change + * @alias changes + * @alias Change + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertChanges (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + initial !== object[prop] + , 'expected .' + prop + ' to change' + , 'expected .' + prop + ' to not change' + ); + } + + Assertion.addChainableMethod('change', assertChanges); + Assertion.addChainableMethod('changes', assertChanges); + + /** + * ### .increase(function) + * + * Asserts that a function increases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * expect(fn).to.increase(obj, 'val'); + * + * @name increase + * @alias increases + * @alias Increase + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertIncreases (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + object[prop] - initial > 0 + , 'expected .' + prop + ' to increase' + , 'expected .' + prop + ' to not increase' + ); + } + + Assertion.addChainableMethod('increase', assertIncreases); + Assertion.addChainableMethod('increases', assertIncreases); + + /** + * ### .decrease(function) + * + * Asserts that a function decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * expect(fn).to.decrease(obj, 'val'); + * + * @name decrease + * @alias decreases + * @alias Decrease + * @param {String} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace BDD + * @api public + */ + + function assertDecreases (object, prop, msg) { + if (msg) flag(this, 'message', msg); + var fn = flag(this, 'object'); + new Assertion(object, msg).to.have.property(prop); + new Assertion(fn).is.a('function'); + + var initial = object[prop]; + fn(); + + this.assert( + object[prop] - initial < 0 + , 'expected .' + prop + ' to decrease' + , 'expected .' + prop + ' to not decrease' + ); + } + + Assertion.addChainableMethod('decrease', assertDecreases); + Assertion.addChainableMethod('decreases', assertDecreases); + + /** + * ### .extensible + * + * Asserts that the target is extensible (can have new properties added to + * it). + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * expect({}).to.be.extensible; + * expect(nonExtensibleObject).to.not.be.extensible; + * expect(sealedObject).to.not.be.extensible; + * expect(frozenObject).to.not.be.extensible; + * + * @name extensible + * @namespace BDD + * @api public + */ + + Assertion.addProperty('extensible', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a non-extensible ordinary object, simply return false. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isExtensible; + + try { + isExtensible = Object.isExtensible(obj); + } catch (err) { + if (err instanceof TypeError) isExtensible = false; + else throw err; + } + + this.assert( + isExtensible + , 'expected #{this} to be extensible' + , 'expected #{this} to not be extensible' + ); + }); + + /** + * ### .sealed + * + * Asserts that the target is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freeze({}); + * + * expect(sealedObject).to.be.sealed; + * expect(frozenObject).to.be.sealed; + * expect({}).to.not.be.sealed; + * + * @name sealed + * @namespace BDD + * @api public + */ + + Assertion.addProperty('sealed', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a sealed ordinary object, simply return true. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isSealed; + + try { + isSealed = Object.isSealed(obj); + } catch (err) { + if (err instanceof TypeError) isSealed = true; + else throw err; + } + + this.assert( + isSealed + , 'expected #{this} to be sealed' + , 'expected #{this} to not be sealed' + ); + }); + + /** + * ### .frozen + * + * Asserts that the target is frozen (cannot have new properties added to it + * and its existing properties cannot be modified). + * + * var frozenObject = Object.freeze({}); + * + * expect(frozenObject).to.be.frozen; + * expect({}).to.not.be.frozen; + * + * @name frozen + * @namespace BDD + * @api public + */ + + Assertion.addProperty('frozen', function() { + var obj = flag(this, 'object'); + + // In ES5, if the argument to this method is not an object (a primitive), then it will cause a TypeError. + // In ES6, a non-object argument will be treated as if it was a frozen ordinary object, simply return true. + // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen + // The following provides ES6 behavior when a TypeError is thrown under ES5. + + var isFrozen; + + try { + isFrozen = Object.isFrozen(obj); + } catch (err) { + if (err instanceof TypeError) isFrozen = true; + else throw err; + } + + this.assert( + isFrozen + , 'expected #{this} to be frozen' + , 'expected #{this} to not be frozen' + ); + }); +}; + +},{}],6:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + + +module.exports = function (chai, util) { + + /*! + * Chai dependencies. + */ + + var Assertion = chai.Assertion + , flag = util.flag; + + /*! + * Module export. + */ + + /** + * ### assert(expression, message) + * + * Write your own test expressions. + * + * assert('foo' !== 'bar', 'foo is not bar'); + * assert(Array.isArray([]), 'empty arrays are arrays'); + * + * @param {Mixed} expression to test for truthiness + * @param {String} message to display on error + * @name assert + * @namespace Assert + * @api public + */ + + var assert = chai.assert = function (express, errmsg) { + var test = new Assertion(null, null, chai.assert); + test.assert( + express + , errmsg + , '[ negation message unavailable ]' + ); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. Node.js `assert` module-compatible. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @namespace Assert + * @api public + */ + + assert.fail = function (actual, expected, message, operator) { + message = message || 'assert.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, assert.fail); + }; + + /** + * ### .isOk(object, [message]) + * + * Asserts that `object` is truthy. + * + * assert.isOk('everything', 'everything is ok'); + * assert.isOk(false, 'this will fail'); + * + * @name isOk + * @alias ok + * @param {Mixed} object to test + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isOk = function (val, msg) { + new Assertion(val, msg).is.ok; + }; + + /** + * ### .isNotOk(object, [message]) + * + * Asserts that `object` is falsy. + * + * assert.isNotOk('everything', 'this will fail'); + * assert.isNotOk(false, 'this will pass'); + * + * @name isNotOk + * @alias notOk + * @param {Mixed} object to test + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotOk = function (val, msg) { + new Assertion(val, msg).is.not.ok; + }; + + /** + * ### .equal(actual, expected, [message]) + * + * Asserts non-strict equality (`==`) of `actual` and `expected`. + * + * assert.equal(3, '3', '== coerces values to strings'); + * + * @name equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.equal = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.equal); + + test.assert( + exp == flag(test, 'object') + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{act}' + , exp + , act + ); + }; + + /** + * ### .notEqual(actual, expected, [message]) + * + * Asserts non-strict inequality (`!=`) of `actual` and `expected`. + * + * assert.notEqual(3, 4, 'these numbers are not equal'); + * + * @name notEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notEqual = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.notEqual); + + test.assert( + exp != flag(test, 'object') + , 'expected #{this} to not equal #{exp}' + , 'expected #{this} to equal #{act}' + , exp + , act + ); + }; + + /** + * ### .strictEqual(actual, expected, [message]) + * + * Asserts strict equality (`===`) of `actual` and `expected`. + * + * assert.strictEqual(true, true, 'these booleans are strictly equal'); + * + * @name strictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.strictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.equal(exp); + }; + + /** + * ### .notStrictEqual(actual, expected, [message]) + * + * Asserts strict inequality (`!==`) of `actual` and `expected`. + * + * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); + * + * @name notStrictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notStrictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.equal(exp); + }; + + /** + * ### .deepEqual(actual, expected, [message]) + * + * Asserts that `actual` is deeply equal to `expected`. + * + * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); + * + * @name deepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.eql(exp); + }; + + /** + * ### .notDeepEqual(actual, expected, [message]) + * + * Assert that `actual` is not deeply equal to `expected`. + * + * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); + * + * @name notDeepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notDeepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.eql(exp); + }; + + /** + * ### .isAbove(valueToCheck, valueToBeAbove, [message]) + * + * Asserts `valueToCheck` is strictly greater than (>) `valueToBeAbove` + * + * assert.isAbove(5, 2, '5 is strictly greater than 2'); + * + * @name isAbove + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAbove + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isAbove = function (val, abv, msg) { + new Assertion(val, msg).to.be.above(abv); + }; + + /** + * ### .isAtLeast(valueToCheck, valueToBeAtLeast, [message]) + * + * Asserts `valueToCheck` is greater than or equal to (>=) `valueToBeAtLeast` + * + * assert.isAtLeast(5, 2, '5 is greater or equal to 2'); + * assert.isAtLeast(3, 3, '3 is greater or equal to 3'); + * + * @name isAtLeast + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAtLeast + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isAtLeast = function (val, atlst, msg) { + new Assertion(val, msg).to.be.least(atlst); + }; + + /** + * ### .isBelow(valueToCheck, valueToBeBelow, [message]) + * + * Asserts `valueToCheck` is strictly less than (<) `valueToBeBelow` + * + * assert.isBelow(3, 6, '3 is strictly less than 6'); + * + * @name isBelow + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeBelow + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isBelow = function (val, blw, msg) { + new Assertion(val, msg).to.be.below(blw); + }; + + /** + * ### .isAtMost(valueToCheck, valueToBeAtMost, [message]) + * + * Asserts `valueToCheck` is less than or equal to (<=) `valueToBeAtMost` + * + * assert.isAtMost(3, 6, '3 is less than or equal to 6'); + * assert.isAtMost(4, 4, '4 is less than or equal to 4'); + * + * @name isAtMost + * @param {Mixed} valueToCheck + * @param {Mixed} valueToBeAtMost + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isAtMost = function (val, atmst, msg) { + new Assertion(val, msg).to.be.most(atmst); + }; + + /** + * ### .isTrue(value, [message]) + * + * Asserts that `value` is true. + * + * var teaServed = true; + * assert.isTrue(teaServed, 'the tea has been served'); + * + * @name isTrue + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isTrue = function (val, msg) { + new Assertion(val, msg).is['true']; + }; + + /** + * ### .isNotTrue(value, [message]) + * + * Asserts that `value` is not true. + * + * var tea = 'tasty chai'; + * assert.isNotTrue(tea, 'great, time for tea!'); + * + * @name isNotTrue + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotTrue = function (val, msg) { + new Assertion(val, msg).to.not.equal(true); + }; + + /** + * ### .isFalse(value, [message]) + * + * Asserts that `value` is false. + * + * var teaServed = false; + * assert.isFalse(teaServed, 'no tea yet? hmm...'); + * + * @name isFalse + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isFalse = function (val, msg) { + new Assertion(val, msg).is['false']; + }; + + /** + * ### .isNotFalse(value, [message]) + * + * Asserts that `value` is not false. + * + * var tea = 'tasty chai'; + * assert.isNotFalse(tea, 'great, time for tea!'); + * + * @name isNotFalse + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotFalse = function (val, msg) { + new Assertion(val, msg).to.not.equal(false); + }; + + /** + * ### .isNull(value, [message]) + * + * Asserts that `value` is null. + * + * assert.isNull(err, 'there was no error'); + * + * @name isNull + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNull = function (val, msg) { + new Assertion(val, msg).to.equal(null); + }; + + /** + * ### .isNotNull(value, [message]) + * + * Asserts that `value` is not null. + * + * var tea = 'tasty chai'; + * assert.isNotNull(tea, 'great, time for tea!'); + * + * @name isNotNull + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotNull = function (val, msg) { + new Assertion(val, msg).to.not.equal(null); + }; + + /** + * ### .isNaN + * Asserts that value is NaN + * + * assert.isNaN('foo', 'foo is NaN'); + * + * @name isNaN + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNaN = function (val, msg) { + new Assertion(val, msg).to.be.NaN; + }; + + /** + * ### .isNotNaN + * Asserts that value is not NaN + * + * assert.isNotNaN(4, '4 is not NaN'); + * + * @name isNotNaN + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + assert.isNotNaN = function (val, msg) { + new Assertion(val, msg).not.to.be.NaN; + }; + + /** + * ### .isUndefined(value, [message]) + * + * Asserts that `value` is `undefined`. + * + * var tea; + * assert.isUndefined(tea, 'no tea defined'); + * + * @name isUndefined + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isUndefined = function (val, msg) { + new Assertion(val, msg).to.equal(undefined); + }; + + /** + * ### .isDefined(value, [message]) + * + * Asserts that `value` is not `undefined`. + * + * var tea = 'cup of chai'; + * assert.isDefined(tea, 'tea has been defined'); + * + * @name isDefined + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isDefined = function (val, msg) { + new Assertion(val, msg).to.not.equal(undefined); + }; + + /** + * ### .isFunction(value, [message]) + * + * Asserts that `value` is a function. + * + * function serveTea() { return 'cup of tea'; }; + * assert.isFunction(serveTea, 'great, we can have tea now'); + * + * @name isFunction + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isFunction = function (val, msg) { + new Assertion(val, msg).to.be.a('function'); + }; + + /** + * ### .isNotFunction(value, [message]) + * + * Asserts that `value` is _not_ a function. + * + * var serveTea = [ 'heat', 'pour', 'sip' ]; + * assert.isNotFunction(serveTea, 'great, we have listed the steps'); + * + * @name isNotFunction + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotFunction = function (val, msg) { + new Assertion(val, msg).to.not.be.a('function'); + }; + + /** + * ### .isObject(value, [message]) + * + * Asserts that `value` is an object (as revealed by + * `Object.prototype.toString`). + * + * var selection = { name: 'Chai', serve: 'with spices' }; + * assert.isObject(selection, 'tea selection is an object'); + * + * @name isObject + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isObject = function (val, msg) { + new Assertion(val, msg).to.be.a('object'); + }; + + /** + * ### .isNotObject(value, [message]) + * + * Asserts that `value` is _not_ an object. + * + * var selection = 'chai' + * assert.isNotObject(selection, 'tea selection is not an object'); + * assert.isNotObject(null, 'null is not an object'); + * + * @name isNotObject + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotObject = function (val, msg) { + new Assertion(val, msg).to.not.be.a('object'); + }; + + /** + * ### .isArray(value, [message]) + * + * Asserts that `value` is an array. + * + * var menu = [ 'green', 'chai', 'oolong' ]; + * assert.isArray(menu, 'what kind of tea do we want?'); + * + * @name isArray + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isArray = function (val, msg) { + new Assertion(val, msg).to.be.an('array'); + }; + + /** + * ### .isNotArray(value, [message]) + * + * Asserts that `value` is _not_ an array. + * + * var menu = 'green|chai|oolong'; + * assert.isNotArray(menu, 'what kind of tea do we want?'); + * + * @name isNotArray + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotArray = function (val, msg) { + new Assertion(val, msg).to.not.be.an('array'); + }; + + /** + * ### .isString(value, [message]) + * + * Asserts that `value` is a string. + * + * var teaOrder = 'chai'; + * assert.isString(teaOrder, 'order placed'); + * + * @name isString + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isString = function (val, msg) { + new Assertion(val, msg).to.be.a('string'); + }; + + /** + * ### .isNotString(value, [message]) + * + * Asserts that `value` is _not_ a string. + * + * var teaOrder = 4; + * assert.isNotString(teaOrder, 'order placed'); + * + * @name isNotString + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotString = function (val, msg) { + new Assertion(val, msg).to.not.be.a('string'); + }; + + /** + * ### .isNumber(value, [message]) + * + * Asserts that `value` is a number. + * + * var cups = 2; + * assert.isNumber(cups, 'how many cups'); + * + * @name isNumber + * @param {Number} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNumber = function (val, msg) { + new Assertion(val, msg).to.be.a('number'); + }; + + /** + * ### .isNotNumber(value, [message]) + * + * Asserts that `value` is _not_ a number. + * + * var cups = '2 cups please'; + * assert.isNotNumber(cups, 'how many cups'); + * + * @name isNotNumber + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotNumber = function (val, msg) { + new Assertion(val, msg).to.not.be.a('number'); + }; + + /** + * ### .isBoolean(value, [message]) + * + * Asserts that `value` is a boolean. + * + * var teaReady = true + * , teaServed = false; + * + * assert.isBoolean(teaReady, 'is the tea ready'); + * assert.isBoolean(teaServed, 'has tea been served'); + * + * @name isBoolean + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isBoolean = function (val, msg) { + new Assertion(val, msg).to.be.a('boolean'); + }; + + /** + * ### .isNotBoolean(value, [message]) + * + * Asserts that `value` is _not_ a boolean. + * + * var teaReady = 'yep' + * , teaServed = 'nope'; + * + * assert.isNotBoolean(teaReady, 'is the tea ready'); + * assert.isNotBoolean(teaServed, 'has tea been served'); + * + * @name isNotBoolean + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.isNotBoolean = function (val, msg) { + new Assertion(val, msg).to.not.be.a('boolean'); + }; + + /** + * ### .typeOf(value, name, [message]) + * + * Asserts that `value`'s type is `name`, as determined by + * `Object.prototype.toString`. + * + * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); + * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); + * assert.typeOf('tea', 'string', 'we have a string'); + * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); + * assert.typeOf(null, 'null', 'we have a null'); + * assert.typeOf(undefined, 'undefined', 'we have an undefined'); + * + * @name typeOf + * @param {Mixed} value + * @param {String} name + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.typeOf = function (val, type, msg) { + new Assertion(val, msg).to.be.a(type); + }; + + /** + * ### .notTypeOf(value, name, [message]) + * + * Asserts that `value`'s type is _not_ `name`, as determined by + * `Object.prototype.toString`. + * + * assert.notTypeOf('tea', 'number', 'strings are not numbers'); + * + * @name notTypeOf + * @param {Mixed} value + * @param {String} typeof name + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notTypeOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.a(type); + }; + + /** + * ### .instanceOf(object, constructor, [message]) + * + * Asserts that `value` is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new Tea('chai'); + * + * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); + * + * @name instanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.instanceOf = function (val, type, msg) { + new Assertion(val, msg).to.be.instanceOf(type); + }; + + /** + * ### .notInstanceOf(object, constructor, [message]) + * + * Asserts `value` is not an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new String('chai'); + * + * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); + * + * @name notInstanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notInstanceOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.instanceOf(type); + }; + + /** + * ### .include(haystack, needle, [message]) + * + * Asserts that `haystack` includes `needle`. Works + * for strings and arrays. + * + * assert.include('foobar', 'bar', 'foobar contains string "bar"'); + * assert.include([ 1, 2, 3 ], 3, 'array contains value'); + * + * @name include + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.include = function (exp, inc, msg) { + new Assertion(exp, msg, assert.include).include(inc); + }; + + /** + * ### .notInclude(haystack, needle, [message]) + * + * Asserts that `haystack` does not include `needle`. Works + * for strings and arrays. + * + * assert.notInclude('foobar', 'baz', 'string not include substring'); + * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); + * + * @name notInclude + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.notInclude).not.include(inc); + }; + + /** + * ### .match(value, regexp, [message]) + * + * Asserts that `value` matches the regular expression `regexp`. + * + * assert.match('foobar', /^foo/, 'regexp matches'); + * + * @name match + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.match = function (exp, re, msg) { + new Assertion(exp, msg).to.match(re); + }; + + /** + * ### .notMatch(value, regexp, [message]) + * + * Asserts that `value` does not match the regular expression `regexp`. + * + * assert.notMatch('foobar', /^foo/, 'regexp does not match'); + * + * @name notMatch + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notMatch = function (exp, re, msg) { + new Assertion(exp, msg).to.not.match(re); + }; + + /** + * ### .property(object, property, [message]) + * + * Asserts that `object` has a property named by `property`. + * + * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * + * @name property + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.property = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.property(prop); + }; + + /** + * ### .notProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`. + * + * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); + * + * @name notProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.property(prop); + }; + + /** + * ### .deepProperty(object, property, [message]) + * + * Asserts that `object` has a property named by `property`, which can be a + * string using dot- and bracket-notation for deep reference. + * + * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); + * + * @name deepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.deep.property(prop); + }; + + /** + * ### .notDeepProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`, which + * can be a string using dot- and bracket-notation for deep reference. + * + * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); + * + * @name notDeepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.notDeepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop); + }; + + /** + * ### .propertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. + * + * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); + * + * @name propertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.propertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.property(prop, val); + }; + + /** + * ### .propertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. + * + * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); + * + * @name propertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.propertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.property(prop, val); + }; + + /** + * ### .deepPropertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. `property` can use dot- and bracket-notation for deep + * reference. + * + * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); + * + * @name deepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.deep.property(prop, val); + }; + + /** + * ### .deepPropertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. `property` can use dot- and + * bracket-notation for deep reference. + * + * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * + * @name deepPropertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.deepPropertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop, val); + }; + + /** + * ### .lengthOf(object, length, [message]) + * + * Asserts that `object` has a `length` property with the expected value. + * + * assert.lengthOf([1,2,3], 3, 'array has length of 3'); + * assert.lengthOf('foobar', 6, 'string has length of 6'); + * + * @name lengthOf + * @param {Mixed} object + * @param {Number} length + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.lengthOf = function (exp, len, msg) { + new Assertion(exp, msg).to.have.length(len); + }; + + /** + * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * assert.throws(fn, 'function throws a reference error'); + * assert.throws(fn, /function throws a reference error/); + * assert.throws(fn, ReferenceError); + * assert.throws(fn, ReferenceError, 'function throws a reference error'); + * assert.throws(fn, ReferenceError, /function throws a reference error/); + * + * @name throws + * @alias throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert + * @api public + */ + + assert.throws = function (fn, errt, errs, msg) { + if ('string' === typeof errt || errt instanceof RegExp) { + errs = errt; + errt = null; + } + + var assertErr = new Assertion(fn, msg).to.throw(errt, errs); + return flag(assertErr, 'object'); + }; + + /** + * ### .doesNotThrow(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * assert.doesNotThrow(fn, Error, 'function does not throw'); + * + * @name doesNotThrow + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @namespace Assert + * @api public + */ + + assert.doesNotThrow = function (fn, type, msg) { + if ('string' === typeof type) { + msg = type; + type = null; + } + + new Assertion(fn, msg).to.not.Throw(type); + }; + + /** + * ### .operator(val1, operator, val2, [message]) + * + * Compares two values using `operator`. + * + * assert.operator(1, '<', 2, 'everything is ok'); + * assert.operator(1, '>', 2, 'this will fail'); + * + * @name operator + * @param {Mixed} val1 + * @param {String} operator + * @param {Mixed} val2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.operator = function (val, operator, val2, msg) { + var ok; + switch(operator) { + case '==': + ok = val == val2; + break; + case '===': + ok = val === val2; + break; + case '>': + ok = val > val2; + break; + case '>=': + ok = val >= val2; + break; + case '<': + ok = val < val2; + break; + case '<=': + ok = val <= val2; + break; + case '!=': + ok = val != val2; + break; + case '!==': + ok = val !== val2; + break; + default: + throw new Error('Invalid operator "' + operator + '"'); + } + var test = new Assertion(ok, msg); + test.assert( + true === flag(test, 'object') + , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) + , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + }; + + /** + * ### .closeTo(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * + * @name closeTo + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.closeTo = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.closeTo(exp, delta); + }; + + /** + * ### .approximately(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.approximately(1.5, 1, 0.5, 'numbers are close'); + * + * @name approximately + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.approximately = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.approximately(exp, delta); + }; + + /** + * ### .sameMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members. + * Order is not taken into account. + * + * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); + * + * @name sameMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.members(set2); + } + + /** + * ### .sameDeepMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members - using a deep equality checking. + * Order is not taken into account. + * + * assert.sameDeepMembers([ {b: 3}, {a: 2}, {c: 5} ], [ {c: 5}, {b: 3}, {a: 2} ], 'same deep members'); + * + * @name sameDeepMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.sameDeepMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.deep.members(set2); + } + + /** + * ### .includeMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset`. + * Order is not taken into account. + * + * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); + * + * @name includeMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.includeMembers = function (superset, subset, msg) { + new Assertion(superset, msg).to.include.members(subset); + } + + /** + * ### .oneOf(inList, list, [message]) + * + * Asserts that non-object, non-array value `inList` appears in the flat array `list`. + * + * assert.oneOf(1, [ 2, 1 ], 'Not found in list'); + * + * @name oneOf + * @param {*} inList + * @param {Array<*>} list + * @param {String} message + * @namespace Assert + * @api public + */ + + assert.oneOf = function (inList, list, msg) { + new Assertion(inList, msg).to.be.oneOf(list); + } + + /** + * ### .changes(function, object, property) + * + * Asserts that a function changes the value of a property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 22 }; + * assert.changes(fn, obj, 'val'); + * + * @name changes + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.changes = function (fn, obj, prop) { + new Assertion(fn).to.change(obj, prop); + } + + /** + * ### .doesNotChange(function, object, property) + * + * Asserts that a function does not changes the value of a property + * + * var obj = { val: 10 }; + * var fn = function() { console.log('foo'); }; + * assert.doesNotChange(fn, obj, 'val'); + * + * @name doesNotChange + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotChange = function (fn, obj, prop) { + new Assertion(fn).to.not.change(obj, prop); + } + + /** + * ### .increases(function, object, property) + * + * Asserts that a function increases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 13 }; + * assert.increases(fn, obj, 'val'); + * + * @name increases + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.increases = function (fn, obj, prop) { + new Assertion(fn).to.increase(obj, prop); + } + + /** + * ### .doesNotIncrease(function, object, property) + * + * Asserts that a function does not increase object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 8 }; + * assert.doesNotIncrease(fn, obj, 'val'); + * + * @name doesNotIncrease + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotIncrease = function (fn, obj, prop) { + new Assertion(fn).to.not.increase(obj, prop); + } + + /** + * ### .decreases(function, object, property) + * + * Asserts that a function decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 5 }; + * assert.decreases(fn, obj, 'val'); + * + * @name decreases + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.decreases = function (fn, obj, prop) { + new Assertion(fn).to.decrease(obj, prop); + } + + /** + * ### .doesNotDecrease(function, object, property) + * + * Asserts that a function does not decreases an object property + * + * var obj = { val: 10 }; + * var fn = function() { obj.val = 15 }; + * assert.doesNotDecrease(fn, obj, 'val'); + * + * @name doesNotDecrease + * @param {Function} modifier function + * @param {Object} object + * @param {String} property name + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.doesNotDecrease = function (fn, obj, prop) { + new Assertion(fn).to.not.decrease(obj, prop); + } + + /*! + * ### .ifError(object) + * + * Asserts if value is not a false value, and throws if it is a true value. + * This is added to allow for chai to be a drop-in replacement for Node's + * assert class. + * + * var err = new Error('I am a custom error'); + * assert.ifError(err); // Rethrows err! + * + * @name ifError + * @param {Object} object + * @namespace Assert + * @api public + */ + + assert.ifError = function (val) { + if (val) { + throw(val); + } + }; + + /** + * ### .isExtensible(object) + * + * Asserts that `object` is extensible (can have new properties added to it). + * + * assert.isExtensible({}); + * + * @name isExtensible + * @alias extensible + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isExtensible = function (obj, msg) { + new Assertion(obj, msg).to.be.extensible; + }; + + /** + * ### .isNotExtensible(object) + * + * Asserts that `object` is _not_ extensible. + * + * var nonExtensibleObject = Object.preventExtensions({}); + * var sealedObject = Object.seal({}); + * var frozenObject = Object.freese({}); + * + * assert.isNotExtensible(nonExtensibleObject); + * assert.isNotExtensible(sealedObject); + * assert.isNotExtensible(frozenObject); + * + * @name isNotExtensible + * @alias notExtensible + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotExtensible = function (obj, msg) { + new Assertion(obj, msg).to.not.be.extensible; + }; + + /** + * ### .isSealed(object) + * + * Asserts that `object` is sealed (cannot have new properties added to it + * and its existing properties cannot be removed). + * + * var sealedObject = Object.seal({}); + * var frozenObject = Object.seal({}); + * + * assert.isSealed(sealedObject); + * assert.isSealed(frozenObject); + * + * @name isSealed + * @alias sealed + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isSealed = function (obj, msg) { + new Assertion(obj, msg).to.be.sealed; + }; + + /** + * ### .isNotSealed(object) + * + * Asserts that `object` is _not_ sealed. + * + * assert.isNotSealed({}); + * + * @name isNotSealed + * @alias notSealed + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotSealed = function (obj, msg) { + new Assertion(obj, msg).to.not.be.sealed; + }; + + /** + * ### .isFrozen(object) + * + * Asserts that `object` is frozen (cannot have new properties added to it + * and its existing properties cannot be modified). + * + * var frozenObject = Object.freeze({}); + * assert.frozen(frozenObject); + * + * @name isFrozen + * @alias frozen + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isFrozen = function (obj, msg) { + new Assertion(obj, msg).to.be.frozen; + }; + + /** + * ### .isNotFrozen(object) + * + * Asserts that `object` is _not_ frozen. + * + * assert.isNotFrozen({}); + * + * @name isNotFrozen + * @alias notFrozen + * @param {Object} object + * @param {String} message _optional_ + * @namespace Assert + * @api public + */ + + assert.isNotFrozen = function (obj, msg) { + new Assertion(obj, msg).to.not.be.frozen; + }; + + /*! + * Aliases. + */ + + (function alias(name, as){ + assert[as] = assert[name]; + return alias; + }) + ('isOk', 'ok') + ('isNotOk', 'notOk') + ('throws', 'throw') + ('throws', 'Throw') + ('isExtensible', 'extensible') + ('isNotExtensible', 'notExtensible') + ('isSealed', 'sealed') + ('isNotSealed', 'notSealed') + ('isFrozen', 'frozen') + ('isNotFrozen', 'notFrozen'); +}; + +},{}],7:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + chai.expect = function (val, message) { + return new chai.Assertion(val, message); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @namespace Expect + * @api public + */ + + chai.expect.fail = function (actual, expected, message, operator) { + message = message || 'expect.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, chai.expect.fail); + }; +}; + +},{}],8:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + var Assertion = chai.Assertion; + + function loadShould () { + // explicitly define this method as function as to have it's name to include as `ssfi` + function shouldGetter() { + if (this instanceof String || this instanceof Number || this instanceof Boolean ) { + return new Assertion(this.valueOf(), null, shouldGetter); + } + return new Assertion(this, null, shouldGetter); + } + function shouldSetter(value) { + // See https://github.com/chaijs/chai/issues/86: this makes + // `whatever.should = someValue` actually set `someValue`, which is + // especially useful for `global.should = require('chai').should()`. + // + // Note that we have to use [[DefineProperty]] instead of [[Put]] + // since otherwise we would trigger this very setter! + Object.defineProperty(this, 'should', { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } + // modify Object.prototype to have `should` + Object.defineProperty(Object.prototype, 'should', { + set: shouldSetter + , get: shouldGetter + , configurable: true + }); + + var should = {}; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @namespace Should + * @api public + */ + + should.fail = function (actual, expected, message, operator) { + message = message || 'should.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, should.fail); + }; + + should.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.equal(val2); + }; + + should.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.Throw(errt, errs); + }; + + should.exist = function (val, msg) { + new Assertion(val, msg).to.exist; + } + + // negation + should.not = {} + + should.not.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.not.equal(val2); + }; + + should.not.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.not.Throw(errt, errs); + }; + + should.not.exist = function (val, msg) { + new Assertion(val, msg).to.not.exist; + } + + should['throw'] = should['Throw']; + should.not['throw'] = should.not['Throw']; + + return should; + }; + + chai.should = loadShould; + chai.Should = loadShould; +}; + +},{}],9:[function(require,module,exports){ +/*! + * Chai - addChainingMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var transferFlags = require('./transferFlags'); +var flag = require('./flag'); +var config = require('../config'); + +/*! + * Module variables + */ + +// Check whether `__proto__` is supported +var hasProtoSupport = '__proto__' in Object; + +// Without `__proto__` support, this module will need to add properties to a function. +// However, some Function.prototype methods cannot be overwritten, +// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). +var excludeNames = /^(?:length|name|arguments|caller)$/; + +// Cache `Function` properties +var call = Function.prototype.call, + apply = Function.prototype.apply; + +/** + * ### addChainableMethod (ctx, name, method, chainingBehavior) + * + * Adds a method to an object, such that the method can also be chained. + * + * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); + * + * The result can then be used as both a method assertion, executing both `method` and + * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. + * + * expect(fooStr).to.be.foo('bar'); + * expect(fooStr).to.be.foo.equal('foo'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for `name`, when called + * @param {Function} chainingBehavior function to be called every time the property is accessed + * @namespace Utils + * @name addChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + if (typeof chainingBehavior !== 'function') { + chainingBehavior = function () { }; + } + + var chainableBehavior = { + method: method + , chainingBehavior: chainingBehavior + }; + + // save the methods so we can overwrite them later, if we need to. + if (!ctx.__methods) { + ctx.__methods = {}; + } + ctx.__methods[name] = chainableBehavior; + + Object.defineProperty(ctx, name, + { get: function () { + chainableBehavior.chainingBehavior.call(this); + + var assert = function assert() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', assert); + var result = chainableBehavior.method.apply(this, arguments); + return result === undefined ? this : result; + }; + + // Use `__proto__` if available + if (hasProtoSupport) { + // Inherit all properties from the object by replacing the `Function` prototype + var prototype = assert.__proto__ = Object.create(this); + // Restore the `call` and `apply` methods from `Function` + prototype.call = call; + prototype.apply = apply; + } + // Otherwise, redefine all properties (slow!) + else { + var asserterNames = Object.getOwnPropertyNames(ctx); + asserterNames.forEach(function (asserterName) { + if (!excludeNames.test(asserterName)) { + var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); + Object.defineProperty(assert, asserterName, pd); + } + }); + } + + transferFlags(this, assert); + return assert; + } + , configurable: true + }); +}; + +},{"../config":4,"./flag":13,"./transferFlags":29}],10:[function(require,module,exports){ +/*! + * Chai - addMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var config = require('../config'); + +/** + * ### .addMethod (ctx, name, method) + * + * Adds a method to the prototype of an object. + * + * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(fooStr).to.be.foo('bar'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for name + * @namespace Utils + * @name addMethod + * @api public + */ +var flag = require('./flag'); + +module.exports = function (ctx, name, method) { + ctx[name] = function () { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', ctx[name]); + var result = method.apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +},{"../config":4,"./flag":13}],11:[function(require,module,exports){ +/*! + * Chai - addProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var config = require('../config'); +var flag = require('./flag'); + +/** + * ### addProperty (ctx, name, getter) + * + * Adds a property to the prototype of an object. + * + * utils.addProperty(chai.Assertion.prototype, 'foo', function () { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.instanceof(Foo); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.foo; + * + * @param {Object} ctx object to which the property is added + * @param {String} name of property to add + * @param {Function} getter function to be used for name + * @namespace Utils + * @name addProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + Object.defineProperty(ctx, name, + { get: function addProperty() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', addProperty); + + var result = getter.call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +},{"../config":4,"./flag":13}],12:[function(require,module,exports){ +/*! + * Chai - expectTypes utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### expectTypes(obj, types) + * + * Ensures that the object being tested against is of a valid type. + * + * utils.expectTypes(this, ['array', 'object', 'string']); + * + * @param {Mixed} obj constructed Assertion + * @param {Array} type A list of allowed types for this assertion + * @namespace Utils + * @name expectTypes + * @api public + */ + +var AssertionError = require('assertion-error'); +var flag = require('./flag'); +var type = require('type-detect'); + +module.exports = function (obj, types) { + var obj = flag(obj, 'object'); + types = types.map(function (t) { return t.toLowerCase(); }); + types.sort(); + + // Transforms ['lorem', 'ipsum'] into 'a lirum, or an ipsum' + var str = types.map(function (t, index) { + var art = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(t.charAt(0)) ? 'an' : 'a'; + var or = types.length > 1 && index === types.length - 1 ? 'or ' : ''; + return or + art + ' ' + t; + }).join(', '); + + if (!types.some(function (expected) { return type(obj) === expected; })) { + throw new AssertionError( + 'object tested must be ' + str + ', but ' + type(obj) + ' given' + ); + } +}; + +},{"./flag":13,"assertion-error":30,"type-detect":35}],13:[function(require,module,exports){ +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### flag(object, key, [value]) + * + * Get or set a flag value on an object. If a + * value is provided it will be set, else it will + * return the currently set value or `undefined` if + * the value is not set. + * + * utils.flag(this, 'foo', 'bar'); // setter + * utils.flag(this, 'foo'); // getter, returns `bar` + * + * @param {Object} object constructed Assertion + * @param {String} key + * @param {Mixed} value (optional) + * @namespace Utils + * @name flag + * @api private + */ + +module.exports = function (obj, key, value) { + var flags = obj.__flags || (obj.__flags = Object.create(null)); + if (arguments.length === 3) { + flags[key] = value; + } else { + return flags[key]; + } +}; + +},{}],14:[function(require,module,exports){ +/*! + * Chai - getActual utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * # getActual(object, [actual]) + * + * Returns the `actual` value for an Assertion + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name getActual + */ + +module.exports = function (obj, args) { + return args.length > 4 ? args[4] : obj._obj; +}; + +},{}],15:[function(require,module,exports){ +/*! + * Chai - getEnumerableProperties utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .getEnumerableProperties(object) + * + * This allows the retrieval of enumerable property names of an object, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @namespace Utils + * @name getEnumerableProperties + * @api public + */ + +module.exports = function getEnumerableProperties(object) { + var result = []; + for (var name in object) { + result.push(name); + } + return result; +}; + +},{}],16:[function(require,module,exports){ +/*! + * Chai - message composition utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('./flag') + , getActual = require('./getActual') + , inspect = require('./inspect') + , objDisplay = require('./objDisplay'); + +/** + * ### .getMessage(object, message, negateMessage) + * + * Construct the error message based on flags + * and template tags. Template tags will return + * a stringified inspection of the object referenced. + * + * Message template tags: + * - `#{this}` current asserted object + * - `#{act}` actual value + * - `#{exp}` expected value + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name getMessage + * @api public + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , val = flag(obj, 'object') + , expected = args[3] + , actual = getActual(obj, args) + , msg = negate ? args[2] : args[1] + , flagMsg = flag(obj, 'message'); + + if(typeof msg === "function") msg = msg(); + msg = msg || ''; + msg = msg + .replace(/#{this}/g, objDisplay(val)) + .replace(/#{act}/g, objDisplay(actual)) + .replace(/#{exp}/g, objDisplay(expected)); + + return flagMsg ? flagMsg + ': ' + msg : msg; +}; + +},{"./flag":13,"./getActual":14,"./inspect":23,"./objDisplay":24}],17:[function(require,module,exports){ +/*! + * Chai - getName utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * # getName(func) + * + * Gets the name of a function, in a cross-browser way. + * + * @param {Function} a function (usually a constructor) + * @namespace Utils + * @name getName + */ + +module.exports = function (func) { + if (func.name) return func.name; + + var match = /^\s?function ([^(]*)\(/.exec(func); + return match && match[1] ? match[1] : ""; +}; + +},{}],18:[function(require,module,exports){ +/*! + * Chai - getPathInfo utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var hasProperty = require('./hasProperty'); + +/** + * ### .getPathInfo(path, object) + * + * This allows the retrieval of property info in an + * object given a string path. + * + * The path info consists of an object with the + * following properties: + * + * * parent - The parent object of the property referenced by `path` + * * name - The name of the final property, a number if it was an array indexer + * * value - The value of the property, if it exists, otherwise `undefined` + * * exists - Whether the property exists or not + * + * @param {String} path + * @param {Object} object + * @returns {Object} info + * @namespace Utils + * @name getPathInfo + * @api public + */ + +module.exports = function getPathInfo(path, obj) { + var parsed = parsePath(path), + last = parsed[parsed.length - 1]; + + var info = { + parent: parsed.length > 1 ? _getPathValue(parsed, obj, parsed.length - 1) : obj, + name: last.p || last.i, + value: _getPathValue(parsed, obj) + }; + info.exists = hasProperty(info.name, info.parent); + + return info; +}; + + +/*! + * ## parsePath(path) + * + * Helper function used to parse string object + * paths. Use in conjunction with `_getPathValue`. + * + * var parsed = parsePath('myobject.property.subprop'); + * + * ### Paths: + * + * * Can be as near infinitely deep and nested + * * Arrays are also valid using the formal `myobject.document[3].property`. + * * Literal dots and brackets (not delimiter) must be backslash-escaped. + * + * @param {String} path + * @returns {Object} parsed + * @api private + */ + +function parsePath (path) { + var str = path.replace(/([^\\])\[/g, '$1.[') + , parts = str.match(/(\\\.|[^.]+?)+/g); + return parts.map(function (value) { + var re = /^\[(\d+)\]$/ + , mArr = re.exec(value); + if (mArr) return { i: parseFloat(mArr[1]) }; + else return { p: value.replace(/\\([.\[\]])/g, '$1') }; + }); +} + + +/*! + * ## _getPathValue(parsed, obj) + * + * Helper companion function for `.parsePath` that returns + * the value located at the parsed address. + * + * var value = getPathValue(parsed, obj); + * + * @param {Object} parsed definition from `parsePath`. + * @param {Object} object to search against + * @param {Number} object to search against + * @returns {Object|Undefined} value + * @api private + */ + +function _getPathValue (parsed, obj, index) { + var tmp = obj + , res; + + index = (index === undefined ? parsed.length : index); + + for (var i = 0, l = index; i < l; i++) { + var part = parsed[i]; + if (tmp) { + if ('undefined' !== typeof part.p) + tmp = tmp[part.p]; + else if ('undefined' !== typeof part.i) + tmp = tmp[part.i]; + if (i == (l - 1)) res = tmp; + } else { + res = undefined; + } + } + return res; +} + +},{"./hasProperty":21}],19:[function(require,module,exports){ +/*! + * Chai - getPathValue utility + * Copyright(c) 2012-2014 Jake Luer + * @see https://github.com/logicalparadox/filtr + * MIT Licensed + */ + +var getPathInfo = require('./getPathInfo'); + +/** + * ### .getPathValue(path, object) + * + * This allows the retrieval of values in an + * object given a string path. + * + * var obj = { + * prop1: { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * , prop2: { + * arr: [ { nested: 'Universe' } ] + * , str: 'Hello again!' + * } + * } + * + * The following would be the results. + * + * getPathValue('prop1.str', obj); // Hello + * getPathValue('prop1.att[2]', obj); // b + * getPathValue('prop2.arr[0].nested', obj); // Universe + * + * @param {String} path + * @param {Object} object + * @returns {Object} value or `undefined` + * @namespace Utils + * @name getPathValue + * @api public + */ +module.exports = function(path, obj) { + var info = getPathInfo(path, obj); + return info.value; +}; + +},{"./getPathInfo":18}],20:[function(require,module,exports){ +/*! + * Chai - getProperties utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .getProperties(object) + * + * This allows the retrieval of property names of an object, enumerable or not, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @namespace Utils + * @name getProperties + * @api public + */ + +module.exports = function getProperties(object) { + var result = Object.getOwnPropertyNames(object); + + function addProperty(property) { + if (result.indexOf(property) === -1) { + result.push(property); + } + } + + var proto = Object.getPrototypeOf(object); + while (proto !== null) { + Object.getOwnPropertyNames(proto).forEach(addProperty); + proto = Object.getPrototypeOf(proto); + } + + return result; +}; + +},{}],21:[function(require,module,exports){ +/*! + * Chai - hasProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var type = require('type-detect'); + +/** + * ### .hasProperty(object, name) + * + * This allows checking whether an object has + * named property or numeric array index. + * + * Basically does the same thing as the `in` + * operator but works properly with natives + * and null/undefined values. + * + * var obj = { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * + * The following would be the results. + * + * hasProperty('str', obj); // true + * hasProperty('constructor', obj); // true + * hasProperty('bar', obj); // false + * + * hasProperty('length', obj.str); // true + * hasProperty(1, obj.str); // true + * hasProperty(5, obj.str); // false + * + * hasProperty('length', obj.arr); // true + * hasProperty(2, obj.arr); // true + * hasProperty(3, obj.arr); // false + * + * @param {Objuect} object + * @param {String|Number} name + * @returns {Boolean} whether it exists + * @namespace Utils + * @name getPathInfo + * @api public + */ + +var literals = { + 'number': Number + , 'string': String +}; + +module.exports = function hasProperty(name, obj) { + var ot = type(obj); + + // Bad Object, obviously no props at all + if(ot === 'null' || ot === 'undefined') + return false; + + // The `in` operator does not work with certain literals + // box these before the check + if(literals[ot] && typeof obj !== 'object') + obj = new literals[ot](obj); + + return name in obj; +}; + +},{"type-detect":35}],22:[function(require,module,exports){ +/*! + * chai + * Copyright(c) 2011 Jake Luer + * MIT Licensed + */ + +/*! + * Main exports + */ + +var exports = module.exports = {}; + +/*! + * test utility + */ + +exports.test = require('./test'); + +/*! + * type utility + */ + +exports.type = require('type-detect'); + +/*! + * expectTypes utility + */ +exports.expectTypes = require('./expectTypes'); + +/*! + * message utility + */ + +exports.getMessage = require('./getMessage'); + +/*! + * actual utility + */ + +exports.getActual = require('./getActual'); + +/*! + * Inspect util + */ + +exports.inspect = require('./inspect'); + +/*! + * Object Display util + */ + +exports.objDisplay = require('./objDisplay'); + +/*! + * Flag utility + */ + +exports.flag = require('./flag'); + +/*! + * Flag transferring utility + */ + +exports.transferFlags = require('./transferFlags'); + +/*! + * Deep equal utility + */ + +exports.eql = require('deep-eql'); + +/*! + * Deep path value + */ + +exports.getPathValue = require('./getPathValue'); + +/*! + * Deep path info + */ + +exports.getPathInfo = require('./getPathInfo'); + +/*! + * Check if a property exists + */ + +exports.hasProperty = require('./hasProperty'); + +/*! + * Function name + */ + +exports.getName = require('./getName'); + +/*! + * add Property + */ + +exports.addProperty = require('./addProperty'); + +/*! + * add Method + */ + +exports.addMethod = require('./addMethod'); + +/*! + * overwrite Property + */ + +exports.overwriteProperty = require('./overwriteProperty'); + +/*! + * overwrite Method + */ + +exports.overwriteMethod = require('./overwriteMethod'); + +/*! + * Add a chainable method + */ + +exports.addChainableMethod = require('./addChainableMethod'); + +/*! + * Overwrite chainable method + */ + +exports.overwriteChainableMethod = require('./overwriteChainableMethod'); + +},{"./addChainableMethod":9,"./addMethod":10,"./addProperty":11,"./expectTypes":12,"./flag":13,"./getActual":14,"./getMessage":16,"./getName":17,"./getPathInfo":18,"./getPathValue":19,"./hasProperty":21,"./inspect":23,"./objDisplay":24,"./overwriteChainableMethod":25,"./overwriteMethod":26,"./overwriteProperty":27,"./test":28,"./transferFlags":29,"deep-eql":31,"type-detect":35}],23:[function(require,module,exports){ +// This is (almost) directly from Node.js utils +// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js + +var getName = require('./getName'); +var getProperties = require('./getProperties'); +var getEnumerableProperties = require('./getEnumerableProperties'); + +module.exports = inspect; + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Boolean} showHidden Flag that shows hidden (not enumerable) + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). + * @namespace Utils + * @name inspect + */ +function inspect(obj, showHidden, depth, colors) { + var ctx = { + showHidden: showHidden, + seen: [], + stylize: function (str) { return str; } + }; + return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); +} + +// Returns true if object is a DOM element. +var isDOMElement = function (object) { + if (typeof HTMLElement === 'object') { + return object instanceof HTMLElement; + } else { + return object && + typeof object === 'object' && + object.nodeType === 1 && + typeof object.nodeName === 'string'; + } +}; + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes); + if (typeof ret !== 'string') { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // If this is a DOM element, try to get the outer HTML. + if (isDOMElement(value)) { + if ('outerHTML' in value) { + return value.outerHTML; + // This value does not have an outerHTML attribute, + // it could still be an XML element + } else { + // Attempt to serialize it + try { + if (document.xmlVersion) { + var xmlSerializer = new XMLSerializer(); + return xmlSerializer.serializeToString(value); + } else { + // Firefox 11- do not support outerHTML + // It does, however, support innerHTML + // Use the following to render the element + var ns = "http://www.w3.org/1999/xhtml"; + var container = document.createElementNS(ns, '_'); + + container.appendChild(value.cloneNode(false)); + html = container.innerHTML + .replace('><', '>' + value.innerHTML + '<'); + container.innerHTML = ''; + return html; + } + } catch (err) { + // This could be a non-native DOM implementation, + // continue with the normal flow: + // printing the element as if it is an object. + } + } + } + + // Look up the keys of the object. + var visibleKeys = getEnumerableProperties(value); + var keys = ctx.showHidden ? getProperties(value) : visibleKeys; + + // Some type of object without properties can be shortcutted. + // In IE, errors have a single `stack` property, or if they are vanilla `Error`, + // a `stack` plus `description` property; ignore those for consistency. + if (keys.length === 0 || (isError(value) && ( + (keys.length === 1 && keys[0] === 'stack') || + (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') + ))) { + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + return ctx.stylize('[Function' + nameSuffix + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + base = ' [Function' + nameSuffix + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + return formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + switch (typeof value) { + case 'undefined': + return ctx.stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + + case 'number': + if (value === 0 && (1/value) === -Infinity) { + return ctx.stylize('-0', 'number'); + } + return ctx.stylize('' + value, 'number'); + + case 'boolean': + return ctx.stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return ctx.stylize('null', 'null'); + } +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (Object.prototype.hasOwnProperty.call(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str; + if (value.__lookupGetter__) { + if (value.__lookupGetter__(key)) { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Setter]', 'special'); + } + } + } + if (visibleKeys.indexOf(key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(value[key]) < 0) { + if (recurseTimes === null) { + str = formatValue(ctx, value[key], null); + } else { + str = formatValue(ctx, value[key], recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + +function isArray(ar) { + return Array.isArray(ar) || + (typeof ar === 'object' && objectToString(ar) === '[object Array]'); +} + +function isRegExp(re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; +} + +function isDate(d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; +} + +function isError(e) { + return typeof e === 'object' && objectToString(e) === '[object Error]'; +} + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + +},{"./getEnumerableProperties":15,"./getName":17,"./getProperties":20}],24:[function(require,module,exports){ +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var inspect = require('./inspect'); +var config = require('../config'); + +/** + * ### .objDisplay (object) + * + * Determines if an object or an array matches + * criteria to be inspected in-line for error + * messages or should be truncated. + * + * @param {Mixed} javascript object to inspect + * @name objDisplay + * @namespace Utils + * @api public + */ + +module.exports = function (obj) { + var str = inspect(obj) + , type = Object.prototype.toString.call(obj); + + if (config.truncateThreshold && str.length >= config.truncateThreshold) { + if (type === '[object Function]') { + return !obj.name || obj.name === '' + ? '[Function]' + : '[Function: ' + obj.name + ']'; + } else if (type === '[object Array]') { + return '[ Array(' + obj.length + ') ]'; + } else if (type === '[object Object]') { + var keys = Object.keys(obj) + , kstr = keys.length > 2 + ? keys.splice(0, 2).join(', ') + ', ...' + : keys.join(', '); + return '{ Object (' + kstr + ') }'; + } else { + return str; + } + } else { + return str; + } +}; + +},{"../config":4,"./inspect":23}],25:[function(require,module,exports){ +/*! + * Chai - overwriteChainableMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteChainableMethod (ctx, name, method, chainingBehavior) + * + * Overwites an already existing chainable method + * and provides access to the previous function or + * property. Must return functions to be used for + * name. + * + * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', + * function (_super) { + * } + * , function (_super) { + * } + * ); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteChainableMethod('foo', fn, fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.have.length(3); + * expect(myFoo).to.have.length.above(3); + * + * @param {Object} ctx object whose method / property is to be overwritten + * @param {String} name of method / property to overwrite + * @param {Function} method function that returns a function to be used for name + * @param {Function} chainingBehavior function that returns a function to be used for property + * @namespace Utils + * @name overwriteChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + var chainableBehavior = ctx.__methods[name]; + + var _chainingBehavior = chainableBehavior.chainingBehavior; + chainableBehavior.chainingBehavior = function () { + var result = chainingBehavior(_chainingBehavior).call(this); + return result === undefined ? this : result; + }; + + var _method = chainableBehavior.method; + chainableBehavior.method = function () { + var result = method(_method).apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +},{}],26:[function(require,module,exports){ +/*! + * Chai - overwriteMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteMethod (ctx, name, fn) + * + * Overwites an already existing method and provides + * access to previous function. Must return function + * to be used for name. + * + * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { + * return function (str) { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.value).to.equal(str); + * } else { + * _super.apply(this, arguments); + * } + * } + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.equal('bar'); + * + * @param {Object} ctx object whose method is to be overwritten + * @param {String} name of method to overwrite + * @param {Function} method function that returns a function to be used for name + * @namespace Utils + * @name overwriteMethod + * @api public + */ + +module.exports = function (ctx, name, method) { + var _method = ctx[name] + , _super = function () { return this; }; + + if (_method && 'function' === typeof _method) + _super = _method; + + ctx[name] = function () { + var result = method(_super).apply(this, arguments); + return result === undefined ? this : result; + } +}; + +},{}],27:[function(require,module,exports){ +/*! + * Chai - overwriteProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteProperty (ctx, name, fn) + * + * Overwites an already existing property getter and provides + * access to previous value. Must return function to use as getter. + * + * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { + * return function () { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.name).to.equal('bar'); + * } else { + * _super.call(this); + * } + * } + * }); + * + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.ok; + * + * @param {Object} ctx object whose property is to be overwritten + * @param {String} name of property to overwrite + * @param {Function} getter function that returns a getter function to be used for name + * @namespace Utils + * @name overwriteProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + var _get = Object.getOwnPropertyDescriptor(ctx, name) + , _super = function () {}; + + if (_get && 'function' === typeof _get.get) + _super = _get.get + + Object.defineProperty(ctx, name, + { get: function () { + var result = getter(_super).call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +},{}],28:[function(require,module,exports){ +/*! + * Chai - test utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('./flag'); + +/** + * # test(object, expression) + * + * Test and object for expression. + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @namespace Utils + * @name test + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , expr = args[0]; + return negate ? !expr : expr; +}; + +},{"./flag":13}],29:[function(require,module,exports){ +/*! + * Chai - transferFlags utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### transferFlags(assertion, object, includeAll = true) + * + * Transfer all the flags for `assertion` to `object`. If + * `includeAll` is set to `false`, then the base Chai + * assertion flags (namely `object`, `ssfi`, and `message`) + * will not be transferred. + * + * + * var newAssertion = new Assertion(); + * utils.transferFlags(assertion, newAssertion); + * + * var anotherAsseriton = new Assertion(myObj); + * utils.transferFlags(assertion, anotherAssertion, false); + * + * @param {Assertion} assertion the assertion to transfer the flags from + * @param {Object} object the object to transfer the flags to; usually a new assertion + * @param {Boolean} includeAll + * @namespace Utils + * @name transferFlags + * @api private + */ + +module.exports = function (assertion, object, includeAll) { + var flags = assertion.__flags || (assertion.__flags = Object.create(null)); + + if (!object.__flags) { + object.__flags = Object.create(null); + } + + includeAll = arguments.length === 3 ? includeAll : true; + + for (var flag in flags) { + if (includeAll || + (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { + object.__flags[flag] = flags[flag]; + } + } +}; + +},{}],30:[function(require,module,exports){ +/*! + * assertion-error + * Copyright(c) 2013 Jake Luer + * MIT Licensed + */ + +/*! + * Return a function that will copy properties from + * one object to another excluding any originally + * listed. Returned function will create a new `{}`. + * + * @param {String} excluded properties ... + * @return {Function} + */ + +function exclude () { + var excludes = [].slice.call(arguments); + + function excludeProps (res, obj) { + Object.keys(obj).forEach(function (key) { + if (!~excludes.indexOf(key)) res[key] = obj[key]; + }); + } + + return function extendExclude () { + var args = [].slice.call(arguments) + , i = 0 + , res = {}; + + for (; i < args.length; i++) { + excludeProps(res, args[i]); + } + + return res; + }; +}; + +/*! + * Primary Exports + */ + +module.exports = AssertionError; + +/** + * ### AssertionError + * + * An extension of the JavaScript `Error` constructor for + * assertion and validation scenarios. + * + * @param {String} message + * @param {Object} properties to include (optional) + * @param {callee} start stack function (optional) + */ + +function AssertionError (message, _props, ssf) { + var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') + , props = extend(_props || {}); + + // default values + this.message = message || 'Unspecified AssertionError'; + this.showDiff = false; + + // copy from properties + for (var key in props) { + this[key] = props[key]; + } + + // capture stack trace + ssf = ssf || arguments.callee; + if (ssf && Error.captureStackTrace) { + Error.captureStackTrace(this, ssf); + } else { + this.stack = new Error().stack; + } +} + +/*! + * Inherit from Error.prototype + */ + +AssertionError.prototype = Object.create(Error.prototype); + +/*! + * Statically set name + */ + +AssertionError.prototype.name = 'AssertionError'; + +/*! + * Ensure correct constructor + */ + +AssertionError.prototype.constructor = AssertionError; + +/** + * Allow errors to be converted to JSON for static transfer. + * + * @param {Boolean} include stack (default: `true`) + * @return {Object} object that can be `JSON.stringify` + */ + +AssertionError.prototype.toJSON = function (stack) { + var extend = exclude('constructor', 'toJSON', 'stack') + , props = extend({ name: this.name }, this); + + // include stack if exists and not turned off + if (false !== stack && this.stack) { + props.stack = this.stack; + } + + return props; +}; + +},{}],31:[function(require,module,exports){ +module.exports = require('./lib/eql'); + +},{"./lib/eql":32}],32:[function(require,module,exports){ +/*! + * deep-eql + * Copyright(c) 2013 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var type = require('type-detect'); + +/*! + * Buffer.isBuffer browser shim + */ + +var Buffer; +try { Buffer = require('buffer').Buffer; } +catch(ex) { + Buffer = {}; + Buffer.isBuffer = function() { return false; } +} + +/*! + * Primary Export + */ + +module.exports = deepEqual; + +/** + * Assert super-strict (egal) equality between + * two objects of any type. + * + * @param {Mixed} a + * @param {Mixed} b + * @param {Array} memoised (optional) + * @return {Boolean} equal match + */ + +function deepEqual(a, b, m) { + if (sameValue(a, b)) { + return true; + } else if ('date' === type(a)) { + return dateEqual(a, b); + } else if ('regexp' === type(a)) { + return regexpEqual(a, b); + } else if (Buffer.isBuffer(a)) { + return bufferEqual(a, b); + } else if ('arguments' === type(a)) { + return argumentsEqual(a, b, m); + } else if (!typeEqual(a, b)) { + return false; + } else if (('object' !== type(a) && 'object' !== type(b)) + && ('array' !== type(a) && 'array' !== type(b))) { + return sameValue(a, b); + } else { + return objectEqual(a, b, m); + } +} + +/*! + * Strict (egal) equality test. Ensures that NaN always + * equals NaN and `-0` does not equal `+0`. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} equal match + */ + +function sameValue(a, b) { + if (a === b) return a !== 0 || 1 / a === 1 / b; + return a !== a && b !== b; +} + +/*! + * Compare the types of two given objects and + * return if they are equal. Note that an Array + * has a type of `array` (not `object`) and arguments + * have a type of `arguments` (not `array`/`object`). + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function typeEqual(a, b) { + return type(a) === type(b); +} + +/*! + * Compare two Date objects by asserting that + * the time values are equal using `saveValue`. + * + * @param {Date} a + * @param {Date} b + * @return {Boolean} result + */ + +function dateEqual(a, b) { + if ('date' !== type(b)) return false; + return sameValue(a.getTime(), b.getTime()); +} + +/*! + * Compare two regular expressions by converting them + * to string and checking for `sameValue`. + * + * @param {RegExp} a + * @param {RegExp} b + * @return {Boolean} result + */ + +function regexpEqual(a, b) { + if ('regexp' !== type(b)) return false; + return sameValue(a.toString(), b.toString()); +} + +/*! + * Assert deep equality of two `arguments` objects. + * Unfortunately, these must be sliced to arrays + * prior to test to ensure no bad behavior. + * + * @param {Arguments} a + * @param {Arguments} b + * @param {Array} memoize (optional) + * @return {Boolean} result + */ + +function argumentsEqual(a, b, m) { + if ('arguments' !== type(b)) return false; + a = [].slice.call(a); + b = [].slice.call(b); + return deepEqual(a, b, m); +} + +/*! + * Get enumerable properties of a given object. + * + * @param {Object} a + * @return {Array} property names + */ + +function enumerable(a) { + var res = []; + for (var key in a) res.push(key); + return res; +} + +/*! + * Simple equality for flat iterable objects + * such as Arrays or Node.js buffers. + * + * @param {Iterable} a + * @param {Iterable} b + * @return {Boolean} result + */ + +function iterableEqual(a, b) { + if (a.length !== b.length) return false; + + var i = 0; + var match = true; + + for (; i < a.length; i++) { + if (a[i] !== b[i]) { + match = false; + break; + } + } + + return match; +} + +/*! + * Extension to `iterableEqual` specifically + * for Node.js Buffers. + * + * @param {Buffer} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function bufferEqual(a, b) { + if (!Buffer.isBuffer(b)) return false; + return iterableEqual(a, b); +} + +/*! + * Block for `objectEqual` ensuring non-existing + * values don't get in. + * + * @param {Mixed} object + * @return {Boolean} result + */ + +function isValue(a) { + return a !== null && a !== undefined; +} + +/*! + * Recursively check the equality of two objects. + * Once basic sameness has been established it will + * defer to `deepEqual` for each enumerable key + * in the object. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function objectEqual(a, b, m) { + if (!isValue(a) || !isValue(b)) { + return false; + } + + if (a.prototype !== b.prototype) { + return false; + } + + var i; + if (m) { + for (i = 0; i < m.length; i++) { + if ((m[i][0] === a && m[i][1] === b) + || (m[i][0] === b && m[i][1] === a)) { + return true; + } + } + } else { + m = []; + } + + try { + var ka = enumerable(a); + var kb = enumerable(b); + } catch (ex) { + return false; + } + + ka.sort(); + kb.sort(); + + if (!iterableEqual(ka, kb)) { + return false; + } + + m.push([ a, b ]); + + var key; + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key], m)) { + return false; + } + } + + return true; +} + +},{"buffer":undefined,"type-detect":33}],33:[function(require,module,exports){ +module.exports = require('./lib/type'); + +},{"./lib/type":34}],34:[function(require,module,exports){ +/*! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/*! + * Detectable javascript natives + */ + +var natives = { + '[object Array]': 'array' + , '[object RegExp]': 'regexp' + , '[object Function]': 'function' + , '[object Arguments]': 'arguments' + , '[object Date]': 'date' +}; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ + +function getType (obj) { + var str = Object.prototype.toString.call(obj); + if (natives[str]) return natives[str]; + if (obj === null) return 'null'; + if (obj === undefined) return 'undefined'; + if (obj === Object(obj)) return 'object'; + return typeof obj; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library () { + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function (type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function (obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +},{}],35:[function(require,module,exports){ +arguments[4][33][0].apply(exports,arguments) +},{"./lib/type":36,"dup":33}],36:[function(require,module,exports){ +/*! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ +var objectTypeRegexp = /^\[object (.*)\]$/; + +function getType(obj) { + var type = Object.prototype.toString.call(obj).match(objectTypeRegexp)[1].toLowerCase(); + // Let "new String('')" return 'object' + if (typeof Promise === 'function' && obj instanceof Promise) return 'promise'; + // PhantomJS has type "DOMWindow" for null + if (obj === null) return 'null'; + // PhantomJS has type "DOMWindow" for undefined + if (obj === undefined) return 'undefined'; + return type; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library() { + if (!(this instanceof Library)) return new Library(); + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function(type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function(obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/tests/main_spec.js b/tests/main_spec.js new file mode 100644 index 0000000..8a2a0f1 --- /dev/null +++ b/tests/main_spec.js @@ -0,0 +1,70 @@ +var expect = chai.expect; + +var people_src = "data:image/jpeg;base64,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"; +var people2_src = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4TIraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MCA2MS4xMzQ3NzcsIDIwMTAvMDIvMTItMTc6MzI6MDAgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+QWRvYmUgRmlyZXdvcmtzIENTNSAxMS4wLjAuNDg0IFdpbmRvd3M8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTItMDktMjVUMDk6MTY6MDdaPC94bXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMTQtMDMtMjVUMTY6NDE6MTBaPC94bXA6TW9kaWZ5RGF0ZT4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvanBlZzwvZGM6Zm9ybWF0PgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg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"; + + +function request_success () { + return new Promise ( function ( resolve, reject ){ + resemble("../demoassets/People.jpg") + .compareTo("../demoassets/People2.jpg") + .onComplete( function ( data ) { + console.info("Reached oncomplete for request_success"); + expect(data.diffBounds).to.deep.equal({ bottom: 431, left: 22, right: 454, top: 58 }); + expect(data.dimensionDifference).to.deep.equal({ height: 0, width: 0 }); + expect(data.isSameDimensions).to.be.true; + expect(data.misMatchPercentage).to.equal("8.65"); + resolve(); + }); + }); +} + + +function base64_string () { + return new Promise ( function ( resolve, reject ){ + resemble(people_src) + .compareTo(people2_src) + .onComplete( function ( data ) { + console.info("Reached oncomplete for base64_string"); + expect(data.diffBounds).to.deep.equal({ bottom: 431, left: 22, right: 454, top: 58 }); + expect(data.dimensionDifference).to.deep.equal({ height: 0, width: 0 }); + expect(data.isSameDimensions).to.be.true; + expect(data.misMatchPercentage).to.equal("8.65"); + resolve(); + }); + }); +} + +function request_404 () { + return new Promise ( function ( resolve, reject ){ + resemble("../demoassets/People.jpg") + .compareTo("../demoassets/404-image.jpg") + .onComplete( function ( data ) { + console.info("Reached oncomplete for request_404"); + expect(data).to.deep.equal({ error : "Image load error." }); + resolve(); + }); + }); +} + +function request_cors () { + return new Promise ( function ( resolve, reject ){ + resemble("../demoassets/People.jpg") + .compareTo("https://www.google.ca/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png") + .onComplete( function ( data ) { + console.info("Reached oncomplete for request_cors"); + expect(data).to.deep.equal({ error : "Image load error." }); + resolve(); + }); + }); +} + +request_success().then(function(){ console.info("Test 1 complete."); }) + .then( request_404 ).then(function(){ console.info("Test 2 complete."); }) + .then( request_success ).then(function(){ console.info("Test 3 complete."); }) + .then( request_404 ).then(function(){ console.info("Test 4 complete."); }) + .then( base64_string ).then(function(){ console.info("Test 5 complete."); }) + .then( request_cors ).then(function(){ console.info("Test 6 complete."); }) + .then( function () { + console.info("All tests completed."); + }); \ No newline at end of file diff --git a/tests/test.html b/tests/test.html new file mode 100644 index 0000000..a293221 --- /dev/null +++ b/tests/test.html @@ -0,0 +1,12 @@ + + + + + + +

Check the console for test results

+ + + + + \ No newline at end of file