aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorMatthew Bergman <[email protected]>2014-02-17 21:05:35 -0500
committerMatthew Bergman <[email protected]>2014-02-17 21:05:35 -0500
commit7710092ab44ce820dc73799193badee4e5ebce0c (patch)
treef5a369600fe0c1f7e675d1eff58ba38ff39da07a /test
parent934945d9ca59f197b9e8971d8d428ad9dd86d419 (diff)
parent47527ec7391b15f915b25e983da80e98360ed04a (diff)
downloadfaker-7710092ab44ce820dc73799193badee4e5ebce0c.tar.xz
faker-7710092ab44ce820dc73799193badee4e5ebce0c.zip
Merge pull request #1 from Marak/master
Merging Upstream into master branch
Diffstat (limited to 'test')
-rw-r--r--test/address.unit.js293
-rw-r--r--test/all.functional.js47
-rw-r--r--test/browser.unit.html28
-rw-r--r--test/company.unit.js110
-rw-r--r--test/helpers.unit.js62
-rw-r--r--test/image.unit.js38
-rw-r--r--test/internet.unit.js85
-rw-r--r--test/lorem.unit.js178
-rw-r--r--test/mocha.opts5
-rw-r--r--test/name.unit.js63
-rw-r--r--test/phone_number.unit.js29
-rwxr-xr-xtest/run.js68
-rw-r--r--test/support/chai.js3403
-rw-r--r--test/support/sinon-1.5.2.js4153
-rw-r--r--test/support/walk_dir.js43
15 files changed, 8605 insertions, 0 deletions
diff --git a/test/address.unit.js b/test/address.unit.js
new file mode 100644
index 00000000..a6e33c0b
--- /dev/null
+++ b/test/address.unit.js
@@ -0,0 +1,293 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("address.js", function () {
+ describe("city()", function () {
+ beforeEach(function () {
+ sinon.spy(Faker.random, 'city_prefix');
+ sinon.spy(Faker.random, 'first_name');
+ sinon.spy(Faker.random, 'last_name');
+ sinon.spy(Faker.random, 'city_suffix');
+ });
+
+ afterEach(function () {
+ Faker.random.number.restore();
+ Faker.random.city_prefix.restore();
+ Faker.random.first_name.restore();
+ Faker.random.last_name.restore();
+ Faker.random.city_suffix.restore();
+ });
+
+ it("occasionally returns prefix + first name + suffix", function () {
+ sinon.stub(Faker.random, 'number').returns(0);
+
+ var city = Faker.Address.city();
+ assert.ok(city);
+
+ assert.ok(Faker.random.city_prefix.calledOnce);
+ assert.ok(Faker.random.first_name.calledOnce);
+ assert.ok(Faker.random.city_suffix.calledOnce);
+ });
+
+ it("occasionally returns prefix + first name", function () {
+ sinon.stub(Faker.random, 'number').returns(1);
+
+ var city = Faker.Address.city();
+ assert.ok(city);
+
+ assert.ok(Faker.random.city_prefix.calledOnce);
+ assert.ok(Faker.random.first_name.calledOnce);
+ assert.ok(!Faker.random.city_suffix.called);
+ });
+
+ it("occasionally returns first name + suffix", function () {
+ sinon.stub(Faker.random, 'number').returns(2);
+
+ var city = Faker.Address.city();
+ assert.ok(city);
+
+ assert.ok(!Faker.random.city_prefix.called);
+ assert.ok(Faker.random.first_name.calledOnce);
+ assert.ok(Faker.random.city_suffix.calledOnce);
+ });
+
+ it("occasionally returns last name + suffix", function () {
+ sinon.stub(Faker.random, 'number').returns(3);
+
+ var city = Faker.Address.city();
+ assert.ok(city);
+
+ assert.ok(!Faker.random.city_prefix.called);
+ assert.ok(!Faker.random.first_name.called);
+ assert.ok(Faker.random.last_name.calledOnce);
+ assert.ok(Faker.random.city_suffix.calledOnce);
+ });
+ });
+
+ describe("streetName()", function () {
+ beforeEach(function () {
+ sinon.spy(Faker.random, 'first_name');
+ sinon.spy(Faker.random, 'last_name');
+ sinon.spy(Faker.random, 'street_suffix');
+ });
+
+ afterEach(function () {
+ Faker.random.number.restore();
+ Faker.random.first_name.restore();
+ Faker.random.last_name.restore();
+ Faker.random.street_suffix.restore();
+ });
+
+ it("occasionally returns last name + suffix", function () {
+ sinon.stub(Faker.random, 'number').returns(0);
+
+ var street_name = Faker.Address.streetName();
+ assert.ok(street_name);
+
+ assert.ok(!Faker.random.first_name.called);
+ assert.ok(Faker.random.last_name.calledOnce);
+ assert.ok(Faker.random.street_suffix.calledOnce);
+ });
+
+ it("occasionally returns first name + suffix", function () {
+ sinon.stub(Faker.random, 'number').returns(1);
+
+ var street_name = Faker.Address.streetName();
+ assert.ok(street_name);
+
+ assert.ok(Faker.random.first_name.calledOnce);
+ assert.ok(!Faker.random.last_name.called);
+ assert.ok(Faker.random.street_suffix.calledOnce);
+ });
+ });
+
+ describe("streetAddress()", function () {
+ beforeEach(function () {
+ sinon.spy(Faker.Address, 'streetName');
+ sinon.spy(Faker.Address, 'secondaryAddress');
+ });
+
+ afterEach(function () {
+ Faker.Address.streetName.restore();
+ Faker.Address.secondaryAddress.restore();
+ });
+
+ it("occasionally returns a 5-digit street number", function () {
+ sinon.stub(Faker.random, 'number').returns(0);
+ var address = Faker.Address.streetAddress();
+ var parts = address.split(' ');
+
+ assert.equal(parts[0].length, 5);
+ assert.ok(Faker.Address.streetName.called);
+
+ Faker.random.number.restore();
+ });
+
+ it("occasionally returns a 4-digit street number", function () {
+ sinon.stub(Faker.random, 'number').returns(1);
+ var address = Faker.Address.streetAddress();
+ var parts = address.split(' ');
+
+ assert.equal(parts[0].length, 4);
+ assert.ok(Faker.Address.streetName.called);
+
+ Faker.random.number.restore();
+ });
+
+ it("occasionally returns a 3-digit street number", function () {
+ sinon.stub(Faker.random, 'number').returns(2);
+ var address = Faker.Address.streetAddress();
+ var parts = address.split(' ');
+
+ assert.equal(parts[0].length, 3);
+ assert.ok(Faker.Address.streetName.called);
+ assert.ok(!Faker.Address.secondaryAddress.called);
+
+ Faker.random.number.restore();
+ });
+
+ context("when useFulladdress is true", function () {
+ it("adds a secondary address to the result", function () {
+ var address = Faker.Address.streetAddress(true);
+ var parts = address.split(' ');
+
+ assert.ok(Faker.Address.secondaryAddress.called);
+ });
+ });
+ });
+
+ describe("secondaryAddress()", function () {
+ it("randomly chooses an Apt or Suite number", function () {
+ sinon.spy(Faker.random, 'array_element');
+
+ var address = Faker.Address.secondaryAddress();
+
+ var expected_array = [
+ 'Apt. ###',
+ 'Suite ###'
+ ];
+
+ assert.ok(address);
+ assert.ok(Faker.random.array_element.calledWith(expected_array));
+ Faker.random.array_element.restore();
+ });
+ });
+
+ describe("brState()", function () {
+ beforeEach(function () {
+ sinon.spy(Faker.random, 'br_state_abbr');
+ sinon.spy(Faker.random, 'br_state');
+ });
+
+ afterEach(function () {
+ Faker.random.br_state_abbr.restore();
+ Faker.random.br_state.restore();
+ });
+
+ context("when useAbbr is true", function () {
+ it("returns a br_state_abbr", function () {
+ var state = Faker.Address.brState(true);
+
+ assert.ok(state);
+ assert.ok(Faker.random.br_state_abbr.called);
+ assert.ok(!Faker.random.br_state.called);
+ });
+ });
+
+ context("when useAbbr is not set", function () {
+ it("returns a br_state", function () {
+ var state = Faker.Address.brState();
+
+ assert.ok(state);
+ assert.ok(!Faker.random.br_state_abbr.called);
+ assert.ok(Faker.random.br_state.called);
+ });
+ });
+ });
+
+ describe("ukCounty()", function () {
+ it("returns random uk_county", function () {
+ sinon.spy(Faker.random, 'uk_county');
+ var county = Faker.Address.ukCounty();
+ assert.ok(county);
+ assert.ok(Faker.random.uk_county.called);
+ Faker.random.uk_county.restore();
+ });
+ });
+
+ describe("ukCountry()", function () {
+ it("returns random uk_country", function () {
+ sinon.spy(Faker.random, 'uk_country');
+ var country = Faker.Address.ukCountry();
+ assert.ok(country);
+ assert.ok(Faker.random.uk_country.called);
+ Faker.random.uk_country.restore();
+ });
+ });
+
+ describe("usState()", function () {
+ beforeEach(function () {
+ sinon.spy(Faker.random, 'us_state_abbr');
+ sinon.spy(Faker.random, 'us_state');
+ });
+
+ afterEach(function () {
+ Faker.random.us_state_abbr.restore();
+ Faker.random.us_state.restore();
+ });
+
+ context("when useAbus is true", function () {
+ it("returns a us_state_abbr", function () {
+ var state = Faker.Address.usState(true);
+
+ assert.ok(state);
+ assert.ok(Faker.random.us_state_abbr.called);
+ assert.ok(!Faker.random.us_state.called);
+ });
+ });
+
+ context("when useAbus is not set", function () {
+ it("returns a us_state", function () {
+ var state = Faker.Address.usState();
+
+ assert.ok(state);
+ assert.ok(!Faker.random.us_state_abbr.called);
+ assert.ok(Faker.random.us_state.called);
+ });
+ });
+ });
+
+ describe("latitude()", function () {
+ it("returns random latitude", function () {
+ for (var i = 0; i < 100; i++) {
+ sinon.spy(Faker.random, 'number');
+ var latitude = Faker.Address.latitude();
+ assert.ok(typeof latitude === 'string');
+ var latitude_float = parseFloat(latitude);
+ assert.ok(latitude_float >= -90.0);
+ assert.ok(latitude_float <= 90.0);
+ assert.ok(Faker.random.number.called);
+ Faker.random.number.restore();
+ }
+ });
+ });
+
+ describe("longitude()", function () {
+ it("returns random longitude", function () {
+ for (var i = 0; i < 100; i++) {
+ sinon.spy(Faker.random, 'number');
+ var longitude = Faker.Address.longitude();
+ assert.ok(typeof longitude === 'string');
+ var longitude_float = parseFloat(longitude);
+ assert.ok(longitude_float >= -180.0);
+ assert.ok(longitude_float <= 180.0);
+ assert.ok(Faker.random.number.called);
+ Faker.random.number.restore();
+ }
+ });
+ });
+
+});
diff --git a/test/all.functional.js b/test/all.functional.js
new file mode 100644
index 00000000..91327214
--- /dev/null
+++ b/test/all.functional.js
@@ -0,0 +1,47 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+// Basic smoke tests to make sure each method is at least implemented and returns a string.
+
+var modules = {
+ Address: [
+ 'city', 'streetName', 'streetAddress', 'secondaryAddress',
+ 'brState', 'ukCountry', 'ukCounty', 'usState', 'zipCode'
+ ],
+
+ Company: ['companyName', 'companySuffix', 'catchPhrase', 'bs'],
+
+ Internet: ['email', 'userName', 'domainName', 'domainWord', 'ip'],
+
+ Lorem: ['words', 'sentence', 'sentences', 'paragraph', 'paragraphs'],
+
+ Name: ['firstName', 'lastName', 'findName'],
+
+ PhoneNumber: ['phoneNumber']
+};
+
+describe("functional tests", function () {
+ Object.keys(modules).forEach(function (module) {
+ describe(module, function () {
+ modules[module].forEach(function (meth) {
+ it(meth + "()", function () {
+ var result = Faker[module][meth]();
+ assert.ok(result);
+ });
+ });
+ });
+ });
+
+ describe("Address", function () {
+ it("zipCodeFormat()", function () {
+ var result = Faker.Address.zipCodeFormat(0);
+ assert.ok(!result.match(/-/));
+
+ result = Faker.Address.zipCodeFormat(1);
+ assert.ok(result.match(/-/));
+ });
+ });
+});
diff --git a/test/browser.unit.html b/test/browser.unit.html
new file mode 100644
index 00000000..375f683c
--- /dev/null
+++ b/test/browser.unit.html
@@ -0,0 +1,28 @@
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Mocha Tests</title>
+ <link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
+</head>
+<body>
+ <div id="mocha"></div>
+ <script src="../node_modules/mocha/mocha.js"></script>
+ <script src="../Faker.js"></script>
+ <script src="./support/chai.js"></script>
+ <script src="./support/sinon-1.5.2.js"></script>
+ <script>assert = chai.assert;</script>
+ <script>mocha.setup('bdd');</script>
+ <script src="all.functional.js"></script>
+ <script src="address.unit.js"></script>
+ <script src="company.unit.js"></script>
+ <script src="helpers.unit.js"></script>
+ <script src="internet.unit.js"></script>
+ <script src="lorem.unit.js"></script>
+ <script src="name.unit.js"></script>
+ <script src="phone_number.unit.js"></script>
+ <script>
+ mocha.run();
+ </script>
+</body>
+</html>
+
diff --git a/test/company.unit.js b/test/company.unit.js
new file mode 100644
index 00000000..0aceac1e
--- /dev/null
+++ b/test/company.unit.js
@@ -0,0 +1,110 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("company.js", function () {
+ describe("companyName()", function () {
+ it("lets you specify the type of name to return", function () {
+ sinon.spy(Faker.random, 'number');
+ var name = Faker.Company.companyName(1);
+
+ assert.ok(name.match(/-/));
+
+ assert.ok(!Faker.random.number.called);
+ Faker.random.number.restore();
+ });
+
+ it("sometimes returns three last names", function () {
+ sinon.spy(Faker.random, 'last_name');
+ sinon.stub(Faker.random, 'number').returns(2);
+ var name = Faker.Company.companyName();
+ var parts = name.split(' ');
+
+ assert.strictEqual(parts.length, 4); // account for word 'and'
+ assert.ok(Faker.random.last_name.calledThrice);
+
+ Faker.random.number.restore();
+ Faker.random.last_name.restore();
+ });
+
+ it("sometimes returns two last names separated by a hyphen", function () {
+ sinon.spy(Faker.random, 'last_name');
+ sinon.stub(Faker.random, 'number').returns(1);
+ var name = Faker.Company.companyName();
+ var parts = name.split('-');
+
+ assert.ok(parts.length >= 2);
+ assert.ok(Faker.random.last_name.calledTwice);
+
+ Faker.random.number.restore();
+ Faker.random.last_name.restore();
+ });
+
+ it("sometimes returns a last name with a company suffix", function () {
+ sinon.spy(Faker.Company, 'companySuffix');
+ sinon.spy(Faker.random, 'last_name');
+ sinon.stub(Faker.random, 'number').returns(0);
+ var name = Faker.Company.companyName();
+ var parts = name.split(' ');
+
+ assert.ok(parts.length >= 2);
+ assert.ok(Faker.random.last_name.calledOnce);
+ assert.ok(Faker.Company.companySuffix.calledOnce);
+
+ Faker.random.number.restore();
+ Faker.random.last_name.restore();
+ Faker.Company.companySuffix.restore();
+ });
+ });
+
+ describe("companySuffix()", function () {
+ it("returns random value from company.suffixes array", function () {
+ var suffix = Faker.Company.companySuffix();
+ assert.ok(Faker.Company.suffixes().indexOf(suffix) !== -1);
+ });
+ });
+
+ describe("catchPhrase()", function () {
+ it("returns phrase comprising of a catch phrase adjective, descriptor, and noun", function () {
+ sinon.spy(Faker.random, 'array_element');
+ sinon.spy(Faker.random, 'catch_phrase_adjective');
+ sinon.spy(Faker.random, 'catch_phrase_descriptor');
+ sinon.spy(Faker.random, 'catch_phrase_noun');
+ var phrase = Faker.Company.catchPhrase();
+
+ assert.ok(phrase.split(' ').length >= 3);
+ assert.ok(Faker.random.array_element.calledThrice);
+ assert.ok(Faker.random.catch_phrase_adjective.calledOnce);
+ assert.ok(Faker.random.catch_phrase_descriptor.calledOnce);
+ assert.ok(Faker.random.catch_phrase_noun.calledOnce);
+
+ Faker.random.array_element.restore();
+ Faker.random.catch_phrase_adjective.restore();
+ Faker.random.catch_phrase_descriptor.restore();
+ Faker.random.catch_phrase_noun.restore();
+ });
+ });
+
+ describe("bs()", function () {
+ it("returns phrase comprising of a BS adjective, buzz, and noun", function () {
+ sinon.spy(Faker.random, 'array_element');
+ sinon.spy(Faker.random, 'bs_adjective');
+ sinon.spy(Faker.random, 'bs_buzz');
+ sinon.spy(Faker.random, 'bs_noun');
+ var bs = Faker.Company.bs();
+
+ assert.ok(typeof bs === 'string');
+ assert.ok(Faker.random.array_element.calledThrice);
+ assert.ok(Faker.random.bs_adjective.calledOnce);
+ assert.ok(Faker.random.bs_buzz.calledOnce);
+ assert.ok(Faker.random.bs_noun.calledOnce);
+
+ Faker.random.array_element.restore();
+ Faker.random.bs_adjective.restore();
+ Faker.random.bs_buzz.restore();
+ Faker.random.bs_noun.restore();
+ });
+ });
+});
diff --git a/test/helpers.unit.js b/test/helpers.unit.js
new file mode 100644
index 00000000..3549099d
--- /dev/null
+++ b/test/helpers.unit.js
@@ -0,0 +1,62 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("helpers.js", function () {
+ describe("replaceSymbolWithNumber()", function () {
+ context("when no symbol passed in", function () {
+ it("uses '#' by default", function () {
+ var num = Faker.Helpers.replaceSymbolWithNumber('#AB');
+ assert.ok(num.match(/\dAB/));
+ });
+ });
+
+ context("when symbol passed in", function () {
+ it("replaces that symbol with integers", function () {
+ var num = Faker.Helpers.replaceSymbolWithNumber('#AB', 'A');
+ assert.ok(num.match(/#\dB/));
+ });
+ });
+ });
+
+ describe("slugify()", function () {
+ it("removes unwanted characters from URI string", function () {
+ assert.equal(Faker.Helpers.slugify("Aiden.HarÂȘann"), "Aiden.Harann");
+ assert.equal(Faker.Helpers.slugify("d'angelo.net"), "dangelo.net");
+ });
+ });
+
+ describe("createCard()", function () {
+ it("returns an object", function () {
+ var card = Faker.Helpers.createCard();
+ assert.ok(typeof card === 'object');
+ });
+ });
+
+ describe("userCard()", function () {
+ it("returns an object", function () {
+ var card = Faker.Helpers.userCard();
+ assert.ok(typeof card === 'object');
+ });
+ });
+
+ // Make sure we keep this function for backward-compatibility.
+ describe("randomNumber()", function () {
+ it("returns an integer", function () {
+ var num = Faker.Helpers.randomNumber();
+ assert.ok(typeof num === 'number');
+ });
+ });
+
+ // Make sure we keep this function for backward-compatibility.
+ describe("randomize()", function () {
+ it("returns a random element from an array", function () {
+ var arr = ['a', 'b', 'c'];
+ var elem = Faker.Helpers.randomize(arr);
+ assert.ok(elem);
+ assert.ok(arr.indexOf(elem) !== -1);
+ });
+ });
+});
diff --git a/test/image.unit.js b/test/image.unit.js
new file mode 100644
index 00000000..046291ad
--- /dev/null
+++ b/test/image.unit.js
@@ -0,0 +1,38 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("image.js", function () {
+ describe("imageUrl()", function () {
+ it("returns a random image url from lorempixel", function () {
+ var imageUrl = Faker.Image.LoremPixel.imageUrl();
+
+ assert.equal(imageUrl, 'http://lorempixel.com/640/480');
+ });
+ it("returns a random image url from lorempixel with width and height", function () {
+ var imageUrl = Faker.Image.LoremPixel.imageUrl(100, 100);
+
+ assert.equal(imageUrl, 'http://lorempixel.com/100/100');
+ });
+ it("returns a random image url in an abstract category", function () {
+ var imageUrl = Faker.Image.LoremPixel.imageUrl(100, 100, 'abstract');
+
+ assert.equal(imageUrl, 'http://lorempixel.com/100/100/abstract');
+ });
+ it("returns a random image url in a category via proxy methods", function () {
+ var nightlife = Faker.Image.LoremPixel.nightlife();
+ assert.equal(nightlife, 'http://lorempixel.com/640/480/nightlife');
+
+ var city = Faker.Image.LoremPixel.city();
+ assert.equal(city, 'http://lorempixel.com/640/480/city');
+
+ var fashion = Faker.Image.LoremPixel.fashion();
+ assert.equal(fashion, 'http://lorempixel.com/640/480/fashion');
+ });
+ it("return a random avatar from UIFaces", function () {
+ assert.notEqual(-1, Faker.Image.UIFaces.avatar().indexOf('s3.amazonaws.com/uifaces/faces'));
+ })
+ });
+});
diff --git a/test/internet.unit.js b/test/internet.unit.js
new file mode 100644
index 00000000..d7d823cf
--- /dev/null
+++ b/test/internet.unit.js
@@ -0,0 +1,85 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("internet.js", function () {
+ describe("email()", function () {
+ it("returns a userName@domainName", function () {
+ sinon.stub(Faker.Internet, 'userName').returns('Aiden.HarÂȘann');
+ sinon.stub(Faker.Internet, 'domainName').returns("ex'ample.net");
+ var email = Faker.Internet.email();
+
+ assert.equal(email, '[email protected]');
+
+ Faker.Internet.userName.restore();
+ Faker.Internet.domainName.restore();
+ });
+ });
+
+ describe("userName()", function () {
+ it("occasionally returns a single firstName", function () {
+ sinon.stub(Faker.random, 'number').returns(0);
+ sinon.spy(Faker.random, 'first_name');
+ var username = Faker.Internet.userName();
+
+ assert.ok(username);
+ assert.ok(Faker.random.first_name.called);
+
+ Faker.random.number.restore();
+ Faker.random.first_name.restore();
+ });
+
+ it("occasionally returns a firstName with a period or hyphen and a lastName", function () {
+ sinon.stub(Faker.random, 'number').returns(1);
+ sinon.spy(Faker.random, 'first_name');
+ sinon.spy(Faker.random, 'last_name');
+ sinon.spy(Faker.random, 'array_element');
+ var username = Faker.Internet.userName();
+
+ assert.ok(username);
+ assert.ok(Faker.random.first_name.called);
+ assert.ok(Faker.random.last_name.called);
+ assert.ok(Faker.random.array_element.calledWith(['.', '_']));
+
+ Faker.random.number.restore();
+ Faker.random.first_name.restore();
+ Faker.random.last_name.restore();
+ });
+ });
+
+ describe("domainName()", function () {
+ it("returns a domainWord plus a random suffix", function () {
+ sinon.stub(Faker.Internet, 'domainWord').returns('bar');
+ sinon.stub(Faker.random, 'domain_suffix').returns('net');
+
+ var domain_name = Faker.Internet.domainName();
+
+ assert.equal(domain_name, 'bar.net');
+
+ Faker.Internet.domainWord.restore();
+ Faker.random.domain_suffix.restore();
+ });
+ });
+
+ describe("domainWord()", function () {
+ it("returns a lower-case firstName", function () {
+ sinon.stub(Faker.random, 'first_name').returns('FOO');
+ var domain_word = Faker.Internet.domainWord();
+
+ assert.ok(domain_word);
+ assert.strictEqual(domain_word, 'foo');
+
+ Faker.random.first_name.restore();
+ });
+ });
+
+ describe("ip()", function () {
+ it("returns a random IP address with four parts", function () {
+ var ip = Faker.Internet.ip();
+ var parts = ip.split('.');
+ assert.equal(parts.length, 4);
+ });
+ });
+});
diff --git a/test/lorem.unit.js b/test/lorem.unit.js
new file mode 100644
index 00000000..d85cce91
--- /dev/null
+++ b/test/lorem.unit.js
@@ -0,0 +1,178 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("lorem.js", function () {
+ describe("words()", function () {
+ beforeEach(function () {
+ sinon.spy(Faker.Helpers, 'shuffle');
+ });
+
+ afterEach(function () {
+ Faker.Helpers.shuffle.restore();
+ });
+
+ context("when no 'num' param passed in", function () {
+ it("returns three words", function () {
+ var words = Faker.Lorem.words();
+
+ assert.ok(Array.isArray(words));
+ assert.equal(words.length, 3);
+ assert.ok(Faker.Helpers.shuffle.called);
+ });
+ });
+
+ context("when 'num' param passed in", function () {
+ it("returns requested number of words", function () {
+ var words = Faker.Lorem.words(7);
+
+ assert.ok(Array.isArray(words));
+ assert.equal(words.length, 7);
+ });
+ });
+ });
+
+ describe("sentence()", function () {
+ context("when no 'wordCount' or 'range' param passed in", function () {
+ it("returns a string of at least three words", function () {
+ sinon.spy(Faker.Lorem, 'words');
+ sinon.stub(Faker.random, 'number').returns(2);
+ var sentence = Faker.Lorem.sentence();
+
+ assert.ok(typeof sentence === 'string');
+ var parts = sentence.split(' ');
+ assert.equal(parts.length, 5); // default 3 plus stubbed 2.
+ assert.ok(Faker.Lorem.words.calledWith(5));
+
+ Faker.Lorem.words.restore();
+ Faker.random.number.restore();
+ });
+ });
+
+ context("when 'wordCount' param passed in", function () {
+ it("returns a string of at least the requested number of words", function () {
+ sinon.spy(Faker.Lorem, 'words');
+ sinon.stub(Faker.random, 'number').returns(2);
+ var sentence = Faker.Lorem.sentence(10);
+
+ assert.ok(typeof sentence === 'string');
+ var parts = sentence.split(' ');
+ assert.equal(parts.length, 12); // requested 10 plus stubbed 2.
+ assert.ok(Faker.Lorem.words.calledWith(12));
+
+ Faker.Lorem.words.restore();
+ Faker.random.number.restore();
+ });
+ });
+
+ context("when 'wordCount' and 'range' params passed in", function () {
+ it("returns a string of at least the requested number of words", function () {
+ sinon.spy(Faker.Lorem, 'words');
+ sinon.stub(Faker.random, 'number').returns(4);
+ var sentence = Faker.Lorem.sentence(10, 4);
+
+ assert.ok(typeof sentence === 'string');
+ var parts = sentence.split(' ');
+ assert.equal(parts.length, 14); // requested 10 plus stubbed 4.
+ assert.ok(Faker.Lorem.words.calledWith(14));
+
+ Faker.Lorem.words.restore();
+ Faker.random.number.restore();
+ });
+ });
+ });
+
+ describe("sentences()", function () {
+ context("when no 'sentenceCount' param passed in", function () {
+ it("returns newline-separated string of three sentences", function () {
+ sinon.spy(Faker.Lorem, 'sentence');
+ var sentences = Faker.Lorem.sentences();
+
+ assert.ok(typeof sentences === 'string');
+ var parts = sentences.split('\n');
+ assert.equal(parts.length, 3);
+ assert.ok(Faker.Lorem.sentence.calledThrice);
+
+ Faker.Lorem.sentence.restore();
+ });
+ });
+
+ context("when 'sentenceCount' param passed in", function () {
+ it("returns newline-separated string of requested number of sentences", function () {
+ sinon.spy(Faker.Lorem, 'sentence');
+ var sentences = Faker.Lorem.sentences(5);
+
+ assert.ok(typeof sentences === 'string');
+ var parts = sentences.split('\n');
+ assert.equal(parts.length, 5);
+
+ Faker.Lorem.sentence.restore();
+ });
+ });
+ });
+
+ describe("paragraph()", function () {
+ context("when no 'wordCount' param passed in", function () {
+ it("returns a string of at least three sentences", function () {
+ sinon.spy(Faker.Lorem, 'sentences');
+ sinon.stub(Faker.random, 'number').returns(2);
+ var paragraph = Faker.Lorem.paragraph();
+
+ assert.ok(typeof paragraph === 'string');
+ var parts = paragraph.split('\n');
+ assert.equal(parts.length, 5); // default 3 plus stubbed 2.
+ assert.ok(Faker.Lorem.sentences.calledWith(5));
+
+ Faker.Lorem.sentences.restore();
+ Faker.random.number.restore();
+ });
+ });
+
+ context("when 'wordCount' param passed in", function () {
+ it("returns a string of at least the requested number of sentences", function () {
+ sinon.spy(Faker.Lorem, 'sentences');
+ sinon.stub(Faker.random, 'number').returns(2);
+ var paragraph = Faker.Lorem.paragraph(10);
+
+ assert.ok(typeof paragraph === 'string');
+ var parts = paragraph.split('\n');
+ assert.equal(parts.length, 12); // requested 10 plus stubbed 2.
+ assert.ok(Faker.Lorem.sentences.calledWith(12));
+
+ Faker.Lorem.sentences.restore();
+ Faker.random.number.restore();
+ });
+ });
+ });
+
+ describe("paragraphs()", function () {
+ context("when no 'paragraphCount' param passed in", function () {
+ it("returns newline-separated string of three paragraphs", function () {
+ sinon.spy(Faker.Lorem, 'paragraph');
+ var paragraphs = Faker.Lorem.paragraphs();
+
+ assert.ok(typeof paragraphs === 'string');
+ var parts = paragraphs.split('\n \r\t');
+ assert.equal(parts.length, 3);
+ assert.ok(Faker.Lorem.paragraph.calledThrice);
+
+ Faker.Lorem.paragraph.restore();
+ });
+ });
+
+ context("when 'paragraphCount' param passed in", function () {
+ it("returns newline-separated string of requested number of paragraphs", function () {
+ sinon.spy(Faker.Lorem, 'paragraph');
+ var paragraphs = Faker.Lorem.paragraphs(5);
+
+ assert.ok(typeof paragraphs === 'string');
+ var parts = paragraphs.split('\n \r\t');
+ assert.equal(parts.length, 5);
+
+ Faker.Lorem.paragraph.restore();
+ });
+ });
+ });
+});
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 00000000..2fc3747d
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,5 @@
+--reporter spec
+--ui bdd
+--globals state,newBlocks,params,type,__coverage__
+--timeout 6500
+--slow 200
diff --git a/test/name.unit.js b/test/name.unit.js
new file mode 100644
index 00000000..84e0ff90
--- /dev/null
+++ b/test/name.unit.js
@@ -0,0 +1,63 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("name.js", function () {
+ describe("firstName()", function () {
+ it("returns a random name", function () {
+ sinon.stub(Faker.random, 'first_name').returns('foo');
+ var first_name = Faker.Name.firstName();
+
+ assert.equal(first_name, 'foo');
+
+ Faker.random.first_name.restore();
+ });
+ });
+
+ describe("lastName()", function () {
+ it("returns a random name", function () {
+ sinon.stub(Faker.random, 'last_name').returns('foo');
+
+ var last_name = Faker.Name.lastName();
+
+ assert.equal(last_name, 'foo');
+
+ Faker.random.last_name.restore();
+ });
+ });
+
+ describe("findName()", function () {
+ it("usually returns a first name and last name", function () {
+ sinon.stub(Faker.random, 'number').returns(5);
+ var name = Faker.Name.findName();
+ assert.ok(name);
+ var parts = name.split(' ');
+
+ assert.strictEqual(parts.length, 2);
+
+ Faker.random.number.restore();
+ });
+
+ it("occasionally returns a first name and last name with a prefix", function () {
+ sinon.stub(Faker.random, 'number').returns(0);
+ var name = Faker.Name.findName();
+ var parts = name.split(' ');
+
+ assert.ok(parts.length >= 3);
+
+ Faker.random.number.restore();
+ });
+
+ it("occasionally returns a first name and last name with a suffix", function () {
+ sinon.stub(Faker.random, 'number').returns(1);
+ var name = Faker.Name.findName();
+ var parts = name.split(' ');
+
+ assert.ok(parts.length >= 3);
+
+ Faker.random.number.restore();
+ });
+ });
+});
diff --git a/test/phone_number.unit.js b/test/phone_number.unit.js
new file mode 100644
index 00000000..91cb1e69
--- /dev/null
+++ b/test/phone_number.unit.js
@@ -0,0 +1,29 @@
+if (typeof module !== 'undefined') {
+ var assert = require('assert');
+ var sinon = require('sinon');
+ var Faker = require('../index');
+}
+
+describe("phone_number.js", function () {
+ describe("phoneNumber()", function () {
+ it("returns a random phoneNumber with a random format", function () {
+ sinon.spy(Faker.random, 'phone_formats');
+ sinon.spy(Faker.Helpers, 'replaceSymbolWithNumber');
+ var phone_number = Faker.PhoneNumber.phoneNumber();
+
+ assert.ok(phone_number.match(/\d/));
+ assert.ok(Faker.random.phone_formats.called);
+ assert.ok(Faker.Helpers.replaceSymbolWithNumber.called);
+
+ Faker.random.phone_formats.restore();
+ Faker.Helpers.replaceSymbolWithNumber.restore();
+ });
+ });
+
+ describe("phoneNumberFormat()", function () {
+ it("returns phone number with requested format (Array index)", function () {
+ var phone_number = Faker.PhoneNumber.phoneNumberFormat(5);
+ assert.ok(phone_number.match(/\(\d\d\d\)\d\d\d-\d\d\d\d/));
+ });
+ });
+});
diff --git a/test/run.js b/test/run.js
new file mode 100755
index 00000000..d577de9a
--- /dev/null
+++ b/test/run.js
@@ -0,0 +1,68 @@
+#!/usr/bin/env node
+process.env.NODE_ENV = 'test';
+
+var fs = require('fs');
+var Mocha = require('mocha');
+var optimist = require('optimist');
+var walk_dir = require('./support/walk_dir');
+
+var argv = optimist
+ .usage("Usage: $0 -t [types] --reporter [reporter] --timeout [timeout]")
+ .default({types: 'unit,functional', reporter: 'spec', timeout: 6000})
+ .describe('types', 'The types of tests to run, separated by commas. E.g., unit,functional,acceptance')
+ .describe('reporter', 'The mocha test reporter to use.')
+ .describe('timeout', 'The mocha timeout to use per test (ms).')
+ .boolean('help')
+ .alias('types', 'T')
+ .alias('timeout', 't')
+ .alias('reporter', 'R')
+ .alias('help', 'h')
+ .argv;
+
+var mocha = new Mocha({timeout: argv.timeout, reporter: argv.reporter, ui: 'bdd'});
+
+var valid_test_types = ['unit', 'functional', 'acceptance', 'integration'];
+var requested_types = argv.types.split(',');
+var types_to_use = [];
+
+valid_test_types.forEach(function (valid_test_type) {
+ if (requested_types.indexOf(valid_test_type) !== -1) {
+ types_to_use.push(valid_test_type);
+ }
+});
+
+if (argv.help || types_to_use.length === 0) {
+ console.log('\n' + optimist.help());
+ process.exit();
+}
+
+var is_valid_file = function (file) {
+ for (var i = 0; i < types_to_use.length; i++) {
+ var test_type = types_to_use[i];
+ var ext = test_type + ".js";
+
+ if (file.indexOf(ext) !== -1) {
+ return true;
+ }
+ }
+
+ return false;
+};
+
+function run(cb) {
+ walk_dir.walk('test', is_valid_file, function (err, files) {
+ if (err) { return cb(err); }
+
+ files.forEach(function (file) {
+ mocha.addFile(file);
+ });
+
+ cb();
+ });
+}
+
+run(function (err) {
+ mocha.run(function (failures) {
+ process.exit(failures);
+ });
+});
diff --git a/test/support/chai.js b/test/support/chai.js
new file mode 100644
index 00000000..43fbf644
--- /dev/null
+++ b/test/support/chai.js
@@ -0,0 +1,3403 @@
+!function (name, definition) {
+ if (typeof define == 'function' && typeof define.amd == 'object') define(definition);
+ else this[name] = definition();
+}('chai', function () {
+
+// CommonJS require()
+
+function require(p){
+ var path = require.resolve(p)
+ , mod = require.modules[path];
+ if (!mod) throw new Error('failed to require "' + p + '"');
+ if (!mod.exports) {
+ mod.exports = {};
+ mod.call(mod.exports, mod, mod.exports, require.relative(path));
+ }
+ return mod.exports;
+ }
+
+require.modules = {};
+
+require.resolve = function (path){
+ var orig = path
+ , reg = path + '.js'
+ , index = path + '/index.js';
+ return require.modules[reg] && reg
+ || require.modules[index] && index
+ || orig;
+ };
+
+require.register = function (path, fn){
+ require.modules[path] = fn;
+ };
+
+require.relative = function (parent) {
+ return function(p){
+ if ('.' != p[0]) return require(p);
+
+ var path = parent.split('/')
+ , segs = p.split('/');
+ path.pop();
+
+ for (var i = 0; i < segs.length; i++) {
+ var seg = segs[i];
+ if ('..' == seg) path.pop();
+ else if ('.' != seg) path.push(seg);
+ }
+
+ return require(path.join('/'));
+ };
+ };
+
+
+require.register("assertion.js", function(module, exports, require){
+/*!
+ * chai
+ * http://chaijs.com
+ * Copyright(c) 2011-2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+
+/*!
+ * Module dependencies.
+ */
+
+var AssertionError = require('./browser/error')
+ , toString = Object.prototype.toString
+ , util = require('./utils')
+ , flag = util.flag;
+
+/*!
+ * Module export.
+ */
+
+module.exports = 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);
+}
+
+/*!
+ * ### Assertion.includeStack
+ *
+ * User configurable property, influences whether stack trace
+ * is included in Assertion error message. Default of false
+ * suppresses stack trace in the error message
+ *
+ * Assertion.includeStack = true; // enable stack on error
+ *
+ * @api public
+ */
+
+Assertion.includeStack = false;
+
+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);
+};
+
+/*!
+ * ### .assert(expression, message, negateMessage, expected, actual)
+ *
+ * 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} message to display if fails
+ * @param {String} 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`
+ * @api private
+ */
+
+Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual) {
+ var msg = util.getMessage(this, arguments)
+ , actual = util.getActual(this, arguments)
+ , ok = util.test(this, arguments);
+
+ if (!ok) {
+ throw new AssertionError({
+ message: msg
+ , actual: actual
+ , expected: expected
+ , stackStartFunction: (Assertion.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);
+ }
+});
+
+/**
+ * ### Language Chains
+ *
+ * The following are provide as chainable getters to
+ * improve the readability of your assertions. They
+ * do not provide an testing capability unless they
+ * have been overwritten by a plugin.
+ *
+ * **Chains**
+ *
+ * - to
+ * - be
+ * - been
+ * - is
+ * - and
+ * - have
+ * - with
+ *
+ * @name language chains
+ * @api public
+ */
+
+[ 'to', 'be', 'been'
+, 'is', 'and', 'have'
+, 'with' ].forEach(function (chain) {
+ Object.defineProperty(Assertion.prototype, chain,
+ { get: function () {
+ return this;
+ }
+ , configurable: true
+ });
+});
+
+/**
+ * ### .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
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'not',
+ { get: function () {
+ flag(this, 'negate', true);
+ return this;
+ }
+ , configurable: 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');
+ *
+ * @name deep
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'deep',
+ { get: function () {
+ flag(this, 'deep', true);
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .a(type)
+ *
+ * The `a` and `an` assertions are aliases that can be
+ * used either as language chains or to assert a value's
+ * type (as revealed by `Object.prototype.toString`).
+ *
+ * // 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');
+ *
+ * // language chain
+ * expect(foo).to.be.an.instanceof(Foo);
+ *
+ * @name a
+ * @alias an
+ * @param {String} type
+ * @api public
+ */
+
+function an(type) {
+ var obj = flag(this, 'object')
+ , klassStart = type.charAt(0).toUpperCase()
+ , klass = klassStart + type.slice(1)
+ , article = ~[ 'A', 'E', 'I', 'O', 'U' ].indexOf(klassStart) ? 'an ' : 'a ';
+
+ this.assert(
+ '[object ' + klass + ']' === toString.call(obj)
+ , 'expected #{this} to be ' + article + type
+ , 'expected #{this} not to be ' + article + type
+ , '[object ' + klass + ']'
+ , toString.call(obj)
+ );
+}
+
+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 `contain` 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
+ * @param {Object|String|Number} obj
+ * @api public
+ */
+
+function includeChainingBehavior () {
+ flag(this, 'contains', true);
+}
+
+function include (val) {
+ var obj = flag(this, 'object')
+ this.assert(
+ ~obj.indexOf(val)
+ , 'expected #{this} to include ' + util.inspect(val)
+ , 'expected #{this} to not include ' + util.inspect(val));
+}
+
+Assertion.addChainableMethod('include', include, includeChainingBehavior);
+Assertion.addChainableMethod('contain', include, includeChainingBehavior);
+
+/**
+ * ### .ok
+ *
+ * Asserts that the target is truthy.
+ *
+ * expect('everthing').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
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'ok',
+ { get: function () {
+ this.assert(
+ flag(this, 'object')
+ , 'expected #{this} to be truthy'
+ , 'expected #{this} to be falsy');
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .true
+ *
+ * Asserts that the target is `true`.
+ *
+ * expect(true).to.be.true;
+ * expect(1).to.not.be.true;
+ *
+ * @name true
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'true',
+ { get: function () {
+ this.assert(
+ true === flag(this, 'object')
+ , 'expected #{this} to be true'
+ , 'expected #{this} to be false'
+ , this.negate ? false : true
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .false
+ *
+ * Asserts that the target is `false`.
+ *
+ * expect(false).to.be.false;
+ * expect(0).to.not.be.false;
+ *
+ * @name false
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'false',
+ { get: function () {
+ this.assert(
+ false === flag(this, 'object')
+ , 'expected #{this} to be false'
+ , 'expected #{this} to be true'
+ , this.negate ? true : false
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .null
+ *
+ * Asserts that the target is `null`.
+ *
+ * expect(null).to.be.null;
+ * expect(undefined).not.to.be.null;
+ *
+ * @name null
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'null',
+ { get: function () {
+ this.assert(
+ null === flag(this, 'object')
+ , 'expected #{this} to be null'
+ , 'expected #{this} not to be null'
+ , this.negate ? false : true
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .undefined
+ *
+ * Asserts that the target is `undefined`.
+ *
+ * expect(undefined).to.be.undefined;
+ * expect(null).to.not.be.undefined;
+ *
+ * @name undefined
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'undefined',
+ { get: function () {
+ this.assert(
+ undefined === flag(this, 'object')
+ , 'expected #{this} to be undefined'
+ , 'expected #{this} not to be undefined'
+ , this.negate ? false : true
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .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
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'exist',
+ { get: function () {
+ this.assert(
+ null != flag(this, 'object')
+ , 'expected #{this} to exist'
+ , 'expected #{this} to not exist'
+ );
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .empty
+ *
+ * Asserts that the target's length is `0`. For arrays, 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
+ * @api public
+ */
+
+Object.defineProperty(Assertion.prototype, 'empty',
+ { get: 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');
+
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .arguments
+ *
+ * Asserts that the target is an arguments object.
+ *
+ * function test () {
+ * expect(arguments).to.be.arguments;
+ * }
+ *
+ * @name arguments
+ * @alias Arguments
+ * @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
+ * @param {Mixed} value
+ * @api public
+ */
+
+Assertion.prototype.equal = function (val) {
+ 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);
+ }
+
+ return this;
+};
+
+/**
+ * ### .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
+ * @param {Mixed} value
+ * @api public
+ */
+
+Assertion.prototype.eql = function (obj) {
+ this.assert(
+ util.eql(obj, flag(this, 'object'))
+ , 'expected #{this} to deeply equal #{exp}'
+ , 'expected #{this} to not deeply equal #{exp}'
+ , obj );
+
+ return this;
+};
+
+/**
+ * ### .above(value)
+ *
+ * Asserts that the target is greater than `value`.
+ *
+ * expect(10).to.be.above(5);
+ *
+ * @name above
+ * @alias gt
+ * @param {Number} value
+ * @api public
+ */
+
+Assertion.prototype.above = function (val) {
+ this.assert(
+ flag(this, 'object') > val
+ , 'expected #{this} to be above ' + val
+ , 'expected #{this} to be below ' + val);
+
+ return this;
+};
+
+/**
+ * ### .below(value)
+ *
+ * Asserts that the target is less than `value`.
+ *
+ * expect(5).to.be.below(10);
+ *
+ * @name below
+ * @alias lt
+ * @param {Number} value
+ * @api public
+ */
+
+Assertion.prototype.below = function (val) {
+ this.assert(
+ flag(this, 'object') < val
+ , 'expected #{this} to be below ' + val
+ , 'expected #{this} to be above ' + val);
+
+ return this;
+};
+
+/**
+ * ### .within(start, finish)
+ *
+ * Asserts that the target is within a range.
+ *
+ * expect(7).to.be.within(5,10);
+ *
+ * @name within
+ * @param {Number} start lowerbound inclusive
+ * @param {Number} finish upperbound inclusive
+ * @api public
+ */
+
+Assertion.prototype.within = function (start, finish) {
+ var obj = flag(this, 'object')
+ , range = start + '..' + finish;
+
+ this.assert(
+ obj >= start && obj <= finish
+ , 'expected #{this} to be within ' + range
+ , 'expected #{this} to not be within ' + range);
+
+ return this;
+};
+
+/**
+ * ### .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
+ * @alias instanceOf
+ * @api public
+ */
+
+Assertion.prototype.instanceOf = function (constructor) {
+ var name = util.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);
+
+ return this;
+};
+
+/**
+ * ### .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');
+ * expect(obj).to.have.property('foo').to.be.a('string');
+ *
+ * // 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');
+ *
+ * @name property
+ * @param {String} name
+ * @param {Mixed} value (optional)
+ * @returns value of property for chaining
+ * @api public
+ */
+
+Assertion.prototype.property = function (name, val) {
+ var obj = flag(this, 'object')
+ , value = flag(this, 'deep') ? util.getPathValue(name, obj) : obj[name]
+ , descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
+ , negate = flag(this, 'negate');
+
+ if (negate && undefined !== val) {
+ if (undefined === value) {
+ throw new Error(util.inspect(obj) + ' has no ' + descriptor + util.inspect(name));
+ }
+ } else {
+ this.assert(
+ undefined !== value
+ , 'expected #{this} to have a ' + descriptor + util.inspect(name)
+ , 'expected #{this} to not have ' + descriptor + util.inspect(name));
+ }
+
+ if (undefined !== val) {
+ this.assert(
+ val === value
+ , 'expected #{this} to have a ' + descriptor + util.inspect(name) + ' of #{exp}, but got #{act}'
+ , 'expected #{this} to not have a ' + descriptor + util.inspect(name) + ' of #{act}'
+ , val
+ , value
+ );
+ }
+
+ flag(this, 'object', value);
+ return this;
+};
+
+/**
+ * ### .ownProperty(name)
+ *
+ * Asserts that the target has an own property `name`.
+ *
+ * expect('test').to.have.ownProperty('length');
+ *
+ * @name ownProperty
+ * @alias haveOwnProperty
+ * @param {String} name
+ * @api public
+ */
+
+Assertion.prototype.ownProperty = function (name) {
+ var obj = flag(this, 'object');
+ this.assert(
+ obj.hasOwnProperty(name)
+ , 'expected #{this} to have own property ' + util.inspect(name)
+ , 'expected #{this} to not have own property ' + util.inspect(name));
+ return this;
+};
+
+/**
+ * ### .length(value)
+ *
+ * Asserts that the target's `length` property has the expected value.
+ *
+ * expect([1,2,3]).to.have.length(3);
+ * expect('foobar').to.have.length(6);
+ *
+ * @name length
+ * @alias lengthOf
+ * @param {Number} length
+ * @api public
+ */
+
+Assertion.prototype.length = function (n) {
+ var obj = flag(this, 'object');
+ new Assertion(obj).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
+ );
+
+ return this;
+};
+
+/**
+ * ### .match(regexp)
+ *
+ * Asserts that the target matches a regular expression.
+ *
+ * expect('foobar').to.match(/^foo/);
+ *
+ * @name match
+ * @param {RegExp} RegularExpression
+ * @api public
+ */
+
+Assertion.prototype.match = function (re) {
+ var obj = flag(this, 'object');
+ this.assert(
+ re.exec(obj)
+ , 'expected #{this} to match ' + re
+ , 'expected #{this} not to match ' + re);
+
+ return this;
+};
+
+
+/**
+ * ### .string(string)
+ *
+ * Asserts that the string target contains another string.
+ *
+ * expect('foobar').to.have.string('bar');
+ *
+ * @name string
+ * @param {String} string
+ * @api public
+ */
+
+Assertion.prototype.string = function (str) {
+ var obj = flag(this, 'object');
+ new Assertion(obj).is.a('string');
+
+ this.assert(
+ ~obj.indexOf(str)
+ , 'expected #{this} to contain ' + util.inspect(str)
+ , 'expected #{this} to not contain ' + util.inspect(str));
+
+ return this;
+};
+
+/**
+ * ### .keys(key1, [key2], [...])
+ *
+ * Asserts that the target has exactly the given keys, or
+ * asserts the inclusion of some keys when using the
+ * `include` or `contain` modifiers.
+ *
+ * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']);
+ * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar');
+ *
+ * @name keys
+ * @alias key
+ * @param {String...|Array} keys
+ * @api public
+ */
+
+Assertion.prototype.keys = function(keys) {
+ var obj = flag(this, 'object')
+ , str
+ , ok = true;
+
+ keys = keys instanceof Array
+ ? keys
+ : Array.prototype.slice.call(arguments);
+
+ if (!keys.length) throw new Error('keys required');
+
+ var actual = Object.keys(obj)
+ , len = keys.length;
+
+ // Inclusion
+ ok = keys.every(function(key){
+ return ~actual.indexOf(key);
+ });
+
+ // Strict
+ if (!flag(this, 'negate') && !flag(this, 'contains')) {
+ ok = ok && keys.length == actual.length;
+ }
+
+ // Key string
+ if (len > 1) {
+ keys = keys.map(function(key){
+ return util.inspect(key);
+ });
+ var last = keys.pop();
+ str = keys.join(', ') + ', and ' + last;
+ } else {
+ str = util.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
+ , keys
+ , Object.keys(obj)
+ );
+
+ return this;
+}
+
+/**
+ * ### .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);
+ * expect(fn).to.not.throw(new RangeError('Out of range.'));
+ *
+ * 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
+ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
+ * @api public
+ */
+
+Assertion.prototype.Throw = function (constructor, msg) {
+ var obj = flag(this, 'object');
+ new Assertion(obj).is.a('function');
+
+ var thrown = false
+ , desiredError = null
+ , name = null;
+
+ if (arguments.length === 0) {
+ msg = null;
+ constructor = null;
+ } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
+ msg = constructor;
+ constructor = null;
+ } else if (constructor && constructor instanceof Error) {
+ desiredError = constructor;
+ constructor = null;
+ msg = null;
+ } else if (typeof constructor === 'function') {
+ 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 ' + util.inspect(desiredError) + ' but ' + util.inspect(err) + ' was thrown'
+ , 'expected #{this} to not throw ' + util.inspect(desiredError)
+ );
+ return this;
+ }
+ // next, check constructor
+ if (constructor) {
+ this.assert(
+ err instanceof constructor
+ , 'expected #{this} to throw ' + name + ' but a ' + err.name + ' was thrown'
+ , 'expected #{this} to not throw ' + name );
+ if (!msg) return this;
+ }
+ // next, check message
+ if (err.message && msg && msg instanceof RegExp) {
+ this.assert(
+ msg.exec(err.message)
+ , 'expected #{this} to throw error matching ' + msg + ' but got ' + util.inspect(err.message)
+ , 'expected #{this} to throw error not matching ' + msg
+ );
+ return this;
+ } else if (err.message && msg && 'string' === typeof msg) {
+ this.assert(
+ ~err.message.indexOf(msg)
+ , 'expected #{this} to throw error including #{exp} but got #{act}'
+ , 'expected #{this} to throw error not including #{act}'
+ , msg
+ , err.message
+ );
+ return this;
+ } else {
+ thrown = true;
+ }
+ }
+
+ var expectedThrown = name ? name : desiredError ? util.inspect(desiredError) : 'an error';
+
+ this.assert(
+ thrown === true
+ , 'expected #{this} to throw ' + expectedThrown
+ , 'expected #{this} to not throw ' + expectedThrown);
+
+ return this;
+};
+
+/**
+ * ### .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
+ * @param {String} method
+ * @api public
+ */
+
+Assertion.prototype.respondTo = function (method) {
+ var obj = flag(this, 'object')
+ , itself = flag(this, 'itself')
+ , context = ('function' === typeof obj && !itself)
+ ? obj.prototype[method]
+ : obj[method];
+
+ this.assert(
+ 'function' === typeof context
+ , 'expected #{this} to respond to ' + util.inspect(method)
+ , 'expected #{this} to not respond to ' + util.inspect(method)
+ , 'function'
+ , typeof context
+ );
+
+ return this;
+};
+
+/**
+ * ### .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
+ * @api public
+ */
+Object.defineProperty(Assertion.prototype, 'itself',
+ { get: function () {
+ flag(this, 'itself', true);
+ return this;
+ }
+ , configurable: true
+});
+
+/**
+ * ### .satisfy(method)
+ *
+ * Asserts that the target passes a given truth test.
+ *
+ * expect(1).to.satisfy(function(num) { return num > 0; });
+ *
+ * @name satisfy
+ * @param {Function} matcher
+ * @api public
+ */
+
+Assertion.prototype.satisfy = function (matcher) {
+ var obj = flag(this, 'object');
+ this.assert(
+ matcher(obj)
+ , 'expected #{this} to satisfy ' + util.inspect(matcher)
+ , 'expected #{this} to not satisfy' + util.inspect(matcher)
+ , this.negate ? false : true
+ , matcher(obj)
+ );
+
+ return this;
+};
+
+/**
+ * ### .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
+ * @param {Number} expected
+ * @param {Number} delta
+ * @api public
+ */
+
+Assertion.prototype.closeTo = function (expected, delta) {
+ var obj = flag(this, 'object');
+ this.assert(
+ (obj - delta === expected) || (obj + delta === expected)
+ , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
+ , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta);
+
+ return this;
+};
+
+/*!
+ * Aliases.
+ */
+
+(function alias(name, as){
+ Assertion.prototype[as] = Assertion.prototype[name];
+ return alias;
+})
+('equal', 'eq')
+('above', 'gt')
+('below', 'lt')
+('length', 'lengthOf')
+('keys', 'key')
+('ownProperty', 'haveOwnProperty')
+('above', 'greaterThan')
+('below', 'lessThan')
+('Throw', 'throws')
+('Throw', 'throw')
+('instanceOf', 'instanceof');
+
+}); // module: assertion.js
+
+require.register("browser/error.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+module.exports = AssertionError;
+
+function AssertionError (options) {
+ options = options || {};
+ this.message = options.message;
+ this.actual = options.actual;
+ this.expected = options.expected;
+ this.operator = options.operator;
+
+ if (options.stackStartFunction && Error.captureStackTrace) {
+ var stackStartFunction = options.stackStartFunction;
+ Error.captureStackTrace(this, stackStartFunction);
+ }
+}
+
+AssertionError.prototype = Object.create(Error.prototype);
+AssertionError.prototype.name = 'AssertionError';
+AssertionError.prototype.constructor = AssertionError;
+
+AssertionError.prototype.toString = function() {
+ return this.message;
+};
+
+}); // module: browser/error.js
+
+require.register("chai.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+var used = []
+ , exports = module.exports = {};
+
+/*!
+ * Chai version
+ */
+
+exports.version = '1.0.4';
+
+/*!
+ * Primary `Assertion` prototype
+ */
+
+exports.Assertion = require('./assertion');
+
+/*!
+ * Assertion Error
+ */
+
+exports.AssertionError = require('./browser/error');
+
+/*!
+ * Utils for plugins (not exported)
+ */
+
+var util = require('./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;
+};
+
+/*!
+ * Expect interface
+ */
+
+var expect = require('./interface/expect');
+exports.use(expect);
+
+/*!
+ * Should interface
+ */
+
+var should = require('./interface/should');
+exports.use(should);
+
+/*!
+ * Assert interface
+ */
+
+var assert = require('./interface/assert');
+exports.use(assert);
+
+}); // module: chai.js
+
+require.register("interface/assert.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <[email protected]>
+ * 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
+ * @api public
+ */
+
+ var assert = chai.assert = function (express, errmsg) {
+ var test = new Assertion(null);
+ 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
+ * @api public
+ */
+
+ assert.fail = function (actual, expected, message, operator) {
+ throw new chai.AssertionError({
+ actual: actual
+ , expected: expected
+ , message: message
+ , operator: operator
+ , stackStartFunction: assert.fail
+ });
+ };
+
+ /**
+ * ### .ok(object, [message])
+ *
+ * Asserts that `object` is truthy.
+ *
+ * assert.ok('everything', 'everything is ok');
+ * assert.ok(false, 'this will fail');
+ *
+ * @name ok
+ * @param {Mixed} object to test
+ * @param {String} message
+ * @api public
+ */
+
+ assert.ok = function (val, msg) {
+ new Assertion(val, msg).is.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
+ * @api public
+ */
+
+ assert.equal = function (act, exp, msg) {
+ var test = new Assertion(act, msg);
+
+ 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
+ * @api public
+ */
+
+ assert.notEqual = function (act, exp, msg) {
+ var test = new Assertion(act, msg);
+
+ 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
+ * @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
+ * @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
+ * @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
+ * @api public
+ */
+
+ assert.notDeepEqual = function (act, exp, msg) {
+ new Assertion(act, msg).to.not.eql(exp);
+ };
+
+ /**
+ * ### .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
+ * @api public
+ */
+
+ assert.isTrue = function (val, msg) {
+ new Assertion(val, msg).is['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
+ * @api public
+ */
+
+ assert.isFalse = function (val, msg) {
+ new Assertion(val, msg).is['false'];
+ };
+
+ /**
+ * ### .isNull(value, [message])
+ *
+ * Asserts that `value` is null.
+ *
+ * assert.isNull(err, 'there was no error');
+ *
+ * @name isNull
+ * @param {Mixed} value
+ * @param {String} message
+ * @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
+ * @api public
+ */
+
+ assert.isNotNull = function (val, msg) {
+ new Assertion(val, msg).to.not.equal(null);
+ };
+
+ /**
+ * ### .isUndefined(value, [message])
+ *
+ * Asserts that `value` is `undefined`.
+ *
+ * var tea;
+ * assert.isUndefined(tea, 'no tea defined');
+ *
+ * @name isUndefined
+ * @param {Mixed} value
+ * @param {String} message
+ * @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 isUndefined
+ * @param {Mixed} value
+ * @param {String} message
+ * @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
+ * @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
+ * @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
+ * @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.isObject(selection, 'tea selection is not an object');
+ * assert.isObject(null, 'null is not an object');
+ *
+ * @name isNotObject
+ * @param {Mixed} value
+ * @param {String} message
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @api public
+ */
+
+ assert.include = function (exp, inc, msg) {
+ var obj = new Assertion(exp, msg);
+
+ if (Array.isArray(exp)) {
+ obj.to.include(inc);
+ } else if ('string' === typeof exp) {
+ obj.to.contain.string(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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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
+ * @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', 5, 'string has length of 6');
+ *
+ * @name lengthOf
+ * @param {Mixed} object
+ * @param {Number} length
+ * @param {String} message
+ * @api public
+ */
+
+ assert.lengthOf = function (exp, len, msg) {
+ new Assertion(exp, msg).to.have.length(len);
+ };
+
+ /**
+ * ### .throws(function, [constructor/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.throw(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
+ * @api public
+ */
+
+ assert.Throw = function (fn, type, msg) {
+ if ('string' === typeof type) {
+ msg = type;
+ type = null;
+ }
+
+ new Assertion(fn, msg).to.Throw(type);
+ };
+
+ /**
+ * ### .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
+ * @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
+ * @api public
+ */
+
+ assert.operator = function (val, operator, val2, msg) {
+ if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) {
+ throw new Error('Invalid operator "' + operator + '"');
+ }
+ var test = new Assertion(eval(val + operator + val2), 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) );
+ };
+
+ /*!
+ * Undocumented / untested
+ */
+
+ assert.ifError = function (val, msg) {
+ new Assertion(val, msg).to.not.be.ok;
+ };
+
+ /*!
+ * Aliases.
+ */
+
+ (function alias(name, as){
+ assert[as] = assert[name];
+ return alias;
+ })
+ ('Throw', 'throw')
+ ('Throw', 'throws');
+};
+
+}); // module: interface/assert.js
+
+require.register("interface/expect.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+module.exports = function (chai, util) {
+ chai.expect = function (val, message) {
+ return new chai.Assertion(val, message);
+ };
+};
+
+
+}); // module: interface/expect.js
+
+require.register("interface/should.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011-2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+module.exports = function (chai, util) {
+ var Assertion = chai.Assertion;
+
+ function loadShould () {
+ // modify Object.prototype to have `should`
+ Object.defineProperty(Object.prototype, 'should',
+ { set: function () {}
+ , get: function(){
+ if (this instanceof String || this instanceof Number) {
+ return new Assertion(this.constructor(this));
+ } else if (this instanceof Boolean) {
+ return new Assertion(this == true);
+ }
+ return new Assertion(this);
+ }
+ , configurable: true
+ });
+
+ var should = {};
+
+ should.equal = function (val1, val2) {
+ new Assertion(val1).to.equal(val2);
+ };
+
+ should.Throw = function (fn, errt, errs) {
+ new Assertion(fn).to.Throw(errt, errs);
+ };
+
+ should.exist = function (val) {
+ new Assertion(val).to.exist;
+ }
+
+ // negation
+ should.not = {}
+
+ should.not.equal = function (val1, val2) {
+ new Assertion(val1).to.not.equal(val2);
+ };
+
+ should.not.Throw = function (fn, errt, errs) {
+ new Assertion(fn).to.not.Throw(errt, errs);
+ };
+
+ should.not.exist = function (val) {
+ new Assertion(val).to.not.exist;
+ }
+
+ should['throw'] = should['Throw'];
+ should.not['throw'] = should.not['Throw'];
+
+ return should;
+ };
+
+ chai.should = loadShould;
+ chai.Should = loadShould;
+};
+
+}); // module: interface/should.js
+
+require.register("utils/addChainableMethod.js", function(module, exports, require){
+/*!
+ * Chai - addChainingMethod utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/*!
+ * Module dependencies
+ */
+
+var transferFlags = require('./transferFlags');
+
+/**
+ * ### 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
+ * @name addChainableMethod
+ * @api public
+ */
+
+module.exports = function (ctx, name, method, chainingBehavior) {
+ if (typeof chainingBehavior !== 'function')
+ chainingBehavior = function () { };
+
+ Object.defineProperty(ctx, name,
+ { get: function () {
+ chainingBehavior.call(this);
+
+ var assert = function () {
+ var result = method.apply(this, arguments);
+ return result === undefined ? this : result;
+ };
+
+ // Re-enumerate every time to better accomodate plugins.
+ var asserterNames = Object.getOwnPropertyNames(ctx);
+ asserterNames.forEach(function (asserterName) {
+ var pd = Object.getOwnPropertyDescriptor(ctx, asserterName)
+ , functionProtoPD = Object.getOwnPropertyDescriptor(Function.prototype, asserterName);
+ // Avoid trying to overwrite things that we can't, like `length` and `arguments`.
+ if (functionProtoPD && !functionProtoPD.configurable) return;
+ if (asserterName === 'arguments') return; // @see chaijs/chai/issues/69
+ Object.defineProperty(assert, asserterName, pd);
+ });
+
+ transferFlags(this, assert);
+ return assert;
+ }
+ , configurable: true
+ });
+};
+
+}); // module: utils/addChainableMethod.js
+
+require.register("utils/addMethod.js", function(module, exports, require){
+/*!
+ * Chai - addMethod utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/**
+ * ### 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
+ * @name addMethod
+ * @api public
+ */
+
+module.exports = function (ctx, name, method) {
+ ctx[name] = function () {
+ var result = method.apply(this, arguments);
+ return result === undefined ? this : result;
+ };
+};
+
+}); // module: utils/addMethod.js
+
+require.register("utils/addProperty.js", function(module, exports, require){
+/*!
+ * Chai - addProperty utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/**
+ * ### 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
+ * @name addProperty
+ * @api public
+ */
+
+module.exports = function (ctx, name, getter) {
+ Object.defineProperty(ctx, name,
+ { get: function () {
+ var result = getter.call(this);
+ return result === undefined ? this : result;
+ }
+ , configurable: true
+ });
+};
+
+}); // module: utils/addProperty.js
+
+require.register("utils/eql.js", function(module, exports, require){
+// This is directly from Node.js assert
+// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js
+
+
+module.exports = _deepEqual;
+
+// For browser implementation
+if (!Buffer) {
+ var Buffer = {
+ isBuffer: function () {
+ return false;
+ }
+ };
+}
+
+function _deepEqual(actual, expected) {
+ // 7.1. All identical values are equivalent, as determined by ===.
+ if (actual === expected) {
+ return true;
+
+ } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
+ if (actual.length != expected.length) return false;
+
+ for (var i = 0; i < actual.length; i++) {
+ if (actual[i] !== expected[i]) return false;
+ }
+
+ return true;
+
+ // 7.2. If the expected value is a Date object, the actual value is
+ // equivalent if it is also a Date object that refers to the same time.
+ } else if (actual instanceof Date && expected instanceof Date) {
+ return actual.getTime() === expected.getTime();
+
+ // 7.3. Other pairs that do not both pass typeof value == 'object',
+ // equivalence is determined by ==.
+ } else if (typeof actual != 'object' && typeof expected != 'object') {
+ return actual === expected;
+
+ // 7.4. For all other Object pairs, including Array objects, equivalence is
+ // determined by having the same number of owned properties (as verified
+ // with Object.prototype.hasOwnProperty.call), the same set of keys
+ // (although not necessarily the same order), equivalent values for every
+ // corresponding key, and an identical 'prototype' property. Note: this
+ // accounts for both named and indexed properties on Arrays.
+ } else {
+ return objEquiv(actual, expected);
+ }
+}
+
+function isUndefinedOrNull(value) {
+ return value === null || value === undefined;
+}
+
+function isArguments(object) {
+ return Object.prototype.toString.call(object) == '[object Arguments]';
+}
+
+function objEquiv(a, b) {
+ if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
+ return false;
+ // an identical 'prototype' property.
+ if (a.prototype !== b.prototype) return false;
+ //~~~I've managed to break Object.keys through screwy arguments passing.
+ // Converting to array solves the problem.
+ if (isArguments(a)) {
+ if (!isArguments(b)) {
+ return false;
+ }
+ a = pSlice.call(a);
+ b = pSlice.call(b);
+ return _deepEqual(a, b);
+ }
+ try {
+ var ka = Object.keys(a),
+ kb = Object.keys(b),
+ key, i;
+ } catch (e) {//happens when one is a string literal and the other isn't
+ return false;
+ }
+ // having the same number of owned properties (keys incorporates
+ // hasOwnProperty)
+ if (ka.length != kb.length)
+ return false;
+ //the same set of keys (although not necessarily the same order),
+ ka.sort();
+ kb.sort();
+ //~~~cheap key test
+ for (i = ka.length - 1; i >= 0; i--) {
+ if (ka[i] != kb[i])
+ return false;
+ }
+ //equivalent values for every corresponding key, and
+ //~~~possibly expensive deep test
+ for (i = ka.length - 1; i >= 0; i--) {
+ key = ka[i];
+ if (!_deepEqual(a[key], b[key])) return false;
+ }
+ return true;
+}
+}); // module: utils/eql.js
+
+require.register("utils/flag.js", function(module, exports, require){
+/*!
+ * Chai - flag utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * 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)
+ * @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];
+ }
+};
+
+}); // module: utils/flag.js
+
+require.register("utils/getActual.js", function(module, exports, require){
+/*!
+ * Chai - getActual utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/**
+ * # getActual(object, [actual])
+ *
+ * Returns the `actual` value for an Assertion
+ *
+ * @param {Object} object (constructed Assertion)
+ * @param {Arguments} chai.Assertion.prototype.assert arguments
+ */
+
+module.exports = function (obj, args) {
+ var actual = args[4];
+ return 'undefined' !== actual ? actual : obj.obj;
+};
+
+}); // module: utils/getActual.js
+
+require.register("utils/getMessage.js", function(module, exports, require){
+/*!
+ * Chai - message composition utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/*!
+ * Module dependancies
+ */
+
+var flag = require('./flag')
+ , getActual = require('./getActual')
+ , inspect = require('./inspect');
+
+/**
+ * # 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.
+ *
+ * Messsage template tags:
+ * - `#{this}` current asserted object
+ * - `#{act}` actual value
+ * - `#{exp}` expected value
+ *
+ * @param {Object} object (constructed Assertion)
+ * @param {Arguments} chai.Assertion.prototype.assert arguments
+ */
+
+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');
+
+ msg = msg || '';
+ msg = msg
+ .replace(/#{this}/g, inspect(val))
+ .replace(/#{act}/g, inspect(actual))
+ .replace(/#{exp}/g, inspect(expected));
+
+ return flagMsg ? flagMsg + ': ' + msg : msg;
+};
+
+}); // module: utils/getMessage.js
+
+require.register("utils/getName.js", function(module, exports, require){
+/*!
+ * Chai - getName utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/**
+ * # getName(func)
+ *
+ * Gets the name of a function, in a cross-browser way.
+ *
+ * @param {Function} a function (usually a constructor)
+ */
+
+module.exports = function (func) {
+ if (func.name) return func.name;
+
+ var match = /^\s?function ([^(]*)\(/.exec(func);
+ return match && match[1] ? match[1] : "";
+};
+
+}); // module: utils/getName.js
+
+require.register("utils/getPathValue.js", function(module, exports, require){
+/*!
+ * Chai - getPathValue utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * @see https://github.com/logicalparadox/filtr
+ * MIT Licensed
+ */
+
+/**
+ * ### .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`
+ * @name getPathValue
+ * @api public
+ */
+
+var getPathValue = module.exports = function (path, obj) {
+ var parsed = parsePath(path);
+ return _getPathValue(parsed, obj);
+};
+
+/*!
+ * ## 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`.
+ *
+ * @param {String} path
+ * @returns {Object} parsed
+ * @api private
+ */
+
+function parsePath (path) {
+ var parts = path.split('.').filter(Boolean);
+ return parts.map(function (value) {
+ var re = /([A-Za-z0-9]+)\[(\d+)\]$/
+ , mArr = re.exec(value)
+ , val;
+ if (mArr) val = { p: mArr[1], i: parseFloat(mArr[2]) };
+ return val || value;
+ });
+};
+
+/*!
+ * ## _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
+ * @returns {Object|Undefined} value
+ * @api private
+ */
+
+function _getPathValue (parsed, obj) {
+ var tmp = obj
+ , res;
+ for (var i = 0, l = parsed.length; i < l; i++) {
+ var part = parsed[i];
+ if (tmp) {
+ if ('object' === typeof part && tmp[part.p]) {
+ tmp = tmp[part.p][part.i];
+ } else {
+ tmp = tmp[part];
+ }
+ if (i == (l - 1)) res = tmp;
+ } else {
+ res = undefined;
+ }
+ }
+ return res;
+};
+
+}); // module: utils/getPathValue.js
+
+require.register("utils/index.js", function(module, exports, require){
+/*!
+ * chai
+ * Copyright(c) 2011 Jake Luer <[email protected]>
+ * MIT Licensed
+ */
+
+/*!
+ * Main exports
+ */
+
+var exports = module.exports = {};
+
+/*!
+ * test utility
+ */
+
+exports.test = require('./test');
+
+/*!
+ * message utility
+ */
+
+exports.getMessage = require('./getMessage');
+
+/*!
+ * actual utility
+ */
+
+exports.getActual = require('./getActual');
+
+/*!
+ * Inspect util
+ */
+
+exports.inspect = require('./inspect');
+
+/*!
+ * Flag utility
+ */
+
+exports.flag = require('./flag');
+
+/*!
+ * Flag transferring utility
+ */
+
+exports.transferFlags = require('./transferFlags');
+
+/*!
+ * Deep equal utility
+ */
+
+exports.eql = require('./eql');
+
+/*!
+ * Deep path value
+ */
+
+exports.getPathValue = require('./getPathValue');
+
+/*!
+ * 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');
+
+
+}); // module: utils/index.js
+
+require.register("utils/inspect.js", function(module, exports, require){
+// This is (almost) directly from Node.js utils
+// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js
+
+var getName = require('./getName');
+
+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).
+ */
+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));
+}
+
+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)) {
+ return value.inspect(recurseTimes);
+ }
+
+ // Primitive types cannot have properties
+ var primitive = formatPrimitive(ctx, value);
+ if (primitive) {
+ return primitive;
+ }
+
+ // Look up the keys of the object.
+ var visibleKeys = Object.keys(value);
+ var keys = ctx.showHidden ? Object.getOwnPropertyNames(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 n = value.name ? ': ' + value.name : '';
+ base = ' [Function' + n + ']';
+ }
+
+ // 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':
+ 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);
+}
+
+}); // module: utils/inspect.js
+
+require.register("utils/overwriteMethod.js", function(module, exports, require){
+/*!
+ * Chai - overwriteMethod utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * 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
+ * @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;
+ }
+};
+
+}); // module: utils/overwriteMethod.js
+
+require.register("utils/overwriteProperty.js", function(module, exports, require){
+/*!
+ * Chai - overwriteProperty utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * 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
+ * @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
+ });
+};
+
+}); // module: utils/overwriteProperty.js
+
+require.register("utils/test.js", function(module, exports, require){
+/*!
+ * Chai - test utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * 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
+ */
+
+module.exports = function (obj, args) {
+ var negate = flag(obj, 'negate')
+ , expr = args[0];
+ return negate ? !expr : expr;
+};
+
+}); // module: utils/test.js
+
+require.register("utils/transferFlags.js", function(module, exports, require){
+/*!
+ * Chai - transferFlags utility
+ * Copyright(c) 2012 Jake Luer <[email protected]>
+ * 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 too; usually a new assertion
+ * @param {Boolean} includeAll
+ * @name getAllFlags
+ * @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];
+ }
+ }
+};
+
+}); // module: utils/transferFlags.js
+
+
+ return require('chai');
+}); \ No newline at end of file
diff --git a/test/support/sinon-1.5.2.js b/test/support/sinon-1.5.2.js
new file mode 100644
index 00000000..c0728bbd
--- /dev/null
+++ b/test/support/sinon-1.5.2.js
@@ -0,0 +1,4153 @@
+/**
+ * Sinon.JS 1.5.2, 2012/11/27
+ *
+ * @author Christian Johansen ([email protected])
+ * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
+ *
+ * (The BSD License)
+ *
+ * Copyright (c) 2010-2012, Christian Johansen, [email protected]
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Christian Johansen nor the names of his contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var sinon = (function () {
+"use strict";
+
+var buster = (function (setTimeout, B) {
+ var isNode = typeof require == "function" && typeof module == "object";
+ var div = typeof document != "undefined" && document.createElement("div");
+ var F = function () {};
+
+ var buster = {
+ bind: function bind(obj, methOrProp) {
+ var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp;
+ var args = Array.prototype.slice.call(arguments, 2);
+ return function () {
+ var allArgs = args.concat(Array.prototype.slice.call(arguments));
+ return method.apply(obj, allArgs);
+ };
+ },
+
+ partial: function partial(fn) {
+ var args = [].slice.call(arguments, 1);
+ return function () {
+ return fn.apply(this, args.concat([].slice.call(arguments)));
+ };
+ },
+
+ create: function create(object) {
+ F.prototype = object;
+ return new F();
+ },
+
+ extend: function extend(target) {
+ if (!target) { return; }
+ for (var i = 1, l = arguments.length, prop; i < l; ++i) {
+ for (prop in arguments[i]) {
+ target[prop] = arguments[i][prop];
+ }
+ }
+ return target;
+ },
+
+ nextTick: function nextTick(callback) {
+ if (typeof process != "undefined" && process.nextTick) {
+ return process.nextTick(callback);
+ }
+ setTimeout(callback, 0);
+ },
+
+ functionName: function functionName(func) {
+ if (!func) return "";
+ if (func.displayName) return func.displayName;
+ if (func.name) return func.name;
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
+ return matches && matches[1] || "";
+ },
+
+ isNode: function isNode(obj) {
+ if (!div) return false;
+ try {
+ obj.appendChild(div);
+ obj.removeChild(div);
+ } catch (e) {
+ return false;
+ }
+ return true;
+ },
+
+ isElement: function isElement(obj) {
+ return obj && obj.nodeType === 1 && buster.isNode(obj);
+ },
+
+ isArray: function isArray(arr) {
+ return Object.prototype.toString.call(arr) == "[object Array]";
+ },
+
+ flatten: function flatten(arr) {
+ var result = [], arr = arr || [];
+ for (var i = 0, l = arr.length; i < l; ++i) {
+ result = result.concat(buster.isArray(arr[i]) ? flatten(arr[i]) : arr[i]);
+ }
+ return result;
+ },
+
+ each: function each(arr, callback) {
+ for (var i = 0, l = arr.length; i < l; ++i) {
+ callback(arr[i]);
+ }
+ },
+
+ map: function map(arr, callback) {
+ var results = [];
+ for (var i = 0, l = arr.length; i < l; ++i) {
+ results.push(callback(arr[i]));
+ }
+ return results;
+ },
+
+ parallel: function parallel(fns, callback) {
+ function cb(err, res) {
+ if (typeof callback == "function") {
+ callback(err, res);
+ callback = null;
+ }
+ }
+ if (fns.length == 0) { return cb(null, []); }
+ var remaining = fns.length, results = [];
+ function makeDone(num) {
+ return function done(err, result) {
+ if (err) { return cb(err); }
+ results[num] = result;
+ if (--remaining == 0) { cb(null, results); }
+ };
+ }
+ for (var i = 0, l = fns.length; i < l; ++i) {
+ fns[i](makeDone(i));
+ }
+ },
+
+ series: function series(fns, callback) {
+ function cb(err, res) {
+ if (typeof callback == "function") {
+ callback(err, res);
+ }
+ }
+ var remaining = fns.slice();
+ var results = [];
+ function callNext() {
+ if (remaining.length == 0) return cb(null, results);
+ var promise = remaining.shift()(next);
+ if (promise && typeof promise.then == "function") {
+ promise.then(buster.partial(next, null), next);
+ }
+ }
+ function next(err, result) {
+ if (err) return cb(err);
+ results.push(result);
+ callNext();
+ }
+ callNext();
+ },
+
+ countdown: function countdown(num, done) {
+ return function () {
+ if (--num == 0) done();
+ };
+ }
+ };
+
+ if (typeof process === "object" &&
+ typeof require === "function" && typeof module === "object") {
+ var crypto = require("crypto");
+ var path = require("path");
+
+ buster.tmpFile = function (fileName) {
+ var hashed = crypto.createHash("sha1");
+ hashed.update(fileName);
+ var tmpfileName = hashed.digest("hex");
+
+ if (process.platform == "win32") {
+ return path.join(process.env["TEMP"], tmpfileName);
+ } else {
+ return path.join("/tmp", tmpfileName);
+ }
+ };
+ }
+
+ if (Array.prototype.some) {
+ buster.some = function (arr, fn, thisp) {
+ return arr.some(fn, thisp);
+ };
+ } else {
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
+ buster.some = function (arr, fun, thisp) {
+ if (arr == null) { throw new TypeError(); }
+ arr = Object(arr);
+ var len = arr.length >>> 0;
+ if (typeof fun !== "function") { throw new TypeError(); }
+
+ for (var i = 0; i < len; i++) {
+ if (arr.hasOwnProperty(i) && fun.call(thisp, arr[i], i, arr)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
+ }
+
+ if (Array.prototype.filter) {
+ buster.filter = function (arr, fn, thisp) {
+ return arr.filter(fn, thisp);
+ };
+ } else {
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter
+ buster.filter = function (fn, thisp) {
+ if (this == null) { throw new TypeError(); }
+
+ var t = Object(this);
+ var len = t.length >>> 0;
+ if (typeof fn != "function") { throw new TypeError(); }
+
+ var res = [];
+ for (var i = 0; i < len; i++) {
+ if (i in t) {
+ var val = t[i]; // in case fun mutates this
+ if (fn.call(thisp, val, i, t)) { res.push(val); }
+ }
+ }
+
+ return res;
+ };
+ }
+
+ if (isNode) {
+ module.exports = buster;
+ buster.eventEmitter = require("./buster-event-emitter");
+ Object.defineProperty(buster, "defineVersionGetter", {
+ get: function () {
+ return require("./define-version-getter");
+ }
+ });
+ }
+
+ return buster.extend(B || {}, buster);
+}(setTimeout, buster));
+if (typeof buster === "undefined") {
+ var buster = {};
+}
+
+if (typeof module === "object" && typeof require === "function") {
+ buster = require("buster-core");
+}
+
+buster.format = buster.format || {};
+buster.format.excludeConstructors = ["Object", /^.$/];
+buster.format.quoteStrings = true;
+
+buster.format.ascii = (function () {
+
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ var specialObjects = [];
+ if (typeof global != "undefined") {
+ specialObjects.push({ obj: global, value: "[object global]" });
+ }
+ if (typeof document != "undefined") {
+ specialObjects.push({ obj: document, value: "[object HTMLDocument]" });
+ }
+ if (typeof window != "undefined") {
+ specialObjects.push({ obj: window, value: "[object Window]" });
+ }
+
+ function keys(object) {
+ var k = Object.keys && Object.keys(object) || [];
+
+ if (k.length == 0) {
+ for (var prop in object) {
+ if (hasOwn.call(object, prop)) {
+ k.push(prop);
+ }
+ }
+ }
+
+ return k.sort();
+ }
+
+ function isCircular(object, objects) {
+ if (typeof object != "object") {
+ return false;
+ }
+
+ for (var i = 0, l = objects.length; i < l; ++i) {
+ if (objects[i] === object) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function ascii(object, processed, indent) {
+ if (typeof object == "string") {
+ var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings;
+ return processed || quote ? '"' + object + '"' : object;
+ }
+
+ if (typeof object == "function" && !(object instanceof RegExp)) {
+ return ascii.func(object);
+ }
+
+ processed = processed || [];
+
+ if (isCircular(object, processed)) {
+ return "[Circular]";
+ }
+
+ if (Object.prototype.toString.call(object) == "[object Array]") {
+ return ascii.array.call(this, object, processed);
+ }
+
+ if (!object) {
+ return "" + object;
+ }
+
+ if (buster.isElement(object)) {
+ return ascii.element(object);
+ }
+
+ if (typeof object.toString == "function" &&
+ object.toString !== Object.prototype.toString) {
+ return object.toString();
+ }
+
+ for (var i = 0, l = specialObjects.length; i < l; i++) {
+ if (object === specialObjects[i].obj) {
+ return specialObjects[i].value;
+ }
+ }
+
+ return ascii.object.call(this, object, processed, indent);
+ }
+
+ ascii.func = function (func) {
+ return "function " + buster.functionName(func) + "() {}";
+ };
+
+ ascii.array = function (array, processed) {
+ processed = processed || [];
+ processed.push(array);
+ var pieces = [];
+
+ for (var i = 0, l = array.length; i < l; ++i) {
+ pieces.push(ascii.call(this, array[i], processed));
+ }
+
+ return "[" + pieces.join(", ") + "]";
+ };
+
+ ascii.object = function (object, processed, indent) {
+ processed = processed || [];
+ processed.push(object);
+ indent = indent || 0;
+ var pieces = [], properties = keys(object), prop, str, obj;
+ var is = "";
+ var length = 3;
+
+ for (var i = 0, l = indent; i < l; ++i) {
+ is += " ";
+ }
+
+ for (i = 0, l = properties.length; i < l; ++i) {
+ prop = properties[i];
+ obj = object[prop];
+
+ if (isCircular(obj, processed)) {
+ str = "[Circular]";
+ } else {
+ str = ascii.call(this, obj, processed, indent + 2);
+ }
+
+ str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+ length += str.length;
+ pieces.push(str);
+ }
+
+ var cons = ascii.constructorName.call(this, object);
+ var prefix = cons ? "[" + cons + "] " : ""
+
+ return (length + indent) > 80 ?
+ prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" :
+ prefix + "{ " + pieces.join(", ") + " }";
+ };
+
+ ascii.element = function (element) {
+ var tagName = element.tagName.toLowerCase();
+ var attrs = element.attributes, attribute, pairs = [], attrName;
+
+ for (var i = 0, l = attrs.length; i < l; ++i) {
+ attribute = attrs.item(i);
+ attrName = attribute.nodeName.toLowerCase().replace("html:", "");
+
+ if (attrName == "contenteditable" && attribute.nodeValue == "inherit") {
+ continue;
+ }
+
+ if (!!attribute.nodeValue) {
+ pairs.push(attrName + "=\"" + attribute.nodeValue + "\"");
+ }
+ }
+
+ var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+ var content = element.innerHTML;
+
+ if (content.length > 20) {
+ content = content.substr(0, 20) + "[...]";
+ }
+
+ var res = formatted + pairs.join(" ") + ">" + content + "</" + tagName + ">";
+
+ return res.replace(/ contentEditable="inherit"/, "");
+ };
+
+ ascii.constructorName = function (object) {
+ var name = buster.functionName(object && object.constructor);
+ var excludes = this.excludeConstructors || buster.format.excludeConstructors || [];
+
+ for (var i = 0, l = excludes.length; i < l; ++i) {
+ if (typeof excludes[i] == "string" && excludes[i] == name) {
+ return "";
+ } else if (excludes[i].test && excludes[i].test(name)) {
+ return "";
+ }
+ }
+
+ return name;
+ };
+
+ return ascii;
+}());
+
+if (typeof module != "undefined") {
+ module.exports = buster.format;
+}
+/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
+/*global module, require, __dirname, document*/
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+var sinon = (function (buster) {
+ var div = typeof document != "undefined" && document.createElement("div");
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ function isDOMNode(obj) {
+ var success = false;
+
+ try {
+ obj.appendChild(div);
+ success = div.parentNode == obj;
+ } catch (e) {
+ return false;
+ } finally {
+ try {
+ obj.removeChild(div);
+ } catch (e) {
+ // Remove failed, not much we can do about that
+ }
+ }
+
+ return success;
+ }
+
+ function isElement(obj) {
+ return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+ }
+
+ function isFunction(obj) {
+ return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
+ }
+
+ function mirrorProperties(target, source) {
+ for (var prop in source) {
+ if (!hasOwn.call(target, prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+
+ var sinon = {
+ wrapMethod: function wrapMethod(object, property, method) {
+ if (!object) {
+ throw new TypeError("Should wrap property of object");
+ }
+
+ if (typeof method != "function") {
+ throw new TypeError("Method wrapper should be function");
+ }
+
+ var wrappedMethod = object[property];
+
+ if (!isFunction(wrappedMethod)) {
+ throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ property + " as function");
+ }
+
+ if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+ throw new TypeError("Attempted to wrap " + property + " which is already wrapped");
+ }
+
+ if (wrappedMethod.calledBefore) {
+ var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
+ throw new TypeError("Attempted to wrap " + property + " which is already " + verb);
+ }
+
+ // IE 8 does not support hasOwnProperty on the window object.
+ var owned = hasOwn.call(object, property);
+ object[property] = method;
+ method.displayName = property;
+
+ method.restore = function () {
+ // For prototype properties try to reset by delete first.
+ // If this fails (ex: localStorage on mobile safari) then force a reset
+ // via direct assignment.
+ if (!owned) {
+ delete object[property];
+ }
+ if (object[property] === method) {
+ object[property] = wrappedMethod;
+ }
+ };
+
+ method.restore.sinon = true;
+ mirrorProperties(method, wrappedMethod);
+
+ return method;
+ },
+
+ extend: function extend(target) {
+ for (var i = 1, l = arguments.length; i < l; i += 1) {
+ for (var prop in arguments[i]) {
+ if (arguments[i].hasOwnProperty(prop)) {
+ target[prop] = arguments[i][prop];
+ }
+
+ // DONT ENUM bug, only care about toString
+ if (arguments[i].hasOwnProperty("toString") &&
+ arguments[i].toString != target.toString) {
+ target.toString = arguments[i].toString;
+ }
+ }
+ }
+
+ return target;
+ },
+
+ create: function create(proto) {
+ var F = function () {};
+ F.prototype = proto;
+ return new F();
+ },
+
+ deepEqual: function deepEqual(a, b) {
+ if (sinon.match && sinon.match.isMatcher(a)) {
+ return a.test(b);
+ }
+ if (typeof a != "object" || typeof b != "object") {
+ return a === b;
+ }
+
+ if (isElement(a) || isElement(b)) {
+ return a === b;
+ }
+
+ if (a === b) {
+ return true;
+ }
+
+ if ((a === null && b !== null) || (a !== null && b === null)) {
+ return false;
+ }
+
+ var aString = Object.prototype.toString.call(a);
+ if (aString != Object.prototype.toString.call(b)) {
+ return false;
+ }
+
+ if (aString == "[object Array]") {
+ if (a.length !== b.length) {
+ return false;
+ }
+
+ for (var i = 0, l = a.length; i < l; i += 1) {
+ if (!deepEqual(a[i], b[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ var prop, aLength = 0, bLength = 0;
+
+ for (prop in a) {
+ aLength += 1;
+
+ if (!deepEqual(a[prop], b[prop])) {
+ return false;
+ }
+ }
+
+ for (prop in b) {
+ bLength += 1;
+ }
+
+ if (aLength != bLength) {
+ return false;
+ }
+
+ return true;
+ },
+
+ functionName: function functionName(func) {
+ var name = func.displayName || func.name;
+
+ // Use function decomposition as a last resort to get function
+ // name. Does not rely on function decomposition to work - if it
+ // doesn't debugging will be slightly less informative
+ // (i.e. toString will say 'spy' rather than 'myFunc').
+ if (!name) {
+ var matches = func.toString().match(/function ([^\s\(]+)/);
+ name = matches && matches[1];
+ }
+
+ return name;
+ },
+
+ functionToString: function toString() {
+ if (this.getCall && this.callCount) {
+ var thisValue, prop, i = this.callCount;
+
+ while (i--) {
+ thisValue = this.getCall(i).thisValue;
+
+ for (prop in thisValue) {
+ if (thisValue[prop] === this) {
+ return prop;
+ }
+ }
+ }
+ }
+
+ return this.displayName || "sinon fake";
+ },
+
+ getConfig: function (custom) {
+ var config = {};
+ custom = custom || {};
+ var defaults = sinon.defaultConfig;
+
+ for (var prop in defaults) {
+ if (defaults.hasOwnProperty(prop)) {
+ config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
+ }
+ }
+
+ return config;
+ },
+
+ format: function (val) {
+ return "" + val;
+ },
+
+ defaultConfig: {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ },
+
+ timesInWords: function timesInWords(count) {
+ return count == 1 && "once" ||
+ count == 2 && "twice" ||
+ count == 3 && "thrice" ||
+ (count || 0) + " times";
+ },
+
+ calledInOrder: function (spies) {
+ for (var i = 1, l = spies.length; i < l; i++) {
+ if (!spies[i - 1].calledBefore(spies[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ orderByFirstCall: function (spies) {
+ return spies.sort(function (a, b) {
+ // uuid, won't ever be equal
+ var aCall = a.getCall(0);
+ var bCall = b.getCall(0);
+ var aId = aCall && aCall.callId || -1;
+ var bId = bCall && bCall.callId || -1;
+
+ return aId < bId ? -1 : 1;
+ });
+ },
+
+ log: function () {},
+
+ logError: function (label, err) {
+ var msg = label + " threw exception: "
+ sinon.log(msg + "[" + err.name + "] " + err.message);
+ if (err.stack) { sinon.log(err.stack); }
+
+ setTimeout(function () {
+ err.message = msg + err.message;
+ throw err;
+ }, 0);
+ },
+
+ typeOf: function (value) {
+ if (value === null) {
+ return "null";
+ }
+ else if (value === undefined) {
+ return "undefined";
+ }
+ var string = Object.prototype.toString.call(value);
+ return string.substring(8, string.length - 1).toLowerCase();
+ }
+ };
+
+ var isNode = typeof module == "object" && typeof require == "function";
+
+ if (isNode) {
+ try {
+ buster = { format: require("buster-format") };
+ } catch (e) {}
+ module.exports = sinon;
+ module.exports.spy = require("./sinon/spy");
+ module.exports.stub = require("./sinon/stub");
+ module.exports.mock = require("./sinon/mock");
+ module.exports.collection = require("./sinon/collection");
+ module.exports.assert = require("./sinon/assert");
+ module.exports.sandbox = require("./sinon/sandbox");
+ module.exports.test = require("./sinon/test");
+ module.exports.testCase = require("./sinon/test_case");
+ module.exports.assert = require("./sinon/assert");
+ module.exports.match = require("./sinon/match");
+ }
+
+ if (buster) {
+ var formatter = sinon.create(buster.format);
+ formatter.quoteStrings = false;
+ sinon.format = function () {
+ return formatter.ascii.apply(formatter, arguments);
+ };
+ } else if (isNode) {
+ try {
+ var util = require("util");
+ sinon.format = function (value) {
+ return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
+ };
+ } catch (e) {
+ /* Node, but no util module - would be very old, but better safe than
+ sorry */
+ }
+ }
+
+ return sinon;
+}(typeof buster == "object" && buster));
+
+/* @depend ../sinon.js */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Match functions
+ *
+ * @author Maximilian Antoni ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2012 Maximilian Antoni
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function assertType(value, type, name) {
+ var actual = sinon.typeOf(value);
+ if (actual !== type) {
+ throw new TypeError("Expected type of " + name + " to be " +
+ type + ", but was " + actual);
+ }
+ }
+
+ var matcher = {
+ toString: function () {
+ return this.message;
+ }
+ };
+
+ function isMatcher(object) {
+ return matcher.isPrototypeOf(object);
+ }
+
+ function matchObject(expectation, actual) {
+ if (actual === null || actual === undefined) {
+ return false;
+ }
+ for (var key in expectation) {
+ if (expectation.hasOwnProperty(key)) {
+ var exp = expectation[key];
+ var act = actual[key];
+ if (match.isMatcher(exp)) {
+ if (!exp.test(act)) {
+ return false;
+ }
+ } else if (sinon.typeOf(exp) === "object") {
+ if (!matchObject(exp, act)) {
+ return false;
+ }
+ } else if (!sinon.deepEqual(exp, act)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ matcher.or = function (m2) {
+ if (!isMatcher(m2)) {
+ throw new TypeError("Matcher expected");
+ }
+ var m1 = this;
+ var or = sinon.create(matcher);
+ or.test = function (actual) {
+ return m1.test(actual) || m2.test(actual);
+ };
+ or.message = m1.message + ".or(" + m2.message + ")";
+ return or;
+ };
+
+ matcher.and = function (m2) {
+ if (!isMatcher(m2)) {
+ throw new TypeError("Matcher expected");
+ }
+ var m1 = this;
+ var and = sinon.create(matcher);
+ and.test = function (actual) {
+ return m1.test(actual) && m2.test(actual);
+ };
+ and.message = m1.message + ".and(" + m2.message + ")";
+ return and;
+ };
+
+ var match = function (expectation, message) {
+ var m = sinon.create(matcher);
+ var type = sinon.typeOf(expectation);
+ switch (type) {
+ case "object":
+ if (typeof expectation.test === "function") {
+ m.test = function (actual) {
+ return expectation.test(actual) === true;
+ };
+ m.message = "match(" + sinon.functionName(expectation.test) + ")";
+ return m;
+ }
+ var str = [];
+ for (var key in expectation) {
+ if (expectation.hasOwnProperty(key)) {
+ str.push(key + ": " + expectation[key]);
+ }
+ }
+ m.test = function (actual) {
+ return matchObject(expectation, actual);
+ };
+ m.message = "match(" + str.join(", ") + ")";
+ break;
+ case "number":
+ m.test = function (actual) {
+ return expectation == actual;
+ };
+ break;
+ case "string":
+ m.test = function (actual) {
+ if (typeof actual !== "string") {
+ return false;
+ }
+ return actual.indexOf(expectation) !== -1;
+ };
+ m.message = "match(\"" + expectation + "\")";
+ break;
+ case "regexp":
+ m.test = function (actual) {
+ if (typeof actual !== "string") {
+ return false;
+ }
+ return expectation.test(actual);
+ };
+ break;
+ case "function":
+ m.test = expectation;
+ if (message) {
+ m.message = message;
+ } else {
+ m.message = "match(" + sinon.functionName(expectation) + ")";
+ }
+ break;
+ default:
+ m.test = function (actual) {
+ return sinon.deepEqual(expectation, actual);
+ };
+ }
+ if (!m.message) {
+ m.message = "match(" + expectation + ")";
+ }
+ return m;
+ };
+
+ match.isMatcher = isMatcher;
+
+ match.any = match(function () {
+ return true;
+ }, "any");
+
+ match.defined = match(function (actual) {
+ return actual !== null && actual !== undefined;
+ }, "defined");
+
+ match.truthy = match(function (actual) {
+ return !!actual;
+ }, "truthy");
+
+ match.falsy = match(function (actual) {
+ return !actual;
+ }, "falsy");
+
+ match.same = function (expectation) {
+ return match(function (actual) {
+ return expectation === actual;
+ }, "same(" + expectation + ")");
+ };
+
+ match.typeOf = function (type) {
+ assertType(type, "string", "type");
+ return match(function (actual) {
+ return sinon.typeOf(actual) === type;
+ }, "typeOf(\"" + type + "\")");
+ };
+
+ match.instanceOf = function (type) {
+ assertType(type, "function", "type");
+ return match(function (actual) {
+ return actual instanceof type;
+ }, "instanceOf(" + sinon.functionName(type) + ")");
+ };
+
+ function createPropertyMatcher(propertyTest, messagePrefix) {
+ return function (property, value) {
+ assertType(property, "string", "property");
+ var onlyProperty = arguments.length === 1;
+ var message = messagePrefix + "(\"" + property + "\"";
+ if (!onlyProperty) {
+ message += ", " + value;
+ }
+ message += ")";
+ return match(function (actual) {
+ if (actual === undefined || actual === null ||
+ !propertyTest(actual, property)) {
+ return false;
+ }
+ return onlyProperty || sinon.deepEqual(value, actual[property]);
+ }, message);
+ };
+ }
+
+ match.has = createPropertyMatcher(function (actual, property) {
+ if (typeof actual === "object") {
+ return property in actual;
+ }
+ return actual[property] !== undefined;
+ }, "has");
+
+ match.hasOwn = createPropertyMatcher(function (actual, property) {
+ return actual.hasOwnProperty(property);
+ }, "hasOwn");
+
+ match.bool = match.typeOf("boolean");
+ match.number = match.typeOf("number");
+ match.string = match.typeOf("string");
+ match.object = match.typeOf("object");
+ match.func = match.typeOf("function");
+ match.array = match.typeOf("array");
+ match.regexp = match.typeOf("regexp");
+ match.date = match.typeOf("date");
+
+ if (commonJSModule) {
+ module.exports = match;
+ } else {
+ sinon.match = match;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend match.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Spy functions
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var spyCall;
+ var callId = 0;
+ var push = [].push;
+ var slice = Array.prototype.slice;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function spy(object, property) {
+ if (!property && typeof object == "function") {
+ return spy.create(object);
+ }
+
+ if (!object && !property) {
+ return spy.create(function () {});
+ }
+
+ var method = object[property];
+ return sinon.wrapMethod(object, property, spy.create(method));
+ }
+
+ sinon.extend(spy, (function () {
+
+ function delegateToCalls(api, method, matchAny, actual, notCalled) {
+ api[method] = function () {
+ if (!this.called) {
+ if (notCalled) {
+ return notCalled.apply(this, arguments);
+ }
+ return false;
+ }
+
+ var currentCall;
+ var matches = 0;
+
+ for (var i = 0, l = this.callCount; i < l; i += 1) {
+ currentCall = this.getCall(i);
+
+ if (currentCall[actual || method].apply(currentCall, arguments)) {
+ matches += 1;
+
+ if (matchAny) {
+ return true;
+ }
+ }
+ }
+
+ return matches === this.callCount;
+ };
+ }
+
+ function matchingFake(fakes, args, strict) {
+ if (!fakes) {
+ return;
+ }
+
+ var alen = args.length;
+
+ for (var i = 0, l = fakes.length; i < l; i++) {
+ if (fakes[i].matches(args, strict)) {
+ return fakes[i];
+ }
+ }
+ }
+
+ function incrementCallCount() {
+ this.called = true;
+ this.callCount += 1;
+ this.notCalled = false;
+ this.calledOnce = this.callCount == 1;
+ this.calledTwice = this.callCount == 2;
+ this.calledThrice = this.callCount == 3;
+ }
+
+ function createCallProperties() {
+ this.firstCall = this.getCall(0);
+ this.secondCall = this.getCall(1);
+ this.thirdCall = this.getCall(2);
+ this.lastCall = this.getCall(this.callCount - 1);
+ }
+
+ var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
+ function createProxy(func) {
+ // Retain the function length:
+ var p;
+ if (func.length) {
+ eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
+ ") { return p.invoke(func, this, slice.call(arguments)); });");
+ }
+ else {
+ p = function proxy() {
+ return p.invoke(func, this, slice.call(arguments));
+ };
+ }
+ return p;
+ }
+
+ var uuid = 0;
+
+ // Public API
+ var spyApi = {
+ reset: function () {
+ this.called = false;
+ this.notCalled = true;
+ this.calledOnce = false;
+ this.calledTwice = false;
+ this.calledThrice = false;
+ this.callCount = 0;
+ this.firstCall = null;
+ this.secondCall = null;
+ this.thirdCall = null;
+ this.lastCall = null;
+ this.args = [];
+ this.returnValues = [];
+ this.thisValues = [];
+ this.exceptions = [];
+ this.callIds = [];
+ if (this.fakes) {
+ for (var i = 0; i < this.fakes.length; i++) {
+ this.fakes[i].reset();
+ }
+ }
+ },
+
+ create: function create(func) {
+ var name;
+
+ if (typeof func != "function") {
+ func = function () {};
+ } else {
+ name = sinon.functionName(func);
+ }
+
+ var proxy = createProxy(func);
+
+ sinon.extend(proxy, spy);
+ delete proxy.create;
+ sinon.extend(proxy, func);
+
+ proxy.reset();
+ proxy.prototype = func.prototype;
+ proxy.displayName = name || "spy";
+ proxy.toString = sinon.functionToString;
+ proxy._create = sinon.spy.create;
+ proxy.id = "spy#" + uuid++;
+
+ return proxy;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ var matching = matchingFake(this.fakes, args);
+ var exception, returnValue;
+
+ incrementCallCount.call(this);
+ push.call(this.thisValues, thisValue);
+ push.call(this.args, args);
+ push.call(this.callIds, callId++);
+
+ try {
+ if (matching) {
+ returnValue = matching.invoke(func, thisValue, args);
+ } else {
+ returnValue = (this.func || func).apply(thisValue, args);
+ }
+ } catch (e) {
+ push.call(this.returnValues, undefined);
+ exception = e;
+ throw e;
+ } finally {
+ push.call(this.exceptions, exception);
+ }
+
+ push.call(this.returnValues, returnValue);
+
+ createCallProperties.call(this);
+
+ return returnValue;
+ },
+
+ getCall: function getCall(i) {
+ if (i < 0 || i >= this.callCount) {
+ return null;
+ }
+
+ return spyCall.create(this, this.thisValues[i], this.args[i],
+ this.returnValues[i], this.exceptions[i],
+ this.callIds[i]);
+ },
+
+ calledBefore: function calledBefore(spyFn) {
+ if (!this.called) {
+ return false;
+ }
+
+ if (!spyFn.called) {
+ return true;
+ }
+
+ return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+ },
+
+ calledAfter: function calledAfter(spyFn) {
+ if (!this.called || !spyFn.called) {
+ return false;
+ }
+
+ return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+ },
+
+ withArgs: function () {
+ var args = slice.call(arguments);
+
+ if (this.fakes) {
+ var match = matchingFake(this.fakes, args, true);
+
+ if (match) {
+ return match;
+ }
+ } else {
+ this.fakes = [];
+ }
+
+ var original = this;
+ var fake = this._create();
+ fake.matchingAguments = args;
+ push.call(this.fakes, fake);
+
+ fake.withArgs = function () {
+ return original.withArgs.apply(original, arguments);
+ };
+
+ for (var i = 0; i < this.args.length; i++) {
+ if (fake.matches(this.args[i])) {
+ incrementCallCount.call(fake);
+ push.call(fake.thisValues, this.thisValues[i]);
+ push.call(fake.args, this.args[i]);
+ push.call(fake.returnValues, this.returnValues[i]);
+ push.call(fake.exceptions, this.exceptions[i]);
+ push.call(fake.callIds, this.callIds[i]);
+ }
+ }
+ createCallProperties.call(fake);
+
+ return fake;
+ },
+
+ matches: function (args, strict) {
+ var margs = this.matchingAguments;
+
+ if (margs.length <= args.length &&
+ sinon.deepEqual(margs, args.slice(0, margs.length))) {
+ return !strict || margs.length == args.length;
+ }
+ },
+
+ printf: function (format) {
+ var spy = this;
+ var args = slice.call(arguments, 1);
+ var formatter;
+
+ return (format || "").replace(/%(.)/g, function (match, specifyer) {
+ formatter = spyApi.formatters[specifyer];
+
+ if (typeof formatter == "function") {
+ return formatter.call(null, spy, args);
+ } else if (!isNaN(parseInt(specifyer), 10)) {
+ return sinon.format(args[specifyer - 1]);
+ }
+
+ return "%" + specifyer;
+ });
+ }
+ };
+
+ delegateToCalls(spyApi, "calledOn", true);
+ delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn");
+ delegateToCalls(spyApi, "calledWith", true);
+ delegateToCalls(spyApi, "calledWithMatch", true);
+ delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith");
+ delegateToCalls(spyApi, "alwaysCalledWithMatch", false, "calledWithMatch");
+ delegateToCalls(spyApi, "calledWithExactly", true);
+ delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly");
+ delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith",
+ function () { return true; });
+ delegateToCalls(spyApi, "neverCalledWithMatch", false, "notCalledWithMatch",
+ function () { return true; });
+ delegateToCalls(spyApi, "threw", true);
+ delegateToCalls(spyApi, "alwaysThrew", false, "threw");
+ delegateToCalls(spyApi, "returned", true);
+ delegateToCalls(spyApi, "alwaysReturned", false, "returned");
+ delegateToCalls(spyApi, "calledWithNew", true);
+ delegateToCalls(spyApi, "alwaysCalledWithNew", false, "calledWithNew");
+ delegateToCalls(spyApi, "callArg", false, "callArgWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+ });
+ spyApi.callArgWith = spyApi.callArg;
+ delegateToCalls(spyApi, "yield", false, "yield", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+ });
+ // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+ spyApi.invokeCallback = spyApi.yield;
+ delegateToCalls(spyApi, "yieldTo", false, "yieldTo", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + property +
+ "' since it was not yet invoked.");
+ });
+
+ spyApi.formatters = {
+ "c": function (spy) {
+ return sinon.timesInWords(spy.callCount);
+ },
+
+ "n": function (spy) {
+ return spy.toString();
+ },
+
+ "C": function (spy) {
+ var calls = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ push.call(calls, " " + spy.getCall(i).toString());
+ }
+
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
+ },
+
+ "t": function (spy) {
+ var objects = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ push.call(objects, sinon.format(spy.thisValues[i]));
+ }
+
+ return objects.join(", ");
+ },
+
+ "*": function (spy, args) {
+ var formatted = [];
+
+ for (var i = 0, l = args.length; i < l; ++i) {
+ push.call(formatted, sinon.format(args[i]));
+ }
+
+ return formatted.join(", ");
+ }
+ };
+
+ return spyApi;
+ }()));
+
+ spyCall = (function () {
+
+ function throwYieldError(proxy, text, args) {
+ var msg = sinon.functionName(proxy) + text;
+ if (args.length) {
+ msg += " Received [" + slice.call(args).join(", ") + "]";
+ }
+ throw new Error(msg);
+ }
+
+ var callApi = {
+ create: function create(spy, thisValue, args, returnValue, exception, id) {
+ var proxyCall = sinon.create(spyCall);
+ delete proxyCall.create;
+ proxyCall.proxy = spy;
+ proxyCall.thisValue = thisValue;
+ proxyCall.args = args;
+ proxyCall.returnValue = returnValue;
+ proxyCall.exception = exception;
+ proxyCall.callId = typeof id == "number" && id || callId++;
+
+ return proxyCall;
+ },
+
+ calledOn: function calledOn(thisValue) {
+ if (sinon.match && sinon.match.isMatcher(thisValue)) {
+ return thisValue.test(this.thisValue);
+ }
+ return this.thisValue === thisValue;
+ },
+
+ calledWith: function calledWith() {
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ calledWithMatch: function calledWithMatch() {
+ for (var i = 0, l = arguments.length; i < l; i += 1) {
+ var actual = this.args[i];
+ var expectation = arguments[i];
+ if (!sinon.match || !sinon.match(expectation).test(actual)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ calledWithExactly: function calledWithExactly() {
+ return arguments.length == this.args.length &&
+ this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWith: function notCalledWith() {
+ return !this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWithMatch: function notCalledWithMatch() {
+ return !this.calledWithMatch.apply(this, arguments);
+ },
+
+ returned: function returned(value) {
+ return sinon.deepEqual(value, this.returnValue);
+ },
+
+ threw: function threw(error) {
+ if (typeof error == "undefined" || !this.exception) {
+ return !!this.exception;
+ }
+
+ if (typeof error == "string") {
+ return this.exception.name == error;
+ }
+
+ return this.exception === error;
+ },
+
+ calledWithNew: function calledWithNew(thisValue) {
+ return this.thisValue instanceof this.proxy;
+ },
+
+ calledBefore: function (other) {
+ return this.callId < other.callId;
+ },
+
+ calledAfter: function (other) {
+ return this.callId > other.callId;
+ },
+
+ callArg: function (pos) {
+ this.args[pos]();
+ },
+
+ callArgWith: function (pos) {
+ var args = slice.call(arguments, 1);
+ this.args[pos].apply(null, args);
+ },
+
+ "yield": function () {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (typeof args[i] === "function") {
+ args[i].apply(null, slice.call(arguments));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+ },
+
+ yieldTo: function (prop) {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (args[i] && typeof args[i][prop] === "function") {
+ args[i][prop].apply(null, slice.call(arguments, 1));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield to '" + prop +
+ "' since no callback was passed.", args);
+ },
+
+ toString: function () {
+ var callStr = this.proxy.toString() + "(";
+ var args = [];
+
+ for (var i = 0, l = this.args.length; i < l; ++i) {
+ push.call(args, sinon.format(this.args[i]));
+ }
+
+ callStr = callStr + args.join(", ") + ")";
+
+ if (typeof this.returnValue != "undefined") {
+ callStr += " => " + sinon.format(this.returnValue);
+ }
+
+ if (this.exception) {
+ callStr += " !" + this.exception.name;
+
+ if (this.exception.message) {
+ callStr += "(" + this.exception.message + ")";
+ }
+ }
+
+ return callStr;
+ }
+ };
+ callApi.invokeCallback = callApi.yield;
+ return callApi;
+ }());
+
+ spy.spyCall = spyCall;
+
+ // This steps outside the module sandbox and will be removed
+ sinon.spyCall = spyCall;
+
+ if (commonJSModule) {
+ module.exports = spy;
+ } else {
+ sinon.spy = spy;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend spy.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global module, require, sinon*/
+/**
+ * Stub functions
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function stub(object, property, func) {
+ if (!!func && typeof func != "function") {
+ throw new TypeError("Custom stub should be function");
+ }
+
+ var wrapper;
+
+ if (func) {
+ wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
+ } else {
+ wrapper = stub.create();
+ }
+
+ if (!object && !property) {
+ return sinon.stub.create();
+ }
+
+ if (!property && !!object && typeof object == "object") {
+ for (var prop in object) {
+ if (typeof object[prop] === "function") {
+ stub(object, prop);
+ }
+ }
+
+ return object;
+ }
+
+ return sinon.wrapMethod(object, property, wrapper);
+ }
+
+ function getChangingValue(stub, property) {
+ var index = stub.callCount - 1;
+ var prop = index in stub[property] ? stub[property][index] : stub[property + "Last"];
+ stub[property + "Last"] = prop;
+
+ return prop;
+ }
+
+ function getCallback(stub, args) {
+ var callArgAt = getChangingValue(stub, "callArgAts");
+
+ if (callArgAt < 0) {
+ var callArgProp = getChangingValue(stub, "callArgProps");
+
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (!callArgProp && typeof args[i] == "function") {
+ return args[i];
+ }
+
+ if (callArgProp && args[i] &&
+ typeof args[i][callArgProp] == "function") {
+ return args[i][callArgProp];
+ }
+ }
+
+ return null;
+ }
+
+ return args[callArgAt];
+ }
+
+ var join = Array.prototype.join;
+
+ function getCallbackError(stub, func, args) {
+ if (stub.callArgAtsLast < 0) {
+ var msg;
+
+ if (stub.callArgPropsLast) {
+ msg = sinon.functionName(stub) +
+ " expected to yield to '" + stub.callArgPropsLast +
+ "', but no object with such a property was passed."
+ } else {
+ msg = sinon.functionName(stub) +
+ " expected to yield, but no callback was passed."
+ }
+
+ if (args.length > 0) {
+ msg += " Received [" + join.call(args, ", ") + "]";
+ }
+
+ return msg;
+ }
+
+ return "argument at index " + stub.callArgAtsLast + " is not a function: " + func;
+ }
+
+ var nextTick = (function () {
+ if (typeof process === "object" && typeof process.nextTick === "function") {
+ return process.nextTick;
+ } else if (typeof msSetImmediate === "function") {
+ return msSetImmediate.bind(window);
+ } else if (typeof setImmediate === "function") {
+ return setImmediate;
+ } else {
+ return function (callback) {
+ setTimeout(callback, 0);
+ };
+ }
+ })();
+
+ function callCallback(stub, args) {
+ if (stub.callArgAts.length > 0) {
+ var func = getCallback(stub, args);
+
+ if (typeof func != "function") {
+ throw new TypeError(getCallbackError(stub, func, args));
+ }
+
+ var index = stub.callCount - 1;
+
+ var callbackArguments = getChangingValue(stub, "callbackArguments");
+ var callbackContext = getChangingValue(stub, "callbackContexts");
+
+ if (stub.callbackAsync) {
+ nextTick(function() {
+ func.apply(callbackContext, callbackArguments);
+ });
+ } else {
+ func.apply(callbackContext, callbackArguments);
+ }
+ }
+ }
+
+ var uuid = 0;
+
+ sinon.extend(stub, (function () {
+ var slice = Array.prototype.slice, proto;
+
+ function throwsException(error, message) {
+ if (typeof error == "string") {
+ this.exception = new Error(message || "");
+ this.exception.name = error;
+ } else if (!error) {
+ this.exception = new Error("Error");
+ } else {
+ this.exception = error;
+ }
+
+ return this;
+ }
+
+ proto = {
+ create: function create() {
+ var functionStub = function () {
+
+ callCallback(functionStub, arguments);
+
+ if (functionStub.exception) {
+ throw functionStub.exception;
+ } else if (typeof functionStub.returnArgAt == 'number') {
+ return arguments[functionStub.returnArgAt];
+ } else if (functionStub.returnThis) {
+ return this;
+ }
+ return functionStub.returnValue;
+ };
+
+ functionStub.id = "stub#" + uuid++;
+ var orig = functionStub;
+ functionStub = sinon.spy.create(functionStub);
+ functionStub.func = orig;
+
+ functionStub.callArgAts = [];
+ functionStub.callbackArguments = [];
+ functionStub.callbackContexts = [];
+ functionStub.callArgProps = [];
+
+ sinon.extend(functionStub, stub);
+ functionStub._create = sinon.stub.create;
+ functionStub.displayName = "stub";
+ functionStub.toString = sinon.functionToString;
+
+ return functionStub;
+ },
+
+ returns: function returns(value) {
+ this.returnValue = value;
+
+ return this;
+ },
+
+ returnsArg: function returnsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.returnArgAt = pos;
+
+ return this;
+ },
+
+ returnsThis: function returnsThis() {
+ this.returnThis = true;
+
+ return this;
+ },
+
+ "throws": throwsException,
+ throwsException: throwsException,
+
+ callsArg: function callsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAts.push(pos);
+ this.callbackArguments.push([]);
+ this.callbackContexts.push(undefined);
+ this.callArgProps.push(undefined);
+
+ return this;
+ },
+
+ callsArgOn: function callsArgOn(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAts.push(pos);
+ this.callbackArguments.push([]);
+ this.callbackContexts.push(context);
+ this.callArgProps.push(undefined);
+
+ return this;
+ },
+
+ callsArgWith: function callsArgWith(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAts.push(pos);
+ this.callbackArguments.push(slice.call(arguments, 1));
+ this.callbackContexts.push(undefined);
+ this.callArgProps.push(undefined);
+
+ return this;
+ },
+
+ callsArgOnWith: function callsArgWith(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAts.push(pos);
+ this.callbackArguments.push(slice.call(arguments, 2));
+ this.callbackContexts.push(context);
+ this.callArgProps.push(undefined);
+
+ return this;
+ },
+
+ yields: function () {
+ this.callArgAts.push(-1);
+ this.callbackArguments.push(slice.call(arguments, 0));
+ this.callbackContexts.push(undefined);
+ this.callArgProps.push(undefined);
+
+ return this;
+ },
+
+ yieldsOn: function (context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAts.push(-1);
+ this.callbackArguments.push(slice.call(arguments, 1));
+ this.callbackContexts.push(context);
+ this.callArgProps.push(undefined);
+
+ return this;
+ },
+
+ yieldsTo: function (prop) {
+ this.callArgAts.push(-1);
+ this.callbackArguments.push(slice.call(arguments, 1));
+ this.callbackContexts.push(undefined);
+ this.callArgProps.push(prop);
+
+ return this;
+ },
+
+ yieldsToOn: function (prop, context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAts.push(-1);
+ this.callbackArguments.push(slice.call(arguments, 2));
+ this.callbackContexts.push(context);
+ this.callArgProps.push(prop);
+
+ return this;
+ }
+ };
+
+ // create asynchronous versions of callsArg* and yields* methods
+ for (var method in proto) {
+ // need to avoid creating anotherasync versions of the newly added async methods
+ if (proto.hasOwnProperty(method) &&
+ method.match(/^(callsArg|yields|thenYields$)/) &&
+ !method.match(/Async/)) {
+ proto[method + 'Async'] = (function (syncFnName) {
+ return function () {
+ this.callbackAsync = true;
+ return this[syncFnName].apply(this, arguments);
+ };
+ })(method);
+ }
+ }
+
+ return proto;
+
+ }()));
+
+ if (commonJSModule) {
+ module.exports = stub;
+ } else {
+ sinon.stub = stub;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false*/
+/*global module, require, sinon*/
+/**
+ * Mock functions.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var push = [].push;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function mock(object) {
+ if (!object) {
+ return sinon.expectation.create("Anonymous mock");
+ }
+
+ return mock.create(object);
+ }
+
+ sinon.mock = mock;
+
+ sinon.extend(mock, (function () {
+ function each(collection, callback) {
+ if (!collection) {
+ return;
+ }
+
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+
+ return {
+ create: function create(object) {
+ if (!object) {
+ throw new TypeError("object is null");
+ }
+
+ var mockObject = sinon.extend({}, mock);
+ mockObject.object = object;
+ delete mockObject.create;
+
+ return mockObject;
+ },
+
+ expects: function expects(method) {
+ if (!method) {
+ throw new TypeError("method is falsy");
+ }
+
+ if (!this.expectations) {
+ this.expectations = {};
+ this.proxies = [];
+ }
+
+ if (!this.expectations[method]) {
+ this.expectations[method] = [];
+ var mockObject = this;
+
+ sinon.wrapMethod(this.object, method, function () {
+ return mockObject.invokeMethod(method, this, arguments);
+ });
+
+ push.call(this.proxies, method);
+ }
+
+ var expectation = sinon.expectation.create(method);
+ push.call(this.expectations[method], expectation);
+
+ return expectation;
+ },
+
+ restore: function restore() {
+ var object = this.object;
+
+ each(this.proxies, function (proxy) {
+ if (typeof object[proxy].restore == "function") {
+ object[proxy].restore();
+ }
+ });
+ },
+
+ verify: function verify() {
+ var expectations = this.expectations || {};
+ var messages = [], met = [];
+
+ each(this.proxies, function (proxy) {
+ each(expectations[proxy], function (expectation) {
+ if (!expectation.met()) {
+ push.call(messages, expectation.toString());
+ } else {
+ push.call(met, expectation.toString());
+ }
+ });
+ });
+
+ this.restore();
+
+ if (messages.length > 0) {
+ sinon.expectation.fail(messages.concat(met).join("\n"));
+ } else {
+ sinon.expectation.pass(messages.concat(met).join("\n"));
+ }
+
+ return true;
+ },
+
+ invokeMethod: function invokeMethod(method, thisValue, args) {
+ var expectations = this.expectations && this.expectations[method];
+ var length = expectations && expectations.length || 0, i;
+
+ for (i = 0; i < length; i += 1) {
+ if (!expectations[i].met() &&
+ expectations[i].allowsCall(thisValue, args)) {
+ return expectations[i].apply(thisValue, args);
+ }
+ }
+
+ var messages = [], available, exhausted = 0;
+
+ for (i = 0; i < length; i += 1) {
+ if (expectations[i].allowsCall(thisValue, args)) {
+ available = available || expectations[i];
+ } else {
+ exhausted += 1;
+ }
+ push.call(messages, " " + expectations[i].toString());
+ }
+
+ if (exhausted === 0) {
+ return available.apply(thisValue, args);
+ }
+
+ messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
+ proxy: method,
+ args: args
+ }));
+
+ sinon.expectation.fail(messages.join("\n"));
+ }
+ };
+ }()));
+
+ var times = sinon.timesInWords;
+
+ sinon.expectation = (function () {
+ var slice = Array.prototype.slice;
+ var _invoke = sinon.spy.invoke;
+
+ function callCountInWords(callCount) {
+ if (callCount == 0) {
+ return "never called";
+ } else {
+ return "called " + times(callCount);
+ }
+ }
+
+ function expectedCallCountInWords(expectation) {
+ var min = expectation.minCalls;
+ var max = expectation.maxCalls;
+
+ if (typeof min == "number" && typeof max == "number") {
+ var str = times(min);
+
+ if (min != max) {
+ str = "at least " + str + " and at most " + times(max);
+ }
+
+ return str;
+ }
+
+ if (typeof min == "number") {
+ return "at least " + times(min);
+ }
+
+ return "at most " + times(max);
+ }
+
+ function receivedMinCalls(expectation) {
+ var hasMinLimit = typeof expectation.minCalls == "number";
+ return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+ }
+
+ function receivedMaxCalls(expectation) {
+ if (typeof expectation.maxCalls != "number") {
+ return false;
+ }
+
+ return expectation.callCount == expectation.maxCalls;
+ }
+
+ return {
+ minCalls: 1,
+ maxCalls: 1,
+
+ create: function create(methodName) {
+ var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
+ delete expectation.create;
+ expectation.method = methodName;
+
+ return expectation;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ this.verifyCallAllowed(thisValue, args);
+
+ return _invoke.apply(this, arguments);
+ },
+
+ atLeast: function atLeast(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.maxCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.minCalls = num;
+
+ return this;
+ },
+
+ atMost: function atMost(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.minCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.maxCalls = num;
+
+ return this;
+ },
+
+ never: function never() {
+ return this.exactly(0);
+ },
+
+ once: function once() {
+ return this.exactly(1);
+ },
+
+ twice: function twice() {
+ return this.exactly(2);
+ },
+
+ thrice: function thrice() {
+ return this.exactly(3);
+ },
+
+ exactly: function exactly(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not a number");
+ }
+
+ this.atLeast(num);
+ return this.atMost(num);
+ },
+
+ met: function met() {
+ return !this.failed && receivedMinCalls(this);
+ },
+
+ verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+ if (receivedMaxCalls(this)) {
+ this.failed = true;
+ sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
+ this.expectedThis);
+ }
+
+ if (!("expectedArguments" in this)) {
+ return;
+ }
+
+ if (!args) {
+ sinon.expectation.fail(this.method + " received no arguments, expected " +
+ sinon.format(this.expectedArguments));
+ }
+
+ if (args.length < this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
+ "), expected " + sinon.format(this.expectedArguments));
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
+ "), expected " + sinon.format(this.expectedArguments));
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+ ", expected " + sinon.format(this.expectedArguments));
+ }
+ }
+ },
+
+ allowsCall: function allowsCall(thisValue, args) {
+ if (this.met() && receivedMaxCalls(this)) {
+ return false;
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ return false;
+ }
+
+ if (!("expectedArguments" in this)) {
+ return true;
+ }
+
+ args = args || [];
+
+ if (args.length < this.expectedArguments.length) {
+ return false;
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ return false;
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ withArgs: function withArgs() {
+ this.expectedArguments = slice.call(arguments);
+ return this;
+ },
+
+ withExactArgs: function withExactArgs() {
+ this.withArgs.apply(this, arguments);
+ this.expectsExactArgCount = true;
+ return this;
+ },
+
+ on: function on(thisValue) {
+ this.expectedThis = thisValue;
+ return this;
+ },
+
+ toString: function () {
+ var args = (this.expectedArguments || []).slice();
+
+ if (!this.expectsExactArgCount) {
+ push.call(args, "[...]");
+ }
+
+ var callStr = sinon.spyCall.toString.call({
+ proxy: this.method, args: args
+ });
+
+ var message = callStr.replace(", [...", "[, ...") + " " +
+ expectedCallCountInWords(this);
+
+ if (this.met()) {
+ return "Expectation met: " + message;
+ }
+
+ return "Expected " + message + " (" +
+ callCountInWords(this.callCount) + ")";
+ },
+
+ verify: function verify() {
+ if (!this.met()) {
+ sinon.expectation.fail(this.toString());
+ } else {
+ sinon.expectation.pass(this.toString());
+ }
+
+ return true;
+ },
+
+ pass: function(message) {
+ sinon.assert.pass(message);
+ },
+ fail: function (message) {
+ var exception = new Error(message);
+ exception.name = "ExpectationError";
+
+ throw exception;
+ }
+ };
+ }());
+
+ if (commonJSModule) {
+ module.exports = mock;
+ } else {
+ sinon.mock = mock;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true*/
+/*global module, require, sinon*/
+/**
+ * Collections of stubs, spies and mocks.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var push = [].push;
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function getFakes(fakeCollection) {
+ if (!fakeCollection.fakes) {
+ fakeCollection.fakes = [];
+ }
+
+ return fakeCollection.fakes;
+ }
+
+ function each(fakeCollection, method) {
+ var fakes = getFakes(fakeCollection);
+
+ for (var i = 0, l = fakes.length; i < l; i += 1) {
+ if (typeof fakes[i][method] == "function") {
+ fakes[i][method]();
+ }
+ }
+ }
+
+ function compact(fakeCollection) {
+ var fakes = getFakes(fakeCollection);
+ var i = 0;
+ while (i < fakes.length) {
+ fakes.splice(i, 1);
+ }
+ }
+
+ var collection = {
+ verify: function resolve() {
+ each(this, "verify");
+ },
+
+ restore: function restore() {
+ each(this, "restore");
+ compact(this);
+ },
+
+ verifyAndRestore: function verifyAndRestore() {
+ var exception;
+
+ try {
+ this.verify();
+ } catch (e) {
+ exception = e;
+ }
+
+ this.restore();
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ add: function add(fake) {
+ push.call(getFakes(this), fake);
+ return fake;
+ },
+
+ spy: function spy() {
+ return this.add(sinon.spy.apply(sinon, arguments));
+ },
+
+ stub: function stub(object, property, value) {
+ if (property) {
+ var original = object[property];
+
+ if (typeof original != "function") {
+ if (!hasOwnProperty.call(object, property)) {
+ throw new TypeError("Cannot stub non-existent own property " + property);
+ }
+
+ object[property] = value;
+
+ return this.add({
+ restore: function () {
+ object[property] = original;
+ }
+ });
+ }
+ }
+ if (!property && !!object && typeof object == "object") {
+ var stubbedObj = sinon.stub.apply(sinon, arguments);
+
+ for (var prop in stubbedObj) {
+ if (typeof stubbedObj[prop] === "function") {
+ this.add(stubbedObj[prop]);
+ }
+ }
+
+ return stubbedObj;
+ }
+
+ return this.add(sinon.stub.apply(sinon, arguments));
+ },
+
+ mock: function mock() {
+ return this.add(sinon.mock.apply(sinon, arguments));
+ },
+
+ inject: function inject(obj) {
+ var col = this;
+
+ obj.spy = function () {
+ return col.spy.apply(col, arguments);
+ };
+
+ obj.stub = function () {
+ return col.stub.apply(col, arguments);
+ };
+
+ obj.mock = function () {
+ return col.mock.apply(col, arguments);
+ };
+
+ return obj;
+ }
+ };
+
+ if (commonJSModule) {
+ module.exports = collection;
+ } else {
+ sinon.collection = collection;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
+/*global module, require, window*/
+/**
+ * Fake timer API
+ * setTimeout
+ * setInterval
+ * clearTimeout
+ * clearInterval
+ * tick
+ * reset
+ * Date
+ *
+ * Inspired by jsUnitMockTimeOut from JsUnit
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+(function (global) {
+ var id = 1;
+
+ function addTimer(args, recurring) {
+ if (args.length === 0) {
+ throw new Error("Function requires at least 1 parameter");
+ }
+
+ var toId = id++;
+ var delay = args[1] || 0;
+
+ if (!this.timeouts) {
+ this.timeouts = {};
+ }
+
+ this.timeouts[toId] = {
+ id: toId,
+ func: args[0],
+ callAt: this.now + delay,
+ invokeArgs: Array.prototype.slice.call(args, 2)
+ };
+
+ if (recurring === true) {
+ this.timeouts[toId].interval = delay;
+ }
+
+ return toId;
+ }
+
+ function parseTime(str) {
+ if (!str) {
+ return 0;
+ }
+
+ var strings = str.split(":");
+ var l = strings.length, i = l;
+ var ms = 0, parsed;
+
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+ throw new Error("tick only understands numbers and 'h:m:s'");
+ }
+
+ while (i--) {
+ parsed = parseInt(strings[i], 10);
+
+ if (parsed >= 60) {
+ throw new Error("Invalid time " + str);
+ }
+
+ ms += parsed * Math.pow(60, (l - i - 1));
+ }
+
+ return ms * 1000;
+ }
+
+ function createObject(object) {
+ var newObject;
+
+ if (Object.create) {
+ newObject = Object.create(object);
+ } else {
+ var F = function () {};
+ F.prototype = object;
+ newObject = new F();
+ }
+
+ newObject.Date.clock = newObject;
+ return newObject;
+ }
+
+ sinon.clock = {
+ now: 0,
+
+ create: function create(now) {
+ var clock = createObject(this);
+
+ if (typeof now == "number") {
+ clock.now = now;
+ }
+
+ if (!!now && typeof now == "object") {
+ throw new TypeError("now should be milliseconds since UNIX epoch");
+ }
+
+ return clock;
+ },
+
+ setTimeout: function setTimeout(callback, timeout) {
+ return addTimer.call(this, arguments, false);
+ },
+
+ clearTimeout: function clearTimeout(timerId) {
+ if (!this.timeouts) {
+ this.timeouts = [];
+ }
+
+ if (timerId in this.timeouts) {
+ delete this.timeouts[timerId];
+ }
+ },
+
+ setInterval: function setInterval(callback, timeout) {
+ return addTimer.call(this, arguments, true);
+ },
+
+ clearInterval: function clearInterval(timerId) {
+ this.clearTimeout(timerId);
+ },
+
+ tick: function tick(ms) {
+ ms = typeof ms == "number" ? ms : parseTime(ms);
+ var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
+ var timer = this.firstTimerInRange(tickFrom, tickTo);
+
+ var firstException;
+ while (timer && tickFrom <= tickTo) {
+ if (this.timeouts[timer.id]) {
+ tickFrom = this.now = timer.callAt;
+ try {
+ this.callTimer(timer);
+ } catch (e) {
+ firstException = firstException || e;
+ }
+ }
+
+ timer = this.firstTimerInRange(previous, tickTo);
+ previous = tickFrom;
+ }
+
+ this.now = tickTo;
+
+ if (firstException) {
+ throw firstException;
+ }
+ },
+
+ firstTimerInRange: function (from, to) {
+ var timer, smallest, originalTimer;
+
+ for (var id in this.timeouts) {
+ if (this.timeouts.hasOwnProperty(id)) {
+ if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
+ continue;
+ }
+
+ if (!smallest || this.timeouts[id].callAt < smallest) {
+ originalTimer = this.timeouts[id];
+ smallest = this.timeouts[id].callAt;
+
+ timer = {
+ func: this.timeouts[id].func,
+ callAt: this.timeouts[id].callAt,
+ interval: this.timeouts[id].interval,
+ id: this.timeouts[id].id,
+ invokeArgs: this.timeouts[id].invokeArgs
+ };
+ }
+ }
+ }
+
+ return timer || null;
+ },
+
+ callTimer: function (timer) {
+ if (typeof timer.interval == "number") {
+ this.timeouts[timer.id].callAt += timer.interval;
+ } else {
+ delete this.timeouts[timer.id];
+ }
+
+ try {
+ if (typeof timer.func == "function") {
+ timer.func.apply(null, timer.invokeArgs);
+ } else {
+ eval(timer.func);
+ }
+ } catch (e) {
+ var exception = e;
+ }
+
+ if (!this.timeouts[timer.id]) {
+ if (exception) {
+ throw exception;
+ }
+ return;
+ }
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ reset: function reset() {
+ this.timeouts = {};
+ },
+
+ Date: (function () {
+ var NativeDate = Date;
+
+ function ClockDate(year, month, date, hour, minute, second, ms) {
+ // Defensive and verbose to avoid potential harm in passing
+ // explicit undefined when user does not pass argument
+ switch (arguments.length) {
+ case 0:
+ return new NativeDate(ClockDate.clock.now);
+ case 1:
+ return new NativeDate(year);
+ case 2:
+ return new NativeDate(year, month);
+ case 3:
+ return new NativeDate(year, month, date);
+ case 4:
+ return new NativeDate(year, month, date, hour);
+ case 5:
+ return new NativeDate(year, month, date, hour, minute);
+ case 6:
+ return new NativeDate(year, month, date, hour, minute, second);
+ default:
+ return new NativeDate(year, month, date, hour, minute, second, ms);
+ }
+ }
+
+ return mirrorDateProperties(ClockDate, NativeDate);
+ }())
+ };
+
+ function mirrorDateProperties(target, source) {
+ if (source.now) {
+ target.now = function now() {
+ return target.clock.now;
+ };
+ } else {
+ delete target.now;
+ }
+
+ if (source.toSource) {
+ target.toSource = function toSource() {
+ return source.toSource();
+ };
+ } else {
+ delete target.toSource;
+ }
+
+ target.toString = function toString() {
+ return source.toString();
+ };
+
+ target.prototype = source.prototype;
+ target.parse = source.parse;
+ target.UTC = source.UTC;
+ target.prototype.toUTCString = source.prototype.toUTCString;
+ return target;
+ }
+
+ var methods = ["Date", "setTimeout", "setInterval",
+ "clearTimeout", "clearInterval"];
+
+ function restore() {
+ var method;
+
+ for (var i = 0, l = this.methods.length; i < l; i++) {
+ method = this.methods[i];
+ if (global[method].hadOwnProperty) {
+ global[method] = this["_" + method];
+ } else {
+ delete global[method];
+ }
+ }
+
+ // Prevent multiple executions which will completely remove these props
+ this.methods = [];
+ }
+
+ function stubGlobal(method, clock) {
+ clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
+ clock["_" + method] = global[method];
+
+ if (method == "Date") {
+ var date = mirrorDateProperties(clock[method], global[method]);
+ global[method] = date;
+ } else {
+ global[method] = function () {
+ return clock[method].apply(clock, arguments);
+ };
+
+ for (var prop in clock[method]) {
+ if (clock[method].hasOwnProperty(prop)) {
+ global[method][prop] = clock[method][prop];
+ }
+ }
+ }
+
+ global[method].clock = clock;
+ }
+
+ sinon.useFakeTimers = function useFakeTimers(now) {
+ var clock = sinon.clock.create(now);
+ clock.restore = restore;
+ clock.methods = Array.prototype.slice.call(arguments,
+ typeof now == "number" ? 1 : 0);
+
+ if (clock.methods.length === 0) {
+ clock.methods = methods;
+ }
+
+ for (var i = 0, l = clock.methods.length; i < l; i++) {
+ stubGlobal(clock.methods[i], clock);
+ }
+
+ return clock;
+ };
+}(typeof global != "undefined" && typeof global !== "function" ? global : this));
+
+sinon.timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+};
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon;
+}
+
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Minimal Event interface implementation
+ *
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
+ * Modifications and tests by Christian Johansen.
+ *
+ * @author Sven Fuchs ([email protected])
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+
+(function () {
+ var push = [].push;
+
+ sinon.Event = function Event(type, bubbles, cancelable) {
+ this.initEvent(type, bubbles, cancelable);
+ };
+
+ sinon.Event.prototype = {
+ initEvent: function(type, bubbles, cancelable) {
+ this.type = type;
+ this.bubbles = bubbles;
+ this.cancelable = cancelable;
+ },
+
+ stopPropagation: function () {},
+
+ preventDefault: function () {
+ this.defaultPrevented = true;
+ }
+ };
+
+ sinon.EventTarget = {
+ addEventListener: function addEventListener(event, listener, useCapture) {
+ this.eventListeners = this.eventListeners || {};
+ this.eventListeners[event] = this.eventListeners[event] || [];
+ push.call(this.eventListeners[event], listener);
+ },
+
+ removeEventListener: function removeEventListener(event, listener, useCapture) {
+ var listeners = this.eventListeners && this.eventListeners[event] || [];
+
+ for (var i = 0, l = listeners.length; i < l; ++i) {
+ if (listeners[i] == listener) {
+ return listeners.splice(i, 1);
+ }
+ }
+ },
+
+ dispatchEvent: function dispatchEvent(event) {
+ var type = event.type;
+ var listeners = this.eventListeners && this.eventListeners[type] || [];
+
+ for (var i = 0; i < listeners.length; i++) {
+ if (typeof listeners[i] == "function") {
+ listeners[i].call(this, event);
+ } else {
+ listeners[i].handleEvent(event);
+ }
+ }
+
+ return !!event.defaultPrevented;
+ }
+ };
+}());
+
+/**
+ * @depend ../../sinon.js
+ * @depend event.js
+ */
+/*jslint eqeqeq: false, onevar: false*/
+/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
+/**
+ * Fake XMLHttpRequest object
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest };
+
+// wrapper for global
+(function(global) {
+ var xhr = sinon.xhr;
+ xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+ xhr.GlobalActiveXObject = global.ActiveXObject;
+ xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
+ xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
+ xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
+ ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
+
+ /*jsl:ignore*/
+ var unsafeHeaders = {
+ "Accept-Charset": true,
+ "Accept-Encoding": true,
+ "Connection": true,
+ "Content-Length": true,
+ "Cookie": true,
+ "Cookie2": true,
+ "Content-Transfer-Encoding": true,
+ "Date": true,
+ "Expect": true,
+ "Host": true,
+ "Keep-Alive": true,
+ "Referer": true,
+ "TE": true,
+ "Trailer": true,
+ "Transfer-Encoding": true,
+ "Upgrade": true,
+ "User-Agent": true,
+ "Via": true
+ };
+ /*jsl:end*/
+
+ function FakeXMLHttpRequest() {
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+ this.requestHeaders = {};
+ this.requestBody = null;
+ this.status = 0;
+ this.statusText = "";
+
+ if (typeof FakeXMLHttpRequest.onCreate == "function") {
+ FakeXMLHttpRequest.onCreate(this);
+ }
+ }
+
+ function verifyState(xhr) {
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+
+ if (xhr.sendFlag) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+ }
+
+ // filtering to enable a white-list version of Sinon FakeXhr,
+ // where whitelisted requests are passed through to real XHR
+ function each(collection, callback) {
+ if (!collection) return;
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+ function some(collection, callback) {
+ for (var index = 0; index < collection.length; index++) {
+ if(callback(collection[index]) === true) return true;
+ };
+ return false;
+ }
+ // largest arity in XHR is 5 - XHR#open
+ var apply = function(obj,method,args) {
+ switch(args.length) {
+ case 0: return obj[method]();
+ case 1: return obj[method](args[0]);
+ case 2: return obj[method](args[0],args[1]);
+ case 3: return obj[method](args[0],args[1],args[2]);
+ case 4: return obj[method](args[0],args[1],args[2],args[3]);
+ case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
+ };
+ };
+
+ FakeXMLHttpRequest.filters = [];
+ FakeXMLHttpRequest.addFilter = function(fn) {
+ this.filters.push(fn)
+ };
+ var IE6Re = /MSIE 6/;
+ FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
+ var xhr = new sinon.xhr.workingXHR();
+ each(["open","setRequestHeader","send","abort","getResponseHeader",
+ "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
+ function(method) {
+ fakeXhr[method] = function() {
+ return apply(xhr,method,arguments);
+ };
+ });
+
+ var copyAttrs = function(args) {
+ each(args, function(attr) {
+ try {
+ fakeXhr[attr] = xhr[attr]
+ } catch(e) {
+ if(!IE6Re.test(navigator.userAgent)) throw e;
+ }
+ });
+ };
+
+ var stateChange = function() {
+ fakeXhr.readyState = xhr.readyState;
+ if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ copyAttrs(["status","statusText"]);
+ }
+ if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+ copyAttrs(["responseText"]);
+ }
+ if(xhr.readyState === FakeXMLHttpRequest.DONE) {
+ copyAttrs(["responseXML"]);
+ }
+ if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr);
+ };
+ if(xhr.addEventListener) {
+ for(var event in fakeXhr.eventListeners) {
+ if(fakeXhr.eventListeners.hasOwnProperty(event)) {
+ each(fakeXhr.eventListeners[event],function(handler) {
+ xhr.addEventListener(event, handler);
+ });
+ }
+ }
+ xhr.addEventListener("readystatechange",stateChange);
+ } else {
+ xhr.onreadystatechange = stateChange;
+ }
+ apply(xhr,"open",xhrArgs);
+ };
+ FakeXMLHttpRequest.useFilters = false;
+
+ function verifyRequestSent(xhr) {
+ if (xhr.readyState == FakeXMLHttpRequest.DONE) {
+ throw new Error("Request done");
+ }
+ }
+
+ function verifyHeadersReceived(xhr) {
+ if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ throw new Error("No headers received");
+ }
+ }
+
+ function verifyResponseBodyType(body) {
+ if (typeof body != "string") {
+ var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+ body + ", which is not a string.");
+ error.name = "InvalidBodyException";
+ throw error;
+ }
+ }
+
+ sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
+ async: true,
+
+ open: function open(method, url, async, username, password) {
+ this.method = method;
+ this.url = url;
+ this.async = typeof async == "boolean" ? async : true;
+ this.username = username;
+ this.password = password;
+ this.responseText = null;
+ this.responseXML = null;
+ this.requestHeaders = {};
+ this.sendFlag = false;
+ if(sinon.FakeXMLHttpRequest.useFilters === true) {
+ var xhrArgs = arguments;
+ var defake = some(FakeXMLHttpRequest.filters,function(filter) {
+ return filter.apply(this,xhrArgs)
+ });
+ if (defake) {
+ return sinon.FakeXMLHttpRequest.defake(this,arguments);
+ }
+ }
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+ },
+
+ readyStateChange: function readyStateChange(state) {
+ this.readyState = state;
+
+ if (typeof this.onreadystatechange == "function") {
+ try {
+ this.onreadystatechange();
+ } catch (e) {
+ sinon.logError("Fake XHR onreadystatechange handler", e);
+ }
+ }
+
+ this.dispatchEvent(new sinon.Event("readystatechange"));
+ },
+
+ setRequestHeader: function setRequestHeader(header, value) {
+ verifyState(this);
+
+ if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
+ throw new Error("Refused to set unsafe header \"" + header + "\"");
+ }
+
+ if (this.requestHeaders[header]) {
+ this.requestHeaders[header] += "," + value;
+ } else {
+ this.requestHeaders[header] = value;
+ }
+ },
+
+ // Helps testing
+ setResponseHeaders: function setResponseHeaders(headers) {
+ this.responseHeaders = {};
+
+ for (var header in headers) {
+ if (headers.hasOwnProperty(header)) {
+ this.responseHeaders[header] = headers[header];
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+ }
+ },
+
+ // Currently treats ALL data as a DOMString (i.e. no Document)
+ send: function send(data) {
+ verifyState(this);
+
+ if (!/^(get|head)$/i.test(this.method)) {
+ if (this.requestHeaders["Content-Type"]) {
+ var value = this.requestHeaders["Content-Type"].split(";");
+ this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
+ } else {
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+ }
+
+ this.requestBody = data;
+ }
+
+ this.errorFlag = false;
+ this.sendFlag = this.async;
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+ if (typeof this.onSend == "function") {
+ this.onSend(this);
+ }
+ },
+
+ abort: function abort() {
+ this.aborted = true;
+ this.responseText = null;
+ this.errorFlag = true;
+ this.requestHeaders = {};
+
+ if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
+ this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
+ this.sendFlag = false;
+ }
+
+ this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
+ },
+
+ getResponseHeader: function getResponseHeader(header) {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return null;
+ }
+
+ if (/^Set-Cookie2?$/i.test(header)) {
+ return null;
+ }
+
+ header = header.toLowerCase();
+
+ for (var h in this.responseHeaders) {
+ if (h.toLowerCase() == header) {
+ return this.responseHeaders[h];
+ }
+ }
+
+ return null;
+ },
+
+ getAllResponseHeaders: function getAllResponseHeaders() {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return "";
+ }
+
+ var headers = "";
+
+ for (var header in this.responseHeaders) {
+ if (this.responseHeaders.hasOwnProperty(header) &&
+ !/^Set-Cookie2?$/i.test(header)) {
+ headers += header + ": " + this.responseHeaders[header] + "\r\n";
+ }
+ }
+
+ return headers;
+ },
+
+ setResponseBody: function setResponseBody(body) {
+ verifyRequestSent(this);
+ verifyHeadersReceived(this);
+ verifyResponseBodyType(body);
+
+ var chunkSize = this.chunkSize || 10;
+ var index = 0;
+ this.responseText = "";
+
+ do {
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.LOADING);
+ }
+
+ this.responseText += body.substring(index, index + chunkSize);
+ index += chunkSize;
+ } while (index < body.length);
+
+ var type = this.getResponseHeader("Content-Type");
+
+ if (this.responseText &&
+ (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
+ try {
+ this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+ } catch (e) {
+ // Unable to parse XML - no biggie
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ } else {
+ this.readyState = FakeXMLHttpRequest.DONE;
+ }
+ },
+
+ respond: function respond(status, headers, body) {
+ this.setResponseHeaders(headers || {});
+ this.status = typeof status == "number" ? status : 200;
+ this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
+ this.setResponseBody(body || "");
+ }
+ });
+
+ sinon.extend(FakeXMLHttpRequest, {
+ UNSENT: 0,
+ OPENED: 1,
+ HEADERS_RECEIVED: 2,
+ LOADING: 3,
+ DONE: 4
+ });
+
+ // Borrowed from JSpec
+ FakeXMLHttpRequest.parseXML = function parseXML(text) {
+ var xmlDoc;
+
+ if (typeof DOMParser != "undefined") {
+ var parser = new DOMParser();
+ xmlDoc = parser.parseFromString(text, "text/xml");
+ } else {
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(text);
+ }
+
+ return xmlDoc;
+ };
+
+ FakeXMLHttpRequest.statusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non-Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 300: "Multiple Choice",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 307: "Temporary Redirect",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Request Entity Too Large",
+ 414: "Request-URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Requested Range Not Satisfiable",
+ 417: "Expectation Failed",
+ 422: "Unprocessable Entity",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported"
+ };
+
+ sinon.useFakeXMLHttpRequest = function () {
+ sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+ if (xhr.supportsXHR) {
+ global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
+ }
+
+ if (xhr.supportsActiveX) {
+ global.ActiveXObject = xhr.GlobalActiveXObject;
+ }
+
+ delete sinon.FakeXMLHttpRequest.restore;
+
+ if (keepOnCreate !== true) {
+ delete sinon.FakeXMLHttpRequest.onCreate;
+ }
+ };
+ if (xhr.supportsXHR) {
+ global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
+ }
+
+ if (xhr.supportsActiveX) {
+ global.ActiveXObject = function ActiveXObject(objId) {
+ if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+ return new sinon.FakeXMLHttpRequest();
+ }
+
+ return new xhr.GlobalActiveXObject(objId);
+ };
+ }
+
+ return sinon.FakeXMLHttpRequest;
+ };
+
+ sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
+})(this);
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon;
+}
+
+/**
+ * @depend fake_xml_http_request.js
+ */
+/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
+/*global module, require, window*/
+/**
+ * The Sinon "server" mimics a web server that receives requests from
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
+ * both synchronously and asynchronously. To respond synchronuously, canned
+ * answers have to be provided upfront.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+sinon.fakeServer = (function () {
+ var push = [].push;
+ function F() {}
+
+ function create(proto) {
+ F.prototype = proto;
+ return new F();
+ }
+
+ function responseArray(handler) {
+ var response = handler;
+
+ if (Object.prototype.toString.call(handler) != "[object Array]") {
+ response = [200, {}, handler];
+ }
+
+ if (typeof response[2] != "string") {
+ throw new TypeError("Fake server response body should be string, but was " +
+ typeof response[2]);
+ }
+
+ return response;
+ }
+
+ var wloc = typeof window !== "undefined" ? window.location : {};
+ var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+ function matchOne(response, reqMethod, reqUrl) {
+ var rmeth = response.method;
+ var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
+ var url = response.url;
+ var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
+
+ return matchMethod && matchUrl;
+ }
+
+ function match(response, request) {
+ var requestMethod = this.getHTTPMethod(request);
+ var requestUrl = request.url;
+
+ if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+ requestUrl = requestUrl.replace(rCurrLoc, "");
+ }
+
+ if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+ if (typeof response.response == "function") {
+ var ru = response.url;
+ var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1));
+ return response.response.apply(response, args);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ return {
+ create: function () {
+ var server = create(this);
+ this.xhr = sinon.useFakeXMLHttpRequest();
+ server.requests = [];
+
+ this.xhr.onCreate = function (xhrObj) {
+ server.addRequest(xhrObj);
+ };
+
+ return server;
+ },
+
+ addRequest: function addRequest(xhrObj) {
+ var server = this;
+ push.call(this.requests, xhrObj);
+
+ xhrObj.onSend = function () {
+ server.handleRequest(this);
+ };
+
+ if (this.autoRespond && !this.responding) {
+ setTimeout(function () {
+ server.responding = false;
+ server.respond();
+ }, this.autoRespondAfter || 10);
+
+ this.responding = true;
+ }
+ },
+
+ getHTTPMethod: function getHTTPMethod(request) {
+ if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+ var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+ return !!matches ? matches[1] : request.method;
+ }
+
+ return request.method;
+ },
+
+ handleRequest: function handleRequest(xhr) {
+ if (xhr.async) {
+ if (!this.queue) {
+ this.queue = [];
+ }
+
+ push.call(this.queue, xhr);
+ } else {
+ this.processRequest(xhr);
+ }
+ },
+
+ respondWith: function respondWith(method, url, body) {
+ if (arguments.length == 1 && typeof method != "function") {
+ this.response = responseArray(method);
+ return;
+ }
+
+ if (!this.responses) { this.responses = []; }
+
+ if (arguments.length == 1) {
+ body = method;
+ url = method = null;
+ }
+
+ if (arguments.length == 2) {
+ body = url;
+ url = method;
+ method = null;
+ }
+
+ push.call(this.responses, {
+ method: method,
+ url: url,
+ response: typeof body == "function" ? body : responseArray(body)
+ });
+ },
+
+ respond: function respond() {
+ if (arguments.length > 0) this.respondWith.apply(this, arguments);
+ var queue = this.queue || [];
+ var request;
+
+ while(request = queue.shift()) {
+ this.processRequest(request);
+ }
+ },
+
+ processRequest: function processRequest(request) {
+ try {
+ if (request.aborted) {
+ return;
+ }
+
+ var response = this.response || [404, {}, ""];
+
+ if (this.responses) {
+ for (var i = 0, l = this.responses.length; i < l; i++) {
+ if (match.call(this, this.responses[i], request)) {
+ response = this.responses[i].response;
+ break;
+ }
+ }
+ }
+
+ if (request.readyState != 4) {
+ request.respond(response[0], response[1], response[2]);
+ }
+ } catch (e) {
+ sinon.logError("Fake server request processing", e);
+ }
+ },
+
+ restore: function restore() {
+ return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+ }
+ };
+}());
+
+if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon;
+}
+
+/**
+ * @depend fake_server.js
+ * @depend fake_timers.js
+ */
+/*jslint browser: true, eqeqeq: false, onevar: false*/
+/*global sinon*/
+/**
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
+ * it polls the object for completion with setInterval. Dispite the direct
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
+ * in any environment where the ajax implementation depends on setInterval or
+ * setTimeout.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function () {
+ function Server() {}
+ Server.prototype = sinon.fakeServer;
+
+ sinon.fakeServerWithClock = new Server();
+
+ sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
+ if (xhr.async) {
+ if (typeof setTimeout.clock == "object") {
+ this.clock = setTimeout.clock;
+ } else {
+ this.clock = sinon.useFakeTimers();
+ this.resetClock = true;
+ }
+
+ if (!this.longestTimeout) {
+ var clockSetTimeout = this.clock.setTimeout;
+ var clockSetInterval = this.clock.setInterval;
+ var server = this;
+
+ this.clock.setTimeout = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetTimeout.apply(this, arguments);
+ };
+
+ this.clock.setInterval = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetInterval.apply(this, arguments);
+ };
+ }
+ }
+
+ return sinon.fakeServer.addRequest.call(this, xhr);
+ };
+
+ sinon.fakeServerWithClock.respond = function respond() {
+ var returnVal = sinon.fakeServer.respond.apply(this, arguments);
+
+ if (this.clock) {
+ this.clock.tick(this.longestTimeout || 0);
+ this.longestTimeout = 0;
+
+ if (this.resetClock) {
+ this.clock.restore();
+ this.resetClock = false;
+ }
+ }
+
+ return returnVal;
+ };
+
+ sinon.fakeServerWithClock.restore = function restore() {
+ if (this.clock) {
+ this.clock.restore();
+ }
+
+ return sinon.fakeServer.restore.apply(this, arguments);
+ };
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend collection.js
+ * @depend util/fake_timers.js
+ * @depend util/fake_server_with_clock.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global require, module*/
+/**
+ * Manages fake collections as well as fake utilities such as Sinon's
+ * timers and fake XHR implementation in one convenient object.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+if (typeof module == "object" && typeof require == "function") {
+ var sinon = require("../sinon");
+ sinon.extend(sinon, require("./util/fake_timers"));
+}
+
+(function () {
+ var push = [].push;
+
+ function exposeValue(sandbox, config, key, value) {
+ if (!value) {
+ return;
+ }
+
+ if (config.injectInto) {
+ config.injectInto[key] = value;
+ } else {
+ push.call(sandbox.args, value);
+ }
+ }
+
+ function prepareSandboxFromConfig(config) {
+ var sandbox = sinon.create(sinon.sandbox);
+
+ if (config.useFakeServer) {
+ if (typeof config.useFakeServer == "object") {
+ sandbox.serverPrototype = config.useFakeServer;
+ }
+
+ sandbox.useFakeServer();
+ }
+
+ if (config.useFakeTimers) {
+ if (typeof config.useFakeTimers == "object") {
+ sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+ } else {
+ sandbox.useFakeTimers();
+ }
+ }
+
+ return sandbox;
+ }
+
+ sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
+ useFakeTimers: function useFakeTimers() {
+ this.clock = sinon.useFakeTimers.apply(sinon, arguments);
+
+ return this.add(this.clock);
+ },
+
+ serverPrototype: sinon.fakeServer,
+
+ useFakeServer: function useFakeServer() {
+ var proto = this.serverPrototype || sinon.fakeServer;
+
+ if (!proto || !proto.create) {
+ return null;
+ }
+
+ this.server = proto.create();
+ return this.add(this.server);
+ },
+
+ inject: function (obj) {
+ sinon.collection.inject.call(this, obj);
+
+ if (this.clock) {
+ obj.clock = this.clock;
+ }
+
+ if (this.server) {
+ obj.server = this.server;
+ obj.requests = this.server.requests;
+ }
+
+ return obj;
+ },
+
+ create: function (config) {
+ if (!config) {
+ return sinon.create(sinon.sandbox);
+ }
+
+ var sandbox = prepareSandboxFromConfig(config);
+ sandbox.args = sandbox.args || [];
+ var prop, value, exposed = sandbox.inject({});
+
+ if (config.properties) {
+ for (var i = 0, l = config.properties.length; i < l; i++) {
+ prop = config.properties[i];
+ value = exposed[prop] || prop == "sandbox" && sandbox;
+ exposeValue(sandbox, config, prop, value);
+ }
+ } else {
+ exposeValue(sandbox, config, "sandbox", value);
+ }
+
+ return sandbox;
+ }
+ });
+
+ sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
+
+ if (typeof module == "object" && typeof require == "function") {
+ module.exports = sinon.sandbox;
+ }
+}());
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ * @depend mock.js
+ * @depend sandbox.js
+ */
+/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Test function, sandboxes fakes
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function test(callback) {
+ var type = typeof callback;
+
+ if (type != "function") {
+ throw new TypeError("sinon.test needs to wrap a test function, got " + type);
+ }
+
+ return function () {
+ var config = sinon.getConfig(sinon.config);
+ config.injectInto = config.injectIntoThis && this || config.injectInto;
+ var sandbox = sinon.sandbox.create(config);
+ var exception, result;
+ var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
+
+ try {
+ result = callback.apply(this, args);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (typeof exception !== "undefined") {
+ sandbox.restore();
+ throw exception;
+ }
+ else {
+ sandbox.verifyAndRestore();
+ }
+
+ return result;
+ };
+ }
+
+ test.config = {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ };
+
+ if (commonJSModule) {
+ module.exports = test;
+ } else {
+ sinon.test = test;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend test.js
+ */
+/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
+/*global module, require, sinon*/
+/**
+ * Test case, sandboxes all test functions
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon || !Object.prototype.hasOwnProperty) {
+ return;
+ }
+
+ function createTest(property, setUp, tearDown) {
+ return function () {
+ if (setUp) {
+ setUp.apply(this, arguments);
+ }
+
+ var exception, result;
+
+ try {
+ result = property.apply(this, arguments);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (tearDown) {
+ tearDown.apply(this, arguments);
+ }
+
+ if (exception) {
+ throw exception;
+ }
+
+ return result;
+ };
+ }
+
+ function testCase(tests, prefix) {
+ /*jsl:ignore*/
+ if (!tests || typeof tests != "object") {
+ throw new TypeError("sinon.testCase needs an object with test functions");
+ }
+ /*jsl:end*/
+
+ prefix = prefix || "test";
+ var rPrefix = new RegExp("^" + prefix);
+ var methods = {}, testName, property, method;
+ var setUp = tests.setUp;
+ var tearDown = tests.tearDown;
+
+ for (testName in tests) {
+ if (tests.hasOwnProperty(testName)) {
+ property = tests[testName];
+
+ if (/^(setUp|tearDown)$/.test(testName)) {
+ continue;
+ }
+
+ if (typeof property == "function" && rPrefix.test(testName)) {
+ method = property;
+
+ if (setUp || tearDown) {
+ method = createTest(property, setUp, tearDown);
+ }
+
+ methods[testName] = sinon.test(method);
+ } else {
+ methods[testName] = tests[testName];
+ }
+ }
+ }
+
+ return methods;
+ }
+
+ if (commonJSModule) {
+ module.exports = testCase;
+ } else {
+ sinon.testCase = testCase;
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend ../sinon.js
+ * @depend stub.js
+ */
+/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Assertions matching the test spy retrieval interface.
+ *
+ * @author Christian Johansen ([email protected])
+ * @license BSD
+ *
+ * Copyright (c) 2010-2011 Christian Johansen
+ */
+
+(function (sinon, global) {
+ var commonJSModule = typeof module == "object" && typeof require == "function";
+ var slice = Array.prototype.slice;
+ var assert;
+
+ if (!sinon && commonJSModule) {
+ sinon = require("../sinon");
+ }
+
+ if (!sinon) {
+ return;
+ }
+
+ function verifyIsStub() {
+ var method;
+
+ for (var i = 0, l = arguments.length; i < l; ++i) {
+ method = arguments[i];
+
+ if (!method) {
+ assert.fail("fake is not a spy");
+ }
+
+ if (typeof method != "function") {
+ assert.fail(method + " is not a function");
+ }
+
+ if (typeof method.getCall != "function") {
+ assert.fail(method + " is not stubbed");
+ }
+ }
+ }
+
+ function failAssertion(object, msg) {
+ object = object || global;
+ var failMethod = object.fail || assert.fail;
+ failMethod.call(object, msg);
+ }
+
+ function mirrorPropAsAssertion(name, method, message) {
+ if (arguments.length == 2) {
+ message = method;
+ method = name;
+ }
+
+ assert[name] = function (fake) {
+ verifyIsStub(fake);
+
+ var args = slice.call(arguments, 1);
+ var failed = false;
+
+ if (typeof method == "function") {
+ failed = !method(fake);
+ } else {
+ failed = typeof fake[method] == "function" ?
+ !fake[method].apply(fake, args) : !fake[method];
+ }
+
+ if (failed) {
+ failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
+ } else {
+ assert.pass(name);
+ }
+ };
+ }
+
+ function exposedName(prefix, prop) {
+ return !prefix || /^fail/.test(prop) ? prop :
+ prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+ };
+
+ assert = {
+ failException: "AssertError",
+
+ fail: function fail(message) {
+ var error = new Error(message);
+ error.name = this.failException || assert.failException;
+
+ throw error;
+ },
+
+ pass: function pass(assertion) {},
+
+ callOrder: function assertCallOrder() {
+ verifyIsStub.apply(null, arguments);
+ var expected = "", actual = "";
+
+ if (!sinon.calledInOrder(arguments)) {
+ try {
+ expected = [].join.call(arguments, ", ");
+ actual = sinon.orderByFirstCall(slice.call(arguments)).join(", ");
+ } catch (e) {
+ // If this fails, we'll just fall back to the blank string
+ }
+
+ failAssertion(this, "expected " + expected + " to be " +
+ "called in order but were called as " + actual);
+ } else {
+ assert.pass("callOrder");
+ }
+ },
+
+ callCount: function assertCallCount(method, count) {
+ verifyIsStub(method);
+
+ if (method.callCount != count) {
+ var msg = "expected %n to be called " + sinon.timesInWords(count) +
+ " but was called %c%C";
+ failAssertion(this, method.printf(msg));
+ } else {
+ assert.pass("callCount");
+ }
+ },
+
+ expose: function expose(target, options) {
+ if (!target) {
+ throw new TypeError("target is null or undefined");
+ }
+
+ var o = options || {};
+ var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
+ var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
+
+ for (var method in this) {
+ if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
+ target[exposedName(prefix, method)] = this[method];
+ }
+ }
+
+ return target;
+ }
+ };
+
+ mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+ mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
+ "expected %n to not have been called but was called %c%C");
+ mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+ mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+ mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+ mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
+ mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
+ mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
+ mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
+ mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
+ mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
+ mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+ mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+ if (commonJSModule) {
+ module.exports = assert;
+ } else {
+ sinon.assert = assert;
+ }
+}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : global));
+
+return sinon;}.call(typeof window != 'undefined' && window || {}));
diff --git a/test/support/walk_dir.js b/test/support/walk_dir.js
new file mode 100644
index 00000000..ab4fef0e
--- /dev/null
+++ b/test/support/walk_dir.js
@@ -0,0 +1,43 @@
+var fs = require('fs');
+
+var methods = {
+ walk: function (dir, validation_function, cb) {
+ if (arguments.length === 2) {
+ cb = validation_function;
+ validation_function = null;
+ }
+
+ var results = [];
+ fs.readdir(dir, function (err, list) {
+ if (err) { return cb(err); }
+
+ var pending = list.length;
+
+ if (!pending) { return cb(null, results); }
+
+ list.forEach(function (file) {
+ file = dir + '/' + file;
+ fs.stat(file, function (err, stat) {
+ if (stat && stat.isDirectory()) {
+ methods.walk(file, validation_function, function (err, res) {
+ results = results.concat(res);
+ if (!--pending) { cb(null, results); }
+ });
+ } else {
+ if (typeof validation_function === 'function') {
+ if (validation_function(file)) {
+ results.push(file);
+ }
+ } else {
+ results.push(file);
+ }
+
+ if (!--pending) { cb(null, results); }
+ }
+ });
+ });
+ });
+ }
+};
+
+module.exports = methods;