From 75ba9c1a285bd4518d70c3156e07093ac1cd51d3 Mon Sep 17 00:00:00 2001 From: Thomas Steur Date: Mon, 22 Jun 2015 14:00:33 +1200 Subject: [PATCH 01/18] Fix ignore nothing still defines a tolerance --- resemble.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resemble.js b/resemble.js index 900e190..0e8843e 100644 --- a/resemble.js +++ b/resemble.js @@ -558,12 +558,12 @@ URL: https://github.com/Huddle/Resemble.js var self = { ignoreNothing: function(){ - tolerance.red = 16; - tolerance.green = 16; - tolerance.blue = 16; - tolerance.alpha = 16; - tolerance.minBrightness = 16; - tolerance.maxBrightness = 240; + tolerance.red = 0; + tolerance.green = 0; + tolerance.blue = 0; + tolerance.alpha = 0; + tolerance.minBrightness = 0; + tolerance.maxBrightness = 255; ignoreAntialiasing = false; ignoreColors = false; From e95dbf52a4bbf2737d4df28068278c828e8489a6 Mon Sep 17 00:00:00 2001 From: James Cryer Date: Thu, 9 Jul 2015 11:10:00 +0100 Subject: [PATCH 02/18] 1.3.0 --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 8bbce3a..21cba06 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "resemblejs", "main": "resemble.js", - "version": "1.2.1", + "version": "1.3.0", "homepage": "https://github.com/Huddle/Resemble.js", "authors": [ "James Cryer " diff --git a/package.json b/package.json index 0d721e3..2f9297c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "1.2.1", + "version": "1.3.0", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From 127e8be80e2bf94b50fcccaf8faf8e687272e88a Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Wed, 30 Sep 2015 23:15:58 -0700 Subject: [PATCH 03/18] Add UMD wrapper for module loaders --- resemble.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/resemble.js b/resemble.js index 0e8843e..5cb5f5c 100644 --- a/resemble.js +++ b/resemble.js @@ -3,7 +3,15 @@ James Cryer / Huddle 2014 URL: https://github.com/Huddle/Resemble.js */ -(function(_this){ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(); + } else { + root.resemble = factory(); + } +}(this, function () { 'use strict'; var pixelTransparency = 1; @@ -63,7 +71,7 @@ URL: https://github.com/Huddle/Resemble.js var document = typeof window != "undefined" ? window.document : {}; var documentDomainRegex = new RegExp('^https?://' + document.domain); - _this['resemble'] = function( fileData ){ + var resemble = function( fileData ){ var data = {}; var images = []; @@ -633,7 +641,7 @@ URL: https://github.com/Huddle/Resemble.js }; - _this['resemble'].outputSettings = function(options){ + resemble.outputSettings = function(options){ var key; var undefined; @@ -656,4 +664,5 @@ URL: https://github.com/Huddle/Resemble.js return this; }; -}(this)); + return resemble; +})); From a5135ff355ab4b969a07a83a01dcf83131302bde Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Thu, 8 Oct 2015 14:51:26 +0100 Subject: [PATCH 04/18] bump patch --- .gitignore | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/package.json b/package.json index 2f9297c..2a81341 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "1.3.0", + "version": "1.3.1", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From 61544bb61792d9d46351631a6493342a757f7f1f Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Fri, 9 Oct 2015 09:33:13 +0100 Subject: [PATCH 05/18] Bump major because of previous contract change via UMD --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2a81341..b80c446 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "1.3.1", + "version": "2.0.0", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From 82b42a60cef4071c028bd5d6d752eb6c8c4844a3 Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Fri, 9 Oct 2015 09:45:19 +0100 Subject: [PATCH 06/18] forgot to bump bower package --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 21cba06..a68e6e5 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "resemblejs", "main": "resemble.js", - "version": "1.3.0", + "version": "2.0.0", "homepage": "https://github.com/Huddle/Resemble.js", "authors": [ "James Cryer " From 8c759b5ac5c224ee02266a505fc8974f7da8e112 Mon Sep 17 00:00:00 2001 From: benwick Date: Tue, 20 Oct 2015 11:15:55 +0200 Subject: [PATCH 07/18] Fix unloaded image issues, mostly in IE and Safari Every now and then, the hiddenImage.onload function will fail, because the width and height of the hiddenImage are zero. The IE will throw an IndexSizeError in line 161, when it tries to get the image data. Safari fails silently. The reason for this is, that only the complete property is evaluated to consider the manual firing of the onload callback. But it can happen sometimes, that the complete property is true, but width and height are not calculated yet. So I added an extra test for the naturalWidth of the image. See also here: http://stackoverflow.com/questions/1977871/check-if-an-image-is-loaded-no-errors-in-javascript#answer-1977898 --- resemble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resemble.js b/resemble.js index 5cb5f5c..ecb6727 100644 --- a/resemble.js +++ b/resemble.js @@ -167,7 +167,7 @@ URL: https://github.com/Huddle/Resemble.js if (typeof fileData === 'string') { hiddenImage.src = fileData; - if (hiddenImage.complete) { + if (hiddenImage.complete && hiddenImage.naturalWidth > 0) { hiddenImage.onload(); } } else if (typeof fileData.data !== 'undefined' From 1498110798442d9eb2268d537ea396ac7f6370f9 Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Tue, 3 Nov 2015 10:19:52 +0000 Subject: [PATCH 08/18] missing semi-colon --- resemble.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resemble.js b/resemble.js index ecb6727..815a5bc 100644 --- a/resemble.js +++ b/resemble.js @@ -1,5 +1,5 @@ /* -James Cryer / Huddle 2014 +James Cryer / Huddle 2015 URL: https://github.com/Huddle/Resemble.js */ @@ -399,7 +399,7 @@ URL: https://github.com/Huddle/Resemble.js diffBounds.right = Math.max(x, diffBounds.right); diffBounds.top = Math.min(y, diffBounds.top); diffBounds.bottom = Math.max(y, diffBounds.bottom); - } + }; var time = Date.now(); From 4f1a8719f020ed2502bc819305b9da599c290a60 Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Tue, 3 Nov 2015 10:20:05 +0000 Subject: [PATCH 09/18] bump patch --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index a68e6e5..6c04409 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "resemblejs", "main": "resemble.js", - "version": "2.0.0", + "version": "2.0.1", "homepage": "https://github.com/Huddle/Resemble.js", "authors": [ "James Cryer " diff --git a/package.json b/package.json index b80c446..26c9eea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "2.0.0", + "version": "2.0.1", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From 6a3a852358ed2f0a0667802b19b929c660536e5f Mon Sep 17 00:00:00 2001 From: Andrew Carreiro Date: Thu, 19 Nov 2015 21:31:44 -0500 Subject: [PATCH 10/18] Surfacing raw mismatch percentage to help with large image diffs --- resemble.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resemble.js b/resemble.js index 815a5bc..7a5bfa5 100644 --- a/resemble.js +++ b/resemble.js @@ -465,7 +465,8 @@ URL: https://github.com/Huddle/Resemble.js }); - data.misMatchPercentage = (mismatchCount / (height*width) * 100).toFixed(2); + data.rawMisMatchPercentage = (mismatchCount / (height*width) * 100); + data.misMatchPercentage = data.rawMisMatchPercentage.toFixed(2); data.diffBounds = diffBounds; data.analysisTime = Date.now() - time; From 9211a80d0ebe792e30907ae588632601242dfff9 Mon Sep 17 00:00:00 2001 From: Andrew Carreiro Date: Thu, 19 Nov 2015 23:15:19 -0500 Subject: [PATCH 11/18] 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 From 6d7fb49946884cc2cd181dc102ffcaf572bfa208 Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Tue, 5 Jan 2016 11:51:37 +0000 Subject: [PATCH 12/18] Fixed tests (perhaps the results are different per machine?) --- tests/chai-3.4.2.js | 6019 ------------------------------------------- tests/main_spec.js | 21 +- tests/test.html | 2 +- 3 files changed, 16 insertions(+), 6026 deletions(-) delete mode 100644 tests/chai-3.4.2.js diff --git a/tests/chai-3.4.2.js b/tests/chai-3.4.2.js deleted file mode 100644 index c467073..0000000 --- a/tests/chai-3.4.2.js +++ /dev/null @@ -1,6019 +0,0 @@ -(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 index 8a2a0f1..90dd231 100644 --- a/tests/main_spec.js +++ b/tests/main_spec.js @@ -10,10 +10,15 @@ function request_success () { .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.diffBounds).to.have.all.keys('bottom', 'left', 'top', 'right'); + expect(data.diffBounds.bottom).to.equal(431); + expect(data.diffBounds.left).to.equal(22); + expect(data.diffBounds.right).to.equal(450); + expect(data.diffBounds.top).to.equal(58); + expect(data.dimensionDifference.height).to.equal(0); + expect(data.dimensionDifference.width).to.equal(0); expect(data.isSameDimensions).to.be.true; - expect(data.misMatchPercentage).to.equal("8.65"); + expect(data.misMatchPercentage).to.equal("8.66"); resolve(); }); }); @@ -26,10 +31,14 @@ function base64_string () { .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.diffBounds.bottom).to.equal(431); + expect(data.diffBounds.left).to.equal(22); + expect(data.diffBounds.right).to.equal(450); + expect(data.diffBounds.top).to.equal(58); + expect(data.dimensionDifference.height).to.equal(0); + expect(data.dimensionDifference.width).to.equal(0); expect(data.isSameDimensions).to.be.true; - expect(data.misMatchPercentage).to.equal("8.65"); + expect(data.misMatchPercentage).to.equal("8.66"); resolve(); }); }); diff --git a/tests/test.html b/tests/test.html index a293221..991f858 100644 --- a/tests/test.html +++ b/tests/test.html @@ -6,7 +6,7 @@

Check the console for test results

- + \ No newline at end of file From d56d8091cc450c390a188c6ec8662895fee3ab8d Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Tue, 5 Jan 2016 11:53:27 +0000 Subject: [PATCH 13/18] v2.1.0 --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 6c04409..749ca4f 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "resemblejs", "main": "resemble.js", - "version": "2.0.1", + "version": "2.1.0", "homepage": "https://github.com/Huddle/Resemble.js", "authors": [ "James Cryer " diff --git a/package.json b/package.json index 26c9eea..580d938 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "2.0.1", + "version": "2.1.0", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From a1a41fc5260a1ba7567173ed3137ce850e32840a Mon Sep 17 00:00:00 2001 From: Alex Kanunnikov Date: Wed, 13 Jan 2016 19:40:59 +0300 Subject: [PATCH 14/18] Large Base64 image files performance tweak --- resemble.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/resemble.js b/resemble.js index 6d0afdb..e8f2ea9 100644 --- a/resemble.js +++ b/resemble.js @@ -144,10 +144,16 @@ URL: https://github.com/Huddle/Resemble.js var fileReader; var hiddenImage = new Image(); - if (httpRegex.test(fileData) && !documentDomainRegex.test(fileData)) { - hiddenImage.setAttribute('crossorigin', 'anonymous'); + if (!(typeof fileData === 'string' + && fileData.length > 6 + && fileData.charAt(4)===':' + && fileData.charAt(5)!=='/' + )) { + if (httpRegex.test(fileData) && !documentDomainRegex.test(fileData)) { + hiddenImage.setAttribute('crossorigin', 'anonymous'); + } } - + hiddenImage.onerror = function () { hiddenImage.onerror = null; //fixes pollution between calls images.push({ error : "Image load error."}); From 15d2b12d083eab01ab29eadae7ebe2780b4cd7dd Mon Sep 17 00:00:00 2001 From: Anton Sivolapov Date: Wed, 24 Feb 2016 21:54:31 +0800 Subject: [PATCH 15/18] add new comparison option "scaleToSameSize" --- README.md | 7 +++++++ demoassets/main.js | 8 ++++++++ index.html | 7 +++++++ resemble.js | 19 +++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/README.md b/README.md index a40312f..4e71e56 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ var diff = resemble(file).compareTo(file2).ignoreColors().onComplete(function(da }); ``` +Scale second image to dimensions of the first one: +```javascript +//diff.useOriginalSize(); +diff.scaleToSameSize(); +``` + You can also change the comparison method after the first analysis. ```javascript @@ -53,6 +59,7 @@ You can also change the comparison method after the first analysis. diff.ignoreAntialiasing(); ``` + And change the output display style. ```javascript diff --git a/demoassets/main.js b/demoassets/main.js index dfa5b89..96085dd 100644 --- a/demoassets/main.js +++ b/demoassets/main.js @@ -115,6 +115,14 @@ $(function(){ resembleControl.ignoreAntialiasing(); } else + if($this.is('#same-size')){ + resembleControl.scaleToSameSize(); + } + else + if($this.is('#original-size')){ + resembleControl.useOriginalSize(); + } + else if($this.is('#pink')){ resemble.outputSettings({ errorColor: { diff --git a/index.html b/index.html index c266060..d24148c 100644 --- a/index.html +++ b/index.html @@ -91,6 +91,13 @@ +
+
+ +

diff --git a/resemble.js b/resemble.js index e8f2ea9..d124c24 100644 --- a/resemble.js +++ b/resemble.js @@ -88,6 +88,7 @@ URL: https://github.com/Huddle/Resemble.js var ignoreAntialiasing = false; var ignoreColors = false; + var scaleToSameSize = false; function triggerDataUpdate(){ var len = updateCallbackArray.length; @@ -165,6 +166,12 @@ URL: https://github.com/Huddle/Resemble.js var hiddenCanvas = document.createElement('canvas'); var imageData; + + if( scaleToSameSize && images.length == 1 ){ + hiddenImage.width = images[0].width; + hiddenImage.height = images[0].height; + } + var width = hiddenImage.width; var height = hiddenImage.height; @@ -584,6 +591,18 @@ URL: https://github.com/Huddle/Resemble.js } var self = { + scaleToSameSize: function(){ + scaleToSameSize = true; + + if(hasMethod) { param(); } + return self; + }, + useOriginalSize: function(){ + scaleToSameSize = false; + + if(hasMethod) { param(); } + return self; + }, ignoreNothing: function(){ tolerance.red = 0; From ed49cffd9451241f7c4edfa97ef89a885b37dad4 Mon Sep 17 00:00:00 2001 From: Anton Sivolapov Date: Wed, 24 Feb 2016 21:54:47 +0800 Subject: [PATCH 16/18] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 580d938..f350e11 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "2.1.0", + "version": "2.1.1", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From 3f16a52b6879b014f9151f4776a52ef8f2a9187f Mon Sep 17 00:00:00 2001 From: "james.cryer" Date: Tue, 1 Mar 2016 13:42:46 +0000 Subject: [PATCH 17/18] Bump feature v2.2.0 --- bower.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 749ca4f..7753009 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "resemblejs", "main": "resemble.js", - "version": "2.1.0", + "version": "2.2.0", "homepage": "https://github.com/Huddle/Resemble.js", "authors": [ "James Cryer " diff --git a/package.json b/package.json index f350e11..938f23a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "resemblejs", - "version": "2.1.1", + "version": "2.2.0", "description": "Image analysis and comparison with HTML5", "main": "resemble.js", "repository": { From 5f408198b6ddcd1d362ae90daf7156813561b716 Mon Sep 17 00:00:00 2001 From: Anton Konovalov Date: Fri, 25 Mar 2016 13:40:59 +0200 Subject: [PATCH 18/18] Add alpha to analysis result. --- demoassets/main.js | 1 + index.html | 5 ++++- resemble.js | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/demoassets/main.js b/demoassets/main.js index 96085dd..f72e8a5 100644 --- a/demoassets/main.js +++ b/demoassets/main.js @@ -44,6 +44,7 @@ $(function(){ $('#red').css('width',data.red+'%'); $('#green').css('width',data.green+'%'); $('#blue').css('width',data.blue+'%'); + $('#alpha').css('width',data.alpha+'%'); $('#brightness').css('width',data.brightness+'%'); }); diff --git a/index.html b/index.html index d24148c..7ced660 100644 --- a/index.html +++ b/index.html @@ -39,7 +39,7 @@