summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarren Smith <garren.smith@gmail.com>2013-07-17 15:56:42 +0200
committerGarren Smith <garren.smith@gmail.com>2013-07-17 15:56:42 +0200
commit302109092b45c4a72f2dd15fded97b54c329ad45 (patch)
tree86a748c4de4483a97de7f906d627c559872bc8c9
parent9b64526db9e22de0c94fd6065186336ad423f4c0 (diff)
downloadcouchdb-302109092b45c4a72f2dd15fded97b54c329ad45.tar.gz
testing framework working with mocha
-rw-r--r--src/fauxton/Gruntfile.js41
-rw-r--r--src/fauxton/app/addons/logs/tests/logSpec.js33
-rw-r--r--src/fauxton/package.json3
-rw-r--r--src/fauxton/tasks/couchserver.js17
-rw-r--r--src/fauxton/tasks/fauxton.js23
-rw-r--r--src/fauxton/tasks/helper.js1
-rw-r--r--src/fauxton/test/jasmine/index.html44
-rw-r--r--src/fauxton/test/jasmine/spec/example.js73
-rw-r--r--src/fauxton/test/jasmine/vendor/MIT.LICENSE20
-rw-r--r--src/fauxton/test/jasmine/vendor/jasmine-html.js190
-rw-r--r--src/fauxton/test/jasmine/vendor/jasmine.css166
-rw-r--r--src/fauxton/test/jasmine/vendor/jasmine.js2476
-rw-r--r--src/fauxton/test/jasmine/vendor/jasmine_favicon.pngbin905 -> 0 bytes
-rw-r--r--src/fauxton/test/mocha/chai.js4330
-rwxr-xr-xsrc/fauxton/test/mocha/mocha.css251
-rwxr-xr-xsrc/fauxton/test/mocha/mocha.js5428
-rw-r--r--src/fauxton/test/qunit/index.html47
-rw-r--r--src/fauxton/test/qunit/tests/example.js54
-rw-r--r--src/fauxton/test/qunit/vendor/qunit.css228
-rw-r--r--src/fauxton/test/qunit/vendor/qunit.js1589
-rw-r--r--src/fauxton/test/runner.html16
-rw-r--r--src/fauxton/test/test.config.js67
-rw-r--r--src/fauxton/test/test.config.underscore15
23 files changed, 10198 insertions, 4914 deletions
diff --git a/src/fauxton/Gruntfile.js b/src/fauxton/Gruntfile.js
index 886272d92..474030fcf 100644
--- a/src/fauxton/Gruntfile.js
+++ b/src/fauxton/Gruntfile.js
@@ -250,18 +250,6 @@ module.exports = function(grunt) {
}
},
- // The headless QUnit testing environment is provided for "free" by Grunt.
- // Simply point the configuration to your test directory.
- qunit: {
- all: ["test/qunit/*.html"]
- },
-
- // The headless Jasmine testing is provided by grunt-jasmine-task. Simply
- // point the configuration to your test directory.
- jasmine: {
- all: ["test/jasmine/*.html"]
- },
-
// Copy build artifacts and library code into the distribution
// see - http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
copy: {
@@ -310,7 +298,19 @@ module.exports = function(grunt) {
mkcouchdb: couch_config,
rmcouchdb: couch_config,
- couchapp: couch_config
+ couchapp: couch_config,
+
+ mochaSetup: {
+ default: {
+ files: { src: helper.watchFiles(['[Ss]pec.js'], ['./app/**/*[Ss]pec.js'])},
+ template: 'test/test.config.underscore',
+ config: './app/config.js'
+ }
+ },
+
+ mocha_phantomjs: {
+ all: ['test/runner.html']
+ }
});
@@ -319,9 +319,6 @@ module.exports = function(grunt) {
if (!!filepath.match(/.js$/)) {
grunt.config(['jshint', 'all'], filepath);
}
- /*} else if (!!filepath.match(/.css$|.less$/)) {
- grunt.task.run(['less', 'concat:index_css']);
- }*/
});
/*
@@ -353,6 +350,7 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
// Load CSSMin task
grunt.loadNpmTasks('grunt-contrib-cssmin');
+ grunt.loadNpmTasks('grunt-mocha-phantomjs');
/*
* Default task
@@ -363,8 +361,9 @@ module.exports = function(grunt) {
/*
* Transformation tasks
*/
- // clean out previous build artefacts, lint and unit test
- grunt.registerTask('test', ['clean', 'jshint']); //qunit
+ // clean out previous build artefactsa and lint
+ grunt.registerTask('lint', ['clean', 'jshint']);
+ grunt.registerTask('test', ['lint', 'mochaSetup', 'mocha_phantomjs']);
// Fetch dependencies (from git or local dir), lint them and make load_addons
grunt.registerTask('dependencies', ['get_deps', 'jshint', 'gen_load_addons:default']);
// build templates, js and css
@@ -378,12 +377,12 @@ module.exports = function(grunt) {
// dev server
grunt.registerTask('dev', ['debugDev', 'couchserver']);
// build a debug release
- grunt.registerTask('debug', ['test', 'dependencies', 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
- grunt.registerTask('debugDev', ['test', 'dependencies', 'less', 'concat:index_css', 'template:development', 'copy:debug']);
+ grunt.registerTask('debug', ['lint', 'dependencies', 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
+ grunt.registerTask('debugDev', ['lint', 'dependencies', 'less', 'concat:index_css', 'template:development', 'copy:debug']);
grunt.registerTask('watchRun', ['dependencies']);
// build a release
- grunt.registerTask('release', ['test' ,'dependencies', 'build', 'minify', 'copy:dist']);
+ grunt.registerTask('release', ['lint' ,'dependencies', 'build', 'minify', 'copy:dist']);
/*
* Install into CouchDB in either debug, release, or couchapp mode
diff --git a/src/fauxton/app/addons/logs/tests/logSpec.js b/src/fauxton/app/addons/logs/tests/logSpec.js
new file mode 100644
index 000000000..7b859f0be
--- /dev/null
+++ b/src/fauxton/app/addons/logs/tests/logSpec.js
@@ -0,0 +1,33 @@
+define([
+ 'addons/logs/base',
+ 'chai'
+], function (Log, chai) {
+ var expect = chai.expect;
+
+ describe('Example AMD test', function(){
+
+ describe('Sum', function(){
+ it('Should add two numbers together', function(){
+ expect(10 + 2).to.equal(12);
+ });
+ });
+
+ describe('Log Model', function () {
+ var log;
+
+ beforeEach(function () {
+ log = new Log.Model({
+ log_level: 'DEBUG',
+ pid: '1234',
+ args: 'testing 123',
+ date: (new Date()).toString()
+ });
+ });
+
+ it('should have a log level', function () {
+ expect(log.logLevel()).to.equal('DEBUG');
+ });
+
+ });
+ });
+});
diff --git a/src/fauxton/package.json b/src/fauxton/package.json
index ad69f2f34..fd5e3d319 100644
--- a/src/fauxton/package.json
+++ b/src/fauxton/package.json
@@ -28,7 +28,8 @@
"url": "~0.7.9",
"urls": "~0.0.3",
"http-proxy": "~0.10.2",
- "send": "~0.1.1"
+ "send": "~0.1.1",
+ "grunt-mocha-phantomjs": "~0.3.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
diff --git a/src/fauxton/tasks/couchserver.js b/src/fauxton/tasks/couchserver.js
index baf2b30b6..9641a88b4 100644
--- a/src/fauxton/tasks/couchserver.js
+++ b/src/fauxton/tasks/couchserver.js
@@ -42,21 +42,28 @@ module.exports = function (grunt) {
var proxy = new httpProxy.HttpProxy(proxy_settings);
http.createServer(function (req, res) {
- var url = req.url,
+ var url = req.url.replace('app/',''),
accept = req.headers.accept.split(','),
filePath;
if (!!url.match(/assets/)) {
// serve any javascript or css files from here assets dir
- filePath = path.join('./',req.url);
+ filePath = path.join('./',url);
+ } else if (!!url.match(/mocha|test\.config/)) {
+ filePath = path.join('./test', url.replace('/test/',''));
} else if (!!url.match(/\.css|img/)) {
- filePath = path.join(dist_dir,req.url);
+ filePath = path.join(dist_dir,url);
} else if (!!url.match(/\/js/)) {
// serve any javascript or files from dist debug dir
filePath = path.join(dist_dir,req.url);
} else if (!!url.match(/\.js$|\.html$/)) {
// server js from app directory
- filePath = path.join(app_dir,req.url.replace('/_utils/fauxton/app',''));
+ filePath = path.join(app_dir, url.replace('/_utils/fauxton/',''));
+ } else if (!!url.match(/testrunner/)) {
+ var testSetup = grunt.util.spawn({cmd: 'grunt', grunt: true, args: ['mochaSetup']}, function (error, result, code) {/* log.writeln(String(result));*/ });
+ testSetup.stdout.pipe(process.stdout);
+ testSetup.stderr.pipe(process.stderr);
+ filePath = path.join('./test/runner.html');
} else if (url === '/' && accept[0] !== 'application/json') {
// serve main index file from here
filePath = path.join(dist_dir, 'index.html');
@@ -70,6 +77,8 @@ module.exports = function (grunt) {
} else {
log.writeln('ERROR', filePath, err);
}
+
+ res.end(err.message);
})
.pipe(res);
}
diff --git a/src/fauxton/tasks/fauxton.js b/src/fauxton/tasks/fauxton.js
index ac48cf385..cfcfc81e6 100644
--- a/src/fauxton/tasks/fauxton.js
+++ b/src/fauxton/tasks/fauxton.js
@@ -89,4 +89,27 @@ module.exports = function(grunt) {
grunt.file.write(dest, tmpl({deps: deps}));
});
+ grunt.registerMultiTask('mochaSetup','Generate a config.js and runner.html for tests', function(){
+ var data = this.data,
+ configInfo,
+ _ = grunt.util._,
+ configTemplateSrc = data.template,
+ testFiles = grunt.file.expand(data.files.src);
+
+ var configTemplate = _.template(grunt.file.read(configTemplateSrc));
+ // a bit of a nasty hack to read our current config.js and get the info so we can change it
+ // for our testing setup
+ var require = {
+ config: function (args) {
+ configInfo = args;
+ configInfo.paths['chai'] = "../test/mocha/chai";
+ configInfo.baseUrl = '../app';
+ delete configInfo.deps;
+ }
+ };
+
+ eval(grunt.file.read(data.config) +'');
+
+ grunt.file.write('./test/test.config.js', configTemplate({configInfo: configInfo, testFiles: testFiles}));
+ });
};
diff --git a/src/fauxton/tasks/helper.js b/src/fauxton/tasks/helper.js
index b3a9fbdd3..4b66e5573 100644
--- a/src/fauxton/tasks/helper.js
+++ b/src/fauxton/tasks/helper.js
@@ -40,7 +40,6 @@ exports.init = function(grunt) {
}
return files
}, defaults);
-
}
};
};
diff --git a/src/fauxton/test/jasmine/index.html b/src/fauxton/test/jasmine/index.html
deleted file mode 100644
index 8905580f4..000000000
--- a/src/fauxton/test/jasmine/index.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="viewport" content="width=device-width,initial-scale=1">
-
- <title>Backbone Boilerplate Jasmine Test Suite</title>
-
- <!-- Jasmine styles -->
- <link rel="stylesheet" href="vendor/jasmine.css">
-</head>
-
-<body>
- <!-- Testing libs -->
- <script src="vendor/jasmine.js"></script>
- <script src="vendor/jasmine-html.js"></script>
-
- <!-- Application libs -->
- <script src="../../assets/js/libs/jquery.js"></script>
- <script src="../../assets/js/libs/lodash.js"></script>
- <script src="../../assets/js/libs/backbone.js"></script>
-
- <!-- Load application -->
- <script data-main="../../app/config"
- src="../../assets/js/libs/require.js"></script>
-
- <!-- Declare your spec files to be run here -->
- <script>
- // Ensure you point to where your spec folder is, base directory is app/,
- // which is why ../test is necessary
- require({ paths: { spec: "../test/jasmine/spec" } }, [
-
- // Load the example spec, replace this and add your own spec
- "spec/example"
-
- ], function() {
- // Set up the jasmine reporters once each spec has been loaded
- jasmine.getEnv().addReporter(new jasmine.TrivialReporter());
- jasmine.getEnv().execute();
- });
- </script>
-</body>
-</html>
diff --git a/src/fauxton/test/jasmine/spec/example.js b/src/fauxton/test/jasmine/spec/example.js
deleted file mode 100644
index bbba3e838..000000000
--- a/src/fauxton/test/jasmine/spec/example.js
+++ /dev/null
@@ -1,73 +0,0 @@
-describe("one tautology", function() {
- it("is a tautology", function() {
- expect(true).toBeTruthy();
- });
-
- describe("is awesome", function() {
- it("is awesome", function() {
- expect(1).toBe(1);
- });
- });
-});
-
-describe("simple tests", function() {
- it("increments", function() {
- var mike = 0;
-
- expect(mike++ === 0).toBeTruthy();
- expect(mike === 1).toBeTruthy();
- });
-
- it("increments (improved)", function() {
- var mike = 0;
-
- expect(mike++).toBe(0);
- expect(mike).toBe(1);
- });
-});
-
-describe("setUp/tearDown", function() {
- beforeEach(function() {
- // console.log("Before");
- });
-
- afterEach(function() {
- // console.log("After");
- });
-
- it("example", function() {
- // console.log("During");
- });
-
- describe("setUp/tearDown", function() {
- beforeEach(function() {
- // console.log("Before2");
- });
-
- afterEach(function() {
- // console.log("After2");
- });
-
- it("example", function() {
- // console.log("During Nested");
- });
- });
-});
-
-describe("async", function() {
- it("multiple async", function() {
- var semaphore = 2;
-
- setTimeout(function() {
- expect(true).toBeTruthy();
- semaphore--;
- }, 500);
-
- setTimeout(function() {
- expect(true).toBeTruthy();
- semaphore--;
- }, 500);
-
- waitsFor(function() { return semaphore === 0 });
- });
-});
diff --git a/src/fauxton/test/jasmine/vendor/MIT.LICENSE b/src/fauxton/test/jasmine/vendor/MIT.LICENSE
deleted file mode 100644
index 7c435baae..000000000
--- a/src/fauxton/test/jasmine/vendor/MIT.LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-Copyright (c) 2008-2011 Pivotal Labs
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/fauxton/test/jasmine/vendor/jasmine-html.js b/src/fauxton/test/jasmine/vendor/jasmine-html.js
deleted file mode 100644
index 73834010f..000000000
--- a/src/fauxton/test/jasmine/vendor/jasmine-html.js
+++ /dev/null
@@ -1,190 +0,0 @@
-jasmine.TrivialReporter = function(doc) {
- this.document = doc || document;
- this.suiteDivs = {};
- this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
- var el = document.createElement(type);
-
- for (var i = 2; i < arguments.length; i++) {
- var child = arguments[i];
-
- if (typeof child === 'string') {
- el.appendChild(document.createTextNode(child));
- } else {
- if (child) { el.appendChild(child); }
- }
- }
-
- for (var attr in attrs) {
- if (attr == "className") {
- el[attr] = attrs[attr];
- } else {
- el.setAttribute(attr, attrs[attr]);
- }
- }
-
- return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
- var showPassed, showSkipped;
-
- this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
- this.createDom('div', { className: 'banner' },
- this.createDom('div', { className: 'logo' },
- this.createDom('span', { className: 'title' }, "Jasmine"),
- this.createDom('span', { className: 'version' }, runner.env.versionString())),
- this.createDom('div', { className: 'options' },
- "Show ",
- showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
- showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
- )
- ),
-
- this.runnerDiv = this.createDom('div', { className: 'runner running' },
- this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
- this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
- this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
- );
-
- this.document.body.appendChild(this.outerDiv);
-
- var suites = runner.suites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- var suiteDiv = this.createDom('div', { className: 'suite' },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
- this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
- this.suiteDivs[suite.id] = suiteDiv;
- var parentDiv = this.outerDiv;
- if (suite.parentSuite) {
- parentDiv = this.suiteDivs[suite.parentSuite.id];
- }
- parentDiv.appendChild(suiteDiv);
- }
-
- this.startedAt = new Date();
-
- var self = this;
- showPassed.onclick = function(evt) {
- if (showPassed.checked) {
- self.outerDiv.className += ' show-passed';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
- }
- };
-
- showSkipped.onclick = function(evt) {
- if (showSkipped.checked) {
- self.outerDiv.className += ' show-skipped';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
- }
- };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
- var results = runner.results();
- var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
- this.runnerDiv.setAttribute("class", className);
- //do it twice for IE
- this.runnerDiv.setAttribute("className", className);
- var specs = runner.specs();
- var specCount = 0;
- for (var i = 0; i < specs.length; i++) {
- if (this.specFilter(specs[i])) {
- specCount++;
- }
- }
- var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
- message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
- this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
- this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
- var results = suite.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.totalCount === 0) { // todo: change this to check results.skipped
- status = 'skipped';
- }
- this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
- if (this.logRunningSpecs) {
- this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
- }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
- var results = spec.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.skipped) {
- status = 'skipped';
- }
- var specDiv = this.createDom('div', { className: 'spec ' + status },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(spec.getFullName()),
- title: spec.getFullName()
- }, spec.description));
-
-
- var resultItems = results.getItems();
- var messagesDiv = this.createDom('div', { className: 'messages' });
- for (var i = 0; i < resultItems.length; i++) {
- var result = resultItems[i];
-
- if (result.type == 'log') {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
- } else if (result.type == 'expect' && result.passed && !result.passed()) {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
- if (result.trace.stack) {
- messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
- }
- }
- }
-
- if (messagesDiv.childNodes.length > 0) {
- specDiv.appendChild(messagesDiv);
- }
-
- this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
- var console = jasmine.getGlobal().console;
- if (console && console.log) {
- if (console.log.apply) {
- console.log.apply(console, arguments);
- } else {
- console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
- }
- }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
- return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
- var paramMap = {};
- var params = this.getLocation().search.substring(1).split('&');
- for (var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
- }
-
- if (!paramMap.spec) {
- return true;
- }
- return spec.getFullName().indexOf(paramMap.spec) === 0;
-};
diff --git a/src/fauxton/test/jasmine/vendor/jasmine.css b/src/fauxton/test/jasmine/vendor/jasmine.css
deleted file mode 100644
index 6583fe7c6..000000000
--- a/src/fauxton/test/jasmine/vendor/jasmine.css
+++ /dev/null
@@ -1,166 +0,0 @@
-body {
- font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
-}
-
-
-.jasmine_reporter a:visited, .jasmine_reporter a {
- color: #303;
-}
-
-.jasmine_reporter a:hover, .jasmine_reporter a:active {
- color: blue;
-}
-
-.run_spec {
- float:right;
- padding-right: 5px;
- font-size: .8em;
- text-decoration: none;
-}
-
-.jasmine_reporter {
- margin: 0 5px;
-}
-
-.banner {
- color: #303;
- background-color: #fef;
- padding: 5px;
-}
-
-.logo {
- float: left;
- font-size: 1.1em;
- padding-left: 5px;
-}
-
-.logo .version {
- font-size: .6em;
- padding-left: 1em;
-}
-
-.runner.running {
- background-color: yellow;
-}
-
-
-.options {
- text-align: right;
- font-size: .8em;
-}
-
-
-
-
-.suite {
- border: 1px outset gray;
- margin: 5px 0;
- padding-left: 1em;
-}
-
-.suite .suite {
- margin: 5px;
-}
-
-.suite.passed {
- background-color: #dfd;
-}
-
-.suite.failed {
- background-color: #fdd;
-}
-
-.spec {
- margin: 5px;
- padding-left: 1em;
- clear: both;
-}
-
-.spec.failed, .spec.passed, .spec.skipped {
- padding-bottom: 5px;
- border: 1px solid gray;
-}
-
-.spec.failed {
- background-color: #fbb;
- border-color: red;
-}
-
-.spec.passed {
- background-color: #bfb;
- border-color: green;
-}
-
-.spec.skipped {
- background-color: #bbb;
-}
-
-.messages {
- border-left: 1px dashed gray;
- padding-left: 1em;
- padding-right: 1em;
-}
-
-.passed {
- background-color: #cfc;
- display: none;
-}
-
-.failed {
- background-color: #fbb;
-}
-
-.skipped {
- color: #777;
- background-color: #eee;
- display: none;
-}
-
-
-/*.resultMessage {*/
- /*white-space: pre;*/
-/*}*/
-
-.resultMessage span.result {
- display: block;
- line-height: 2em;
- color: black;
-}
-
-.resultMessage .mismatch {
- color: black;
-}
-
-.stackTrace {
- white-space: pre;
- font-size: .8em;
- margin-left: 10px;
- max-height: 5em;
- overflow: auto;
- border: 1px inset red;
- padding: 1em;
- background: #eef;
-}
-
-.finished-at {
- padding-left: 1em;
- font-size: .6em;
-}
-
-.show-passed .passed,
-.show-skipped .skipped {
- display: block;
-}
-
-
-#jasmine_content {
- position:fixed;
- right: 100%;
-}
-
-.runner {
- border: 1px solid gray;
- display: block;
- margin: 5px 0;
- padding: 2px 0 2px 10px;
-}
diff --git a/src/fauxton/test/jasmine/vendor/jasmine.js b/src/fauxton/test/jasmine/vendor/jasmine.js
deleted file mode 100644
index c3d2dc7d2..000000000
--- a/src/fauxton/test/jasmine/vendor/jasmine.js
+++ /dev/null
@@ -1,2476 +0,0 @@
-var isCommonJS = typeof window == "undefined";
-
-/**
- * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
- *
- * @namespace
- */
-var jasmine = {};
-if (isCommonJS) exports.jasmine = jasmine;
-/**
- * @private
- */
-jasmine.unimplementedMethod_ = function() {
- throw new Error("unimplemented method");
-};
-
-/**
- * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
- * a plain old variable and may be redefined by somebody else.
- *
- * @private
- */
-jasmine.undefined = jasmine.___undefined___;
-
-/**
- * Show diagnostic messages in the console if set to true
- *
- */
-jasmine.VERBOSE = false;
-
-/**
- * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
- *
- */
-jasmine.DEFAULT_UPDATE_INTERVAL = 250;
-
-/**
- * Default timeout interval in milliseconds for waitsFor() blocks.
- */
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
-
-jasmine.getGlobal = function() {
- function getGlobal() {
- return this;
- }
-
- return getGlobal();
-};
-
-/**
- * Allows for bound functions to be compared. Internal use only.
- *
- * @ignore
- * @private
- * @param base {Object} bound 'this' for the function
- * @param name {Function} function to find
- */
-jasmine.bindOriginal_ = function(base, name) {
- var original = base[name];
- if (original.apply) {
- return function() {
- return original.apply(base, arguments);
- };
- } else {
- // IE support
- return jasmine.getGlobal()[name];
- }
-};
-
-jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
-jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
-jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
-jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
-
-jasmine.MessageResult = function(values) {
- this.type = 'log';
- this.values = values;
- this.trace = new Error(); // todo: test better
-};
-
-jasmine.MessageResult.prototype.toString = function() {
- var text = "";
- for (var i = 0; i < this.values.length; i++) {
- if (i > 0) text += " ";
- if (jasmine.isString_(this.values[i])) {
- text += this.values[i];
- } else {
- text += jasmine.pp(this.values[i]);
- }
- }
- return text;
-};
-
-jasmine.ExpectationResult = function(params) {
- this.type = 'expect';
- this.matcherName = params.matcherName;
- this.passed_ = params.passed;
- this.expected = params.expected;
- this.actual = params.actual;
- this.message = this.passed_ ? 'Passed.' : params.message;
-
- var trace = (params.trace || new Error(this.message));
- this.trace = this.passed_ ? '' : trace;
-};
-
-jasmine.ExpectationResult.prototype.toString = function () {
- return this.message;
-};
-
-jasmine.ExpectationResult.prototype.passed = function () {
- return this.passed_;
-};
-
-/**
- * Getter for the Jasmine environment. Ensures one gets created
- */
-jasmine.getEnv = function() {
- var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
- return env;
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isArray_ = function(value) {
- return jasmine.isA_("Array", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isString_ = function(value) {
- return jasmine.isA_("String", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isNumber_ = function(value) {
- return jasmine.isA_("Number", value);
-};
-
-/**
- * @ignore
- * @private
- * @param {String} typeName
- * @param value
- * @returns {Boolean}
- */
-jasmine.isA_ = function(typeName, value) {
- return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
-};
-
-/**
- * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
- *
- * @param value {Object} an object to be outputted
- * @returns {String}
- */
-jasmine.pp = function(value) {
- var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
- stringPrettyPrinter.format(value);
- return stringPrettyPrinter.string;
-};
-
-/**
- * Returns true if the object is a DOM Node.
- *
- * @param {Object} obj object to check
- * @returns {Boolean}
- */
-jasmine.isDomNode = function(obj) {
- return obj.nodeType > 0;
-};
-
-/**
- * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
- *
- * @example
- * // don't care about which function is passed in, as long as it's a function
- * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
- *
- * @param {Class} clazz
- * @returns matchable object of the type clazz
- */
-jasmine.any = function(clazz) {
- return new jasmine.Matchers.Any(clazz);
-};
-
-/**
- * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
- *
- * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
- * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
- *
- * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
- *
- * Spies are torn down at the end of every spec.
- *
- * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
- *
- * @example
- * // a stub
- * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
- *
- * // spy example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- *
- * // actual foo.not will not be called, execution stops
- * spyOn(foo, 'not');
-
- // foo.not spied upon, execution will continue to implementation
- * spyOn(foo, 'not').andCallThrough();
- *
- * // fake example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- *
- * // foo.not(val) will return val
- * spyOn(foo, 'not').andCallFake(function(value) {return value;});
- *
- * // mock example
- * foo.not(7 == 7);
- * expect(foo.not).toHaveBeenCalled();
- * expect(foo.not).toHaveBeenCalledWith(true);
- *
- * @constructor
- * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
- * @param {String} name
- */
-jasmine.Spy = function(name) {
- /**
- * The name of the spy, if provided.
- */
- this.identity = name || 'unknown';
- /**
- * Is this Object a spy?
- */
- this.isSpy = true;
- /**
- * The actual function this spy stubs.
- */
- this.plan = function() {
- };
- /**
- * Tracking of the most recent call to the spy.
- * @example
- * var mySpy = jasmine.createSpy('foo');
- * mySpy(1, 2);
- * mySpy.mostRecentCall.args = [1, 2];
- */
- this.mostRecentCall = {};
-
- /**
- * Holds arguments for each call to the spy, indexed by call count
- * @example
- * var mySpy = jasmine.createSpy('foo');
- * mySpy(1, 2);
- * mySpy(7, 8);
- * mySpy.mostRecentCall.args = [7, 8];
- * mySpy.argsForCall[0] = [1, 2];
- * mySpy.argsForCall[1] = [7, 8];
- */
- this.argsForCall = [];
- this.calls = [];
-};
-
-/**
- * Tells a spy to call through to the actual implemenatation.
- *
- * @example
- * var foo = {
- * bar: function() { // do some stuff }
- * }
- *
- * // defining a spy on an existing property: foo.bar
- * spyOn(foo, 'bar').andCallThrough();
- */
-jasmine.Spy.prototype.andCallThrough = function() {
- this.plan = this.originalValue;
- return this;
-};
-
-/**
- * For setting the return value of a spy.
- *
- * @example
- * // defining a spy from scratch: foo() returns 'baz'
- * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
- *
- * // defining a spy on an existing property: foo.bar() returns 'baz'
- * spyOn(foo, 'bar').andReturn('baz');
- *
- * @param {Object} value
- */
-jasmine.Spy.prototype.andReturn = function(value) {
- this.plan = function() {
- return value;
- };
- return this;
-};
-
-/**
- * For throwing an exception when a spy is called.
- *
- * @example
- * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
- * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
- *
- * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
- * spyOn(foo, 'bar').andThrow('baz');
- *
- * @param {String} exceptionMsg
- */
-jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
- this.plan = function() {
- throw exceptionMsg;
- };
- return this;
-};
-
-/**
- * Calls an alternate implementation when a spy is called.
- *
- * @example
- * var baz = function() {
- * // do some stuff, return something
- * }
- * // defining a spy from scratch: foo() calls the function baz
- * var foo = jasmine.createSpy('spy on foo').andCall(baz);
- *
- * // defining a spy on an existing property: foo.bar() calls an anonymnous function
- * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
- *
- * @param {Function} fakeFunc
- */
-jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
- this.plan = fakeFunc;
- return this;
-};
-
-/**
- * Resets all of a spy's the tracking variables so that it can be used again.
- *
- * @example
- * spyOn(foo, 'bar');
- *
- * foo.bar();
- *
- * expect(foo.bar.callCount).toEqual(1);
- *
- * foo.bar.reset();
- *
- * expect(foo.bar.callCount).toEqual(0);
- */
-jasmine.Spy.prototype.reset = function() {
- this.wasCalled = false;
- this.callCount = 0;
- this.argsForCall = [];
- this.calls = [];
- this.mostRecentCall = {};
-};
-
-jasmine.createSpy = function(name) {
-
- var spyObj = function() {
- spyObj.wasCalled = true;
- spyObj.callCount++;
- var args = jasmine.util.argsToArray(arguments);
- spyObj.mostRecentCall.object = this;
- spyObj.mostRecentCall.args = args;
- spyObj.argsForCall.push(args);
- spyObj.calls.push({object: this, args: args});
- return spyObj.plan.apply(this, arguments);
- };
-
- var spy = new jasmine.Spy(name);
-
- for (var prop in spy) {
- spyObj[prop] = spy[prop];
- }
-
- spyObj.reset();
-
- return spyObj;
-};
-
-/**
- * Determines whether an object is a spy.
- *
- * @param {jasmine.Spy|Object} putativeSpy
- * @returns {Boolean}
- */
-jasmine.isSpy = function(putativeSpy) {
- return putativeSpy && putativeSpy.isSpy;
-};
-
-/**
- * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
- * large in one call.
- *
- * @param {String} baseName name of spy class
- * @param {Array} methodNames array of names of methods to make spies
- */
-jasmine.createSpyObj = function(baseName, methodNames) {
- if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
- throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
- }
- var obj = {};
- for (var i = 0; i < methodNames.length; i++) {
- obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
- }
- return obj;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.log = function() {
- var spec = jasmine.getEnv().currentSpec;
- spec.log.apply(spec, arguments);
-};
-
-/**
- * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
- *
- * @example
- * // spy example
- * var foo = {
- * not: function(bool) { return !bool; }
- * }
- * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
- *
- * @see jasmine.createSpy
- * @param obj
- * @param methodName
- * @returns a Jasmine spy that can be chained with all spy methods
- */
-var spyOn = function(obj, methodName) {
- return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
-};
-if (isCommonJS) exports.spyOn = spyOn;
-
-/**
- * Creates a Jasmine spec that will be added to the current suite.
- *
- * // TODO: pending tests
- *
- * @example
- * it('should be true', function() {
- * expect(true).toEqual(true);
- * });
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var it = function(desc, func) {
- return jasmine.getEnv().it(desc, func);
-};
-if (isCommonJS) exports.it = it;
-
-/**
- * Creates a <em>disabled</em> Jasmine spec.
- *
- * A convenience method that allows existing specs to be disabled temporarily during development.
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var xit = function(desc, func) {
- return jasmine.getEnv().xit(desc, func);
-};
-if (isCommonJS) exports.xit = xit;
-
-/**
- * Starts a chain for a Jasmine expectation.
- *
- * It is passed an Object that is the actual value and should chain to one of the many
- * jasmine.Matchers functions.
- *
- * @param {Object} actual Actual value to test against and expected value
- */
-var expect = function(actual) {
- return jasmine.getEnv().currentSpec.expect(actual);
-};
-if (isCommonJS) exports.expect = expect;
-
-/**
- * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
- *
- * @param {Function} func Function that defines part of a jasmine spec.
- */
-var runs = function(func) {
- jasmine.getEnv().currentSpec.runs(func);
-};
-if (isCommonJS) exports.runs = runs;
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-var waits = function(timeout) {
- jasmine.getEnv().currentSpec.waits(timeout);
-};
-if (isCommonJS) exports.waits = waits;
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
- jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
-};
-if (isCommonJS) exports.waitsFor = waitsFor;
-
-/**
- * A function that is called before each spec in a suite.
- *
- * Used for spec setup, including validating assumptions.
- *
- * @param {Function} beforeEachFunction
- */
-var beforeEach = function(beforeEachFunction) {
- jasmine.getEnv().beforeEach(beforeEachFunction);
-};
-if (isCommonJS) exports.beforeEach = beforeEach;
-
-/**
- * A function that is called after each spec in a suite.
- *
- * Used for restoring any state that is hijacked during spec execution.
- *
- * @param {Function} afterEachFunction
- */
-var afterEach = function(afterEachFunction) {
- jasmine.getEnv().afterEach(afterEachFunction);
-};
-if (isCommonJS) exports.afterEach = afterEach;
-
-/**
- * Defines a suite of specifications.
- *
- * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
- * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
- * of setup in some tests.
- *
- * @example
- * // TODO: a simple suite
- *
- * // TODO: a simple suite with a nested describe block
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var describe = function(description, specDefinitions) {
- return jasmine.getEnv().describe(description, specDefinitions);
-};
-if (isCommonJS) exports.describe = describe;
-
-/**
- * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var xdescribe = function(description, specDefinitions) {
- return jasmine.getEnv().xdescribe(description, specDefinitions);
-};
-if (isCommonJS) exports.xdescribe = xdescribe;
-
-
-// Provide the XMLHttpRequest class for IE 5.x-6.x:
-jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
- function tryIt(f) {
- try {
- return f();
- } catch(e) {
- }
- return null;
- }
-
- var xhr = tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP.6.0");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP.3.0");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Msxml2.XMLHTTP");
- }) ||
- tryIt(function() {
- return new ActiveXObject("Microsoft.XMLHTTP");
- });
-
- if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
-
- return xhr;
-} : XMLHttpRequest;
-/**
- * @namespace
- */
-jasmine.util = {};
-
-/**
- * Declare that a child class inherit it's prototype from the parent class.
- *
- * @private
- * @param {Function} childClass
- * @param {Function} parentClass
- */
-jasmine.util.inherit = function(childClass, parentClass) {
- /**
- * @private
- */
- var subclass = function() {
- };
- subclass.prototype = parentClass.prototype;
- childClass.prototype = new subclass();
-};
-
-jasmine.util.formatException = function(e) {
- var lineNumber;
- if (e.line) {
- lineNumber = e.line;
- }
- else if (e.lineNumber) {
- lineNumber = e.lineNumber;
- }
-
- var file;
-
- if (e.sourceURL) {
- file = e.sourceURL;
- }
- else if (e.fileName) {
- file = e.fileName;
- }
-
- var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
-
- if (file && lineNumber) {
- message += ' in ' + file + ' (line ' + lineNumber + ')';
- }
-
- return message;
-};
-
-jasmine.util.htmlEscape = function(str) {
- if (!str) return str;
- return str.replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;');
-};
-
-jasmine.util.argsToArray = function(args) {
- var arrayOfArgs = [];
- for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
- return arrayOfArgs;
-};
-
-jasmine.util.extend = function(destination, source) {
- for (var property in source) destination[property] = source[property];
- return destination;
-};
-
-/**
- * Environment for Jasmine
- *
- * @constructor
- */
-jasmine.Env = function() {
- this.currentSpec = null;
- this.currentSuite = null;
- this.currentRunner_ = new jasmine.Runner(this);
-
- this.reporter = new jasmine.MultiReporter();
-
- this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
- this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
- this.lastUpdate = 0;
- this.specFilter = function() {
- return true;
- };
-
- this.nextSpecId_ = 0;
- this.nextSuiteId_ = 0;
- this.equalityTesters_ = [];
-
- // wrap matchers
- this.matchersClass = function() {
- jasmine.Matchers.apply(this, arguments);
- };
- jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
-
- jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
-};
-
-
-jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
-jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
-jasmine.Env.prototype.setInterval = jasmine.setInterval;
-jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
-
-/**
- * @returns an object containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.version = function () {
- if (jasmine.version_) {
- return jasmine.version_;
- } else {
- throw new Error('Version not set');
- }
-};
-
-/**
- * @returns string containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.versionString = function() {
- if (!jasmine.version_) {
- return "version unknown";
- }
-
- var version = this.version();
- var versionString = version.major + "." + version.minor + "." + version.build;
- if (version.release_candidate) {
- versionString += ".rc" + version.release_candidate;
- }
- versionString += " revision " + version.revision;
- return versionString;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSpecId = function () {
- return this.nextSpecId_++;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSuiteId = function () {
- return this.nextSuiteId_++;
-};
-
-/**
- * Register a reporter to receive status updates from Jasmine.
- * @param {jasmine.Reporter} reporter An object which will receive status updates.
- */
-jasmine.Env.prototype.addReporter = function(reporter) {
- this.reporter.addReporter(reporter);
-};
-
-jasmine.Env.prototype.execute = function() {
- this.currentRunner_.execute();
-};
-
-jasmine.Env.prototype.describe = function(description, specDefinitions) {
- var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
-
- var parentSuite = this.currentSuite;
- if (parentSuite) {
- parentSuite.add(suite);
- } else {
- this.currentRunner_.add(suite);
- }
-
- this.currentSuite = suite;
-
- var declarationError = null;
- try {
- specDefinitions.call(suite);
- } catch(e) {
- declarationError = e;
- }
-
- if (declarationError) {
- this.it("encountered a declaration exception", function() {
- throw declarationError;
- });
- }
-
- this.currentSuite = parentSuite;
-
- return suite;
-};
-
-jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
- if (this.currentSuite) {
- this.currentSuite.beforeEach(beforeEachFunction);
- } else {
- this.currentRunner_.beforeEach(beforeEachFunction);
- }
-};
-
-jasmine.Env.prototype.currentRunner = function () {
- return this.currentRunner_;
-};
-
-jasmine.Env.prototype.afterEach = function(afterEachFunction) {
- if (this.currentSuite) {
- this.currentSuite.afterEach(afterEachFunction);
- } else {
- this.currentRunner_.afterEach(afterEachFunction);
- }
-
-};
-
-jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
- return {
- execute: function() {
- }
- };
-};
-
-jasmine.Env.prototype.it = function(description, func) {
- var spec = new jasmine.Spec(this, this.currentSuite, description);
- this.currentSuite.add(spec);
- this.currentSpec = spec;
-
- if (func) {
- spec.runs(func);
- }
-
- return spec;
-};
-
-jasmine.Env.prototype.xit = function(desc, func) {
- return {
- id: this.nextSpecId(),
- runs: function() {
- }
- };
-};
-
-jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
- if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
- return true;
- }
-
- a.__Jasmine_been_here_before__ = b;
- b.__Jasmine_been_here_before__ = a;
-
- var hasKey = function(obj, keyName) {
- return obj !== null && obj[keyName] !== jasmine.undefined;
- };
-
- for (var property in b) {
- if (!hasKey(a, property) && hasKey(b, property)) {
- mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
- }
- }
- for (property in a) {
- if (!hasKey(b, property) && hasKey(a, property)) {
- mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
- }
- }
- for (property in b) {
- if (property == '__Jasmine_been_here_before__') continue;
- if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
- mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
- }
- }
-
- if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
- mismatchValues.push("arrays were not the same length");
- }
-
- delete a.__Jasmine_been_here_before__;
- delete b.__Jasmine_been_here_before__;
- return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
- mismatchKeys = mismatchKeys || [];
- mismatchValues = mismatchValues || [];
-
- for (var i = 0; i < this.equalityTesters_.length; i++) {
- var equalityTester = this.equalityTesters_[i];
- var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
- if (result !== jasmine.undefined) return result;
- }
-
- if (a === b) return true;
-
- if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
- return (a == jasmine.undefined && b == jasmine.undefined);
- }
-
- if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
- return a === b;
- }
-
- if (a instanceof Date && b instanceof Date) {
- return a.getTime() == b.getTime();
- }
-
- if (a instanceof jasmine.Matchers.Any) {
- return a.matches(b);
- }
-
- if (b instanceof jasmine.Matchers.Any) {
- return b.matches(a);
- }
-
- if (jasmine.isString_(a) && jasmine.isString_(b)) {
- return (a == b);
- }
-
- if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
- return (a == b);
- }
-
- if (typeof a === "object" && typeof b === "object") {
- return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
- }
-
- //Straight check
- return (a === b);
-};
-
-jasmine.Env.prototype.contains_ = function(haystack, needle) {
- if (jasmine.isArray_(haystack)) {
- for (var i = 0; i < haystack.length; i++) {
- if (this.equals_(haystack[i], needle)) return true;
- }
- return false;
- }
- return haystack.indexOf(needle) >= 0;
-};
-
-jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
- this.equalityTesters_.push(equalityTester);
-};
-/** No-op base class for Jasmine reporters.
- *
- * @constructor
- */
-jasmine.Reporter = function() {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecResults = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.log = function(str) {
-};
-
-/**
- * Blocks are functions with executable code that make up a spec.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {Function} func
- * @param {jasmine.Spec} spec
- */
-jasmine.Block = function(env, func, spec) {
- this.env = env;
- this.func = func;
- this.spec = spec;
-};
-
-jasmine.Block.prototype.execute = function(onComplete) {
- try {
- this.func.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
- }
- onComplete();
-};
-/** JavaScript API reporter.
- *
- * @constructor
- */
-jasmine.JsApiReporter = function() {
- this.started = false;
- this.finished = false;
- this.suites_ = [];
- this.results_ = {};
-};
-
-jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
- this.started = true;
- var suites = runner.topLevelSuites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- this.suites_.push(this.summarize_(suite));
- }
-};
-
-jasmine.JsApiReporter.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
- var isSuite = suiteOrSpec instanceof jasmine.Suite;
- var summary = {
- id: suiteOrSpec.id,
- name: suiteOrSpec.description,
- type: isSuite ? 'suite' : 'spec',
- children: []
- };
-
- if (isSuite) {
- var children = suiteOrSpec.children();
- for (var i = 0; i < children.length; i++) {
- summary.children.push(this.summarize_(children[i]));
- }
- }
- return summary;
-};
-
-jasmine.JsApiReporter.prototype.results = function() {
- return this.results_;
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
- return this.results_[specId];
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
- this.finished = true;
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
- this.results_[spec.id] = {
- messages: spec.results().getItems(),
- result: spec.results().failedCount > 0 ? "failed" : "passed"
- };
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.log = function(str) {
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
- var results = {};
- for (var i = 0; i < specIds.length; i++) {
- var specId = specIds[i];
- results[specId] = this.summarizeResult_(this.results_[specId]);
- }
- return results;
-};
-
-jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
- var summaryMessages = [];
- var messagesLength = result.messages.length;
- for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
- var resultMessage = result.messages[messageIndex];
- summaryMessages.push({
- text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
- passed: resultMessage.passed ? resultMessage.passed() : true,
- type: resultMessage.type,
- message: resultMessage.message,
- trace: {
- stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
- }
- });
- }
-
- return {
- result : result.result,
- messages : summaryMessages
- };
-};
-
-/**
- * @constructor
- * @param {jasmine.Env} env
- * @param actual
- * @param {jasmine.Spec} spec
- */
-jasmine.Matchers = function(env, actual, spec, opt_isNot) {
- this.env = env;
- this.actual = actual;
- this.spec = spec;
- this.isNot = opt_isNot || false;
- this.reportWasCalled_ = false;
-};
-
-// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
-jasmine.Matchers.pp = function(str) {
- throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
-};
-
-// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
-jasmine.Matchers.prototype.report = function(result, failing_message, details) {
- throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
-};
-
-jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
- for (var methodName in prototype) {
- if (methodName == 'report') continue;
- var orig = prototype[methodName];
- matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
- }
-};
-
-jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
- return function() {
- var matcherArgs = jasmine.util.argsToArray(arguments);
- var result = matcherFunction.apply(this, arguments);
-
- if (this.isNot) {
- result = !result;
- }
-
- if (this.reportWasCalled_) return result;
-
- var message;
- if (!result) {
- if (this.message) {
- message = this.message.apply(this, arguments);
- if (jasmine.isArray_(message)) {
- message = message[this.isNot ? 1 : 0];
- }
- } else {
- var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
- message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
- if (matcherArgs.length > 0) {
- for (var i = 0; i < matcherArgs.length; i++) {
- if (i > 0) message += ",";
- message += " " + jasmine.pp(matcherArgs[i]);
- }
- }
- message += ".";
- }
- }
- var expectationResult = new jasmine.ExpectationResult({
- matcherName: matcherName,
- passed: result,
- expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
- actual: this.actual,
- message: message
- });
- this.spec.addMatcherResult(expectationResult);
- return jasmine.undefined;
- };
-};
-
-
-
-
-/**
- * toBe: compares the actual to the expected using ===
- * @param expected
- */
-jasmine.Matchers.prototype.toBe = function(expected) {
- return this.actual === expected;
-};
-
-/**
- * toNotBe: compares the actual to the expected using !==
- * @param expected
- * @deprecated as of 1.0. Use not.toBe() instead.
- */
-jasmine.Matchers.prototype.toNotBe = function(expected) {
- return this.actual !== expected;
-};
-
-/**
- * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toEqual = function(expected) {
- return this.env.equals_(this.actual, expected);
-};
-
-/**
- * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
- * @param expected
- * @deprecated as of 1.0. Use not.toNotEqual() instead.
- */
-jasmine.Matchers.prototype.toNotEqual = function(expected) {
- return !this.env.equals_(this.actual, expected);
-};
-
-/**
- * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
- * a pattern or a String.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toMatch = function(expected) {
- return new RegExp(expected).test(this.actual);
-};
-
-/**
- * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
- * @param expected
- * @deprecated as of 1.0. Use not.toMatch() instead.
- */
-jasmine.Matchers.prototype.toNotMatch = function(expected) {
- return !(new RegExp(expected).test(this.actual));
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeDefined = function() {
- return (this.actual !== jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeUndefined = function() {
- return (this.actual === jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to null.
- */
-jasmine.Matchers.prototype.toBeNull = function() {
- return (this.actual === null);
-};
-
-/**
- * Matcher that boolean not-nots the actual.
- */
-jasmine.Matchers.prototype.toBeTruthy = function() {
- return !!this.actual;
-};
-
-
-/**
- * Matcher that boolean nots the actual.
- */
-jasmine.Matchers.prototype.toBeFalsy = function() {
- return !this.actual;
-};
-
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called.
- */
-jasmine.Matchers.prototype.toHaveBeenCalled = function() {
- if (arguments.length > 0) {
- throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy " + this.actual.identity + " to have been called.",
- "Expected spy " + this.actual.identity + " not to have been called."
- ];
- };
-
- return this.actual.wasCalled;
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
-jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was not called.
- *
- * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
- */
-jasmine.Matchers.prototype.wasNotCalled = function() {
- if (arguments.length > 0) {
- throw new Error('wasNotCalled does not take arguments');
- }
-
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy " + this.actual.identity + " to not have been called.",
- "Expected spy " + this.actual.identity + " to have been called."
- ];
- };
-
- return !this.actual.wasCalled;
-};
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
- *
- * @example
- *
- */
-jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
- this.message = function() {
- if (this.actual.callCount === 0) {
- // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
- return [
- "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
- "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
- ];
- } else {
- return [
- "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
- "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
- ];
- }
- };
-
- return this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
-
-/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasNotCalledWith = function() {
- var expectedArgs = jasmine.util.argsToArray(arguments);
- if (!jasmine.isSpy(this.actual)) {
- throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
- }
-
- this.message = function() {
- return [
- "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
- "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
- ];
- };
-
- return !this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/**
- * Matcher that checks that the expected item is an element in the actual Array.
- *
- * @param {Object} expected
- */
-jasmine.Matchers.prototype.toContain = function(expected) {
- return this.env.contains_(this.actual, expected);
-};
-
-/**
- * Matcher that checks that the expected item is NOT an element in the actual Array.
- *
- * @param {Object} expected
- * @deprecated as of 1.0. Use not.toNotContain() instead.
- */
-jasmine.Matchers.prototype.toNotContain = function(expected) {
- return !this.env.contains_(this.actual, expected);
-};
-
-jasmine.Matchers.prototype.toBeLessThan = function(expected) {
- return this.actual < expected;
-};
-
-jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
- return this.actual > expected;
-};
-
-/**
- * Matcher that checks that the expected item is equal to the actual item
- * up to a given level of decimal precision (default 2).
- *
- * @param {Number} expected
- * @param {Number} precision
- */
-jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
- if (!(precision === 0)) {
- precision = precision || 2;
- }
- var multiplier = Math.pow(10, precision);
- var actual = Math.round(this.actual * multiplier);
- expected = Math.round(expected * multiplier);
- return expected == actual;
-};
-
-/**
- * Matcher that checks that the expected exception was thrown by the actual.
- *
- * @param {String} expected
- */
-jasmine.Matchers.prototype.toThrow = function(expected) {
- var result = false;
- var exception;
- if (typeof this.actual != 'function') {
- throw new Error('Actual is not a function');
- }
- try {
- this.actual();
- } catch (e) {
- exception = e;
- }
- if (exception) {
- result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
- }
-
- var not = this.isNot ? "not " : "";
-
- this.message = function() {
- if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
- return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
- } else {
- return "Expected function to throw an exception.";
- }
- };
-
- return result;
-};
-
-jasmine.Matchers.Any = function(expectedClass) {
- this.expectedClass = expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.matches = function(other) {
- if (this.expectedClass == String) {
- return typeof other == 'string' || other instanceof String;
- }
-
- if (this.expectedClass == Number) {
- return typeof other == 'number' || other instanceof Number;
- }
-
- if (this.expectedClass == Function) {
- return typeof other == 'function' || other instanceof Function;
- }
-
- if (this.expectedClass == Object) {
- return typeof other == 'object';
- }
-
- return other instanceof this.expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.toString = function() {
- return '<jasmine.any(' + this.expectedClass + ')>';
-};
-
-/**
- * @constructor
- */
-jasmine.MultiReporter = function() {
- this.subReporters_ = [];
-};
-jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
-
-jasmine.MultiReporter.prototype.addReporter = function(reporter) {
- this.subReporters_.push(reporter);
-};
-
-(function() {
- var functionNames = [
- "reportRunnerStarting",
- "reportRunnerResults",
- "reportSuiteResults",
- "reportSpecStarting",
- "reportSpecResults",
- "log"
- ];
- for (var i = 0; i < functionNames.length; i++) {
- var functionName = functionNames[i];
- jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
- return function() {
- for (var j = 0; j < this.subReporters_.length; j++) {
- var subReporter = this.subReporters_[j];
- if (subReporter[functionName]) {
- subReporter[functionName].apply(subReporter, arguments);
- }
- }
- };
- })(functionName);
- }
-})();
-/**
- * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
- *
- * @constructor
- */
-jasmine.NestedResults = function() {
- /**
- * The total count of results
- */
- this.totalCount = 0;
- /**
- * Number of passed results
- */
- this.passedCount = 0;
- /**
- * Number of failed results
- */
- this.failedCount = 0;
- /**
- * Was this suite/spec skipped?
- */
- this.skipped = false;
- /**
- * @ignore
- */
- this.items_ = [];
-};
-
-/**
- * Roll up the result counts.
- *
- * @param result
- */
-jasmine.NestedResults.prototype.rollupCounts = function(result) {
- this.totalCount += result.totalCount;
- this.passedCount += result.passedCount;
- this.failedCount += result.failedCount;
-};
-
-/**
- * Adds a log message.
- * @param values Array of message parts which will be concatenated later.
- */
-jasmine.NestedResults.prototype.log = function(values) {
- this.items_.push(new jasmine.MessageResult(values));
-};
-
-/**
- * Getter for the results: message & results.
- */
-jasmine.NestedResults.prototype.getItems = function() {
- return this.items_;
-};
-
-/**
- * Adds a result, tracking counts (total, passed, & failed)
- * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
- */
-jasmine.NestedResults.prototype.addResult = function(result) {
- if (result.type != 'log') {
- if (result.items_) {
- this.rollupCounts(result);
- } else {
- this.totalCount++;
- if (result.passed()) {
- this.passedCount++;
- } else {
- this.failedCount++;
- }
- }
- }
- this.items_.push(result);
-};
-
-/**
- * @returns {Boolean} True if <b>everything</b> below passed
- */
-jasmine.NestedResults.prototype.passed = function() {
- return this.passedCount === this.totalCount;
-};
-/**
- * Base class for pretty printing for expectation results.
- */
-jasmine.PrettyPrinter = function() {
- this.ppNestLevel_ = 0;
-};
-
-/**
- * Formats a value in a nice, human-readable string.
- *
- * @param value
- */
-jasmine.PrettyPrinter.prototype.format = function(value) {
- if (this.ppNestLevel_ > 40) {
- throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
- }
-
- this.ppNestLevel_++;
- try {
- if (value === jasmine.undefined) {
- this.emitScalar('undefined');
- } else if (value === null) {
- this.emitScalar('null');
- } else if (value === jasmine.getGlobal()) {
- this.emitScalar('<global>');
- } else if (value instanceof jasmine.Matchers.Any) {
- this.emitScalar(value.toString());
- } else if (typeof value === 'string') {
- this.emitString(value);
- } else if (jasmine.isSpy(value)) {
- this.emitScalar("spy on " + value.identity);
- } else if (value instanceof RegExp) {
- this.emitScalar(value.toString());
- } else if (typeof value === 'function') {
- this.emitScalar('Function');
- } else if (typeof value.nodeType === 'number') {
- this.emitScalar('HTMLNode');
- } else if (value instanceof Date) {
- this.emitScalar('Date(' + value + ')');
- } else if (value.__Jasmine_been_here_before__) {
- this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
- } else if (jasmine.isArray_(value) || typeof value == 'object') {
- value.__Jasmine_been_here_before__ = true;
- if (jasmine.isArray_(value)) {
- this.emitArray(value);
- } else {
- this.emitObject(value);
- }
- delete value.__Jasmine_been_here_before__;
- } else {
- this.emitScalar(value.toString());
- }
- } finally {
- this.ppNestLevel_--;
- }
-};
-
-jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
- for (var property in obj) {
- if (property == '__Jasmine_been_here_before__') continue;
- fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
- obj.__lookupGetter__(property) !== null) : false);
- }
-};
-
-jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
-
-jasmine.StringPrettyPrinter = function() {
- jasmine.PrettyPrinter.call(this);
-
- this.string = '';
-};
-jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
-
-jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
- this.append(value);
-};
-
-jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
- this.append("'" + value + "'");
-};
-
-jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
- this.append('[ ');
- for (var i = 0; i < array.length; i++) {
- if (i > 0) {
- this.append(', ');
- }
- this.format(array[i]);
- }
- this.append(' ]');
-};
-
-jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
- var self = this;
- this.append('{ ');
- var first = true;
-
- this.iterateObject(obj, function(property, isGetter) {
- if (first) {
- first = false;
- } else {
- self.append(', ');
- }
-
- self.append(property);
- self.append(' : ');
- if (isGetter) {
- self.append('<getter>');
- } else {
- self.format(obj[property]);
- }
- });
-
- this.append(' }');
-};
-
-jasmine.StringPrettyPrinter.prototype.append = function(value) {
- this.string += value;
-};
-jasmine.Queue = function(env) {
- this.env = env;
- this.blocks = [];
- this.running = false;
- this.index = 0;
- this.offset = 0;
- this.abort = false;
-};
-
-jasmine.Queue.prototype.addBefore = function(block) {
- this.blocks.unshift(block);
-};
-
-jasmine.Queue.prototype.add = function(block) {
- this.blocks.push(block);
-};
-
-jasmine.Queue.prototype.insertNext = function(block) {
- this.blocks.splice((this.index + this.offset + 1), 0, block);
- this.offset++;
-};
-
-jasmine.Queue.prototype.start = function(onComplete) {
- this.running = true;
- this.onComplete = onComplete;
- this.next_();
-};
-
-jasmine.Queue.prototype.isRunning = function() {
- return this.running;
-};
-
-jasmine.Queue.LOOP_DONT_RECURSE = true;
-
-jasmine.Queue.prototype.next_ = function() {
- var self = this;
- var goAgain = true;
-
- while (goAgain) {
- goAgain = false;
-
- if (self.index < self.blocks.length && !this.abort) {
- var calledSynchronously = true;
- var completedSynchronously = false;
-
- var onComplete = function () {
- if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
- completedSynchronously = true;
- return;
- }
-
- if (self.blocks[self.index].abort) {
- self.abort = true;
- }
-
- self.offset = 0;
- self.index++;
-
- var now = new Date().getTime();
- if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
- self.env.lastUpdate = now;
- self.env.setTimeout(function() {
- self.next_();
- }, 0);
- } else {
- if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
- goAgain = true;
- } else {
- self.next_();
- }
- }
- };
- self.blocks[self.index].execute(onComplete);
-
- calledSynchronously = false;
- if (completedSynchronously) {
- onComplete();
- }
-
- } else {
- self.running = false;
- if (self.onComplete) {
- self.onComplete();
- }
- }
- }
-};
-
-jasmine.Queue.prototype.results = function() {
- var results = new jasmine.NestedResults();
- for (var i = 0; i < this.blocks.length; i++) {
- if (this.blocks[i].results) {
- results.addResult(this.blocks[i].results());
- }
- }
- return results;
-};
-
-
-/**
- * Runner
- *
- * @constructor
- * @param {jasmine.Env} env
- */
-jasmine.Runner = function(env) {
- var self = this;
- self.env = env;
- self.queue = new jasmine.Queue(env);
- self.before_ = [];
- self.after_ = [];
- self.suites_ = [];
-};
-
-jasmine.Runner.prototype.execute = function() {
- var self = this;
- if (self.env.reporter.reportRunnerStarting) {
- self.env.reporter.reportRunnerStarting(this);
- }
- self.queue.start(function () {
- self.finishCallback();
- });
-};
-
-jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
- beforeEachFunction.typeName = 'beforeEach';
- this.before_.splice(0,0,beforeEachFunction);
-};
-
-jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
- afterEachFunction.typeName = 'afterEach';
- this.after_.splice(0,0,afterEachFunction);
-};
-
-
-jasmine.Runner.prototype.finishCallback = function() {
- this.env.reporter.reportRunnerResults(this);
-};
-
-jasmine.Runner.prototype.addSuite = function(suite) {
- this.suites_.push(suite);
-};
-
-jasmine.Runner.prototype.add = function(block) {
- if (block instanceof jasmine.Suite) {
- this.addSuite(block);
- }
- this.queue.add(block);
-};
-
-jasmine.Runner.prototype.specs = function () {
- var suites = this.suites();
- var specs = [];
- for (var i = 0; i < suites.length; i++) {
- specs = specs.concat(suites[i].specs());
- }
- return specs;
-};
-
-jasmine.Runner.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.Runner.prototype.topLevelSuites = function() {
- var topLevelSuites = [];
- for (var i = 0; i < this.suites_.length; i++) {
- if (!this.suites_[i].parentSuite) {
- topLevelSuites.push(this.suites_[i]);
- }
- }
- return topLevelSuites;
-};
-
-jasmine.Runner.prototype.results = function() {
- return this.queue.results();
-};
-/**
- * Internal representation of a Jasmine specification, or test.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {jasmine.Suite} suite
- * @param {String} description
- */
-jasmine.Spec = function(env, suite, description) {
- if (!env) {
- throw new Error('jasmine.Env() required');
- }
- if (!suite) {
- throw new Error('jasmine.Suite() required');
- }
- var spec = this;
- spec.id = env.nextSpecId ? env.nextSpecId() : null;
- spec.env = env;
- spec.suite = suite;
- spec.description = description;
- spec.queue = new jasmine.Queue(env);
-
- spec.afterCallbacks = [];
- spec.spies_ = [];
-
- spec.results_ = new jasmine.NestedResults();
- spec.results_.description = description;
- spec.matchersClass = null;
-};
-
-jasmine.Spec.prototype.getFullName = function() {
- return this.suite.getFullName() + ' ' + this.description + '.';
-};
-
-
-jasmine.Spec.prototype.results = function() {
- return this.results_;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.Spec.prototype.log = function() {
- return this.results_.log(arguments);
-};
-
-jasmine.Spec.prototype.runs = function (func) {
- var block = new jasmine.Block(this.env, func, this);
- this.addToQueue(block);
- return this;
-};
-
-jasmine.Spec.prototype.addToQueue = function (block) {
- if (this.queue.isRunning()) {
- this.queue.insertNext(block);
- } else {
- this.queue.add(block);
- }
-};
-
-/**
- * @param {jasmine.ExpectationResult} result
- */
-jasmine.Spec.prototype.addMatcherResult = function(result) {
- this.results_.addResult(result);
-};
-
-jasmine.Spec.prototype.expect = function(actual) {
- var positive = new (this.getMatchersClass_())(this.env, actual, this);
- positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
- return positive;
-};
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-jasmine.Spec.prototype.waits = function(timeout) {
- var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
- this.addToQueue(waitsFunc);
- return this;
-};
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
- var latchFunction_ = null;
- var optional_timeoutMessage_ = null;
- var optional_timeout_ = null;
-
- for (var i = 0; i < arguments.length; i++) {
- var arg = arguments[i];
- switch (typeof arg) {
- case 'function':
- latchFunction_ = arg;
- break;
- case 'string':
- optional_timeoutMessage_ = arg;
- break;
- case 'number':
- optional_timeout_ = arg;
- break;
- }
- }
-
- var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
- this.addToQueue(waitsForFunc);
- return this;
-};
-
-jasmine.Spec.prototype.fail = function (e) {
- var expectationResult = new jasmine.ExpectationResult({
- passed: false,
- message: e ? jasmine.util.formatException(e) : 'Exception',
- trace: { stack: e.stack }
- });
- this.results_.addResult(expectationResult);
-};
-
-jasmine.Spec.prototype.getMatchersClass_ = function() {
- return this.matchersClass || this.env.matchersClass;
-};
-
-jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
- var parent = this.getMatchersClass_();
- var newMatchersClass = function() {
- parent.apply(this, arguments);
- };
- jasmine.util.inherit(newMatchersClass, parent);
- jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
- this.matchersClass = newMatchersClass;
-};
-
-jasmine.Spec.prototype.finishCallback = function() {
- this.env.reporter.reportSpecResults(this);
-};
-
-jasmine.Spec.prototype.finish = function(onComplete) {
- this.removeAllSpies();
- this.finishCallback();
- if (onComplete) {
- onComplete();
- }
-};
-
-jasmine.Spec.prototype.after = function(doAfter) {
- if (this.queue.isRunning()) {
- this.queue.add(new jasmine.Block(this.env, doAfter, this));
- } else {
- this.afterCallbacks.unshift(doAfter);
- }
-};
-
-jasmine.Spec.prototype.execute = function(onComplete) {
- var spec = this;
- if (!spec.env.specFilter(spec)) {
- spec.results_.skipped = true;
- spec.finish(onComplete);
- return;
- }
-
- this.env.reporter.reportSpecStarting(this);
-
- spec.env.currentSpec = spec;
-
- spec.addBeforesAndAftersToQueue();
-
- spec.queue.start(function () {
- spec.finish(onComplete);
- });
-};
-
-jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
- var runner = this.env.currentRunner();
- var i;
-
- for (var suite = this.suite; suite; suite = suite.parentSuite) {
- for (i = 0; i < suite.before_.length; i++) {
- this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
- }
- }
- for (i = 0; i < runner.before_.length; i++) {
- this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
- }
- for (i = 0; i < this.afterCallbacks.length; i++) {
- this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
- }
- for (suite = this.suite; suite; suite = suite.parentSuite) {
- for (i = 0; i < suite.after_.length; i++) {
- this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
- }
- }
- for (i = 0; i < runner.after_.length; i++) {
- this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
- }
-};
-
-jasmine.Spec.prototype.explodes = function() {
- throw 'explodes function should not have been called';
-};
-
-jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
- if (obj == jasmine.undefined) {
- throw "spyOn could not find an object to spy upon for " + methodName + "()";
- }
-
- if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
- throw methodName + '() method does not exist';
- }
-
- if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
- throw new Error(methodName + ' has already been spied upon');
- }
-
- var spyObj = jasmine.createSpy(methodName);
-
- this.spies_.push(spyObj);
- spyObj.baseObj = obj;
- spyObj.methodName = methodName;
- spyObj.originalValue = obj[methodName];
-
- obj[methodName] = spyObj;
-
- return spyObj;
-};
-
-jasmine.Spec.prototype.removeAllSpies = function() {
- for (var i = 0; i < this.spies_.length; i++) {
- var spy = this.spies_[i];
- spy.baseObj[spy.methodName] = spy.originalValue;
- }
- this.spies_ = [];
-};
-
-/**
- * Internal representation of a Jasmine suite.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {String} description
- * @param {Function} specDefinitions
- * @param {jasmine.Suite} parentSuite
- */
-jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
- var self = this;
- self.id = env.nextSuiteId ? env.nextSuiteId() : null;
- self.description = description;
- self.queue = new jasmine.Queue(env);
- self.parentSuite = parentSuite;
- self.env = env;
- self.before_ = [];
- self.after_ = [];
- self.children_ = [];
- self.suites_ = [];
- self.specs_ = [];
-};
-
-jasmine.Suite.prototype.getFullName = function() {
- var fullName = this.description;
- for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
- fullName = parentSuite.description + ' ' + fullName;
- }
- return fullName;
-};
-
-jasmine.Suite.prototype.finish = function(onComplete) {
- this.env.reporter.reportSuiteResults(this);
- this.finished = true;
- if (typeof(onComplete) == 'function') {
- onComplete();
- }
-};
-
-jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
- beforeEachFunction.typeName = 'beforeEach';
- this.before_.unshift(beforeEachFunction);
-};
-
-jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
- afterEachFunction.typeName = 'afterEach';
- this.after_.unshift(afterEachFunction);
-};
-
-jasmine.Suite.prototype.results = function() {
- return this.queue.results();
-};
-
-jasmine.Suite.prototype.add = function(suiteOrSpec) {
- this.children_.push(suiteOrSpec);
- if (suiteOrSpec instanceof jasmine.Suite) {
- this.suites_.push(suiteOrSpec);
- this.env.currentRunner().addSuite(suiteOrSpec);
- } else {
- this.specs_.push(suiteOrSpec);
- }
- this.queue.add(suiteOrSpec);
-};
-
-jasmine.Suite.prototype.specs = function() {
- return this.specs_;
-};
-
-jasmine.Suite.prototype.suites = function() {
- return this.suites_;
-};
-
-jasmine.Suite.prototype.children = function() {
- return this.children_;
-};
-
-jasmine.Suite.prototype.execute = function(onComplete) {
- var self = this;
- this.queue.start(function () {
- self.finish(onComplete);
- });
-};
-jasmine.WaitsBlock = function(env, timeout, spec) {
- this.timeout = timeout;
- jasmine.Block.call(this, env, null, spec);
-};
-
-jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
-
-jasmine.WaitsBlock.prototype.execute = function (onComplete) {
- if (jasmine.VERBOSE) {
- this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
- }
- this.env.setTimeout(function () {
- onComplete();
- }, this.timeout);
-};
-/**
- * A block which waits for some condition to become true, with timeout.
- *
- * @constructor
- * @extends jasmine.Block
- * @param {jasmine.Env} env The Jasmine environment.
- * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
- * @param {Function} latchFunction A function which returns true when the desired condition has been met.
- * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
- * @param {jasmine.Spec} spec The Jasmine spec.
- */
-jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
- this.timeout = timeout || env.defaultTimeoutInterval;
- this.latchFunction = latchFunction;
- this.message = message;
- this.totalTimeSpentWaitingForLatch = 0;
- jasmine.Block.call(this, env, null, spec);
-};
-jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
-
-jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
-
-jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
- if (jasmine.VERBOSE) {
- this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
- }
- var latchFunctionResult;
- try {
- latchFunctionResult = this.latchFunction.apply(this.spec);
- } catch (e) {
- this.spec.fail(e);
- onComplete();
- return;
- }
-
- if (latchFunctionResult) {
- onComplete();
- } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
- var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
- this.spec.fail({
- name: 'timeout',
- message: message
- });
-
- this.abort = true;
- onComplete();
- } else {
- this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
- var self = this;
- this.env.setTimeout(function() {
- self.execute(onComplete);
- }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
- }
-};
-// Mock setTimeout, clearTimeout
-// Contributed by Pivotal Computer Systems, www.pivotalsf.com
-
-jasmine.FakeTimer = function() {
- this.reset();
-
- var self = this;
- self.setTimeout = function(funcToCall, millis) {
- self.timeoutsMade++;
- self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
- return self.timeoutsMade;
- };
-
- self.setInterval = function(funcToCall, millis) {
- self.timeoutsMade++;
- self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
- return self.timeoutsMade;
- };
-
- self.clearTimeout = function(timeoutKey) {
- self.scheduledFunctions[timeoutKey] = jasmine.undefined;
- };
-
- self.clearInterval = function(timeoutKey) {
- self.scheduledFunctions[timeoutKey] = jasmine.undefined;
- };
-
-};
-
-jasmine.FakeTimer.prototype.reset = function() {
- this.timeoutsMade = 0;
- this.scheduledFunctions = {};
- this.nowMillis = 0;
-};
-
-jasmine.FakeTimer.prototype.tick = function(millis) {
- var oldMillis = this.nowMillis;
- var newMillis = oldMillis + millis;
- this.runFunctionsWithinRange(oldMillis, newMillis);
- this.nowMillis = newMillis;
-};
-
-jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
- var scheduledFunc;
- var funcsToRun = [];
- for (var timeoutKey in this.scheduledFunctions) {
- scheduledFunc = this.scheduledFunctions[timeoutKey];
- if (scheduledFunc != jasmine.undefined &&
- scheduledFunc.runAtMillis >= oldMillis &&
- scheduledFunc.runAtMillis <= nowMillis) {
- funcsToRun.push(scheduledFunc);
- this.scheduledFunctions[timeoutKey] = jasmine.undefined;
- }
- }
-
- if (funcsToRun.length > 0) {
- funcsToRun.sort(function(a, b) {
- return a.runAtMillis - b.runAtMillis;
- });
- for (var i = 0; i < funcsToRun.length; ++i) {
- try {
- var funcToRun = funcsToRun[i];
- this.nowMillis = funcToRun.runAtMillis;
- funcToRun.funcToCall();
- if (funcToRun.recurring) {
- this.scheduleFunction(funcToRun.timeoutKey,
- funcToRun.funcToCall,
- funcToRun.millis,
- true);
- }
- } catch(e) {
- }
- }
- this.runFunctionsWithinRange(oldMillis, nowMillis);
- }
-};
-
-jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
- this.scheduledFunctions[timeoutKey] = {
- runAtMillis: this.nowMillis + millis,
- funcToCall: funcToCall,
- recurring: recurring,
- timeoutKey: timeoutKey,
- millis: millis
- };
-};
-
-/**
- * @namespace
- */
-jasmine.Clock = {
- defaultFakeTimer: new jasmine.FakeTimer(),
-
- reset: function() {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.defaultFakeTimer.reset();
- },
-
- tick: function(millis) {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.defaultFakeTimer.tick(millis);
- },
-
- runFunctionsWithinRange: function(oldMillis, nowMillis) {
- jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
- },
-
- scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
- jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
- },
-
- useMock: function() {
- if (!jasmine.Clock.isInstalled()) {
- var spec = jasmine.getEnv().currentSpec;
- spec.after(jasmine.Clock.uninstallMock);
-
- jasmine.Clock.installMock();
- }
- },
-
- installMock: function() {
- jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
- },
-
- uninstallMock: function() {
- jasmine.Clock.assertInstalled();
- jasmine.Clock.installed = jasmine.Clock.real;
- },
-
- real: {
- setTimeout: jasmine.getGlobal().setTimeout,
- clearTimeout: jasmine.getGlobal().clearTimeout,
- setInterval: jasmine.getGlobal().setInterval,
- clearInterval: jasmine.getGlobal().clearInterval
- },
-
- assertInstalled: function() {
- if (!jasmine.Clock.isInstalled()) {
- throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
- }
- },
-
- isInstalled: function() {
- return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
- },
-
- installed: null
-};
-jasmine.Clock.installed = jasmine.Clock.real;
-
-//else for IE support
-jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
- if (jasmine.Clock.installed.setTimeout.apply) {
- return jasmine.Clock.installed.setTimeout.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.setTimeout(funcToCall, millis);
- }
-};
-
-jasmine.getGlobal().setInterval = function(funcToCall, millis) {
- if (jasmine.Clock.installed.setInterval.apply) {
- return jasmine.Clock.installed.setInterval.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.setInterval(funcToCall, millis);
- }
-};
-
-jasmine.getGlobal().clearTimeout = function(timeoutKey) {
- if (jasmine.Clock.installed.clearTimeout.apply) {
- return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.clearTimeout(timeoutKey);
- }
-};
-
-jasmine.getGlobal().clearInterval = function(timeoutKey) {
- if (jasmine.Clock.installed.clearTimeout.apply) {
- return jasmine.Clock.installed.clearInterval.apply(this, arguments);
- } else {
- return jasmine.Clock.installed.clearInterval(timeoutKey);
- }
-};
-
-jasmine.version_= {
- "major": 1,
- "minor": 1,
- "build": 0,
- "revision": 1315677058
-};
diff --git a/src/fauxton/test/jasmine/vendor/jasmine_favicon.png b/src/fauxton/test/jasmine/vendor/jasmine_favicon.png
deleted file mode 100644
index 218f3b437..000000000
--- a/src/fauxton/test/jasmine/vendor/jasmine_favicon.png
+++ /dev/null
Binary files differ
diff --git a/src/fauxton/test/mocha/chai.js b/src/fauxton/test/mocha/chai.js
new file mode 100644
index 000000000..2a67f982b
--- /dev/null
+++ b/src/fauxton/test/mocha/chai.js
@@ -0,0 +1,4330 @@
+;(function(){
+
+/**
+ * Require the given path.
+ *
+ * @param {String} path
+ * @return {Object} exports
+ * @api public
+ */
+
+function require(path, parent, orig) {
+ var resolved = require.resolve(path);
+
+ // lookup failed
+ if (null == resolved) {
+ orig = orig || path;
+ parent = parent || 'root';
+ var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
+ err.path = orig;
+ err.parent = parent;
+ err.require = true;
+ throw err;
+ }
+
+ var module = require.modules[resolved];
+
+ // perform real require()
+ // by invoking the module's
+ // registered function
+ if (!module.exports) {
+ module.exports = {};
+ module.client = module.component = true;
+ module.call(this, module.exports, require.relative(resolved), module);
+ }
+
+ return module.exports;
+}
+
+/**
+ * Registered modules.
+ */
+
+require.modules = {};
+
+/**
+ * Registered aliases.
+ */
+
+require.aliases = {};
+
+/**
+ * Resolve `path`.
+ *
+ * Lookup:
+ *
+ * - PATH/index.js
+ * - PATH.js
+ * - PATH
+ *
+ * @param {String} path
+ * @return {String} path or null
+ * @api private
+ */
+
+require.resolve = function(path) {
+ if (path.charAt(0) === '/') path = path.slice(1);
+
+ var paths = [
+ path,
+ path + '.js',
+ path + '.json',
+ path + '/index.js',
+ path + '/index.json'
+ ];
+
+ for (var i = 0; i < paths.length; i++) {
+ var path = paths[i];
+ if (require.modules.hasOwnProperty(path)) return path;
+ if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
+ }
+};
+
+/**
+ * Normalize `path` relative to the current path.
+ *
+ * @param {String} curr
+ * @param {String} path
+ * @return {String}
+ * @api private
+ */
+
+require.normalize = function(curr, path) {
+ var segs = [];
+
+ if ('.' != path.charAt(0)) return path;
+
+ curr = curr.split('/');
+ path = path.split('/');
+
+ for (var i = 0; i < path.length; ++i) {
+ if ('..' == path[i]) {
+ curr.pop();
+ } else if ('.' != path[i] && '' != path[i]) {
+ segs.push(path[i]);
+ }
+ }
+
+ return curr.concat(segs).join('/');
+};
+
+/**
+ * Register module at `path` with callback `definition`.
+ *
+ * @param {String} path
+ * @param {Function} definition
+ * @api private
+ */
+
+require.register = function(path, definition) {
+ require.modules[path] = definition;
+};
+
+/**
+ * Alias a module definition.
+ *
+ * @param {String} from
+ * @param {String} to
+ * @api private
+ */
+
+require.alias = function(from, to) {
+ if (!require.modules.hasOwnProperty(from)) {
+ throw new Error('Failed to alias "' + from + '", it does not exist');
+ }
+ require.aliases[to] = from;
+};
+
+/**
+ * Return a require function relative to the `parent` path.
+ *
+ * @param {String} parent
+ * @return {Function}
+ * @api private
+ */
+
+require.relative = function(parent) {
+ var p = require.normalize(parent, '..');
+
+ /**
+ * lastIndexOf helper.
+ */
+
+ function lastIndexOf(arr, obj) {
+ var i = arr.length;
+ while (i--) {
+ if (arr[i] === obj) return i;
+ }
+ return -1;
+ }
+
+ /**
+ * The relative require() itself.
+ */
+
+ function localRequire(path) {
+ var resolved = localRequire.resolve(path);
+ return require(resolved, parent, path);
+ }
+
+ /**
+ * Resolve relative to the parent.
+ */
+
+ localRequire.resolve = function(path) {
+ var c = path.charAt(0);
+ if ('/' == c) return path.slice(1);
+ if ('.' == c) return require.normalize(p, path);
+
+ // resolve deps by returning
+ // the dep in the nearest "deps"
+ // directory
+ var segs = parent.split('/');
+ var i = lastIndexOf(segs, 'deps') + 1;
+ if (!i) i = 0;
+ path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
+ return path;
+ };
+
+ /**
+ * Check if module is defined at `path`.
+ */
+
+ localRequire.exists = function(path) {
+ return require.modules.hasOwnProperty(localRequire.resolve(path));
+ };
+
+ return localRequire;
+};
+require.register("chaijs-assertion-error/index.js", function(exports, require, module){
+/*!
+ * assertion-error
+ * Copyright(c) 2013 Jake Luer <jake@qualiancy.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Return a function that will copy properties from
+ * one object to another excluding any originally
+ * listed. Returned function will create a new `{}`.
+ *
+ * @param {String} excluded properties ...
+ * @return {Function}
+ */
+
+function exclude () {
+ var excludes = [].slice.call(arguments);
+
+ function excludeProps (res, obj) {
+ Object.keys(obj).forEach(function (key) {
+ if (!~excludes.indexOf(key)) res[key] = obj[key];
+ });
+ }
+
+ return function extendExclude () {
+ var args = [].slice.call(arguments)
+ , i = 0
+ , res = {};
+
+ for (; i < args.length; i++) {
+ excludeProps(res, args[i]);
+ }
+
+ return res;
+ };
+};
+
+/*!
+ * Primary Exports
+ */
+
+module.exports = AssertionError;
+
+/**
+ * ### AssertionError
+ *
+ * An extension of the JavaScript `Error` constructor for
+ * assertion and validation scenarios.
+ *
+ * @param {String} message
+ * @param {Object} properties to include (optional)
+ * @param {callee} start stack function (optional)
+ */
+
+function AssertionError (message, _props, ssf) {
+ var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON')
+ , props = extend(_props || {});
+
+ // default values
+ this.message = message || 'Unspecified AssertionError';
+ this.showDiff = false;
+
+ // copy from properties
+ for (var key in props) {
+ this[key] = props[key];
+ }
+
+ // capture stack trace
+ ssf = ssf || arguments.callee;
+ if (ssf && Error.captureStackTrace) {
+ Error.captureStackTrace(this, ssf);
+ }
+}
+
+/*!
+ * Inherit from Error.prototype
+ */
+
+AssertionError.prototype = Object.create(Error.prototype);
+
+/*!
+ * Statically set name
+ */
+
+AssertionError.prototype.name = 'AssertionError';
+
+/*!
+ * Ensure correct constructor
+ */
+
+AssertionError.prototype.constructor = AssertionError;
+
+/**
+ * Allow errors to be converted to JSON for static transfer.
+ *
+ * @param {Boolean} include stack (default: `true`)
+ * @return {Object} object that can be `JSON.stringify`
+ */
+
+AssertionError.prototype.toJSON = function (stack) {
+ var extend = exclude('constructor', 'toJSON', 'stack')
+ , props = extend({ name: this.name }, this);
+
+ // include stack if exists and not turned off
+ if (false !== stack && this.stack) {
+ props.stack = this.stack;
+ }
+
+ return props;
+};
+
+});
+require.register("chai/index.js", function(exports, require, module){
+module.exports = require('./lib/chai');
+
+});
+require.register("chai/lib/chai.js", function(exports, require, module){
+/*!
+ * chai
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+var used = []
+ , exports = module.exports = {};
+
+/*!
+ * Chai version
+ */
+
+exports.version = '1.7.2';
+
+/*!
+ * Assertion Error
+ */
+
+exports.AssertionError = require('assertion-error');
+
+/*!
+ * Utils for plugins (not exported)
+ */
+
+var util = require('./chai/utils');
+
+/**
+ * # .use(function)
+ *
+ * Provides a way to extend the internals of Chai
+ *
+ * @param {Function}
+ * @returns {this} for chaining
+ * @api public
+ */
+
+exports.use = function (fn) {
+ if (!~used.indexOf(fn)) {
+ fn(this, util);
+ used.push(fn);
+ }
+
+ return this;
+};
+
+/*!
+ * Primary `Assertion` prototype
+ */
+
+var assertion = require('./chai/assertion');
+exports.use(assertion);
+
+/*!
+ * Core Assertions
+ */
+
+var core = require('./chai/core/assertions');
+exports.use(core);
+
+/*!
+ * Expect interface
+ */
+
+var expect = require('./chai/interface/expect');
+exports.use(expect);
+
+/*!
+ * Should interface
+ */
+
+var should = require('./chai/interface/should');
+exports.use(should);
+
+/*!
+ * Assert interface
+ */
+
+var assert = require('./chai/interface/assert');
+exports.use(assert);
+
+});
+require.register("chai/lib/chai/assertion.js", function(exports, require, module){
+/*!
+ * chai
+ * http://chaijs.com
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+module.exports = function (_chai, util) {
+ /*!
+ * Module dependencies.
+ */
+
+ var AssertionError = _chai.AssertionError
+ , flag = util.flag;
+
+ /*!
+ * Module export.
+ */
+
+ _chai.Assertion = Assertion;
+
+ /*!
+ * Assertion Constructor
+ *
+ * Creates object for chaining.
+ *
+ * @api private
+ */
+
+ function Assertion (obj, msg, stack) {
+ flag(this, 'ssfi', stack || arguments.callee);
+ flag(this, 'object', obj);
+ flag(this, 'message', msg);
+ }
+
+ /*!
+ * ### 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.showDiff
+ *
+ * User configurable property, influences whether or not
+ * the `showDiff` flag should be included in the thrown
+ * AssertionErrors. `false` will always be `false`; `true`
+ * will be true when the assertion has requested a diff
+ * be shown.
+ *
+ * @api public
+ */
+
+ Assertion.showDiff = true;
+
+ 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, showDiff) {
+ var ok = util.test(this, arguments);
+ if (true !== showDiff) showDiff = false;
+ if (true !== Assertion.showDiff) showDiff = false;
+
+ if (!ok) {
+ var msg = util.getMessage(this, arguments)
+ , actual = util.getActual(this, arguments);
+ throw new AssertionError(msg, {
+ actual: actual
+ , expected: expected
+ , showDiff: showDiff
+ }, (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);
+ }
+ });
+};
+
+});
+require.register("chai/lib/chai/core/assertions.js", function(exports, require, module){
+/*!
+ * chai
+ * http://chaijs.com
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+module.exports = function (chai, _) {
+ var Assertion = chai.Assertion
+ , toString = Object.prototype.toString
+ , flag = _.flag;
+
+ /**
+ * ### 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
+ * - that
+ * - and
+ * - have
+ * - with
+ * - at
+ * - of
+ * - same
+ *
+ * @name language chains
+ * @api public
+ */
+
+ [ 'to', 'be', 'been'
+ , 'is', 'and', 'have'
+ , 'with', 'that', 'at'
+ , 'of', 'same' ].forEach(function (chain) {
+ Assertion.addProperty(chain, function () {
+ return this;
+ });
+ });
+
+ /**
+ * ### .not
+ *
+ * Negates any of assertions following in the chain.
+ *
+ * expect(foo).to.not.equal('bar');
+ * expect(goodFn).to.not.throw(Error);
+ * expect({ foo: 'baz' }).to.have.property('foo')
+ * .and.not.equal('bar');
+ *
+ * @name not
+ * @api public
+ */
+
+ Assertion.addProperty('not', function () {
+ flag(this, 'negate', true);
+ });
+
+ /**
+ * ### .deep
+ *
+ * Sets the `deep` flag, later used by the `equal` and
+ * `property` assertions.
+ *
+ * expect(foo).to.deep.equal({ bar: 'baz' });
+ * expect({ foo: { bar: { baz: 'quux' } } })
+ * .to.have.deep.property('foo.bar.baz', 'quux');
+ *
+ * @name deep
+ * @api public
+ */
+
+ Assertion.addProperty('deep', function () {
+ flag(this, 'deep', 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.
+ *
+ * // 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
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function an (type, msg) {
+ if (msg) flag(this, 'message', msg);
+ type = type.toLowerCase();
+ var obj = flag(this, 'object')
+ , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a ';
+
+ this.assert(
+ type === _.type(obj)
+ , 'expected #{this} to be ' + article + type
+ , 'expected #{this} not to be ' + article + type
+ );
+ }
+
+ Assertion.addChainableMethod('an', an);
+ Assertion.addChainableMethod('a', an);
+
+ /**
+ * ### .include(value)
+ *
+ * The `include` and `contain` assertions can be used as either property
+ * based language chains or as methods to assert the inclusion of an object
+ * in an array or a substring in a string. When used as language chains,
+ * they toggle the `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
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function includeChainingBehavior () {
+ flag(this, 'contains', true);
+ }
+
+ function include (val, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object')
+ this.assert(
+ ~obj.indexOf(val)
+ , 'expected #{this} to include ' + _.inspect(val)
+ , 'expected #{this} to not include ' + _.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
+ */
+
+ Assertion.addProperty('ok', function () {
+ this.assert(
+ flag(this, 'object')
+ , 'expected #{this} to be truthy'
+ , 'expected #{this} to be falsy');
+ });
+
+ /**
+ * ### .true
+ *
+ * Asserts that the target is `true`.
+ *
+ * expect(true).to.be.true;
+ * expect(1).to.not.be.true;
+ *
+ * @name true
+ * @api public
+ */
+
+ Assertion.addProperty('true', function () {
+ this.assert(
+ true === flag(this, 'object')
+ , 'expected #{this} to be true'
+ , 'expected #{this} to be false'
+ , this.negate ? false : true
+ );
+ });
+
+ /**
+ * ### .false
+ *
+ * Asserts that the target is `false`.
+ *
+ * expect(false).to.be.false;
+ * expect(0).to.not.be.false;
+ *
+ * @name false
+ * @api public
+ */
+
+ Assertion.addProperty('false', function () {
+ this.assert(
+ false === flag(this, 'object')
+ , 'expected #{this} to be false'
+ , 'expected #{this} to be true'
+ , this.negate ? true : false
+ );
+ });
+
+ /**
+ * ### .null
+ *
+ * Asserts that the target is `null`.
+ *
+ * expect(null).to.be.null;
+ * expect(undefined).not.to.be.null;
+ *
+ * @name null
+ * @api public
+ */
+
+ Assertion.addProperty('null', function () {
+ this.assert(
+ null === flag(this, 'object')
+ , 'expected #{this} to be null'
+ , 'expected #{this} not to be null'
+ );
+ });
+
+ /**
+ * ### .undefined
+ *
+ * Asserts that the target is `undefined`.
+ *
+ * expect(undefined).to.be.undefined;
+ * expect(null).to.not.be.undefined;
+ *
+ * @name undefined
+ * @api public
+ */
+
+ Assertion.addProperty('undefined', function () {
+ this.assert(
+ undefined === flag(this, 'object')
+ , 'expected #{this} to be undefined'
+ , 'expected #{this} not to be undefined'
+ );
+ });
+
+ /**
+ * ### .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
+ */
+
+ Assertion.addProperty('exist', function () {
+ this.assert(
+ null != flag(this, 'object')
+ , 'expected #{this} to exist'
+ , 'expected #{this} to not exist'
+ );
+ });
+
+
+ /**
+ * ### .empty
+ *
+ * Asserts that the target's length is `0`. For arrays, 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
+ */
+
+ Assertion.addProperty('empty', function () {
+ var obj = flag(this, 'object')
+ , expected = obj;
+
+ if (Array.isArray(obj) || 'string' === typeof object) {
+ expected = obj.length;
+ } else if (typeof obj === 'object') {
+ expected = Object.keys(obj).length;
+ }
+
+ this.assert(
+ !expected
+ , 'expected #{this} to be empty'
+ , 'expected #{this} not to be empty'
+ );
+ });
+
+ /**
+ * ### .arguments
+ *
+ * Asserts that the target is an arguments object.
+ *
+ * function test () {
+ * expect(arguments).to.be.arguments;
+ * }
+ *
+ * @name arguments
+ * @alias Arguments
+ * @api public
+ */
+
+ function checkArguments () {
+ var obj = flag(this, 'object')
+ , type = Object.prototype.toString.call(obj);
+ this.assert(
+ '[object Arguments]' === type
+ , 'expected #{this} to be arguments but got ' + type
+ , 'expected #{this} to not be arguments'
+ );
+ }
+
+ Assertion.addProperty('arguments', checkArguments);
+ Assertion.addProperty('Arguments', checkArguments);
+
+ /**
+ * ### .equal(value)
+ *
+ * Asserts that the target is strictly equal (`===`) to `value`.
+ * Alternately, if the `deep` flag is set, asserts that
+ * the target is deeply equal to `value`.
+ *
+ * expect('hello').to.equal('hello');
+ * expect(42).to.equal(42);
+ * expect(1).to.not.equal(true);
+ * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
+ * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
+ *
+ * @name equal
+ * @alias equals
+ * @alias eq
+ * @alias deep.equal
+ * @param {Mixed} value
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertEqual (val, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ if (flag(this, 'deep')) {
+ return this.eql(val);
+ } else {
+ this.assert(
+ val === obj
+ , 'expected #{this} to equal #{exp}'
+ , 'expected #{this} to not equal #{exp}'
+ , val
+ , this._obj
+ , true
+ );
+ }
+ }
+
+ Assertion.addMethod('equal', assertEqual);
+ Assertion.addMethod('equals', assertEqual);
+ Assertion.addMethod('eq', assertEqual);
+
+ /**
+ * ### .eql(value)
+ *
+ * Asserts that the target is deeply equal to `value`.
+ *
+ * expect({ foo: 'bar' }).to.eql({ foo: 'bar' });
+ * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]);
+ *
+ * @name eql
+ * @alias eqls
+ * @param {Mixed} value
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertEql(obj, msg) {
+ if (msg) flag(this, 'message', msg);
+ this.assert(
+ _.eql(obj, flag(this, 'object'))
+ , 'expected #{this} to deeply equal #{exp}'
+ , 'expected #{this} to not deeply equal #{exp}'
+ , obj
+ , this._obj
+ , true
+ );
+ }
+
+ Assertion.addMethod('eql', assertEql);
+ Assertion.addMethod('eqls', assertEql);
+
+ /**
+ * ### .above(value)
+ *
+ * Asserts that the target is greater than `value`.
+ *
+ * expect(10).to.be.above(5);
+ *
+ * Can also be used in conjunction with `length` to
+ * assert a minimum length. The benefit being a
+ * more informative error message than if the length
+ * was supplied directly.
+ *
+ * expect('foo').to.have.length.above(2);
+ * expect([ 1, 2, 3 ]).to.have.length.above(2);
+ *
+ * @name above
+ * @alias gt
+ * @alias greaterThan
+ * @param {Number} value
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertAbove (n, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ if (flag(this, 'doLength')) {
+ new Assertion(obj, msg).to.have.property('length');
+ var len = obj.length;
+ this.assert(
+ len > n
+ , 'expected #{this} to have a length above #{exp} but got #{act}'
+ , 'expected #{this} to not have a length above #{exp}'
+ , n
+ , len
+ );
+ } else {
+ this.assert(
+ obj > n
+ , 'expected #{this} to be above ' + n
+ , 'expected #{this} to be at most ' + n
+ );
+ }
+ }
+
+ Assertion.addMethod('above', assertAbove);
+ Assertion.addMethod('gt', assertAbove);
+ Assertion.addMethod('greaterThan', assertAbove);
+
+ /**
+ * ### .least(value)
+ *
+ * Asserts that the target is greater than or equal to `value`.
+ *
+ * expect(10).to.be.at.least(10);
+ *
+ * Can also be used in conjunction with `length` to
+ * assert a minimum length. The benefit being a
+ * more informative error message than if the length
+ * was supplied directly.
+ *
+ * expect('foo').to.have.length.of.at.least(2);
+ * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3);
+ *
+ * @name least
+ * @alias gte
+ * @param {Number} value
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertLeast (n, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ if (flag(this, 'doLength')) {
+ new Assertion(obj, msg).to.have.property('length');
+ var len = obj.length;
+ this.assert(
+ len >= n
+ , 'expected #{this} to have a length at least #{exp} but got #{act}'
+ , 'expected #{this} to have a length below #{exp}'
+ , n
+ , len
+ );
+ } else {
+ this.assert(
+ obj >= n
+ , 'expected #{this} to be at least ' + n
+ , 'expected #{this} to be below ' + n
+ );
+ }
+ }
+
+ Assertion.addMethod('least', assertLeast);
+ Assertion.addMethod('gte', assertLeast);
+
+ /**
+ * ### .below(value)
+ *
+ * Asserts that the target is less than `value`.
+ *
+ * expect(5).to.be.below(10);
+ *
+ * Can also be used in conjunction with `length` to
+ * assert a maximum length. The benefit being a
+ * more informative error message than if the length
+ * was supplied directly.
+ *
+ * expect('foo').to.have.length.below(4);
+ * expect([ 1, 2, 3 ]).to.have.length.below(4);
+ *
+ * @name below
+ * @alias lt
+ * @alias lessThan
+ * @param {Number} value
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertBelow (n, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ if (flag(this, 'doLength')) {
+ new Assertion(obj, msg).to.have.property('length');
+ var len = obj.length;
+ this.assert(
+ len < n
+ , 'expected #{this} to have a length below #{exp} but got #{act}'
+ , 'expected #{this} to not have a length below #{exp}'
+ , n
+ , len
+ );
+ } else {
+ this.assert(
+ obj < n
+ , 'expected #{this} to be below ' + n
+ , 'expected #{this} to be at least ' + n
+ );
+ }
+ }
+
+ Assertion.addMethod('below', assertBelow);
+ Assertion.addMethod('lt', assertBelow);
+ Assertion.addMethod('lessThan', assertBelow);
+
+ /**
+ * ### .most(value)
+ *
+ * Asserts that the target is less than or equal to `value`.
+ *
+ * expect(5).to.be.at.most(5);
+ *
+ * Can also be used in conjunction with `length` to
+ * assert a maximum length. The benefit being a
+ * more informative error message than if the length
+ * was supplied directly.
+ *
+ * expect('foo').to.have.length.of.at.most(4);
+ * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3);
+ *
+ * @name most
+ * @alias lte
+ * @param {Number} value
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertMost (n, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ if (flag(this, 'doLength')) {
+ new Assertion(obj, msg).to.have.property('length');
+ var len = obj.length;
+ this.assert(
+ len <= n
+ , 'expected #{this} to have a length at most #{exp} but got #{act}'
+ , 'expected #{this} to have a length above #{exp}'
+ , n
+ , len
+ );
+ } else {
+ this.assert(
+ obj <= n
+ , 'expected #{this} to be at most ' + n
+ , 'expected #{this} to be above ' + n
+ );
+ }
+ }
+
+ Assertion.addMethod('most', assertMost);
+ Assertion.addMethod('lte', assertMost);
+
+ /**
+ * ### .within(start, finish)
+ *
+ * Asserts that the target is within a range.
+ *
+ * expect(7).to.be.within(5,10);
+ *
+ * Can also be used in conjunction with `length` to
+ * assert a length range. The benefit being a
+ * more informative error message than if the length
+ * was supplied directly.
+ *
+ * expect('foo').to.have.length.within(2,4);
+ * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
+ *
+ * @name within
+ * @param {Number} start lowerbound inclusive
+ * @param {Number} finish upperbound inclusive
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('within', function (start, finish, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object')
+ , range = start + '..' + finish;
+ if (flag(this, 'doLength')) {
+ new Assertion(obj, msg).to.have.property('length');
+ var len = obj.length;
+ this.assert(
+ len >= start && len <= finish
+ , 'expected #{this} to have a length within ' + range
+ , 'expected #{this} to not have a length within ' + range
+ );
+ } else {
+ this.assert(
+ obj >= start && obj <= finish
+ , 'expected #{this} to be within ' + range
+ , 'expected #{this} to not be within ' + range
+ );
+ }
+ });
+
+ /**
+ * ### .instanceof(constructor)
+ *
+ * Asserts that the target is an instance of `constructor`.
+ *
+ * var Tea = function (name) { this.name = name; }
+ * , Chai = new Tea('chai');
+ *
+ * expect(Chai).to.be.an.instanceof(Tea);
+ * expect([ 1, 2, 3 ]).to.be.instanceof(Array);
+ *
+ * @name instanceof
+ * @param {Constructor} constructor
+ * @param {String} message _optional_
+ * @alias instanceOf
+ * @api public
+ */
+
+ function assertInstanceOf (constructor, msg) {
+ if (msg) flag(this, 'message', msg);
+ var name = _.getName(constructor);
+ this.assert(
+ flag(this, 'object') instanceof constructor
+ , 'expected #{this} to be an instance of ' + name
+ , 'expected #{this} to not be an instance of ' + name
+ );
+ };
+
+ Assertion.addMethod('instanceof', assertInstanceOf);
+ Assertion.addMethod('instanceOf', assertInstanceOf);
+
+ /**
+ * ### .property(name, [value])
+ *
+ * Asserts that the target has a property `name`, optionally asserting that
+ * the value of that property is strictly equal to `value`.
+ * If the `deep` flag is set, you can use dot- and bracket-notation for deep
+ * references into objects and arrays.
+ *
+ * // simple referencing
+ * var obj = { foo: 'bar' };
+ * expect(obj).to.have.property('foo');
+ * expect(obj).to.have.property('foo', 'bar');
+ *
+ * // deep referencing
+ * var deepObj = {
+ * green: { tea: 'matcha' }
+ * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
+ * };
+
+ * expect(deepObj).to.have.deep.property('green.tea', 'matcha');
+ * expect(deepObj).to.have.deep.property('teas[1]', 'matcha');
+ * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha');
+ *
+ * You can also use an array as the starting point of a `deep.property`
+ * assertion, or traverse nested arrays.
+ *
+ * var arr = [
+ * [ 'chai', 'matcha', 'konacha' ]
+ * , [ { tea: 'chai' }
+ * , { tea: 'matcha' }
+ * , { tea: 'konacha' } ]
+ * ];
+ *
+ * expect(arr).to.have.deep.property('[0][1]', 'matcha');
+ * expect(arr).to.have.deep.property('[1][2].tea', 'konacha');
+ *
+ * Furthermore, `property` changes the subject of the assertion
+ * to be the value of that property from the original object. This
+ * permits for further chainable assertions on that property.
+ *
+ * expect(obj).to.have.property('foo')
+ * .that.is.a('string');
+ * expect(deepObj).to.have.property('green')
+ * .that.is.an('object')
+ * .that.deep.equals({ tea: 'matcha' });
+ * expect(deepObj).to.have.property('teas')
+ * .that.is.an('array')
+ * .with.deep.property('[2]')
+ * .that.deep.equals({ tea: 'konacha' });
+ *
+ * @name property
+ * @alias deep.property
+ * @param {String} name
+ * @param {Mixed} value (optional)
+ * @param {String} message _optional_
+ * @returns value of property for chaining
+ * @api public
+ */
+
+ Assertion.addMethod('property', function (name, val, msg) {
+ if (msg) flag(this, 'message', msg);
+
+ var descriptor = flag(this, 'deep') ? 'deep property ' : 'property '
+ , negate = flag(this, 'negate')
+ , obj = flag(this, 'object')
+ , value = flag(this, 'deep')
+ ? _.getPathValue(name, obj)
+ : obj[name];
+
+ if (negate && undefined !== val) {
+ if (undefined === value) {
+ msg = (msg != null) ? msg + ': ' : '';
+ throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name));
+ }
+ } else {
+ this.assert(
+ undefined !== value
+ , 'expected #{this} to have a ' + descriptor + _.inspect(name)
+ , 'expected #{this} to not have ' + descriptor + _.inspect(name));
+ }
+
+ if (undefined !== val) {
+ this.assert(
+ val === value
+ , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}'
+ , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}'
+ , val
+ , value
+ );
+ }
+
+ flag(this, 'object', value);
+ });
+
+
+ /**
+ * ### .ownProperty(name)
+ *
+ * Asserts that the target has an own property `name`.
+ *
+ * expect('test').to.have.ownProperty('length');
+ *
+ * @name ownProperty
+ * @alias haveOwnProperty
+ * @param {String} name
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertOwnProperty (name, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ this.assert(
+ obj.hasOwnProperty(name)
+ , 'expected #{this} to have own property ' + _.inspect(name)
+ , 'expected #{this} to not have own property ' + _.inspect(name)
+ );
+ }
+
+ Assertion.addMethod('ownProperty', assertOwnProperty);
+ Assertion.addMethod('haveOwnProperty', assertOwnProperty);
+
+ /**
+ * ### .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);
+ *
+ * Can also be used as a chain precursor to a value
+ * comparison for the length property.
+ *
+ * expect('foo').to.have.length.above(2);
+ * expect([ 1, 2, 3 ]).to.have.length.above(2);
+ * expect('foo').to.have.length.below(4);
+ * expect([ 1, 2, 3 ]).to.have.length.below(4);
+ * expect('foo').to.have.length.within(2,4);
+ * expect([ 1, 2, 3 ]).to.have.length.within(2,4);
+ *
+ * @name length
+ * @alias lengthOf
+ * @param {Number} length
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ function assertLengthChain () {
+ flag(this, 'doLength', true);
+ }
+
+ function assertLength (n, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ new Assertion(obj, msg).to.have.property('length');
+ var len = obj.length;
+
+ this.assert(
+ len == n
+ , 'expected #{this} to have a length of #{exp} but got #{act}'
+ , 'expected #{this} to not have a length of #{act}'
+ , n
+ , len
+ );
+ }
+
+ Assertion.addChainableMethod('length', assertLength, assertLengthChain);
+ Assertion.addMethod('lengthOf', assertLength, assertLengthChain);
+
+ /**
+ * ### .match(regexp)
+ *
+ * Asserts that the target matches a regular expression.
+ *
+ * expect('foobar').to.match(/^foo/);
+ *
+ * @name match
+ * @param {RegExp} RegularExpression
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('match', function (re, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ this.assert(
+ re.exec(obj)
+ , 'expected #{this} to match ' + re
+ , 'expected #{this} not to match ' + re
+ );
+ });
+
+ /**
+ * ### .string(string)
+ *
+ * Asserts that the string target contains another string.
+ *
+ * expect('foobar').to.have.string('bar');
+ *
+ * @name string
+ * @param {String} string
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('string', function (str, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ new Assertion(obj, msg).is.a('string');
+
+ this.assert(
+ ~obj.indexOf(str)
+ , 'expected #{this} to contain ' + _.inspect(str)
+ , 'expected #{this} to not contain ' + _.inspect(str)
+ );
+ });
+
+
+ /**
+ * ### .keys(key1, [key2], [...])
+ *
+ * Asserts that the target 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
+ */
+
+ function assertKeys (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 _.inspect(key);
+ });
+ var last = keys.pop();
+ str = keys.join(', ') + ', and ' + last;
+ } else {
+ str = _.inspect(keys[0]);
+ }
+
+ // Form
+ str = (len > 1 ? 'keys ' : 'key ') + str;
+
+ // Have / include
+ str = (flag(this, 'contains') ? 'contain ' : 'have ') + str;
+
+ // Assertion
+ this.assert(
+ ok
+ , 'expected #{this} to ' + str
+ , 'expected #{this} to not ' + str
+ );
+ }
+
+ Assertion.addMethod('keys', assertKeys);
+ Assertion.addMethod('key', assertKeys);
+
+ /**
+ * ### .throw(constructor)
+ *
+ * Asserts that the function target will throw a specific error, or specific type of error
+ * (as determined using `instanceof`), optionally with a RegExp or string inclusion test
+ * for the error's message.
+ *
+ * var err = new ReferenceError('This is a bad function.');
+ * var fn = function () { throw err; }
+ * expect(fn).to.throw(ReferenceError);
+ * expect(fn).to.throw(Error);
+ * expect(fn).to.throw(/bad function/);
+ * expect(fn).to.not.throw('good function');
+ * expect(fn).to.throw(ReferenceError, /bad function/);
+ * expect(fn).to.throw(err);
+ * 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
+ * @param {String|RegExp} expected error message
+ * @param {String} message _optional_
+ * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types
+ * @api public
+ */
+
+ function assertThrows (constructor, errMsg, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ new Assertion(obj, msg).is.a('function');
+
+ var thrown = false
+ , desiredError = null
+ , name = null
+ , thrownError = null;
+
+ if (arguments.length === 0) {
+ errMsg = null;
+ constructor = null;
+ } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) {
+ errMsg = constructor;
+ constructor = null;
+ } else if (constructor && constructor instanceof Error) {
+ desiredError = constructor;
+ constructor = null;
+ errMsg = null;
+ } else if (typeof constructor === 'function') {
+ name = (new constructor()).name;
+ } else {
+ constructor = null;
+ }
+
+ try {
+ obj();
+ } catch (err) {
+ // first, check desired error
+ if (desiredError) {
+ this.assert(
+ err === desiredError
+ , 'expected #{this} to throw #{exp} but #{act} was thrown'
+ , 'expected #{this} to not throw #{exp}'
+ , desiredError
+ , err
+ );
+
+ return this;
+ }
+ // next, check constructor
+ if (constructor) {
+ this.assert(
+ err instanceof constructor
+ , 'expected #{this} to throw #{exp} but #{act} was thrown'
+ , 'expected #{this} to not throw #{exp} but #{act} was thrown'
+ , name
+ , err
+ );
+
+ if (!errMsg) return this;
+ }
+ // next, check message
+ var message = 'object' === _.type(err) && "message" in err
+ ? err.message
+ : '' + err;
+
+ if ((message != null) && errMsg && errMsg instanceof RegExp) {
+ this.assert(
+ errMsg.exec(message)
+ , 'expected #{this} to throw error matching #{exp} but got #{act}'
+ , 'expected #{this} to throw error not matching #{exp}'
+ , errMsg
+ , message
+ );
+
+ return this;
+ } else if ((message != null) && errMsg && 'string' === typeof errMsg) {
+ this.assert(
+ ~message.indexOf(errMsg)
+ , 'expected #{this} to throw error including #{exp} but got #{act}'
+ , 'expected #{this} to throw error not including #{act}'
+ , errMsg
+ , message
+ );
+
+ return this;
+ } else {
+ thrown = true;
+ thrownError = err;
+ }
+ }
+
+ var actuallyGot = ''
+ , expectedThrown = name !== null
+ ? name
+ : desiredError
+ ? '#{exp}' //_.inspect(desiredError)
+ : 'an error';
+
+ if (thrown) {
+ actuallyGot = ' but #{act} was thrown'
+ }
+
+ this.assert(
+ thrown === true
+ , 'expected #{this} to throw ' + expectedThrown + actuallyGot
+ , 'expected #{this} to not throw ' + expectedThrown + actuallyGot
+ , desiredError
+ , thrownError
+ );
+ };
+
+ Assertion.addMethod('throw', assertThrows);
+ Assertion.addMethod('throws', assertThrows);
+ Assertion.addMethod('Throw', assertThrows);
+
+ /**
+ * ### .respondTo(method)
+ *
+ * Asserts that the object or class target will respond to a method.
+ *
+ * Klass.prototype.bar = function(){};
+ * expect(Klass).to.respondTo('bar');
+ * expect(obj).to.respondTo('bar');
+ *
+ * To check if a constructor will respond to a static function,
+ * set the `itself` flag.
+ *
+ * Klass.baz = function(){};
+ * expect(Klass).itself.to.respondTo('baz');
+ *
+ * @name respondTo
+ * @param {String} method
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('respondTo', function (method, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object')
+ , itself = flag(this, 'itself')
+ , context = ('function' === _.type(obj) && !itself)
+ ? obj.prototype[method]
+ : obj[method];
+
+ this.assert(
+ 'function' === typeof context
+ , 'expected #{this} to respond to ' + _.inspect(method)
+ , 'expected #{this} to not respond to ' + _.inspect(method)
+ );
+ });
+
+ /**
+ * ### .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
+ */
+
+ Assertion.addProperty('itself', function () {
+ flag(this, 'itself', true);
+ });
+
+ /**
+ * ### .satisfy(method)
+ *
+ * Asserts that the target passes a given truth test.
+ *
+ * expect(1).to.satisfy(function(num) { return num > 0; });
+ *
+ * @name satisfy
+ * @param {Function} matcher
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('satisfy', function (matcher, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ this.assert(
+ matcher(obj)
+ , 'expected #{this} to satisfy ' + _.objDisplay(matcher)
+ , 'expected #{this} to not satisfy' + _.objDisplay(matcher)
+ , this.negate ? false : true
+ , matcher(obj)
+ );
+ });
+
+ /**
+ * ### .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
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('closeTo', function (expected, delta, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+ this.assert(
+ Math.abs(obj - expected) <= delta
+ , 'expected #{this} to be close to ' + expected + ' +/- ' + delta
+ , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta
+ );
+ });
+
+ function isSubsetOf(subset, superset) {
+ return subset.every(function(elem) {
+ return superset.indexOf(elem) !== -1;
+ })
+ }
+
+ /**
+ * ### .members(set)
+ *
+ * Asserts that the target is a superset of `set`,
+ * or that the target and `set` have the same members.
+ *
+ * expect([1, 2, 3]).to.include.members([3, 2]);
+ * expect([1, 2, 3]).to.not.include.members([3, 2, 8]);
+ *
+ * expect([4, 2]).to.have.members([2, 4]);
+ * expect([5, 2]).to.not.have.members([5, 2, 1]);
+ *
+ * @name members
+ * @param {Array} set
+ * @param {String} message _optional_
+ * @api public
+ */
+
+ Assertion.addMethod('members', function (subset, msg) {
+ if (msg) flag(this, 'message', msg);
+ var obj = flag(this, 'object');
+
+ new Assertion(obj).to.be.an('array');
+ new Assertion(subset).to.be.an('array');
+
+ if (flag(this, 'contains')) {
+ return this.assert(
+ isSubsetOf(subset, obj)
+ , 'expected #{this} to be a superset of #{act}'
+ , 'expected #{this} to not be a superset of #{act}'
+ , obj
+ , subset
+ );
+ }
+
+ this.assert(
+ isSubsetOf(obj, subset) && isSubsetOf(subset, obj)
+ , 'expected #{this} to have the same members as #{act}'
+ , 'expected #{this} to not have the same members as #{act}'
+ , obj
+ , subset
+ );
+ });
+};
+
+});
+require.register("chai/lib/chai/interface/assert.js", function(exports, require, module){
+/*!
+ * chai
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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;
+ };
+
+ /**
+ * ### .notOk(object, [message])
+ *
+ * Asserts that `object` is falsy.
+ *
+ * assert.notOk('everything', 'this will fail');
+ * assert.notOk(false, 'this will pass');
+ *
+ * @name notOk
+ * @param {Mixed} object to test
+ * @param {String} message
+ * @api public
+ */
+
+ assert.notOk = function (val, msg) {
+ new Assertion(val, msg).is.not.ok;
+ };
+
+ /**
+ * ### .equal(actual, expected, [message])
+ *
+ * Asserts non-strict equality (`==`) of `actual` and `expected`.
+ *
+ * assert.equal(3, '3', '== coerces values to strings');
+ *
+ * @name equal
+ * @param {Mixed} actual
+ * @param {Mixed} expected
+ * @param {String} message
+ * @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 isDefined
+ * @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);
+ } else {
+ throw new chai.AssertionError(
+ 'expected an array or string'
+ , null
+ , assert.include
+ );
+ }
+ };
+
+ /**
+ * ### .notInclude(haystack, needle, [message])
+ *
+ * Asserts that `haystack` does not include `needle`. Works
+ * for strings and arrays.
+ *i
+ * assert.notInclude('foobar', 'baz', 'string not include substring');
+ * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value');
+ *
+ * @name notInclude
+ * @param {Array|String} haystack
+ * @param {Mixed} needle
+ * @param {String} message
+ * @api public
+ */
+
+ assert.notInclude = function (exp, inc, msg) {
+ var obj = new Assertion(exp, msg);
+
+ if (Array.isArray(exp)) {
+ obj.to.not.include(inc);
+ } else if ('string' === typeof exp) {
+ obj.to.not.contain.string(inc);
+ } else {
+ throw new chai.AssertionError(
+ 'expected an array or string'
+ , null
+ , assert.notInclude
+ );
+ }
+ };
+
+ /**
+ * ### .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/string/regexp], [string/regexp], [message])
+ *
+ * Asserts that `function` will throw an error that is an instance of
+ * `constructor`, or alternately that it will throw an error with message
+ * matching `regexp`.
+ *
+ * assert.throw(fn, 'function throws a reference error');
+ * assert.throw(fn, /function throws a reference error/);
+ * assert.throw(fn, ReferenceError);
+ * assert.throw(fn, ReferenceError, 'function throws a reference error');
+ * 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, errt, errs, msg) {
+ if ('string' === typeof errt || errt instanceof RegExp) {
+ errs = errt;
+ errt = null;
+ }
+
+ new Assertion(fn, msg).to.Throw(errt, errs);
+ };
+
+ /**
+ * ### .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) );
+ };
+
+ /**
+ * ### .closeTo(actual, expected, delta, [message])
+ *
+ * Asserts that the target is equal `expected`, to within a +/- `delta` range.
+ *
+ * assert.closeTo(1.5, 1, 0.5, 'numbers are close');
+ *
+ * @name closeTo
+ * @param {Number} actual
+ * @param {Number} expected
+ * @param {Number} delta
+ * @param {String} message
+ * @api public
+ */
+
+ assert.closeTo = function (act, exp, delta, msg) {
+ new Assertion(act, msg).to.be.closeTo(exp, delta);
+ };
+
+ /**
+ * ### .sameMembers(set1, set2, [message])
+ *
+ * Asserts that `set1` and `set2` have the same members.
+ * Order is not taken into account.
+ *
+ * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members');
+ *
+ * @name sameMembers
+ * @param {Array} superset
+ * @param {Array} subset
+ * @param {String} message
+ * @api public
+ */
+
+ assert.sameMembers = function (set1, set2, msg) {
+ new Assertion(set1, msg).to.have.same.members(set2);
+ }
+
+ /**
+ * ### .includeMembers(superset, subset, [message])
+ *
+ * Asserts that `subset` is included in `superset`.
+ * Order is not taken into account.
+ *
+ * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members');
+ *
+ * @name includeMembers
+ * @param {Array} superset
+ * @param {Array} subset
+ * @param {String} message
+ * @api public
+ */
+
+ assert.includeMembers = function (superset, subset, msg) {
+ new Assertion(superset, msg).to.include.members(subset);
+ }
+
+ /*!
+ * 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');
+};
+
+});
+require.register("chai/lib/chai/interface/expect.js", function(exports, require, module){
+/*!
+ * chai
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+module.exports = function (chai, util) {
+ chai.expect = function (val, message) {
+ return new chai.Assertion(val, message);
+ };
+};
+
+
+});
+require.register("chai/lib/chai/interface/should.js", function(exports, require, module){
+/*!
+ * chai
+ * Copyright(c) 2011-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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 (value) {
+ // See https://github.com/chaijs/chai/issues/86: this makes
+ // `whatever.should = someValue` actually set `someValue`, which is
+ // especially useful for `global.should = require('chai').should()`.
+ //
+ // Note that we have to use [[DefineProperty]] instead of [[Put]]
+ // since otherwise we would trigger this very setter!
+ Object.defineProperty(this, 'should', {
+ value: value,
+ enumerable: true,
+ configurable: true,
+ writable: true
+ });
+ }
+ , 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, msg) {
+ new Assertion(val1, msg).to.equal(val2);
+ };
+
+ should.Throw = function (fn, errt, errs, msg) {
+ new Assertion(fn, msg).to.Throw(errt, errs);
+ };
+
+ should.exist = function (val, msg) {
+ new Assertion(val, msg).to.exist;
+ }
+
+ // negation
+ should.not = {}
+
+ should.not.equal = function (val1, val2, msg) {
+ new Assertion(val1, msg).to.not.equal(val2);
+ };
+
+ should.not.Throw = function (fn, errt, errs, msg) {
+ new Assertion(fn, msg).to.not.Throw(errt, errs);
+ };
+
+ should.not.exist = function (val, msg) {
+ new Assertion(val, msg).to.not.exist;
+ }
+
+ should['throw'] = should['Throw'];
+ should.not['throw'] = should.not['Throw'];
+
+ return should;
+ };
+
+ chai.should = loadShould;
+ chai.Should = loadShould;
+};
+
+});
+require.register("chai/lib/chai/utils/addChainableMethod.js", function(exports, require, module){
+/*!
+ * Chai - addChainingMethod utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Module dependencies
+ */
+
+var transferFlags = require('./transferFlags');
+
+/*!
+ * Module variables
+ */
+
+// Check whether `__proto__` is supported
+var hasProtoSupport = '__proto__' in Object;
+
+// Without `__proto__` support, this module will need to add properties to a function.
+// However, some Function.prototype methods cannot be overwritten,
+// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69).
+var excludeNames = /^(?:length|name|arguments|caller)$/;
+
+// Cache `Function` properties
+var call = Function.prototype.call,
+ apply = Function.prototype.apply;
+
+/**
+ * ### addChainableMethod (ctx, name, method, chainingBehavior)
+ *
+ * Adds a method to an object, such that the method can also be chained.
+ *
+ * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) {
+ * var obj = utils.flag(this, 'object');
+ * new chai.Assertion(obj).to.be.equal(str);
+ * });
+ *
+ * Can also be accessed directly from `chai.Assertion`.
+ *
+ * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior);
+ *
+ * The result can then be used as both a method assertion, executing both `method` and
+ * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`.
+ *
+ * expect(fooStr).to.be.foo('bar');
+ * expect(fooStr).to.be.foo.equal('foo');
+ *
+ * @param {Object} ctx object to which the method is added
+ * @param {String} name of method to add
+ * @param {Function} method function to be used for `name`, when called
+ * @param {Function} chainingBehavior function to be called every time the property is accessed
+ * @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;
+ };
+
+ // Use `__proto__` if available
+ if (hasProtoSupport) {
+ // Inherit all properties from the object by replacing the `Function` prototype
+ var prototype = assert.__proto__ = Object.create(this);
+ // Restore the `call` and `apply` methods from `Function`
+ prototype.call = call;
+ prototype.apply = apply;
+ }
+ // Otherwise, redefine all properties (slow!)
+ else {
+ var asserterNames = Object.getOwnPropertyNames(ctx);
+ asserterNames.forEach(function (asserterName) {
+ if (!excludeNames.test(asserterName)) {
+ var pd = Object.getOwnPropertyDescriptor(ctx, asserterName);
+ Object.defineProperty(assert, asserterName, pd);
+ }
+ });
+ }
+
+ transferFlags(this, assert);
+ return assert;
+ }
+ , configurable: true
+ });
+};
+
+});
+require.register("chai/lib/chai/utils/addMethod.js", function(exports, require, module){
+/*!
+ * Chai - addMethod utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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;
+ };
+};
+
+});
+require.register("chai/lib/chai/utils/addProperty.js", function(exports, require, module){
+/*!
+ * Chai - addProperty utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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
+ });
+};
+
+});
+require.register("chai/lib/chai/utils/eql.js", function(exports, require, module){
+// This is (almost) directly from Node.js assert
+// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/assert.js
+
+module.exports = _deepEqual;
+
+var getEnumerableProperties = require('./getEnumerableProperties');
+
+// for the browser
+var Buffer;
+try {
+ Buffer = require('buffer').Buffer;
+} catch (ex) {
+ Buffer = {
+ isBuffer: function () { return false; }
+ };
+}
+
+function _deepEqual(actual, expected, memos) {
+
+ // 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 (expected instanceof Date) {
+ if (!(actual instanceof Date)) return false;
+ 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;
+
+ } else if (expected instanceof RegExp) {
+ if (!(actual instanceof RegExp)) return false;
+ return actual.toString() === expected.toString();
+
+ // 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, memos);
+ }
+}
+
+function isUndefinedOrNull(value) {
+ return value === null || value === undefined;
+}
+
+function isArguments(object) {
+ return Object.prototype.toString.call(object) == '[object Arguments]';
+}
+
+function objEquiv(a, b, memos) {
+ if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
+ return false;
+
+ // an identical 'prototype' property.
+ if (a.prototype !== b.prototype) return false;
+
+ // check if we have already compared a and b
+ var i;
+ if (memos) {
+ for(i = 0; i < memos.length; i++) {
+ if ((memos[i][0] === a && memos[i][1] === b) ||
+ (memos[i][0] === b && memos[i][1] === a))
+ return true;
+ }
+ } else {
+ memos = [];
+ }
+
+ //~~~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, memos);
+ }
+ try {
+ var ka = getEnumerableProperties(a),
+ kb = getEnumerableProperties(b),
+ key;
+ } 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;
+ }
+
+ // remember objects we have compared to guard against circular references
+ memos.push([ a, b ]);
+
+ //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], memos)) return false;
+ }
+
+ return true;
+}
+
+});
+require.register("chai/lib/chai/utils/flag.js", function(exports, require, module){
+/*!
+ * Chai - flag utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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];
+ }
+};
+
+});
+require.register("chai/lib/chai/utils/getActual.js", function(exports, require, module){
+/*!
+ * Chai - getActual utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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' !== typeof actual ? actual : obj._obj;
+};
+
+});
+require.register("chai/lib/chai/utils/getEnumerableProperties.js", function(exports, require, module){
+/*!
+ * Chai - getEnumerableProperties utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/**
+ * ### .getEnumerableProperties(object)
+ *
+ * This allows the retrieval of enumerable property names of an object,
+ * inherited or not.
+ *
+ * @param {Object} object
+ * @returns {Array}
+ * @name getEnumerableProperties
+ * @api public
+ */
+
+module.exports = function getEnumerableProperties(object) {
+ var result = [];
+ for (var name in object) {
+ result.push(name);
+ }
+ return result;
+};
+
+});
+require.register("chai/lib/chai/utils/getMessage.js", function(exports, require, module){
+/*!
+ * Chai - message composition utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Module dependancies
+ */
+
+var flag = require('./flag')
+ , getActual = require('./getActual')
+ , inspect = require('./inspect')
+ , objDisplay = require('./objDisplay');
+
+/**
+ * ### .getMessage(object, message, negateMessage)
+ *
+ * Construct the error message based on flags
+ * and template tags. Template tags will return
+ * a stringified inspection of the object referenced.
+ *
+ * Message template tags:
+ * - `#{this}` current asserted object
+ * - `#{act}` actual value
+ * - `#{exp}` expected value
+ *
+ * @param {Object} object (constructed Assertion)
+ * @param {Arguments} chai.Assertion.prototype.assert arguments
+ * @name getMessage
+ * @api public
+ */
+
+module.exports = function (obj, args) {
+ var negate = flag(obj, 'negate')
+ , val = flag(obj, 'object')
+ , expected = args[3]
+ , actual = getActual(obj, args)
+ , msg = negate ? args[2] : args[1]
+ , flagMsg = flag(obj, 'message');
+
+ msg = msg || '';
+ msg = msg
+ .replace(/#{this}/g, objDisplay(val))
+ .replace(/#{act}/g, objDisplay(actual))
+ .replace(/#{exp}/g, objDisplay(expected));
+
+ return flagMsg ? flagMsg + ': ' + msg : msg;
+};
+
+});
+require.register("chai/lib/chai/utils/getName.js", function(exports, require, module){
+/*!
+ * Chai - getName utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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] : "";
+};
+
+});
+require.register("chai/lib/chai/utils/getPathValue.js", function(exports, require, module){
+/*!
+ * Chai - getPathValue utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * @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 str = path.replace(/\[/g, '.[')
+ , parts = str.match(/(\\\.|[^.]+?)+/g);
+ return parts.map(function (value) {
+ var re = /\[(\d+)\]$/
+ , mArr = re.exec(value)
+ if (mArr) return { i: parseFloat(mArr[1]) };
+ else return { p: value };
+ });
+};
+
+/*!
+ * ## _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 ('undefined' !== typeof part.p)
+ tmp = tmp[part.p];
+ else if ('undefined' !== typeof part.i)
+ tmp = tmp[part.i];
+ if (i == (l - 1)) res = tmp;
+ } else {
+ res = undefined;
+ }
+ }
+ return res;
+};
+
+});
+require.register("chai/lib/chai/utils/getProperties.js", function(exports, require, module){
+/*!
+ * Chai - getProperties utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/**
+ * ### .getProperties(object)
+ *
+ * This allows the retrieval of property names of an object, enumerable or not,
+ * inherited or not.
+ *
+ * @param {Object} object
+ * @returns {Array}
+ * @name getProperties
+ * @api public
+ */
+
+module.exports = function getProperties(object) {
+ var result = Object.getOwnPropertyNames(subject);
+
+ function addProperty(property) {
+ if (result.indexOf(property) === -1) {
+ result.push(property);
+ }
+ }
+
+ var proto = Object.getPrototypeOf(subject);
+ while (proto !== null) {
+ Object.getOwnPropertyNames(proto).forEach(addProperty);
+ proto = Object.getPrototypeOf(proto);
+ }
+
+ return result;
+};
+
+});
+require.register("chai/lib/chai/utils/index.js", function(exports, require, module){
+/*!
+ * chai
+ * Copyright(c) 2011 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Main exports
+ */
+
+var exports = module.exports = {};
+
+/*!
+ * test utility
+ */
+
+exports.test = require('./test');
+
+/*!
+ * type utility
+ */
+
+exports.type = require('./type');
+
+/*!
+ * message utility
+ */
+
+exports.getMessage = require('./getMessage');
+
+/*!
+ * actual utility
+ */
+
+exports.getActual = require('./getActual');
+
+/*!
+ * Inspect util
+ */
+
+exports.inspect = require('./inspect');
+
+/*!
+ * Object Display util
+ */
+
+exports.objDisplay = require('./objDisplay');
+
+/*!
+ * Flag utility
+ */
+
+exports.flag = require('./flag');
+
+/*!
+ * Flag transferring utility
+ */
+
+exports.transferFlags = require('./transferFlags');
+
+/*!
+ * Deep equal utility
+ */
+
+exports.eql = require('./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');
+
+
+});
+require.register("chai/lib/chai/utils/inspect.js", function(exports, require, module){
+// This is (almost) directly from Node.js utils
+// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js
+
+var getName = require('./getName');
+var getProperties = require('./getProperties');
+var getEnumerableProperties = require('./getEnumerableProperties');
+
+module.exports = inspect;
+
+/**
+ * Echos the value of a value. Trys to print the value out
+ * in the best way possible given the different types.
+ *
+ * @param {Object} obj The object to print out.
+ * @param {Boolean} showHidden Flag that shows hidden (not enumerable)
+ * properties of objects.
+ * @param {Number} depth Depth in which to descend in object. Default is 2.
+ * @param {Boolean} colors Flag to turn on ANSI escape codes to color the
+ * output. Default is false (no coloring).
+ */
+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));
+}
+
+// https://gist.github.com/1044128/
+var getOuterHTML = function(element) {
+ if ('outerHTML' in element) return element.outerHTML;
+ var ns = "http://www.w3.org/1999/xhtml";
+ var container = document.createElementNS(ns, '_');
+ var elemProto = (window.HTMLElement || window.Element).prototype;
+ var xmlSerializer = new XMLSerializer();
+ var html;
+ if (document.xmlVersion) {
+ return xmlSerializer.serializeToString(element);
+ } else {
+ container.appendChild(element.cloneNode(false));
+ html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');
+ container.innerHTML = '';
+ return html;
+ }
+};
+
+// Returns true if object is a DOM element.
+var isDOMElement = function (object) {
+ if (typeof HTMLElement === 'object') {
+ return object instanceof HTMLElement;
+ } else {
+ return object &&
+ typeof object === 'object' &&
+ object.nodeType === 1 &&
+ typeof object.nodeName === 'string';
+ }
+};
+
+function formatValue(ctx, value, recurseTimes) {
+ // Provide a hook for user-specified inspect functions.
+ // Check that value is an object with an inspect function on it
+ if (value && typeof value.inspect === 'function' &&
+ // Filter out the util module, it's inspect function is special
+ value.inspect !== exports.inspect &&
+ // Also filter out any prototype objects using the circular check.
+ !(value.constructor && value.constructor.prototype === value)) {
+ var ret = value.inspect(recurseTimes);
+ if (typeof ret !== 'string') {
+ ret = formatValue(ctx, ret, recurseTimes);
+ }
+ return ret;
+ }
+
+ // Primitive types cannot have properties
+ var primitive = formatPrimitive(ctx, value);
+ if (primitive) {
+ return primitive;
+ }
+
+ // If it's DOM elem, get outer HTML.
+ if (isDOMElement(value)) {
+ return getOuterHTML(value);
+ }
+
+ // Look up the keys of the object.
+ var visibleKeys = getEnumerableProperties(value);
+ var keys = ctx.showHidden ? getProperties(value) : visibleKeys;
+
+ // Some type of object without properties can be shortcutted.
+ // In IE, errors have a single `stack` property, or if they are vanilla `Error`,
+ // a `stack` plus `description` property; ignore those for consistency.
+ if (keys.length === 0 || (isError(value) && (
+ (keys.length === 1 && keys[0] === 'stack') ||
+ (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack')
+ ))) {
+ if (typeof value === 'function') {
+ var name = getName(value);
+ var nameSuffix = name ? ': ' + name : '';
+ return ctx.stylize('[Function' + nameSuffix + ']', 'special');
+ }
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ }
+ if (isDate(value)) {
+ return ctx.stylize(Date.prototype.toUTCString.call(value), 'date');
+ }
+ if (isError(value)) {
+ return formatError(value);
+ }
+ }
+
+ var base = '', array = false, braces = ['{', '}'];
+
+ // Make Array say that they are Array
+ if (isArray(value)) {
+ array = true;
+ braces = ['[', ']'];
+ }
+
+ // Make functions say that they are functions
+ if (typeof value === 'function') {
+ var name = getName(value);
+ var nameSuffix = name ? ': ' + name : '';
+ base = ' [Function' + nameSuffix + ']';
+ }
+
+ // Make RegExps say that they are RegExps
+ if (isRegExp(value)) {
+ base = ' ' + RegExp.prototype.toString.call(value);
+ }
+
+ // Make dates with properties first say the date
+ if (isDate(value)) {
+ base = ' ' + Date.prototype.toUTCString.call(value);
+ }
+
+ // Make error with message first say the error
+ if (isError(value)) {
+ return formatError(value);
+ }
+
+ if (keys.length === 0 && (!array || value.length == 0)) {
+ return braces[0] + base + braces[1];
+ }
+
+ if (recurseTimes < 0) {
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ } else {
+ return ctx.stylize('[Object]', 'special');
+ }
+ }
+
+ ctx.seen.push(value);
+
+ var output;
+ if (array) {
+ output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+ } else {
+ output = keys.map(function(key) {
+ return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+ });
+ }
+
+ ctx.seen.pop();
+
+ return reduceToSingleString(output, base, braces);
+}
+
+
+function formatPrimitive(ctx, value) {
+ switch (typeof value) {
+ case 'undefined':
+ return ctx.stylize('undefined', 'undefined');
+
+ case 'string':
+ var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+ .replace(/'/g, "\\'")
+ .replace(/\\"/g, '"') + '\'';
+ return ctx.stylize(simple, 'string');
+
+ case 'number':
+ 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);
+}
+
+});
+require.register("chai/lib/chai/utils/objDisplay.js", function(exports, require, module){
+/*!
+ * Chai - flag utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Module dependancies
+ */
+
+var inspect = require('./inspect');
+
+/**
+ * ### .objDisplay (object)
+ *
+ * Determines if an object or an array matches
+ * criteria to be inspected in-line for error
+ * messages or should be truncated.
+ *
+ * @param {Mixed} javascript object to inspect
+ * @name objDisplay
+ * @api public
+ */
+
+module.exports = function (obj) {
+ var str = inspect(obj)
+ , type = Object.prototype.toString.call(obj);
+
+ if (str.length >= 40) {
+ if (type === '[object Function]') {
+ return !obj.name || obj.name === ''
+ ? '[Function]'
+ : '[Function: ' + obj.name + ']';
+ } else if (type === '[object Array]') {
+ return '[ Array(' + obj.length + ') ]';
+ } else if (type === '[object Object]') {
+ var keys = Object.keys(obj)
+ , kstr = keys.length > 2
+ ? keys.splice(0, 2).join(', ') + ', ...'
+ : keys.join(', ');
+ return '{ Object (' + kstr + ') }';
+ } else {
+ return str;
+ }
+ } else {
+ return str;
+ }
+};
+
+});
+require.register("chai/lib/chai/utils/overwriteMethod.js", function(exports, require, module){
+/*!
+ * Chai - overwriteMethod utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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;
+ }
+};
+
+});
+require.register("chai/lib/chai/utils/overwriteProperty.js", function(exports, require, module){
+/*!
+ * Chai - overwriteProperty utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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
+ });
+};
+
+});
+require.register("chai/lib/chai/utils/test.js", function(exports, require, module){
+/*!
+ * Chai - test utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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;
+};
+
+});
+require.register("chai/lib/chai/utils/transferFlags.js", function(exports, require, module){
+/*!
+ * Chai - transferFlags utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * 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];
+ }
+ }
+};
+
+});
+require.register("chai/lib/chai/utils/type.js", function(exports, require, module){
+/*!
+ * Chai - type utility
+ * Copyright(c) 2012-2013 Jake Luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+
+/*!
+ * Detectable javascript natives
+ */
+
+var natives = {
+ '[object Arguments]': 'arguments'
+ , '[object Array]': 'array'
+ , '[object Date]': 'date'
+ , '[object Function]': 'function'
+ , '[object Number]': 'number'
+ , '[object RegExp]': 'regexp'
+ , '[object String]': 'string'
+};
+
+/**
+ * ### type(object)
+ *
+ * Better implementation of `typeof` detection that can
+ * be used cross-browser. Handles the inconsistencies of
+ * Array, `null`, and `undefined` detection.
+ *
+ * utils.type({}) // 'object'
+ * utils.type(null) // `null'
+ * utils.type(undefined) // `undefined`
+ * utils.type([]) // `array`
+ *
+ * @param {Mixed} object to detect type of
+ * @name type
+ * @api private
+ */
+
+module.exports = function (obj) {
+ var str = Object.prototype.toString.call(obj);
+ if (natives[str]) return natives[str];
+ if (obj === null) return 'null';
+ if (obj === undefined) return 'undefined';
+ if (obj === Object(obj)) return 'object';
+ return typeof obj;
+};
+
+});
+require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js");
+require.alias("chaijs-assertion-error/index.js", "chai/deps/assertion-error/index.js");
+require.alias("chaijs-assertion-error/index.js", "assertion-error/index.js");
+require.alias("chaijs-assertion-error/index.js", "chaijs-assertion-error/index.js");
+
+require.alias("chai/index.js", "chai/index.js");
+
+if (typeof exports == "object") {
+ module.exports = require("chai");
+} else if (typeof define == "function" && define.amd) {
+ define(function(){ return require("chai"); });
+} else {
+ this["chai"] = require("chai");
+}})();
diff --git a/src/fauxton/test/mocha/mocha.css b/src/fauxton/test/mocha/mocha.css
new file mode 100755
index 000000000..1d7478401
--- /dev/null
+++ b/src/fauxton/test/mocha/mocha.css
@@ -0,0 +1,251 @@
+@charset "utf-8";
+
+body {
+ margin:0;
+}
+
+#mocha {
+ font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 60px 50px;
+}
+
+#mocha ul, #mocha li {
+ margin: 0;
+ padding: 0;
+}
+
+#mocha ul {
+ list-style: none;
+}
+
+#mocha h1, #mocha h2 {
+ margin: 0;
+}
+
+#mocha h1 {
+ margin-top: 15px;
+ font-size: 1em;
+ font-weight: 200;
+}
+
+#mocha h1 a {
+ text-decoration: none;
+ color: inherit;
+}
+
+#mocha h1 a:hover {
+ text-decoration: underline;
+}
+
+#mocha .suite .suite h1 {
+ margin-top: 0;
+ font-size: .8em;
+}
+
+#mocha .hidden {
+ display: none;
+}
+
+#mocha h2 {
+ font-size: 12px;
+ font-weight: normal;
+ cursor: pointer;
+}
+
+#mocha .suite {
+ margin-left: 15px;
+}
+
+#mocha .test {
+ margin-left: 15px;
+ overflow: hidden;
+}
+
+#mocha .test.pending:hover h2::after {
+ content: '(pending)';
+ font-family: arial, sans-serif;
+}
+
+#mocha .test.pass.medium .duration {
+ background: #C09853;
+}
+
+#mocha .test.pass.slow .duration {
+ background: #B94A48;
+}
+
+#mocha .test.pass::before {
+ content: '✓';
+ font-size: 12px;
+ display: block;
+ float: left;
+ margin-right: 5px;
+ color: #00d6b2;
+}
+
+#mocha .test.pass .duration {
+ font-size: 9px;
+ margin-left: 5px;
+ padding: 2px 5px;
+ color: white;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -ms-border-radius: 5px;
+ -o-border-radius: 5px;
+ border-radius: 5px;
+}
+
+#mocha .test.pass.fast .duration {
+ display: none;
+}
+
+#mocha .test.pending {
+ color: #0b97c4;
+}
+
+#mocha .test.pending::before {
+ content: '◦';
+ color: #0b97c4;
+}
+
+#mocha .test.fail {
+ color: #c00;
+}
+
+#mocha .test.fail pre {
+ color: black;
+}
+
+#mocha .test.fail::before {
+ content: '✖';
+ font-size: 12px;
+ display: block;
+ float: left;
+ margin-right: 5px;
+ color: #c00;
+}
+
+#mocha .test pre.error {
+ color: #c00;
+ max-height: 300px;
+ overflow: auto;
+}
+
+#mocha .test pre {
+ display: block;
+ float: left;
+ clear: left;
+ font: 12px/1.5 monaco, monospace;
+ margin: 5px;
+ padding: 15px;
+ border: 1px solid #eee;
+ border-bottom-color: #ddd;
+ -webkit-border-radius: 3px;
+ -webkit-box-shadow: 0 1px 3px #eee;
+ -moz-border-radius: 3px;
+ -moz-box-shadow: 0 1px 3px #eee;
+}
+
+#mocha .test h2 {
+ position: relative;
+}
+
+#mocha .test a.replay {
+ position: absolute;
+ top: 3px;
+ right: 0;
+ text-decoration: none;
+ vertical-align: middle;
+ display: block;
+ width: 15px;
+ height: 15px;
+ line-height: 15px;
+ text-align: center;
+ background: #eee;
+ font-size: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;
+ -webkit-transition: opacity 200ms;
+ -moz-transition: opacity 200ms;
+ transition: opacity 200ms;
+ opacity: 0.3;
+ color: #888;
+}
+
+#mocha .test:hover a.replay {
+ opacity: 1;
+}
+
+#mocha-report.pass .test.fail {
+ display: none;
+}
+
+#mocha-report.fail .test.pass {
+ display: none;
+}
+
+#mocha-error {
+ color: #c00;
+ font-size: 1.5em;
+ font-weight: 100;
+ letter-spacing: 1px;
+}
+
+#mocha-stats {
+ position: fixed;
+ top: 15px;
+ right: 10px;
+ font-size: 12px;
+ margin: 0;
+ color: #888;
+ z-index: 1;
+}
+
+#mocha-stats .progress {
+ float: right;
+ padding-top: 0;
+}
+
+#mocha-stats em {
+ color: black;
+}
+
+#mocha-stats a {
+ text-decoration: none;
+ color: inherit;
+}
+
+#mocha-stats a:hover {
+ border-bottom: 1px solid #eee;
+}
+
+#mocha-stats li {
+ display: inline-block;
+ margin: 0 5px;
+ list-style: none;
+ padding-top: 11px;
+}
+
+#mocha-stats canvas {
+ width: 40px;
+ height: 40px;
+}
+
+#mocha code .comment { color: #ddd }
+#mocha code .init { color: #2F6FAD }
+#mocha code .string { color: #5890AD }
+#mocha code .keyword { color: #8A6343 }
+#mocha code .number { color: #2F6FAD }
+
+@media screen and (max-device-width: 480px) {
+ #mocha {
+ margin: 60px 0px;
+ }
+
+ #mocha #stats {
+ position: absolute;
+ }
+}
diff --git a/src/fauxton/test/mocha/mocha.js b/src/fauxton/test/mocha/mocha.js
new file mode 100755
index 000000000..a55115a31
--- /dev/null
+++ b/src/fauxton/test/mocha/mocha.js
@@ -0,0 +1,5428 @@
+;(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.charAt(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("browser/debug.js", function(module, exports, require){
+
+module.exports = function(type){
+ return function(){
+ }
+};
+
+}); // module: browser/debug.js
+
+require.register("browser/diff.js", function(module, exports, require){
+/* See license.txt for terms of usage */
+
+/*
+ * Text diff implementation.
+ *
+ * This library supports the following APIS:
+ * JsDiff.diffChars: Character by character diff
+ * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
+ * JsDiff.diffLines: Line based diff
+ *
+ * JsDiff.diffCss: Diff targeted at CSS content
+ *
+ * These methods are based on the implementation proposed in
+ * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
+ */
+var JsDiff = (function() {
+ function clonePath(path) {
+ return { newPos: path.newPos, components: path.components.slice(0) };
+ }
+ function removeEmpty(array) {
+ var ret = [];
+ for (var i = 0; i < array.length; i++) {
+ if (array[i]) {
+ ret.push(array[i]);
+ }
+ }
+ return ret;
+ }
+ function escapeHTML(s) {
+ var n = s;
+ n = n.replace(/&/g, "&amp;");
+ n = n.replace(/</g, "&lt;");
+ n = n.replace(/>/g, "&gt;");
+ n = n.replace(/"/g, "&quot;");
+
+ return n;
+ }
+
+
+ var fbDiff = function(ignoreWhitespace) {
+ this.ignoreWhitespace = ignoreWhitespace;
+ };
+ fbDiff.prototype = {
+ diff: function(oldString, newString) {
+ // Handle the identity case (this is due to unrolling editLength == 0
+ if (newString == oldString) {
+ return [{ value: newString }];
+ }
+ if (!newString) {
+ return [{ value: oldString, removed: true }];
+ }
+ if (!oldString) {
+ return [{ value: newString, added: true }];
+ }
+
+ newString = this.tokenize(newString);
+ oldString = this.tokenize(oldString);
+
+ var newLen = newString.length, oldLen = oldString.length;
+ var maxEditLength = newLen + oldLen;
+ var bestPath = [{ newPos: -1, components: [] }];
+
+ // Seed editLength = 0
+ var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
+ if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
+ return bestPath[0].components;
+ }
+
+ for (var editLength = 1; editLength <= maxEditLength; editLength++) {
+ for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
+ var basePath;
+ var addPath = bestPath[diagonalPath-1],
+ removePath = bestPath[diagonalPath+1];
+ oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
+ if (addPath) {
+ // No one else is going to attempt to use this value, clear it
+ bestPath[diagonalPath-1] = undefined;
+ }
+
+ var canAdd = addPath && addPath.newPos+1 < newLen;
+ var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
+ if (!canAdd && !canRemove) {
+ bestPath[diagonalPath] = undefined;
+ continue;
+ }
+
+ // Select the diagonal that we want to branch from. We select the prior
+ // path whose position in the new string is the farthest from the origin
+ // and does not pass the bounds of the diff graph
+ if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
+ basePath = clonePath(removePath);
+ this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
+ } else {
+ basePath = clonePath(addPath);
+ basePath.newPos++;
+ this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
+ }
+
+ var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
+
+ if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
+ return basePath.components;
+ } else {
+ bestPath[diagonalPath] = basePath;
+ }
+ }
+ }
+ },
+
+ pushComponent: function(components, value, added, removed) {
+ var last = components[components.length-1];
+ if (last && last.added === added && last.removed === removed) {
+ // We need to clone here as the component clone operation is just
+ // as shallow array clone
+ components[components.length-1] =
+ {value: this.join(last.value, value), added: added, removed: removed };
+ } else {
+ components.push({value: value, added: added, removed: removed });
+ }
+ },
+ extractCommon: function(basePath, newString, oldString, diagonalPath) {
+ var newLen = newString.length,
+ oldLen = oldString.length,
+ newPos = basePath.newPos,
+ oldPos = newPos - diagonalPath;
+ while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
+ newPos++;
+ oldPos++;
+
+ this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
+ }
+ basePath.newPos = newPos;
+ return oldPos;
+ },
+
+ equals: function(left, right) {
+ var reWhitespace = /\S/;
+ if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
+ return true;
+ } else {
+ return left == right;
+ }
+ },
+ join: function(left, right) {
+ return left + right;
+ },
+ tokenize: function(value) {
+ return value;
+ }
+ };
+
+ var CharDiff = new fbDiff();
+
+ var WordDiff = new fbDiff(true);
+ WordDiff.tokenize = function(value) {
+ return removeEmpty(value.split(/(\s+|\b)/));
+ };
+
+ var CssDiff = new fbDiff(true);
+ CssDiff.tokenize = function(value) {
+ return removeEmpty(value.split(/([{}:;,]|\s+)/));
+ };
+
+ var LineDiff = new fbDiff();
+ LineDiff.tokenize = function(value) {
+ return value.split(/^/m);
+ };
+
+ return {
+ diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
+ diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
+ diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
+
+ diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
+
+ createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
+ var ret = [];
+
+ ret.push("Index: " + fileName);
+ ret.push("===================================================================");
+ ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
+ ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
+
+ var diff = LineDiff.diff(oldStr, newStr);
+ if (!diff[diff.length-1].value) {
+ diff.pop(); // Remove trailing newline add
+ }
+ diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier
+
+ function contextLines(lines) {
+ return lines.map(function(entry) { return ' ' + entry; });
+ }
+ function eofNL(curRange, i, current) {
+ var last = diff[diff.length-2],
+ isLast = i === diff.length-2,
+ isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);
+
+ // Figure out if this is the last line for the given file and missing NL
+ if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
+ curRange.push('\\ No newline at end of file');
+ }
+ }
+
+ var oldRangeStart = 0, newRangeStart = 0, curRange = [],
+ oldLine = 1, newLine = 1;
+ for (var i = 0; i < diff.length; i++) {
+ var current = diff[i],
+ lines = current.lines || current.value.replace(/\n$/, "").split("\n");
+ current.lines = lines;
+
+ if (current.added || current.removed) {
+ if (!oldRangeStart) {
+ var prev = diff[i-1];
+ oldRangeStart = oldLine;
+ newRangeStart = newLine;
+
+ if (prev) {
+ curRange = contextLines(prev.lines.slice(-4));
+ oldRangeStart -= curRange.length;
+ newRangeStart -= curRange.length;
+ }
+ }
+ curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
+ eofNL(curRange, i, current);
+
+ if (current.added) {
+ newLine += lines.length;
+ } else {
+ oldLine += lines.length;
+ }
+ } else {
+ if (oldRangeStart) {
+ // Close out any changes that have been output (or join overlapping)
+ if (lines.length <= 8 && i < diff.length-2) {
+ // Overlapping
+ curRange.push.apply(curRange, contextLines(lines));
+ } else {
+ // end the range and output
+ var contextSize = Math.min(lines.length, 4);
+ ret.push(
+ "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
+ + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
+ + " @@");
+ ret.push.apply(ret, curRange);
+ ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
+ if (lines.length <= 4) {
+ eofNL(ret, i, current);
+ }
+
+ oldRangeStart = 0; newRangeStart = 0; curRange = [];
+ }
+ }
+ oldLine += lines.length;
+ newLine += lines.length;
+ }
+ }
+
+ return ret.join('\n') + '\n';
+ },
+
+ convertChangesToXML: function(changes){
+ var ret = [];
+ for ( var i = 0; i < changes.length; i++) {
+ var change = changes[i];
+ if (change.added) {
+ ret.push("<ins>");
+ } else if (change.removed) {
+ ret.push("<del>");
+ }
+
+ ret.push(escapeHTML(change.value));
+
+ if (change.added) {
+ ret.push("</ins>");
+ } else if (change.removed) {
+ ret.push("</del>");
+ }
+ }
+ return ret.join("");
+ }
+ };
+})();
+
+if (typeof module !== "undefined") {
+ module.exports = JsDiff;
+}
+
+}); // module: browser/diff.js
+
+require.register("browser/events.js", function(module, exports, require){
+
+/**
+ * Module exports.
+ */
+
+exports.EventEmitter = EventEmitter;
+
+/**
+ * Check if `obj` is an array.
+ */
+
+function isArray(obj) {
+ return '[object Array]' == {}.toString.call(obj);
+}
+
+/**
+ * Event emitter constructor.
+ *
+ * @api public
+ */
+
+function EventEmitter(){};
+
+/**
+ * Adds a listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.on = function (name, fn) {
+ if (!this.$events) {
+ this.$events = {};
+ }
+
+ if (!this.$events[name]) {
+ this.$events[name] = fn;
+ } else if (isArray(this.$events[name])) {
+ this.$events[name].push(fn);
+ } else {
+ this.$events[name] = [this.$events[name], fn];
+ }
+
+ return this;
+};
+
+EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+/**
+ * Adds a volatile listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.once = function (name, fn) {
+ var self = this;
+
+ function on () {
+ self.removeListener(name, on);
+ fn.apply(this, arguments);
+ };
+
+ on.listener = fn;
+ this.on(name, on);
+
+ return this;
+};
+
+/**
+ * Removes a listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.removeListener = function (name, fn) {
+ if (this.$events && this.$events[name]) {
+ var list = this.$events[name];
+
+ if (isArray(list)) {
+ var pos = -1;
+
+ for (var i = 0, l = list.length; i < l; i++) {
+ if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
+ pos = i;
+ break;
+ }
+ }
+
+ if (pos < 0) {
+ return this;
+ }
+
+ list.splice(pos, 1);
+
+ if (!list.length) {
+ delete this.$events[name];
+ }
+ } else if (list === fn || (list.listener && list.listener === fn)) {
+ delete this.$events[name];
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Removes all listeners for an event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.removeAllListeners = function (name) {
+ if (name === undefined) {
+ this.$events = {};
+ return this;
+ }
+
+ if (this.$events && this.$events[name]) {
+ this.$events[name] = null;
+ }
+
+ return this;
+};
+
+/**
+ * Gets all listeners for a certain event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.listeners = function (name) {
+ if (!this.$events) {
+ this.$events = {};
+ }
+
+ if (!this.$events[name]) {
+ this.$events[name] = [];
+ }
+
+ if (!isArray(this.$events[name])) {
+ this.$events[name] = [this.$events[name]];
+ }
+
+ return this.$events[name];
+};
+
+/**
+ * Emits an event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.emit = function (name) {
+ if (!this.$events) {
+ return false;
+ }
+
+ var handler = this.$events[name];
+
+ if (!handler) {
+ return false;
+ }
+
+ var args = [].slice.call(arguments, 1);
+
+ if ('function' == typeof handler) {
+ handler.apply(this, args);
+ } else if (isArray(handler)) {
+ var listeners = handler.slice();
+
+ for (var i = 0, l = listeners.length; i < l; i++) {
+ listeners[i].apply(this, args);
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+};
+}); // module: browser/events.js
+
+require.register("browser/fs.js", function(module, exports, require){
+
+}); // module: browser/fs.js
+
+require.register("browser/path.js", function(module, exports, require){
+
+}); // module: browser/path.js
+
+require.register("browser/progress.js", function(module, exports, require){
+
+/**
+ * Expose `Progress`.
+ */
+
+module.exports = Progress;
+
+/**
+ * Initialize a new `Progress` indicator.
+ */
+
+function Progress() {
+ this.percent = 0;
+ this.size(0);
+ this.fontSize(11);
+ this.font('helvetica, arial, sans-serif');
+}
+
+/**
+ * Set progress size to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.size = function(n){
+ this._size = n;
+ return this;
+};
+
+/**
+ * Set text to `str`.
+ *
+ * @param {String} str
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.text = function(str){
+ this._text = str;
+ return this;
+};
+
+/**
+ * Set font size to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.fontSize = function(n){
+ this._fontSize = n;
+ return this;
+};
+
+/**
+ * Set font `family`.
+ *
+ * @param {String} family
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.font = function(family){
+ this._font = family;
+ return this;
+};
+
+/**
+ * Update percentage to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.update = function(n){
+ this.percent = n;
+ return this;
+};
+
+/**
+ * Draw on `ctx`.
+ *
+ * @param {CanvasRenderingContext2d} ctx
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.draw = function(ctx){
+ var percent = Math.min(this.percent, 100)
+ , size = this._size
+ , half = size / 2
+ , x = half
+ , y = half
+ , rad = half - 1
+ , fontSize = this._fontSize;
+
+ ctx.font = fontSize + 'px ' + this._font;
+
+ var angle = Math.PI * 2 * (percent / 100);
+ ctx.clearRect(0, 0, size, size);
+
+ // outer circle
+ ctx.strokeStyle = '#9f9f9f';
+ ctx.beginPath();
+ ctx.arc(x, y, rad, 0, angle, false);
+ ctx.stroke();
+
+ // inner circle
+ ctx.strokeStyle = '#eee';
+ ctx.beginPath();
+ ctx.arc(x, y, rad - 1, 0, angle, true);
+ ctx.stroke();
+
+ // text
+ var text = this._text || (percent | 0) + '%'
+ , w = ctx.measureText(text).width;
+
+ ctx.fillText(
+ text
+ , x - w / 2 + 1
+ , y + fontSize / 2 - 1);
+
+ return this;
+};
+
+}); // module: browser/progress.js
+
+require.register("browser/tty.js", function(module, exports, require){
+
+exports.isatty = function(){
+ return true;
+};
+
+exports.getWindowSize = function(){
+ if ('innerHeight' in global) {
+ return [global.innerHeight, global.innerWidth];
+ } else {
+ // In a Web Worker, the DOM Window is not available.
+ return [640, 480];
+ }
+};
+
+}); // module: browser/tty.js
+
+require.register("context.js", function(module, exports, require){
+
+/**
+ * Expose `Context`.
+ */
+
+module.exports = Context;
+
+/**
+ * Initialize a new `Context`.
+ *
+ * @api private
+ */
+
+function Context(){}
+
+/**
+ * Set or get the context `Runnable` to `runnable`.
+ *
+ * @param {Runnable} runnable
+ * @return {Context}
+ * @api private
+ */
+
+Context.prototype.runnable = function(runnable){
+ if (0 == arguments.length) return this._runnable;
+ this.test = this._runnable = runnable;
+ return this;
+};
+
+/**
+ * Set test timeout `ms`.
+ *
+ * @param {Number} ms
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.timeout = function(ms){
+ this.runnable().timeout(ms);
+ return this;
+};
+
+/**
+ * Set test slowness threshold `ms`.
+ *
+ * @param {Number} ms
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.slow = function(ms){
+ this.runnable().slow(ms);
+ return this;
+};
+
+/**
+ * Inspect the context void of `._runnable`.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Context.prototype.inspect = function(){
+ return JSON.stringify(this, function(key, val){
+ if ('_runnable' == key) return;
+ if ('test' == key) return;
+ return val;
+ }, 2);
+};
+
+}); // module: context.js
+
+require.register("hook.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Runnable = require('./runnable');
+
+/**
+ * Expose `Hook`.
+ */
+
+module.exports = Hook;
+
+/**
+ * Initialize a new `Hook` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Hook(title, fn) {
+ Runnable.call(this, title, fn);
+ this.type = 'hook';
+}
+
+/**
+ * Inherit from `Runnable.prototype`.
+ */
+
+function F(){};
+F.prototype = Runnable.prototype;
+Hook.prototype = new F;
+Hook.prototype.constructor = Hook;
+
+
+/**
+ * Get or set the test `err`.
+ *
+ * @param {Error} err
+ * @return {Error}
+ * @api public
+ */
+
+Hook.prototype.error = function(err){
+ if (0 == arguments.length) {
+ var err = this._error;
+ this._error = null;
+ return err;
+ }
+
+ this._error = err;
+};
+
+}); // module: hook.js
+
+require.register("interfaces/bdd.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+ , Test = require('../test');
+
+/**
+ * BDD-style interface:
+ *
+ * describe('Array', function(){
+ * describe('#indexOf()', function(){
+ * it('should return -1 when not present', function(){
+ *
+ * });
+ *
+ * it('should return the index when present', function(){
+ *
+ * });
+ * });
+ * });
+ *
+ */
+
+module.exports = function(suite){
+ var suites = [suite];
+
+ suite.on('pre-require', function(context, file, mocha){
+
+ /**
+ * Execute before running tests.
+ */
+
+ context.before = function(fn){
+ suites[0].beforeAll(fn);
+ };
+
+ /**
+ * Execute after running tests.
+ */
+
+ context.after = function(fn){
+ suites[0].afterAll(fn);
+ };
+
+ /**
+ * Execute before each test case.
+ */
+
+ context.beforeEach = function(fn){
+ suites[0].beforeEach(fn);
+ };
+
+ /**
+ * Execute after each test case.
+ */
+
+ context.afterEach = function(fn){
+ suites[0].afterEach(fn);
+ };
+
+ /**
+ * Describe a "suite" with the given `title`
+ * and callback `fn` containing nested suites
+ * and/or tests.
+ */
+
+ context.describe = context.context = function(title, fn){
+ var suite = Suite.create(suites[0], title);
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ return suite;
+ };
+
+ /**
+ * Pending describe.
+ */
+
+ context.xdescribe =
+ context.xcontext =
+ context.describe.skip = function(title, fn){
+ var suite = Suite.create(suites[0], title);
+ suite.pending = true;
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ };
+
+ /**
+ * Exclusive suite.
+ */
+
+ context.describe.only = function(title, fn){
+ var suite = context.describe(title, fn);
+ mocha.grep(suite.fullTitle());
+ };
+
+ /**
+ * Describe a specification or test-case
+ * with the given `title` and callback `fn`
+ * acting as a thunk.
+ */
+
+ context.it = context.specify = function(title, fn){
+ var suite = suites[0];
+ if (suite.pending) var fn = null;
+ var test = new Test(title, fn);
+ suite.addTest(test);
+ return test;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.it.only = function(title, fn){
+ var test = context.it(title, fn);
+ mocha.grep(test.fullTitle());
+ };
+
+ /**
+ * Pending test case.
+ */
+
+ context.xit =
+ context.xspecify =
+ context.it.skip = function(title){
+ context.it(title);
+ };
+ });
+};
+
+}); // module: interfaces/bdd.js
+
+require.register("interfaces/exports.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+ , Test = require('../test');
+
+/**
+ * TDD-style interface:
+ *
+ * exports.Array = {
+ * '#indexOf()': {
+ * 'should return -1 when the value is not present': function(){
+ *
+ * },
+ *
+ * 'should return the correct index when the value is present': function(){
+ *
+ * }
+ * }
+ * };
+ *
+ */
+
+module.exports = function(suite){
+ var suites = [suite];
+
+ suite.on('require', visit);
+
+ function visit(obj) {
+ var suite;
+ for (var key in obj) {
+ if ('function' == typeof obj[key]) {
+ var fn = obj[key];
+ switch (key) {
+ case 'before':
+ suites[0].beforeAll(fn);
+ break;
+ case 'after':
+ suites[0].afterAll(fn);
+ break;
+ case 'beforeEach':
+ suites[0].beforeEach(fn);
+ break;
+ case 'afterEach':
+ suites[0].afterEach(fn);
+ break;
+ default:
+ suites[0].addTest(new Test(key, fn));
+ }
+ } else {
+ var suite = Suite.create(suites[0], key);
+ suites.unshift(suite);
+ visit(obj[key]);
+ suites.shift();
+ }
+ }
+ }
+};
+
+}); // module: interfaces/exports.js
+
+require.register("interfaces/index.js", function(module, exports, require){
+
+exports.bdd = require('./bdd');
+exports.tdd = require('./tdd');
+exports.qunit = require('./qunit');
+exports.exports = require('./exports');
+
+}); // module: interfaces/index.js
+
+require.register("interfaces/qunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+ , Test = require('../test');
+
+/**
+ * QUnit-style interface:
+ *
+ * suite('Array');
+ *
+ * test('#length', function(){
+ * var arr = [1,2,3];
+ * ok(arr.length == 3);
+ * });
+ *
+ * test('#indexOf()', function(){
+ * var arr = [1,2,3];
+ * ok(arr.indexOf(1) == 0);
+ * ok(arr.indexOf(2) == 1);
+ * ok(arr.indexOf(3) == 2);
+ * });
+ *
+ * suite('String');
+ *
+ * test('#length', function(){
+ * ok('foo'.length == 3);
+ * });
+ *
+ */
+
+module.exports = function(suite){
+ var suites = [suite];
+
+ suite.on('pre-require', function(context, file, mocha){
+
+ /**
+ * Execute before running tests.
+ */
+
+ context.before = function(fn){
+ suites[0].beforeAll(fn);
+ };
+
+ /**
+ * Execute after running tests.
+ */
+
+ context.after = function(fn){
+ suites[0].afterAll(fn);
+ };
+
+ /**
+ * Execute before each test case.
+ */
+
+ context.beforeEach = function(fn){
+ suites[0].beforeEach(fn);
+ };
+
+ /**
+ * Execute after each test case.
+ */
+
+ context.afterEach = function(fn){
+ suites[0].afterEach(fn);
+ };
+
+ /**
+ * Describe a "suite" with the given `title`.
+ */
+
+ context.suite = function(title){
+ if (suites.length > 1) suites.shift();
+ var suite = Suite.create(suites[0], title);
+ suites.unshift(suite);
+ return suite;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.suite.only = function(title, fn){
+ var suite = context.suite(title, fn);
+ mocha.grep(suite.fullTitle());
+ };
+
+ /**
+ * Describe a specification or test-case
+ * with the given `title` and callback `fn`
+ * acting as a thunk.
+ */
+
+ context.test = function(title, fn){
+ var test = new Test(title, fn);
+ suites[0].addTest(test);
+ return test;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.test.only = function(title, fn){
+ var test = context.test(title, fn);
+ mocha.grep(test.fullTitle());
+ };
+
+ /**
+ * Pending test case.
+ */
+
+ context.test.skip = function(title){
+ context.test(title);
+ };
+ });
+};
+
+}); // module: interfaces/qunit.js
+
+require.register("interfaces/tdd.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+ , Test = require('../test');
+
+/**
+ * TDD-style interface:
+ *
+ * suite('Array', function(){
+ * suite('#indexOf()', function(){
+ * suiteSetup(function(){
+ *
+ * });
+ *
+ * test('should return -1 when not present', function(){
+ *
+ * });
+ *
+ * test('should return the index when present', function(){
+ *
+ * });
+ *
+ * suiteTeardown(function(){
+ *
+ * });
+ * });
+ * });
+ *
+ */
+
+module.exports = function(suite){
+ var suites = [suite];
+
+ suite.on('pre-require', function(context, file, mocha){
+
+ /**
+ * Execute before each test case.
+ */
+
+ context.setup = function(fn){
+ suites[0].beforeEach(fn);
+ };
+
+ /**
+ * Execute after each test case.
+ */
+
+ context.teardown = function(fn){
+ suites[0].afterEach(fn);
+ };
+
+ /**
+ * Execute before the suite.
+ */
+
+ context.suiteSetup = function(fn){
+ suites[0].beforeAll(fn);
+ };
+
+ /**
+ * Execute after the suite.
+ */
+
+ context.suiteTeardown = function(fn){
+ suites[0].afterAll(fn);
+ };
+
+ /**
+ * Describe a "suite" with the given `title`
+ * and callback `fn` containing nested suites
+ * and/or tests.
+ */
+
+ context.suite = function(title, fn){
+ var suite = Suite.create(suites[0], title);
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ return suite;
+ };
+
+ /**
+ * Pending suite.
+ */
+ context.suite.skip = function(title, fn) {
+ var suite = Suite.create(suites[0], title);
+ suite.pending = true;
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.suite.only = function(title, fn){
+ var suite = context.suite(title, fn);
+ mocha.grep(suite.fullTitle());
+ };
+
+ /**
+ * Describe a specification or test-case
+ * with the given `title` and callback `fn`
+ * acting as a thunk.
+ */
+
+ context.test = function(title, fn){
+ var suite = suites[0];
+ if (suite.pending) var fn = null;
+ var test = new Test(title, fn);
+ suite.addTest(test);
+ return test;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.test.only = function(title, fn){
+ var test = context.test(title, fn);
+ mocha.grep(test.fullTitle());
+ };
+
+ /**
+ * Pending test case.
+ */
+
+ context.test.skip = function(title){
+ context.test(title);
+ };
+ });
+};
+
+}); // module: interfaces/tdd.js
+
+require.register("mocha.js", function(module, exports, require){
+/*!
+ * mocha
+ * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var path = require('browser/path')
+ , utils = require('./utils');
+
+/**
+ * Expose `Mocha`.
+ */
+
+exports = module.exports = Mocha;
+
+/**
+ * Expose internals.
+ */
+
+exports.utils = utils;
+exports.interfaces = require('./interfaces');
+exports.reporters = require('./reporters');
+exports.Runnable = require('./runnable');
+exports.Context = require('./context');
+exports.Runner = require('./runner');
+exports.Suite = require('./suite');
+exports.Hook = require('./hook');
+exports.Test = require('./test');
+
+/**
+ * Return image `name` path.
+ *
+ * @param {String} name
+ * @return {String}
+ * @api private
+ */
+
+function image(name) {
+ return __dirname + '/../images/' + name + '.png';
+}
+
+/**
+ * Setup mocha with `options`.
+ *
+ * Options:
+ *
+ * - `ui` name "bdd", "tdd", "exports" etc
+ * - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
+ * - `globals` array of accepted globals
+ * - `timeout` timeout in milliseconds
+ * - `bail` bail on the first test failure
+ * - `slow` milliseconds to wait before considering a test slow
+ * - `ignoreLeaks` ignore global leaks
+ * - `grep` string or regexp to filter tests with
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+function Mocha(options) {
+ options = options || {};
+ this.files = [];
+ this.options = options;
+ this.grep(options.grep);
+ this.suite = new exports.Suite('', new exports.Context);
+ this.ui(options.ui);
+ this.bail(options.bail);
+ this.reporter(options.reporter);
+ if (options.timeout) this.timeout(options.timeout);
+ if (options.slow) this.slow(options.slow);
+}
+
+/**
+ * Enable or disable bailing on the first failure.
+ *
+ * @param {Boolean} [bail]
+ * @api public
+ */
+
+Mocha.prototype.bail = function(bail){
+ if (0 == arguments.length) bail = true;
+ this.suite.bail(bail);
+ return this;
+};
+
+/**
+ * Add test `file`.
+ *
+ * @param {String} file
+ * @api public
+ */
+
+Mocha.prototype.addFile = function(file){
+ this.files.push(file);
+ return this;
+};
+
+/**
+ * Set reporter to `reporter`, defaults to "dot".
+ *
+ * @param {String|Function} reporter name or constructor
+ * @api public
+ */
+
+Mocha.prototype.reporter = function(reporter){
+ if ('function' == typeof reporter) {
+ this._reporter = reporter;
+ } else {
+ reporter = reporter || 'dot';
+ try {
+ this._reporter = require('./reporters/' + reporter);
+ } catch (err) {
+ this._reporter = require(reporter);
+ }
+ if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"');
+ }
+ return this;
+};
+
+/**
+ * Set test UI `name`, defaults to "bdd".
+ *
+ * @param {String} bdd
+ * @api public
+ */
+
+Mocha.prototype.ui = function(name){
+ name = name || 'bdd';
+ this._ui = exports.interfaces[name];
+ if (!this._ui) throw new Error('invalid interface "' + name + '"');
+ this._ui = this._ui(this.suite);
+ return this;
+};
+
+/**
+ * Load registered files.
+ *
+ * @api private
+ */
+
+Mocha.prototype.loadFiles = function(fn){
+ var self = this;
+ var suite = this.suite;
+ var pending = this.files.length;
+ this.files.forEach(function(file){
+ file = path.resolve(file);
+ suite.emit('pre-require', global, file, self);
+ suite.emit('require', require(file), file, self);
+ suite.emit('post-require', global, file, self);
+ --pending || (fn && fn());
+ });
+};
+
+/**
+ * Enable growl support.
+ *
+ * @api private
+ */
+
+Mocha.prototype._growl = function(runner, reporter) {
+ var notify = require('growl');
+
+ runner.on('end', function(){
+ var stats = reporter.stats;
+ if (stats.failures) {
+ var msg = stats.failures + ' of ' + runner.total + ' tests failed';
+ notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
+ } else {
+ notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
+ name: 'mocha'
+ , title: 'Passed'
+ , image: image('ok')
+ });
+ }
+ });
+};
+
+/**
+ * Add regexp to grep, if `re` is a string it is escaped.
+ *
+ * @param {RegExp|String} re
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.grep = function(re){
+ this.options.grep = 'string' == typeof re
+ ? new RegExp(utils.escapeRegexp(re))
+ : re;
+ return this;
+};
+
+/**
+ * Invert `.grep()` matches.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.invert = function(){
+ this.options.invert = true;
+ return this;
+};
+
+/**
+ * Ignore global leaks.
+ *
+ * @param {Boolean} ignore
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.ignoreLeaks = function(ignore){
+ this.options.ignoreLeaks = !!ignore;
+ return this;
+};
+
+/**
+ * Enable global leak checking.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.checkLeaks = function(){
+ this.options.ignoreLeaks = false;
+ return this;
+};
+
+/**
+ * Enable growl support.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.growl = function(){
+ this.options.growl = true;
+ return this;
+};
+
+/**
+ * Ignore `globals` array or string.
+ *
+ * @param {Array|String} globals
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.globals = function(globals){
+ this.options.globals = (this.options.globals || []).concat(globals);
+ return this;
+};
+
+/**
+ * Set the timeout in milliseconds.
+ *
+ * @param {Number} timeout
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.timeout = function(timeout){
+ this.suite.timeout(timeout);
+ return this;
+};
+
+/**
+ * Set slowness threshold in milliseconds.
+ *
+ * @param {Number} slow
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.slow = function(slow){
+ this.suite.slow(slow);
+ return this;
+};
+
+/**
+ * Makes all tests async (accepting a callback)
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.asyncOnly = function(){
+ this.options.asyncOnly = true;
+ return this;
+};
+
+/**
+ * Run tests and invoke `fn()` when complete.
+ *
+ * @param {Function} fn
+ * @return {Runner}
+ * @api public
+ */
+
+Mocha.prototype.run = function(fn){
+ if (this.files.length) this.loadFiles();
+ var suite = this.suite;
+ var options = this.options;
+ var runner = new exports.Runner(suite);
+ var reporter = new this._reporter(runner);
+ runner.ignoreLeaks = false !== options.ignoreLeaks;
+ runner.asyncOnly = options.asyncOnly;
+ if (options.grep) runner.grep(options.grep, options.invert);
+ if (options.globals) runner.globals(options.globals);
+ if (options.growl) this._growl(runner, reporter);
+ return runner.run(fn);
+};
+
+}); // module: mocha.js
+
+require.register("ms.js", function(module, exports, require){
+
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * @param {String|Number} val
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function(val){
+ if ('string' == typeof val) return parse(val);
+ return format(val);
+}
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+ var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
+ if (!m) return;
+ var n = parseFloat(m[1]);
+ var type = (m[2] || 'ms').toLowerCase();
+ switch (type) {
+ case 'years':
+ case 'year':
+ case 'y':
+ return n * 31557600000;
+ case 'days':
+ case 'day':
+ case 'd':
+ return n * 86400000;
+ case 'hours':
+ case 'hour':
+ case 'h':
+ return n * 3600000;
+ case 'minutes':
+ case 'minute':
+ case 'm':
+ return n * 60000;
+ case 'seconds':
+ case 'second':
+ case 's':
+ return n * 1000;
+ case 'ms':
+ return n;
+ }
+}
+
+/**
+ * Format the given `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api public
+ */
+
+function format(ms) {
+ if (ms == d) return Math.round(ms / d) + ' day';
+ if (ms > d) return Math.round(ms / d) + ' days';
+ if (ms == h) return Math.round(ms / h) + ' hour';
+ if (ms > h) return Math.round(ms / h) + ' hours';
+ if (ms == m) return Math.round(ms / m) + ' minute';
+ if (ms > m) return Math.round(ms / m) + ' minutes';
+ if (ms == s) return Math.round(ms / s) + ' second';
+ if (ms > s) return Math.round(ms / s) + ' seconds';
+ return ms + ' ms';
+}
+}); // module: ms.js
+
+require.register("reporters/base.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var tty = require('browser/tty')
+ , diff = require('browser/diff')
+ , ms = require('../ms');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
+ * Check if both stdio streams are associated with a tty.
+ */
+
+var isatty = tty.isatty(1) && tty.isatty(2);
+
+/**
+ * Expose `Base`.
+ */
+
+exports = module.exports = Base;
+
+/**
+ * Enable coloring by default.
+ */
+
+exports.useColors = isatty;
+
+/**
+ * Default color map.
+ */
+
+exports.colors = {
+ 'pass': 90
+ , 'fail': 31
+ , 'bright pass': 92
+ , 'bright fail': 91
+ , 'bright yellow': 93
+ , 'pending': 36
+ , 'suite': 0
+ , 'error title': 0
+ , 'error message': 31
+ , 'error stack': 90
+ , 'checkmark': 32
+ , 'fast': 90
+ , 'medium': 33
+ , 'slow': 31
+ , 'green': 32
+ , 'light': 90
+ , 'diff gutter': 90
+ , 'diff added': 42
+ , 'diff removed': 41
+};
+
+/**
+ * Default symbol map.
+ */
+
+exports.symbols = {
+ ok: '✓',
+ err: '✖',
+ dot: '․'
+};
+
+// With node.js on Windows: use symbols available in terminal default fonts
+if ('win32' == process.platform) {
+ exports.symbols.ok = '\u221A';
+ exports.symbols.err = '\u00D7';
+ exports.symbols.dot = '.';
+}
+
+/**
+ * Color `str` with the given `type`,
+ * allowing colors to be disabled,
+ * as well as user-defined color
+ * schemes.
+ *
+ * @param {String} type
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+var color = exports.color = function(type, str) {
+ if (!exports.useColors) return str;
+ return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Expose term window size, with some
+ * defaults for when stderr is not a tty.
+ */
+
+exports.window = {
+ width: isatty
+ ? process.stdout.getWindowSize
+ ? process.stdout.getWindowSize(1)[0]
+ : tty.getWindowSize()[1]
+ : 75
+};
+
+/**
+ * Expose some basic cursor interactions
+ * that are common among reporters.
+ */
+
+exports.cursor = {
+ hide: function(){
+ process.stdout.write('\u001b[?25l');
+ },
+
+ show: function(){
+ process.stdout.write('\u001b[?25h');
+ },
+
+ deleteLine: function(){
+ process.stdout.write('\u001b[2K');
+ },
+
+ beginningOfLine: function(){
+ process.stdout.write('\u001b[0G');
+ },
+
+ CR: function(){
+ exports.cursor.deleteLine();
+ exports.cursor.beginningOfLine();
+ }
+};
+
+/**
+ * Outut the given `failures` as a list.
+ *
+ * @param {Array} failures
+ * @api public
+ */
+
+exports.list = function(failures){
+ console.error();
+ failures.forEach(function(test, i){
+ // format
+ var fmt = color('error title', ' %s) %s:\n')
+ + color('error message', ' %s')
+ + color('error stack', '\n%s\n');
+
+ // msg
+ var err = test.err
+ , message = err.message || ''
+ , stack = err.stack || message
+ , index = stack.indexOf(message) + message.length
+ , msg = stack.slice(0, index)
+ , actual = err.actual
+ , expected = err.expected
+ , escape = true;
+
+ // uncaught
+ if (err.uncaught) {
+ msg = 'Uncaught ' + msg;
+ }
+
+ // explicitly show diff
+ if (err.showDiff && sameType(actual, expected)) {
+ escape = false;
+ err.actual = actual = stringify(actual);
+ err.expected = expected = stringify(expected);
+ }
+
+ // actual / expected diff
+ if ('string' == typeof actual && 'string' == typeof expected) {
+ msg = errorDiff(err, 'Words', escape);
+
+ // linenos
+ var lines = msg.split('\n');
+ if (lines.length > 4) {
+ var width = String(lines.length).length;
+ msg = lines.map(function(str, i){
+ return pad(++i, width) + ' |' + ' ' + str;
+ }).join('\n');
+ }
+
+ // legend
+ msg = '\n'
+ + color('diff removed', 'actual')
+ + ' '
+ + color('diff added', 'expected')
+ + '\n\n'
+ + msg
+ + '\n';
+
+ // indent
+ msg = msg.replace(/^/gm, ' ');
+
+ fmt = color('error title', ' %s) %s:\n%s')
+ + color('error stack', '\n%s\n');
+ }
+
+ // indent stack trace without msg
+ stack = stack.slice(index ? index + 1 : index)
+ .replace(/^/gm, ' ');
+
+ console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+ });
+};
+
+/**
+ * Initialize a new `Base` reporter.
+ *
+ * All other reporters generally
+ * inherit from this reporter, providing
+ * stats such as test duration, number
+ * of tests passed / failed etc.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Base(runner) {
+ var self = this
+ , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
+ , failures = this.failures = [];
+
+ if (!runner) return;
+ this.runner = runner;
+
+ runner.stats = stats;
+
+ runner.on('start', function(){
+ stats.start = new Date;
+ });
+
+ runner.on('suite', function(suite){
+ stats.suites = stats.suites || 0;
+ suite.root || stats.suites++;
+ });
+
+ runner.on('test end', function(test){
+ stats.tests = stats.tests || 0;
+ stats.tests++;
+ });
+
+ runner.on('pass', function(test){
+ stats.passes = stats.passes || 0;
+
+ var medium = test.slow() / 2;
+ test.speed = test.duration > test.slow()
+ ? 'slow'
+ : test.duration > medium
+ ? 'medium'
+ : 'fast';
+
+ stats.passes++;
+ });
+
+ runner.on('fail', function(test, err){
+ stats.failures = stats.failures || 0;
+ stats.failures++;
+ test.err = err;
+ failures.push(test);
+ });
+
+ runner.on('end', function(){
+ stats.end = new Date;
+ stats.duration = new Date - stats.start;
+ });
+
+ runner.on('pending', function(){
+ stats.pending++;
+ });
+}
+
+/**
+ * Output common epilogue used by many of
+ * the bundled reporters.
+ *
+ * @api public
+ */
+
+Base.prototype.epilogue = function(){
+ var stats = this.stats;
+ var tests;
+ var fmt;
+
+ console.log();
+
+ // passes
+ fmt = color('bright pass', ' ')
+ + color('green', ' %d passing')
+ + color('light', ' (%s)');
+
+ console.log(fmt,
+ stats.passes || 0,
+ ms(stats.duration));
+
+ // pending
+ if (stats.pending) {
+ fmt = color('pending', ' ')
+ + color('pending', ' %d pending');
+
+ console.log(fmt, stats.pending);
+ }
+
+ // failures
+ if (stats.failures) {
+ fmt = color('fail', ' %d failing');
+
+ console.error(fmt,
+ stats.failures);
+
+ Base.list(this.failures);
+ console.error();
+ }
+
+ console.log();
+};
+
+/**
+ * Pad the given `str` to `len`.
+ *
+ * @param {String} str
+ * @param {String} len
+ * @return {String}
+ * @api private
+ */
+
+function pad(str, len) {
+ str = String(str);
+ return Array(len - str.length + 1).join(' ') + str;
+}
+
+/**
+ * Return a character diff for `err`.
+ *
+ * @param {Error} err
+ * @return {String}
+ * @api private
+ */
+
+function errorDiff(err, type, escape) {
+ return diff['diff' + type](err.actual, err.expected).map(function(str){
+ if (escape) {
+ str.value = str.value
+ .replace(/\t/g, '<tab>')
+ .replace(/\r/g, '<CR>')
+ .replace(/\n/g, '<LF>\n');
+ }
+ if (str.added) return colorLines('diff added', str.value);
+ if (str.removed) return colorLines('diff removed', str.value);
+ return str.value;
+ }).join('');
+}
+
+/**
+ * Color lines for `str`, using the color `name`.
+ *
+ * @param {String} name
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function colorLines(name, str) {
+ return str.split('\n').map(function(str){
+ return color(name, str);
+ }).join('\n');
+}
+
+/**
+ * Stringify `obj`.
+ *
+ * @param {Mixed} obj
+ * @return {String}
+ * @api private
+ */
+
+function stringify(obj) {
+ if (obj instanceof RegExp) return obj.toString();
+ return JSON.stringify(obj, null, 2);
+}
+
+/**
+ * Check that a / b have the same type.
+ *
+ * @param {Object} a
+ * @param {Object} b
+ * @return {Boolean}
+ * @api private
+ */
+
+function sameType(a, b) {
+ a = Object.prototype.toString.call(a);
+ b = Object.prototype.toString.call(b);
+ return a == b;
+}
+
+}); // module: reporters/base.js
+
+require.register("reporters/doc.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , utils = require('../utils');
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = Doc;
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Doc(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , total = runner.total
+ , indents = 2;
+
+ function indent() {
+ return Array(indents).join(' ');
+ }
+
+ runner.on('suite', function(suite){
+ if (suite.root) return;
+ ++indents;
+ console.log('%s<section class="suite">', indent());
+ ++indents;
+ console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
+ console.log('%s<dl>', indent());
+ });
+
+ runner.on('suite end', function(suite){
+ if (suite.root) return;
+ console.log('%s</dl>', indent());
+ --indents;
+ console.log('%s</section>', indent());
+ --indents;
+ });
+
+ runner.on('pass', function(test){
+ console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title));
+ var code = utils.escape(utils.clean(test.fn.toString()));
+ console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
+ });
+}
+
+}); // module: reporters/doc.js
+
+require.register("reporters/dot.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = Dot;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Dot(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , width = Base.window.width * .75 | 0
+ , n = 0;
+
+ runner.on('start', function(){
+ process.stdout.write('\n ');
+ });
+
+ runner.on('pending', function(test){
+ process.stdout.write(color('pending', Base.symbols.dot));
+ });
+
+ runner.on('pass', function(test){
+ if (++n % width == 0) process.stdout.write('\n ');
+ if ('slow' == test.speed) {
+ process.stdout.write(color('bright yellow', Base.symbols.dot));
+ } else {
+ process.stdout.write(color(test.speed, Base.symbols.dot));
+ }
+ });
+
+ runner.on('fail', function(test, err){
+ if (++n % width == 0) process.stdout.write('\n ');
+ process.stdout.write(color('fail', Base.symbols.dot));
+ });
+
+ runner.on('end', function(){
+ console.log();
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Dot.prototype = new F;
+Dot.prototype.constructor = Dot;
+
+}); // module: reporters/dot.js
+
+require.register("reporters/html-cov.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var JSONCov = require('./json-cov')
+ , fs = require('browser/fs');
+
+/**
+ * Expose `HTMLCov`.
+ */
+
+exports = module.exports = HTMLCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function HTMLCov(runner) {
+ var jade = require('jade')
+ , file = __dirname + '/templates/coverage.jade'
+ , str = fs.readFileSync(file, 'utf8')
+ , fn = jade.compile(str, { filename: file })
+ , self = this;
+
+ JSONCov.call(this, runner, false);
+
+ runner.on('end', function(){
+ process.stdout.write(fn({
+ cov: self.cov
+ , coverageClass: coverageClass
+ }));
+ });
+}
+
+/**
+ * Return coverage class for `n`.
+ *
+ * @return {String}
+ * @api private
+ */
+
+function coverageClass(n) {
+ if (n >= 75) return 'high';
+ if (n >= 50) return 'medium';
+ if (n >= 25) return 'low';
+ return 'terrible';
+}
+}); // module: reporters/html-cov.js
+
+require.register("reporters/html.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , utils = require('../utils')
+ , Progress = require('../browser/progress')
+ , escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = HTML;
+
+/**
+ * Stats template.
+ */
+
+var statsTemplate = '<ul id="mocha-stats">'
+ + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
+ + '<li class="passes"><a href="#">passes:</a> <em>0</em></li>'
+ + '<li class="failures"><a href="#">failures:</a> <em>0</em></li>'
+ + '<li class="duration">duration: <em>0</em>s</li>'
+ + '</ul>';
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function HTML(runner, root) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , total = runner.total
+ , stat = fragment(statsTemplate)
+ , items = stat.getElementsByTagName('li')
+ , passes = items[1].getElementsByTagName('em')[0]
+ , passesLink = items[1].getElementsByTagName('a')[0]
+ , failures = items[2].getElementsByTagName('em')[0]
+ , failuresLink = items[2].getElementsByTagName('a')[0]
+ , duration = items[3].getElementsByTagName('em')[0]
+ , canvas = stat.getElementsByTagName('canvas')[0]
+ , report = fragment('<ul id="mocha-report"></ul>')
+ , stack = [report]
+ , progress
+ , ctx
+
+ root = root || document.getElementById('mocha');
+
+ if (canvas.getContext) {
+ var ratio = window.devicePixelRatio || 1;
+ canvas.style.width = canvas.width;
+ canvas.style.height = canvas.height;
+ canvas.width *= ratio;
+ canvas.height *= ratio;
+ ctx = canvas.getContext('2d');
+ ctx.scale(ratio, ratio);
+ progress = new Progress;
+ }
+
+ if (!root) return error('#mocha div missing, add it to your document');
+
+ // pass toggle
+ on(passesLink, 'click', function(){
+ unhide();
+ var name = /pass/.test(report.className) ? '' : ' pass';
+ report.className = report.className.replace(/fail|pass/g, '') + name;
+ if (report.className.trim()) hideSuitesWithout('test pass');
+ });
+
+ // failure toggle
+ on(failuresLink, 'click', function(){
+ unhide();
+ var name = /fail/.test(report.className) ? '' : ' fail';
+ report.className = report.className.replace(/fail|pass/g, '') + name;
+ if (report.className.trim()) hideSuitesWithout('test fail');
+ });
+
+ root.appendChild(stat);
+ root.appendChild(report);
+
+ if (progress) progress.size(40);
+
+ runner.on('suite', function(suite){
+ if (suite.root) return;
+
+ // suite
+ var url = '?grep=' + encodeURIComponent(suite.fullTitle());
+ var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title));
+
+ // container
+ stack[0].appendChild(el);
+ stack.unshift(document.createElement('ul'));
+ el.appendChild(stack[0]);
+ });
+
+ runner.on('suite end', function(suite){
+ if (suite.root) return;
+ stack.shift();
+ });
+
+ runner.on('fail', function(test, err){
+ if ('hook' == test.type) runner.emit('test end', test);
+ });
+
+ runner.on('test end', function(test){
+ // TODO: add to stats
+ var percent = stats.tests / this.total * 100 | 0;
+ if (progress) progress.update(percent).draw(ctx);
+
+ // update stats
+ var ms = new Date - stats.start;
+ text(passes, stats.passes);
+ text(failures, stats.failures);
+ text(duration, (ms / 1000).toFixed(2));
+
+ // test
+ if ('passed' == test.state) {
+ var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="?grep=%e" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));
+ } else if (test.pending) {
+ var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
+ } else {
+ var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
+ var str = test.err.stack || test.err.toString();
+
+ // FF / Opera do not add the message
+ if (!~str.indexOf(test.err.message)) {
+ str = test.err.message + '\n' + str;
+ }
+
+ // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
+ // check for the result of the stringifying.
+ if ('[object Error]' == str) str = test.err.message;
+
+ // Safari doesn't give you a stack. Let's at least provide a source line.
+ if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
+ str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")";
+ }
+
+ el.appendChild(fragment('<pre class="error">%e</pre>', str));
+ }
+
+ // toggle code
+ // TODO: defer
+ if (!test.pending) {
+ var h2 = el.getElementsByTagName('h2')[0];
+
+ on(h2, 'click', function(){
+ pre.style.display = 'none' == pre.style.display
+ ? 'block'
+ : 'none';
+ });
+
+ var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));
+ el.appendChild(pre);
+ pre.style.display = 'none';
+ }
+
+ // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
+ if (stack[0]) stack[0].appendChild(el);
+ });
+}
+
+/**
+ * Display error `msg`.
+ */
+
+function error(msg) {
+ document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
+}
+
+/**
+ * Return a DOM fragment from `html`.
+ */
+
+function fragment(html) {
+ var args = arguments
+ , div = document.createElement('div')
+ , i = 1;
+
+ div.innerHTML = html.replace(/%([se])/g, function(_, type){
+ switch (type) {
+ case 's': return String(args[i++]);
+ case 'e': return escape(args[i++]);
+ }
+ });
+
+ return div.firstChild;
+}
+
+/**
+ * Check for suites that do not have elements
+ * with `classname`, and hide them.
+ */
+
+function hideSuitesWithout(classname) {
+ var suites = document.getElementsByClassName('suite');
+ for (var i = 0; i < suites.length; i++) {
+ var els = suites[i].getElementsByClassName(classname);
+ if (0 == els.length) suites[i].className += ' hidden';
+ }
+}
+
+/**
+ * Unhide .hidden suites.
+ */
+
+function unhide() {
+ var els = document.getElementsByClassName('suite hidden');
+ for (var i = 0; i < els.length; ++i) {
+ els[i].className = els[i].className.replace('suite hidden', 'suite');
+ }
+}
+
+/**
+ * Set `el` text to `str`.
+ */
+
+function text(el, str) {
+ if (el.textContent) {
+ el.textContent = str;
+ } else {
+ el.innerText = str;
+ }
+}
+
+/**
+ * Listen on `event` with callback `fn`.
+ */
+
+function on(el, event, fn) {
+ if (el.addEventListener) {
+ el.addEventListener(event, fn, false);
+ } else {
+ el.attachEvent('on' + event, fn);
+ }
+}
+
+}); // module: reporters/html.js
+
+require.register("reporters/index.js", function(module, exports, require){
+
+exports.Base = require('./base');
+exports.Dot = require('./dot');
+exports.Doc = require('./doc');
+exports.TAP = require('./tap');
+exports.JSON = require('./json');
+exports.HTML = require('./html');
+exports.List = require('./list');
+exports.Min = require('./min');
+exports.Spec = require('./spec');
+exports.Nyan = require('./nyan');
+exports.XUnit = require('./xunit');
+exports.Markdown = require('./markdown');
+exports.Progress = require('./progress');
+exports.Landing = require('./landing');
+exports.JSONCov = require('./json-cov');
+exports.HTMLCov = require('./html-cov');
+exports.JSONStream = require('./json-stream');
+exports.Teamcity = require('./teamcity');
+
+}); // module: reporters/index.js
+
+require.register("reporters/json-cov.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `JSONCov`.
+ */
+
+exports = module.exports = JSONCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @param {Runner} runner
+ * @param {Boolean} output
+ * @api public
+ */
+
+function JSONCov(runner, output) {
+ var self = this
+ , output = 1 == arguments.length ? true : output;
+
+ Base.call(this, runner);
+
+ var tests = []
+ , failures = []
+ , passes = [];
+
+ runner.on('test end', function(test){
+ tests.push(test);
+ });
+
+ runner.on('pass', function(test){
+ passes.push(test);
+ });
+
+ runner.on('fail', function(test){
+ failures.push(test);
+ });
+
+ runner.on('end', function(){
+ var cov = global._$jscoverage || {};
+ var result = self.cov = map(cov);
+ result.stats = self.stats;
+ result.tests = tests.map(clean);
+ result.failures = failures.map(clean);
+ result.passes = passes.map(clean);
+ if (!output) return;
+ process.stdout.write(JSON.stringify(result, null, 2 ));
+ });
+}
+
+/**
+ * Map jscoverage data to a JSON structure
+ * suitable for reporting.
+ *
+ * @param {Object} cov
+ * @return {Object}
+ * @api private
+ */
+
+function map(cov) {
+ var ret = {
+ instrumentation: 'node-jscoverage'
+ , sloc: 0
+ , hits: 0
+ , misses: 0
+ , coverage: 0
+ , files: []
+ };
+
+ for (var filename in cov) {
+ var data = coverage(filename, cov[filename]);
+ ret.files.push(data);
+ ret.hits += data.hits;
+ ret.misses += data.misses;
+ ret.sloc += data.sloc;
+ }
+
+ ret.files.sort(function(a, b) {
+ return a.filename.localeCompare(b.filename);
+ });
+
+ if (ret.sloc > 0) {
+ ret.coverage = (ret.hits / ret.sloc) * 100;
+ }
+
+ return ret;
+};
+
+/**
+ * Map jscoverage data for a single source file
+ * to a JSON structure suitable for reporting.
+ *
+ * @param {String} filename name of the source file
+ * @param {Object} data jscoverage coverage data
+ * @return {Object}
+ * @api private
+ */
+
+function coverage(filename, data) {
+ var ret = {
+ filename: filename,
+ coverage: 0,
+ hits: 0,
+ misses: 0,
+ sloc: 0,
+ source: {}
+ };
+
+ data.source.forEach(function(line, num){
+ num++;
+
+ if (data[num] === 0) {
+ ret.misses++;
+ ret.sloc++;
+ } else if (data[num] !== undefined) {
+ ret.hits++;
+ ret.sloc++;
+ }
+
+ ret.source[num] = {
+ source: line
+ , coverage: data[num] === undefined
+ ? ''
+ : data[num]
+ };
+ });
+
+ ret.coverage = ret.hits / ret.sloc * 100;
+
+ return ret;
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+ return {
+ title: test.title
+ , fullTitle: test.fullTitle()
+ , duration: test.duration
+ }
+}
+
+}); // module: reporters/json-cov.js
+
+require.register("reporters/json-stream.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , color = Base.color;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function List(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , total = runner.total;
+
+ runner.on('start', function(){
+ console.log(JSON.stringify(['start', { total: total }]));
+ });
+
+ runner.on('pass', function(test){
+ console.log(JSON.stringify(['pass', clean(test)]));
+ });
+
+ runner.on('fail', function(test, err){
+ console.log(JSON.stringify(['fail', clean(test)]));
+ });
+
+ runner.on('end', function(){
+ process.stdout.write(JSON.stringify(['end', self.stats]));
+ });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+ return {
+ title: test.title
+ , fullTitle: test.fullTitle()
+ , duration: test.duration
+ }
+}
+}); // module: reporters/json-stream.js
+
+require.register("reporters/json.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , cursor = Base.cursor
+ , color = Base.color;
+
+/**
+ * Expose `JSON`.
+ */
+
+exports = module.exports = JSONReporter;
+
+/**
+ * Initialize a new `JSON` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function JSONReporter(runner) {
+ var self = this;
+ Base.call(this, runner);
+
+ var tests = []
+ , failures = []
+ , passes = [];
+
+ runner.on('test end', function(test){
+ tests.push(test);
+ });
+
+ runner.on('pass', function(test){
+ passes.push(test);
+ });
+
+ runner.on('fail', function(test){
+ failures.push(test);
+ });
+
+ runner.on('end', function(){
+ var obj = {
+ stats: self.stats
+ , tests: tests.map(clean)
+ , failures: failures.map(clean)
+ , passes: passes.map(clean)
+ };
+
+ process.stdout.write(JSON.stringify(obj, null, 2));
+ });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+ return {
+ title: test.title
+ , fullTitle: test.fullTitle()
+ , duration: test.duration
+ }
+}
+}); // module: reporters/json.js
+
+require.register("reporters/landing.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , cursor = Base.cursor
+ , color = Base.color;
+
+/**
+ * Expose `Landing`.
+ */
+
+exports = module.exports = Landing;
+
+/**
+ * Airplane color.
+ */
+
+Base.colors.plane = 0;
+
+/**
+ * Airplane crash color.
+ */
+
+Base.colors['plane crash'] = 31;
+
+/**
+ * Runway color.
+ */
+
+Base.colors.runway = 90;
+
+/**
+ * Initialize a new `Landing` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Landing(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , width = Base.window.width * .75 | 0
+ , total = runner.total
+ , stream = process.stdout
+ , plane = color('plane', '✈')
+ , crashed = -1
+ , n = 0;
+
+ function runway() {
+ var buf = Array(width).join('-');
+ return ' ' + color('runway', buf);
+ }
+
+ runner.on('start', function(){
+ stream.write('\n ');
+ cursor.hide();
+ });
+
+ runner.on('test end', function(test){
+ // check if the plane crashed
+ var col = -1 == crashed
+ ? width * ++n / total | 0
+ : crashed;
+
+ // show the crash
+ if ('failed' == test.state) {
+ plane = color('plane crash', '✈');
+ crashed = col;
+ }
+
+ // render landing strip
+ stream.write('\u001b[4F\n\n');
+ stream.write(runway());
+ stream.write('\n ');
+ stream.write(color('runway', Array(col).join('⋅')));
+ stream.write(plane)
+ stream.write(color('runway', Array(width - col).join('⋅') + '\n'));
+ stream.write(runway());
+ stream.write('\u001b[0m');
+ });
+
+ runner.on('end', function(){
+ cursor.show();
+ console.log();
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Landing.prototype = new F;
+Landing.prototype.constructor = Landing;
+
+}); // module: reporters/landing.js
+
+require.register("reporters/list.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , cursor = Base.cursor
+ , color = Base.color;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function List(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , n = 0;
+
+ runner.on('start', function(){
+ console.log();
+ });
+
+ runner.on('test', function(test){
+ process.stdout.write(color('pass', ' ' + test.fullTitle() + ': '));
+ });
+
+ runner.on('pending', function(test){
+ var fmt = color('checkmark', ' -')
+ + color('pending', ' %s');
+ console.log(fmt, test.fullTitle());
+ });
+
+ runner.on('pass', function(test){
+ var fmt = color('checkmark', ' '+Base.symbols.dot)
+ + color('pass', ' %s: ')
+ + color(test.speed, '%dms');
+ cursor.CR();
+ console.log(fmt, test.fullTitle(), test.duration);
+ });
+
+ runner.on('fail', function(test, err){
+ cursor.CR();
+ console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
+ });
+
+ runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+List.prototype = new F;
+List.prototype.constructor = List;
+
+
+}); // module: reporters/list.js
+
+require.register("reporters/markdown.js", function(module, exports, require){
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , utils = require('../utils');
+
+/**
+ * Expose `Markdown`.
+ */
+
+exports = module.exports = Markdown;
+
+/**
+ * Initialize a new `Markdown` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Markdown(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , level = 0
+ , buf = '';
+
+ function title(str) {
+ return Array(level).join('#') + ' ' + str;
+ }
+
+ function indent() {
+ return Array(level).join(' ');
+ }
+
+ function mapTOC(suite, obj) {
+ var ret = obj;
+ obj = obj[suite.title] = obj[suite.title] || { suite: suite };
+ suite.suites.forEach(function(suite){
+ mapTOC(suite, obj);
+ });
+ return ret;
+ }
+
+ function stringifyTOC(obj, level) {
+ ++level;
+ var buf = '';
+ var link;
+ for (var key in obj) {
+ if ('suite' == key) continue;
+ if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
+ if (key) buf += Array(level).join(' ') + link;
+ buf += stringifyTOC(obj[key], level);
+ }
+ --level;
+ return buf;
+ }
+
+ function generateTOC(suite) {
+ var obj = mapTOC(suite, {});
+ return stringifyTOC(obj, 0);
+ }
+
+ generateTOC(runner.suite);
+
+ runner.on('suite', function(suite){
+ ++level;
+ var slug = utils.slug(suite.fullTitle());
+ buf += '<a name="' + slug + '"></a>' + '\n';
+ buf += title(suite.title) + '\n';
+ });
+
+ runner.on('suite end', function(suite){
+ --level;
+ });
+
+ runner.on('pass', function(test){
+ var code = utils.clean(test.fn.toString());
+ buf += test.title + '.\n';
+ buf += '\n```js\n';
+ buf += code + '\n';
+ buf += '```\n\n';
+ });
+
+ runner.on('end', function(){
+ process.stdout.write('# TOC\n');
+ process.stdout.write(generateTOC(runner.suite));
+ process.stdout.write(buf);
+ });
+}
+}); // module: reporters/markdown.js
+
+require.register("reporters/min.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `Min`.
+ */
+
+exports = module.exports = Min;
+
+/**
+ * Initialize a new `Min` minimal test reporter (best used with --watch).
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Min(runner) {
+ Base.call(this, runner);
+
+ runner.on('start', function(){
+ // clear screen
+ process.stdout.write('\u001b[2J');
+ // set cursor position
+ process.stdout.write('\u001b[1;3H');
+ });
+
+ runner.on('end', this.epilogue.bind(this));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Min.prototype = new F;
+Min.prototype.constructor = Min;
+
+
+}); // module: reporters/min.js
+
+require.register("reporters/nyan.js", function(module, exports, require){
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = NyanCat;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function NyanCat(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , width = Base.window.width * .75 | 0
+ , rainbowColors = this.rainbowColors = self.generateColors()
+ , colorIndex = this.colorIndex = 0
+ , numerOfLines = this.numberOfLines = 4
+ , trajectories = this.trajectories = [[], [], [], []]
+ , nyanCatWidth = this.nyanCatWidth = 11
+ , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)
+ , scoreboardWidth = this.scoreboardWidth = 5
+ , tick = this.tick = 0
+ , n = 0;
+
+ runner.on('start', function(){
+ Base.cursor.hide();
+ self.draw('start');
+ });
+
+ runner.on('pending', function(test){
+ self.draw('pending');
+ });
+
+ runner.on('pass', function(test){
+ self.draw('pass');
+ });
+
+ runner.on('fail', function(test, err){
+ self.draw('fail');
+ });
+
+ runner.on('end', function(){
+ Base.cursor.show();
+ for (var i = 0; i < self.numberOfLines; i++) write('\n');
+ self.epilogue();
+ });
+}
+
+/**
+ * Draw the nyan cat with runner `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.draw = function(status){
+ this.appendRainbow();
+ this.drawScoreboard();
+ this.drawRainbow();
+ this.drawNyanCat(status);
+ this.tick = !this.tick;
+};
+
+/**
+ * Draw the "scoreboard" showing the number
+ * of passes, failures and pending tests.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawScoreboard = function(){
+ var stats = this.stats;
+ var colors = Base.colors;
+
+ function draw(color, n) {
+ write(' ');
+ write('\u001b[' + color + 'm' + n + '\u001b[0m');
+ write('\n');
+ }
+
+ draw(colors.green, stats.passes);
+ draw(colors.fail, stats.failures);
+ draw(colors.pending, stats.pending);
+ write('\n');
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Append the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.appendRainbow = function(){
+ var segment = this.tick ? '_' : '-';
+ var rainbowified = this.rainbowify(segment);
+
+ for (var index = 0; index < this.numberOfLines; index++) {
+ var trajectory = this.trajectories[index];
+ if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();
+ trajectory.push(rainbowified);
+ }
+};
+
+/**
+ * Draw the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawRainbow = function(){
+ var self = this;
+
+ this.trajectories.forEach(function(line, index) {
+ write('\u001b[' + self.scoreboardWidth + 'C');
+ write(line.join(''));
+ write('\n');
+ });
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Draw the nyan cat with `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.drawNyanCat = function(status) {
+ var self = this;
+ var startWidth = this.scoreboardWidth + this.trajectories[0].length;
+ var color = '\u001b[' + startWidth + 'C';
+ var padding = '';
+
+ write(color);
+ write('_,------,');
+ write('\n');
+
+ write(color);
+ padding = self.tick ? ' ' : ' ';
+ write('_|' + padding + '/\\_/\\ ');
+ write('\n');
+
+ write(color);
+ padding = self.tick ? '_' : '__';
+ var tail = self.tick ? '~' : '^';
+ var face;
+ switch (status) {
+ case 'pass':
+ face = '( ^ .^)';
+ break;
+ case 'fail':
+ face = '( o .o)';
+ break;
+ default:
+ face = '( - .-)';
+ }
+ write(tail + '|' + padding + face + ' ');
+ write('\n');
+
+ write(color);
+ padding = self.tick ? ' ' : ' ';
+ write(padding + '"" "" ');
+ write('\n');
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Move cursor up `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorUp = function(n) {
+ write('\u001b[' + n + 'A');
+};
+
+/**
+ * Move cursor down `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorDown = function(n) {
+ write('\u001b[' + n + 'B');
+};
+
+/**
+ * Generate rainbow colors.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+NyanCat.prototype.generateColors = function(){
+ var colors = [];
+
+ for (var i = 0; i < (6 * 7); i++) {
+ var pi3 = Math.floor(Math.PI / 3);
+ var n = (i * (1.0 / 6));
+ var r = Math.floor(3 * Math.sin(n) + 3);
+ var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);
+ var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);
+ colors.push(36 * r + 6 * g + b + 16);
+ }
+
+ return colors;
+};
+
+/**
+ * Apply rainbow to the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+NyanCat.prototype.rainbowify = function(str){
+ var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
+ this.colorIndex += 1;
+ return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Stdout helper.
+ */
+
+function write(string) {
+ process.stdout.write(string);
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+NyanCat.prototype = new F;
+NyanCat.prototype.constructor = NyanCat;
+
+
+}); // module: reporters/nyan.js
+
+require.register("reporters/progress.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , cursor = Base.cursor
+ , color = Base.color;
+
+/**
+ * Expose `Progress`.
+ */
+
+exports = module.exports = Progress;
+
+/**
+ * General progress bar color.
+ */
+
+Base.colors.progress = 90;
+
+/**
+ * Initialize a new `Progress` bar test reporter.
+ *
+ * @param {Runner} runner
+ * @param {Object} options
+ * @api public
+ */
+
+function Progress(runner, options) {
+ Base.call(this, runner);
+
+ var self = this
+ , options = options || {}
+ , stats = this.stats
+ , width = Base.window.width * .50 | 0
+ , total = runner.total
+ , complete = 0
+ , max = Math.max;
+
+ // default chars
+ options.open = options.open || '[';
+ options.complete = options.complete || '▬';
+ options.incomplete = options.incomplete || Base.symbols.dot;
+ options.close = options.close || ']';
+ options.verbose = false;
+
+ // tests started
+ runner.on('start', function(){
+ console.log();
+ cursor.hide();
+ });
+
+ // tests complete
+ runner.on('test end', function(){
+ complete++;
+ var incomplete = total - complete
+ , percent = complete / total
+ , n = width * percent | 0
+ , i = width - n;
+
+ cursor.CR();
+ process.stdout.write('\u001b[J');
+ process.stdout.write(color('progress', ' ' + options.open));
+ process.stdout.write(Array(n).join(options.complete));
+ process.stdout.write(Array(i).join(options.incomplete));
+ process.stdout.write(color('progress', options.close));
+ if (options.verbose) {
+ process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
+ }
+ });
+
+ // tests are complete, output some stats
+ // and the failures if any
+ runner.on('end', function(){
+ cursor.show();
+ console.log();
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Progress.prototype = new F;
+Progress.prototype.constructor = Progress;
+
+
+}); // module: reporters/progress.js
+
+require.register("reporters/spec.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , cursor = Base.cursor
+ , color = Base.color;
+
+/**
+ * Expose `Spec`.
+ */
+
+exports = module.exports = Spec;
+
+/**
+ * Initialize a new `Spec` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Spec(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , indents = 0
+ , n = 0;
+
+ function indent() {
+ return Array(indents).join(' ')
+ }
+
+ runner.on('start', function(){
+ console.log();
+ });
+
+ runner.on('suite', function(suite){
+ ++indents;
+ console.log(color('suite', '%s%s'), indent(), suite.title);
+ });
+
+ runner.on('suite end', function(suite){
+ --indents;
+ if (1 == indents) console.log();
+ });
+
+ runner.on('test', function(test){
+ process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': '));
+ });
+
+ runner.on('pending', function(test){
+ var fmt = indent() + color('pending', ' - %s');
+ console.log(fmt, test.title);
+ });
+
+ runner.on('pass', function(test){
+ if ('fast' == test.speed) {
+ var fmt = indent()
+ + color('checkmark', ' ' + Base.symbols.ok)
+ + color('pass', ' %s ');
+ cursor.CR();
+ console.log(fmt, test.title);
+ } else {
+ var fmt = indent()
+ + color('checkmark', ' ' + Base.symbols.ok)
+ + color('pass', ' %s ')
+ + color(test.speed, '(%dms)');
+ cursor.CR();
+ console.log(fmt, test.title, test.duration);
+ }
+ });
+
+ runner.on('fail', function(test, err){
+ cursor.CR();
+ console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
+ });
+
+ runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Spec.prototype = new F;
+Spec.prototype.constructor = Spec;
+
+
+}); // module: reporters/spec.js
+
+require.register("reporters/tap.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , cursor = Base.cursor
+ , color = Base.color;
+
+/**
+ * Expose `TAP`.
+ */
+
+exports = module.exports = TAP;
+
+/**
+ * Initialize a new `TAP` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function TAP(runner) {
+ Base.call(this, runner);
+
+ var self = this
+ , stats = this.stats
+ , n = 1
+ , passes = 0
+ , failures = 0;
+
+ runner.on('start', function(){
+ var total = runner.grepTotal(runner.suite);
+ console.log('%d..%d', 1, total);
+ });
+
+ runner.on('test end', function(){
+ ++n;
+ });
+
+ runner.on('pending', function(test){
+ console.log('ok %d %s # SKIP -', n, title(test));
+ });
+
+ runner.on('pass', function(test){
+ passes++;
+ console.log('ok %d %s', n, title(test));
+ });
+
+ runner.on('fail', function(test, err){
+ failures++;
+ console.log('not ok %d %s', n, title(test));
+ if (err.stack) console.log(err.stack.replace(/^/gm, ' '));
+ });
+
+ runner.on('end', function(){
+ console.log('# tests ' + (passes + failures));
+ console.log('# pass ' + passes);
+ console.log('# fail ' + failures);
+ });
+}
+
+/**
+ * Return a TAP-safe title of `test`
+ *
+ * @param {Object} test
+ * @return {String}
+ * @api private
+ */
+
+function title(test) {
+ return test.fullTitle().replace(/#/g, '');
+}
+
+}); // module: reporters/tap.js
+
+require.register("reporters/teamcity.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `Teamcity`.
+ */
+
+exports = module.exports = Teamcity;
+
+/**
+ * Initialize a new `Teamcity` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Teamcity(runner) {
+ Base.call(this, runner);
+ var stats = this.stats;
+
+ runner.on('start', function() {
+ console.log("##teamcity[testSuiteStarted name='mocha.suite']");
+ });
+
+ runner.on('test', function(test) {
+ console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']");
+ });
+
+ runner.on('fail', function(test, err) {
+ console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']");
+ });
+
+ runner.on('pending', function(test) {
+ console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']");
+ });
+
+ runner.on('test end', function(test) {
+ console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']");
+ });
+
+ runner.on('end', function() {
+ console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']");
+ });
+}
+
+/**
+ * Escape the given `str`.
+ */
+
+function escape(str) {
+ return str
+ .replace(/\|/g, "||")
+ .replace(/\n/g, "|n")
+ .replace(/\r/g, "|r")
+ .replace(/\[/g, "|[")
+ .replace(/\]/g, "|]")
+ .replace(/\u0085/g, "|x")
+ .replace(/\u2028/g, "|l")
+ .replace(/\u2029/g, "|p")
+ .replace(/'/g, "|'");
+}
+
+}); // module: reporters/teamcity.js
+
+require.register("reporters/xunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+ , utils = require('../utils')
+ , escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
+ * Expose `XUnit`.
+ */
+
+exports = module.exports = XUnit;
+
+/**
+ * Initialize a new `XUnit` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function XUnit(runner) {
+ Base.call(this, runner);
+ var stats = this.stats
+ , tests = []
+ , self = this;
+
+ runner.on('pass', function(test){
+ tests.push(test);
+ });
+
+ runner.on('fail', function(test){
+ tests.push(test);
+ });
+
+ runner.on('end', function(){
+ console.log(tag('testsuite', {
+ name: 'Mocha Tests'
+ , tests: stats.tests
+ , failures: stats.failures
+ , errors: stats.failures
+ , skipped: stats.tests - stats.failures - stats.passes
+ , timestamp: (new Date).toUTCString()
+ , time: (stats.duration / 1000) || 0
+ }, false));
+
+ tests.forEach(test);
+ console.log('</testsuite>');
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+XUnit.prototype = new F;
+XUnit.prototype.constructor = XUnit;
+
+
+/**
+ * Output tag for the given `test.`
+ */
+
+function test(test) {
+ var attrs = {
+ classname: test.parent.fullTitle()
+ , name: test.title
+ , time: test.duration / 1000
+ };
+
+ if ('failed' == test.state) {
+ var err = test.err;
+ attrs.message = escape(err.message);
+ console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
+ } else if (test.pending) {
+ console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
+ } else {
+ console.log(tag('testcase', attrs, true) );
+ }
+}
+
+/**
+ * HTML tag helper.
+ */
+
+function tag(name, attrs, close, content) {
+ var end = close ? '/>' : '>'
+ , pairs = []
+ , tag;
+
+ for (var key in attrs) {
+ pairs.push(key + '="' + escape(attrs[key]) + '"');
+ }
+
+ tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
+ if (content) tag += content + '</' + name + end;
+ return tag;
+}
+
+/**
+ * Return cdata escaped CDATA `str`.
+ */
+
+function cdata(str) {
+ return '<![CDATA[' + escape(str) + ']]>';
+}
+
+}); // module: reporters/xunit.js
+
+require.register("runnable.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('browser/events').EventEmitter
+ , debug = require('browser/debug')('mocha:runnable')
+ , milliseconds = require('./ms');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+ , setTimeout = global.setTimeout
+ , setInterval = global.setInterval
+ , clearTimeout = global.clearTimeout
+ , clearInterval = global.clearInterval;
+
+/**
+ * Object#toString().
+ */
+
+var toString = Object.prototype.toString;
+
+/**
+ * Expose `Runnable`.
+ */
+
+module.exports = Runnable;
+
+/**
+ * Initialize a new `Runnable` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Runnable(title, fn) {
+ this.title = title;
+ this.fn = fn;
+ this.async = fn && fn.length;
+ this.sync = ! this.async;
+ this._timeout = 2000;
+ this._slow = 75;
+ this.timedOut = false;
+}
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+
+function F(){};
+F.prototype = EventEmitter.prototype;
+Runnable.prototype = new F;
+Runnable.prototype.constructor = Runnable;
+
+
+/**
+ * Set & get timeout `ms`.
+ *
+ * @param {Number|String} ms
+ * @return {Runnable|Number} ms or self
+ * @api private
+ */
+
+Runnable.prototype.timeout = function(ms){
+ if (0 == arguments.length) return this._timeout;
+ if ('string' == typeof ms) ms = milliseconds(ms);
+ debug('timeout %d', ms);
+ this._timeout = ms;
+ if (this.timer) this.resetTimeout();
+ return this;
+};
+
+/**
+ * Set & get slow `ms`.
+ *
+ * @param {Number|String} ms
+ * @return {Runnable|Number} ms or self
+ * @api private
+ */
+
+Runnable.prototype.slow = function(ms){
+ if (0 === arguments.length) return this._slow;
+ if ('string' == typeof ms) ms = milliseconds(ms);
+ debug('timeout %d', ms);
+ this._slow = ms;
+ return this;
+};
+
+/**
+ * Return the full title generated by recursively
+ * concatenating the parent's full title.
+ *
+ * @return {String}
+ * @api public
+ */
+
+Runnable.prototype.fullTitle = function(){
+ return this.parent.fullTitle() + ' ' + this.title;
+};
+
+/**
+ * Clear the timeout.
+ *
+ * @api private
+ */
+
+Runnable.prototype.clearTimeout = function(){
+ clearTimeout(this.timer);
+};
+
+/**
+ * Inspect the runnable void of private properties.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Runnable.prototype.inspect = function(){
+ return JSON.stringify(this, function(key, val){
+ if ('_' == key[0]) return;
+ if ('parent' == key) return '#<Suite>';
+ if ('ctx' == key) return '#<Context>';
+ return val;
+ }, 2);
+};
+
+/**
+ * Reset the timeout.
+ *
+ * @api private
+ */
+
+Runnable.prototype.resetTimeout = function(){
+ var self = this;
+ var ms = this.timeout() || 1e9;
+
+ this.clearTimeout();
+ this.timer = setTimeout(function(){
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
+ self.timedOut = true;
+ }, ms);
+};
+
+/**
+ * Run the test and invoke `fn(err)`.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+
+Runnable.prototype.run = function(fn){
+ var self = this
+ , ms = this.timeout()
+ , start = new Date
+ , ctx = this.ctx
+ , finished
+ , emitted;
+
+ if (ctx) ctx.runnable(this);
+
+ // timeout
+ if (this.async) {
+ if (ms) {
+ this.timer = setTimeout(function(){
+ done(new Error('timeout of ' + ms + 'ms exceeded'));
+ self.timedOut = true;
+ }, ms);
+ }
+ }
+
+ // called multiple times
+ function multiple(err) {
+ if (emitted) return;
+ emitted = true;
+ self.emit('error', err || new Error('done() called multiple times'));
+ }
+
+ // finished
+ function done(err) {
+ if (self.timedOut) return;
+ if (finished) return multiple(err);
+ self.clearTimeout();
+ self.duration = new Date - start;
+ finished = true;
+ fn(err);
+ }
+
+ // for .resetTimeout()
+ this.callback = done;
+
+ // async
+ if (this.async) {
+ try {
+ this.fn.call(ctx, function(err){
+ if (err instanceof Error || toString.call(err) === "[object Error]") return done(err);
+ if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
+ done();
+ });
+ } catch (err) {
+ done(err);
+ }
+ return;
+ }
+
+ if (this.asyncOnly) {
+ return done(new Error('--async-only option in use without declaring `done()`'));
+ }
+
+ // sync
+ try {
+ if (!this.pending) this.fn.call(ctx);
+ this.duration = new Date - start;
+ fn();
+ } catch (err) {
+ fn(err);
+ }
+};
+
+}); // module: runnable.js
+
+require.register("runner.js", function(module, exports, require){
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('browser/events').EventEmitter
+ , debug = require('browser/debug')('mocha:runner')
+ , Test = require('./test')
+ , utils = require('./utils')
+ , filter = utils.filter
+ , keys = utils.keys;
+
+/**
+ * Non-enumerable globals.
+ */
+
+var globals = [
+ 'setTimeout',
+ 'clearTimeout',
+ 'setInterval',
+ 'clearInterval',
+ 'XMLHttpRequest',
+ 'Date'
+];
+
+/**
+ * Expose `Runner`.
+ */
+
+module.exports = Runner;
+
+/**
+ * Initialize a `Runner` for the given `suite`.
+ *
+ * Events:
+ *
+ * - `start` execution started
+ * - `end` execution complete
+ * - `suite` (suite) test suite execution started
+ * - `suite end` (suite) all tests (and sub-suites) have finished
+ * - `test` (test) test execution started
+ * - `test end` (test) test completed
+ * - `hook` (hook) hook execution started
+ * - `hook end` (hook) hook complete
+ * - `pass` (test) test passed
+ * - `fail` (test, err) test failed
+ * - `pending` (test) test pending
+ *
+ * @api public
+ */
+
+function Runner(suite) {
+ var self = this;
+ this._globals = [];
+ this.suite = suite;
+ this.total = suite.total();
+ this.failures = 0;
+ this.on('test end', function(test){ self.checkGlobals(test); });
+ this.on('hook end', function(hook){ self.checkGlobals(hook); });
+ this.grep(/.*/);
+ this.globals(this.globalProps().concat(['errno']));
+}
+
+/**
+ * Wrapper for setImmediate, process.nextTick, or browser polyfill.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.immediately = global.setImmediate || process.nextTick;
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+
+function F(){};
+F.prototype = EventEmitter.prototype;
+Runner.prototype = new F;
+Runner.prototype.constructor = Runner;
+
+
+/**
+ * Run tests with full titles matching `re`. Updates runner.total
+ * with number of tests matched.
+ *
+ * @param {RegExp} re
+ * @param {Boolean} invert
+ * @return {Runner} for chaining
+ * @api public
+ */
+
+Runner.prototype.grep = function(re, invert){
+ debug('grep %s', re);
+ this._grep = re;
+ this._invert = invert;
+ this.total = this.grepTotal(this.suite);
+ return this;
+};
+
+/**
+ * Returns the number of tests matching the grep search for the
+ * given suite.
+ *
+ * @param {Suite} suite
+ * @return {Number}
+ * @api public
+ */
+
+Runner.prototype.grepTotal = function(suite) {
+ var self = this;
+ var total = 0;
+
+ suite.eachTest(function(test){
+ var match = self._grep.test(test.fullTitle());
+ if (self._invert) match = !match;
+ if (match) total++;
+ });
+
+ return total;
+};
+
+/**
+ * Return a list of global properties.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+Runner.prototype.globalProps = function() {
+ var props = utils.keys(global);
+
+ // non-enumerables
+ for (var i = 0; i < globals.length; ++i) {
+ if (~utils.indexOf(props, globals[i])) continue;
+ props.push(globals[i]);
+ }
+
+ return props;
+};
+
+/**
+ * Allow the given `arr` of globals.
+ *
+ * @param {Array} arr
+ * @return {Runner} for chaining
+ * @api public
+ */
+
+Runner.prototype.globals = function(arr){
+ if (0 == arguments.length) return this._globals;
+ debug('globals %j', arr);
+ utils.forEach(arr, function(arr){
+ this._globals.push(arr);
+ }, this);
+ return this;
+};
+
+/**
+ * Check for global variable leaks.
+ *
+ * @api private
+ */
+
+Runner.prototype.checkGlobals = function(test){
+ if (this.ignoreLeaks) return;
+ var ok = this._globals;
+ var globals = this.globalProps();
+ var isNode = process.kill;
+ var leaks;
+
+ // check length - 2 ('errno' and 'location' globals)
+ if (isNode && 1 == ok.length - globals.length) return
+ else if (2 == ok.length - globals.length) return;
+
+ leaks = filterLeaks(ok, globals);
+ this._globals = this._globals.concat(leaks);
+
+ if (leaks.length > 1) {
+ this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
+ } else if (leaks.length) {
+ this.fail(test, new Error('global leak detected: ' + leaks[0]));
+ }
+};
+
+/**
+ * Fail the given `test`.
+ *
+ * @param {Test} test
+ * @param {Error} err
+ * @api private
+ */
+
+Runner.prototype.fail = function(test, err){
+ ++this.failures;
+ test.state = 'failed';
+
+ if ('string' == typeof err) {
+ err = new Error('the string "' + err + '" was thrown, throw an Error :)');
+ }
+
+ this.emit('fail', test, err);
+};
+
+/**
+ * Fail the given `hook` with `err`.
+ *
+ * Hook failures (currently) hard-end due
+ * to that fact that a failing hook will
+ * surely cause subsequent tests to fail,
+ * causing jumbled reporting.
+ *
+ * @param {Hook} hook
+ * @param {Error} err
+ * @api private
+ */
+
+Runner.prototype.failHook = function(hook, err){
+ this.fail(hook, err);
+ this.emit('end');
+};
+
+/**
+ * Run hook `name` callbacks and then invoke `fn()`.
+ *
+ * @param {String} name
+ * @param {Function} function
+ * @api private
+ */
+
+Runner.prototype.hook = function(name, fn){
+ var suite = this.suite
+ , hooks = suite['_' + name]
+ , self = this
+ , timer;
+
+ function next(i) {
+ var hook = hooks[i];
+ if (!hook) return fn();
+ if (self.failures && suite.bail()) return fn();
+ self.currentRunnable = hook;
+
+ hook.ctx.currentTest = self.test;
+
+ self.emit('hook', hook);
+
+ hook.on('error', function(err){
+ self.failHook(hook, err);
+ });
+
+ hook.run(function(err){
+ hook.removeAllListeners('error');
+ var testError = hook.error();
+ if (testError) self.fail(self.test, testError);
+ if (err) return self.failHook(hook, err);
+ self.emit('hook end', hook);
+ delete hook.ctx.currentTest;
+ next(++i);
+ });
+ }
+
+ Runner.immediately(function(){
+ next(0);
+ });
+};
+
+/**
+ * Run hook `name` for the given array of `suites`
+ * in order, and callback `fn(err)`.
+ *
+ * @param {String} name
+ * @param {Array} suites
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.prototype.hooks = function(name, suites, fn){
+ var self = this
+ , orig = this.suite;
+
+ function next(suite) {
+ self.suite = suite;
+
+ if (!suite) {
+ self.suite = orig;
+ return fn();
+ }
+
+ self.hook(name, function(err){
+ if (err) {
+ self.suite = orig;
+ return fn(err);
+ }
+
+ next(suites.pop());
+ });
+ }
+
+ next(suites.pop());
+};
+
+/**
+ * Run hooks from the top level down.
+ *
+ * @param {String} name
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.prototype.hookUp = function(name, fn){
+ var suites = [this.suite].concat(this.parents()).reverse();
+ this.hooks(name, suites, fn);
+};
+
+/**
+ * Run hooks from the bottom up.
+ *
+ * @param {String} name
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.prototype.hookDown = function(name, fn){
+ var suites = [this.suite].concat(this.parents());
+ this.hooks(name, suites, fn);
+};
+
+/**
+ * Return an array of parent Suites from
+ * closest to furthest.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+Runner.prototype.parents = function(){
+ var suite = this.suite
+ , suites = [];
+ while (suite = suite.parent) suites.push(suite);
+ return suites;
+};
+
+/**
+ * Run the current test and callback `fn(err)`.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.prototype.runTest = function(fn){
+ var test = this.test
+ , self = this;
+
+ if (this.asyncOnly) test.asyncOnly = true;
+
+ try {
+ test.on('error', function(err){
+ self.fail(test, err);
+ });
+ test.run(fn);
+ } catch (err) {
+ fn(err);
+ }
+};
+
+/**
+ * Run tests in the given `suite` and invoke
+ * the callback `fn()` when complete.
+ *
+ * @param {Suite} suite
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.prototype.runTests = function(suite, fn){
+ var self = this
+ , tests = suite.tests.slice()
+ , test;
+
+ function next(err) {
+ // if we bail after first err
+ if (self.failures && suite._bail) return fn();
+
+ // next test
+ test = tests.shift();
+
+ // all done
+ if (!test) return fn();
+
+ // grep
+ var match = self._grep.test(test.fullTitle());
+ if (self._invert) match = !match;
+ if (!match) return next();
+
+ // pending
+ if (test.pending) {
+ self.emit('pending', test);
+ self.emit('test end', test);
+ return next();
+ }
+
+ // execute test and hook(s)
+ self.emit('test', self.test = test);
+ self.hookDown('beforeEach', function(){
+ self.currentRunnable = self.test;
+ self.runTest(function(err){
+ test = self.test;
+
+ if (err) {
+ self.fail(test, err);
+ self.emit('test end', test);
+ return self.hookUp('afterEach', next);
+ }
+
+ test.state = 'passed';
+ self.emit('pass', test);
+ self.emit('test end', test);
+ self.hookUp('afterEach', next);
+ });
+ });
+ }
+
+ this.next = next;
+ next();
+};
+
+/**
+ * Run the given `suite` and invoke the
+ * callback `fn()` when complete.
+ *
+ * @param {Suite} suite
+ * @param {Function} fn
+ * @api private
+ */
+
+Runner.prototype.runSuite = function(suite, fn){
+ var total = this.grepTotal(suite)
+ , self = this
+ , i = 0;
+
+ debug('run suite %s', suite.fullTitle());
+
+ if (!total) return fn();
+
+ this.emit('suite', this.suite = suite);
+
+ function next() {
+ var curr = suite.suites[i++];
+ if (!curr) return done();
+ self.runSuite(curr, next);
+ }
+
+ function done() {
+ self.suite = suite;
+ self.hook('afterAll', function(){
+ self.emit('suite end', suite);
+ fn();
+ });
+ }
+
+ this.hook('beforeAll', function(){
+ self.runTests(suite, next);
+ });
+};
+
+/**
+ * Handle uncaught exceptions.
+ *
+ * @param {Error} err
+ * @api private
+ */
+
+Runner.prototype.uncaught = function(err){
+ debug('uncaught exception %s', err.message);
+ var runnable = this.currentRunnable;
+ if (!runnable || 'failed' == runnable.state) return;
+ runnable.clearTimeout();
+ err.uncaught = true;
+ this.fail(runnable, err);
+
+ // recover from test
+ if ('test' == runnable.type) {
+ this.emit('test end', runnable);
+ this.hookUp('afterEach', this.next);
+ return;
+ }
+
+ // bail on hooks
+ this.emit('end');
+};
+
+/**
+ * Run the root suite and invoke `fn(failures)`
+ * on completion.
+ *
+ * @param {Function} fn
+ * @return {Runner} for chaining
+ * @api public
+ */
+
+Runner.prototype.run = function(fn){
+ var self = this
+ , fn = fn || function(){};
+
+ function uncaught(err){
+ self.uncaught(err);
+ }
+
+ debug('start');
+
+ // callback
+ this.on('end', function(){
+ debug('end');
+ process.removeListener('uncaughtException', uncaught);
+ fn(self.failures);
+ });
+
+ // run suites
+ this.emit('start');
+ this.runSuite(this.suite, function(){
+ debug('finished running');
+ self.emit('end');
+ });
+
+ // uncaught exception
+ process.on('uncaughtException', uncaught);
+
+ return this;
+};
+
+/**
+ * Filter leaks with the given globals flagged as `ok`.
+ *
+ * @param {Array} ok
+ * @param {Array} globals
+ * @return {Array}
+ * @api private
+ */
+
+function filterLeaks(ok, globals) {
+ return filter(globals, function(key){
+ // Firefox and Chrome exposes iframes as index inside the window object
+ if (/^d+/.test(key)) return false;
+ var matched = filter(ok, function(ok){
+ if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]);
+ // Opera and IE expose global variables for HTML element IDs (issue #243)
+ if (/^mocha-/.test(key)) return true;
+ return key == ok;
+ });
+ return matched.length == 0 && (!global.navigator || 'onerror' !== key);
+ });
+}
+
+}); // module: runner.js
+
+require.register("suite.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('browser/events').EventEmitter
+ , debug = require('browser/debug')('mocha:suite')
+ , milliseconds = require('./ms')
+ , utils = require('./utils')
+ , Hook = require('./hook');
+
+/**
+ * Expose `Suite`.
+ */
+
+exports = module.exports = Suite;
+
+/**
+ * Create a new `Suite` with the given `title`
+ * and parent `Suite`. When a suite with the
+ * same title is already present, that suite
+ * is returned to provide nicer reporter
+ * and more flexible meta-testing.
+ *
+ * @param {Suite} parent
+ * @param {String} title
+ * @return {Suite}
+ * @api public
+ */
+
+exports.create = function(parent, title){
+ var suite = new Suite(title, parent.ctx);
+ suite.parent = parent;
+ if (parent.pending) suite.pending = true;
+ title = suite.fullTitle();
+ parent.addSuite(suite);
+ return suite;
+};
+
+/**
+ * Initialize a new `Suite` with the given
+ * `title` and `ctx`.
+ *
+ * @param {String} title
+ * @param {Context} ctx
+ * @api private
+ */
+
+function Suite(title, ctx) {
+ this.title = title;
+ this.ctx = ctx;
+ this.suites = [];
+ this.tests = [];
+ this.pending = false;
+ this._beforeEach = [];
+ this._beforeAll = [];
+ this._afterEach = [];
+ this._afterAll = [];
+ this.root = !title;
+ this._timeout = 2000;
+ this._slow = 75;
+ this._bail = false;
+}
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+
+function F(){};
+F.prototype = EventEmitter.prototype;
+Suite.prototype = new F;
+Suite.prototype.constructor = Suite;
+
+
+/**
+ * Return a clone of this `Suite`.
+ *
+ * @return {Suite}
+ * @api private
+ */
+
+Suite.prototype.clone = function(){
+ var suite = new Suite(this.title);
+ debug('clone');
+ suite.ctx = this.ctx;
+ suite.timeout(this.timeout());
+ suite.slow(this.slow());
+ suite.bail(this.bail());
+ return suite;
+};
+
+/**
+ * Set timeout `ms` or short-hand such as "2s".
+ *
+ * @param {Number|String} ms
+ * @return {Suite|Number} for chaining
+ * @api private
+ */
+
+Suite.prototype.timeout = function(ms){
+ if (0 == arguments.length) return this._timeout;
+ if ('string' == typeof ms) ms = milliseconds(ms);
+ debug('timeout %d', ms);
+ this._timeout = parseInt(ms, 10);
+ return this;
+};
+
+/**
+ * Set slow `ms` or short-hand such as "2s".
+ *
+ * @param {Number|String} ms
+ * @return {Suite|Number} for chaining
+ * @api private
+ */
+
+Suite.prototype.slow = function(ms){
+ if (0 === arguments.length) return this._slow;
+ if ('string' == typeof ms) ms = milliseconds(ms);
+ debug('slow %d', ms);
+ this._slow = ms;
+ return this;
+};
+
+/**
+ * Sets whether to bail after first error.
+ *
+ * @parma {Boolean} bail
+ * @return {Suite|Number} for chaining
+ * @api private
+ */
+
+Suite.prototype.bail = function(bail){
+ if (0 == arguments.length) return this._bail;
+ debug('bail %s', bail);
+ this._bail = bail;
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` before running tests.
+ *
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ * @api private
+ */
+
+Suite.prototype.beforeAll = function(fn){
+ if (this.pending) return this;
+ var hook = new Hook('"before all" hook', fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._beforeAll.push(hook);
+ this.emit('beforeAll', hook);
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` after running tests.
+ *
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ * @api private
+ */
+
+Suite.prototype.afterAll = function(fn){
+ if (this.pending) return this;
+ var hook = new Hook('"after all" hook', fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._afterAll.push(hook);
+ this.emit('afterAll', hook);
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` before each test case.
+ *
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ * @api private
+ */
+
+Suite.prototype.beforeEach = function(fn){
+ if (this.pending) return this;
+ var hook = new Hook('"before each" hook', fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._beforeEach.push(hook);
+ this.emit('beforeEach', hook);
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` after each test case.
+ *
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ * @api private
+ */
+
+Suite.prototype.afterEach = function(fn){
+ if (this.pending) return this;
+ var hook = new Hook('"after each" hook', fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._afterEach.push(hook);
+ this.emit('afterEach', hook);
+ return this;
+};
+
+/**
+ * Add a test `suite`.
+ *
+ * @param {Suite} suite
+ * @return {Suite} for chaining
+ * @api private
+ */
+
+Suite.prototype.addSuite = function(suite){
+ suite.parent = this;
+ suite.timeout(this.timeout());
+ suite.slow(this.slow());
+ suite.bail(this.bail());
+ this.suites.push(suite);
+ this.emit('suite', suite);
+ return this;
+};
+
+/**
+ * Add a `test` to this suite.
+ *
+ * @param {Test} test
+ * @return {Suite} for chaining
+ * @api private
+ */
+
+Suite.prototype.addTest = function(test){
+ test.parent = this;
+ test.timeout(this.timeout());
+ test.slow(this.slow());
+ test.ctx = this.ctx;
+ this.tests.push(test);
+ this.emit('test', test);
+ return this;
+};
+
+/**
+ * Return the full title generated by recursively
+ * concatenating the parent's full title.
+ *
+ * @return {String}
+ * @api public
+ */
+
+Suite.prototype.fullTitle = function(){
+ if (this.parent) {
+ var full = this.parent.fullTitle();
+ if (full) return full + ' ' + this.title;
+ }
+ return this.title;
+};
+
+/**
+ * Return the total number of tests.
+ *
+ * @return {Number}
+ * @api public
+ */
+
+Suite.prototype.total = function(){
+ return utils.reduce(this.suites, function(sum, suite){
+ return sum + suite.total();
+ }, 0) + this.tests.length;
+};
+
+/**
+ * Iterates through each suite recursively to find
+ * all tests. Applies a function in the format
+ * `fn(test)`.
+ *
+ * @param {Function} fn
+ * @return {Suite}
+ * @api private
+ */
+
+Suite.prototype.eachTest = function(fn){
+ utils.forEach(this.tests, fn);
+ utils.forEach(this.suites, function(suite){
+ suite.eachTest(fn);
+ });
+ return this;
+};
+
+}); // module: suite.js
+
+require.register("test.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Runnable = require('./runnable');
+
+/**
+ * Expose `Test`.
+ */
+
+module.exports = Test;
+
+/**
+ * Initialize a new `Test` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Test(title, fn) {
+ Runnable.call(this, title, fn);
+ this.pending = !fn;
+ this.type = 'test';
+}
+
+/**
+ * Inherit from `Runnable.prototype`.
+ */
+
+function F(){};
+F.prototype = Runnable.prototype;
+Test.prototype = new F;
+Test.prototype.constructor = Test;
+
+
+}); // module: test.js
+
+require.register("utils.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('browser/fs')
+ , path = require('browser/path')
+ , join = path.join
+ , debug = require('browser/debug')('mocha:watch');
+
+/**
+ * Ignored directories.
+ */
+
+var ignore = ['node_modules', '.git'];
+
+/**
+ * Escape special characters in the given string of html.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+exports.escape = function(html){
+ return String(html)
+ .replace(/&/g, '&amp;')
+ .replace(/"/g, '&quot;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+};
+
+/**
+ * Array#forEach (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @param {Object} scope
+ * @api private
+ */
+
+exports.forEach = function(arr, fn, scope){
+ for (var i = 0, l = arr.length; i < l; i++)
+ fn.call(scope, arr[i], i);
+};
+
+/**
+ * Array#indexOf (<=IE8)
+ *
+ * @parma {Array} arr
+ * @param {Object} obj to find index of
+ * @param {Number} start
+ * @api private
+ */
+
+exports.indexOf = function(arr, obj, start){
+ for (var i = start || 0, l = arr.length; i < l; i++) {
+ if (arr[i] === obj)
+ return i;
+ }
+ return -1;
+};
+
+/**
+ * Array#reduce (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @param {Object} initial value
+ * @api private
+ */
+
+exports.reduce = function(arr, fn, val){
+ var rval = val;
+
+ for (var i = 0, l = arr.length; i < l; i++) {
+ rval = fn(rval, arr[i], i, arr);
+ }
+
+ return rval;
+};
+
+/**
+ * Array#filter (<=IE8)
+ *
+ * @param {Array} array
+ * @param {Function} fn
+ * @api private
+ */
+
+exports.filter = function(arr, fn){
+ var ret = [];
+
+ for (var i = 0, l = arr.length; i < l; i++) {
+ var val = arr[i];
+ if (fn(val, i, arr)) ret.push(val);
+ }
+
+ return ret;
+};
+
+/**
+ * Object.keys (<=IE8)
+ *
+ * @param {Object} obj
+ * @return {Array} keys
+ * @api private
+ */
+
+exports.keys = Object.keys || function(obj) {
+ var keys = []
+ , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
+
+ for (var key in obj) {
+ if (has.call(obj, key)) {
+ keys.push(key);
+ }
+ }
+
+ return keys;
+};
+
+/**
+ * Watch the given `files` for changes
+ * and invoke `fn(file)` on modification.
+ *
+ * @param {Array} files
+ * @param {Function} fn
+ * @api private
+ */
+
+exports.watch = function(files, fn){
+ var options = { interval: 100 };
+ files.forEach(function(file){
+ debug('file %s', file);
+ fs.watchFile(file, options, function(curr, prev){
+ if (prev.mtime < curr.mtime) fn(file);
+ });
+ });
+};
+
+/**
+ * Ignored files.
+ */
+
+function ignored(path){
+ return !~ignore.indexOf(path);
+}
+
+/**
+ * Lookup files in the given `dir`.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+exports.files = function(dir, ret){
+ ret = ret || [];
+
+ fs.readdirSync(dir)
+ .filter(ignored)
+ .forEach(function(path){
+ path = join(dir, path);
+ if (fs.statSync(path).isDirectory()) {
+ exports.files(path, ret);
+ } else if (path.match(/\.(js|coffee)$/)) {
+ ret.push(path);
+ }
+ });
+
+ return ret;
+};
+
+/**
+ * Compute a slug from the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.slug = function(str){
+ return str
+ .toLowerCase()
+ .replace(/ +/g, '-')
+ .replace(/[^-\w]/g, '');
+};
+
+/**
+ * Strip the function definition from `str`,
+ * and re-indent for pre whitespace.
+ */
+
+exports.clean = function(str) {
+ str = str
+ .replace(/^function *\(.*\) *{/, '')
+ .replace(/\s+\}$/, '');
+
+ var whitespace = str.match(/^\n?(\s*)/)[1]
+ , re = new RegExp('^' + whitespace, 'gm');
+
+ str = str.replace(re, '');
+
+ return exports.trim(str);
+};
+
+/**
+ * Escape regular expression characters in `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.escapeRegexp = function(str){
+ return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&");
+};
+
+/**
+ * Trim the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+exports.trim = function(str){
+ return str.replace(/^\s+|\s+$/g, '');
+};
+
+/**
+ * Parse the given `qs`.
+ *
+ * @param {String} qs
+ * @return {Object}
+ * @api private
+ */
+
+exports.parseQuery = function(qs){
+ return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){
+ var i = pair.indexOf('=')
+ , key = pair.slice(0, i)
+ , val = pair.slice(++i);
+
+ obj[key] = decodeURIComponent(val);
+ return obj;
+ }, {});
+};
+
+/**
+ * Highlight the given string of `js`.
+ *
+ * @param {String} js
+ * @return {String}
+ * @api private
+ */
+
+function highlight(js) {
+ return js
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
+ .replace(/('.*?')/gm, '<span class="string">$1</span>')
+ .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
+ .replace(/(\d+)/gm, '<span class="number">$1</span>')
+ .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
+ .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
+}
+
+/**
+ * Highlight the contents of tag `name`.
+ *
+ * @param {String} name
+ * @api private
+ */
+
+exports.highlightTags = function(name) {
+ var code = document.getElementsByTagName(name);
+ for (var i = 0, len = code.length; i < len; ++i) {
+ code[i].innerHTML = highlight(code[i].innerHTML);
+ }
+};
+
+}); // module: utils.js
+// The global object is "self" in Web Workers.
+global = (function() { return this; })();
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date;
+var setTimeout = global.setTimeout;
+var setInterval = global.setInterval;
+var clearTimeout = global.clearTimeout;
+var clearInterval = global.clearInterval;
+
+/**
+ * Node shims.
+ *
+ * These are meant only to allow
+ * mocha.js to run untouched, not
+ * to allow running node code in
+ * the browser.
+ */
+
+var process = {};
+process.exit = function(status){};
+process.stdout = {};
+
+/**
+ * Remove uncaughtException listener.
+ */
+
+process.removeListener = function(e){
+ if ('uncaughtException' == e) {
+ global.onerror = function() {};
+ }
+};
+
+/**
+ * Implements uncaughtException listener.
+ */
+
+process.on = function(e, fn){
+ if ('uncaughtException' == e) {
+ global.onerror = function(err, url, line){
+ fn(new Error(err + ' (' + url + ':' + line + ')'));
+ };
+ }
+};
+
+/**
+ * Expose mocha.
+ */
+
+var Mocha = global.Mocha = require('mocha'),
+ mocha = global.mocha = new Mocha({ reporter: 'html' });
+
+var immediateQueue = []
+ , immediateTimeout;
+
+function timeslice() {
+ var immediateStart = new Date().getTime();
+ while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) {
+ immediateQueue.shift()();
+ }
+ if (immediateQueue.length) {
+ immediateTimeout = setTimeout(timeslice, 0);
+ } else {
+ immediateTimeout = null;
+ }
+}
+
+/**
+ * High-performance override of Runner.immediately.
+ */
+
+Mocha.Runner.immediately = function(callback) {
+ immediateQueue.push(callback);
+ if (!immediateTimeout) {
+ immediateTimeout = setTimeout(timeslice, 0);
+ }
+};
+
+/**
+ * Override ui to ensure that the ui functions are initialized.
+ * Normally this would happen in Mocha.prototype.loadFiles.
+ */
+
+mocha.ui = function(ui){
+ Mocha.prototype.ui.call(this, ui);
+ this.suite.emit('pre-require', global, null, this);
+ return this;
+};
+
+/**
+ * Setup mocha with the given setting options.
+ */
+
+mocha.setup = function(opts){
+ if ('string' == typeof opts) opts = { ui: opts };
+ for (var opt in opts) this[opt](opts[opt]);
+ return this;
+};
+
+/**
+ * Run mocha, returning the Runner.
+ */
+
+mocha.run = function(fn){
+ var options = mocha.options;
+ mocha.globals('location');
+
+ var query = Mocha.utils.parseQuery(global.location.search || '');
+ if (query.grep) mocha.grep(query.grep);
+ if (query.invert) mocha.invert();
+
+ return Mocha.prototype.run.call(mocha, function(){
+ // The DOM Document is not available in Web Workers.
+ if (global.document) {
+ Mocha.utils.highlightTags('code');
+ }
+ if (fn) fn();
+ });
+};
+
+/**
+ * Expose the process shim.
+ */
+
+Mocha.process = process;
+})(); \ No newline at end of file
diff --git a/src/fauxton/test/qunit/index.html b/src/fauxton/test/qunit/index.html
deleted file mode 100644
index 6b400a273..000000000
--- a/src/fauxton/test/qunit/index.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <meta name="viewport" content="width=device-width,initial-scale=1">
-
- <title>Backbone Boilerplate QUnit Test Suite</title>
-
- <!-- QUnit styles -->
- <link rel="stylesheet" href="vendor/qunit.css">
-</head>
-
-<body>
- <!-- QUnit stucture -->
- <div class="dataset-test">
- <h1 id="qunit-header">Backbone Boilerplate QUnit Test Suite</h1>
- <h2 id="qunit-banner"></h2>
- <h2 id="qunit-userAgent"></h2>
- <ol id="qunit-tests"></ol>
- </div>
-
- <!-- Testing libs -->
- <script src="vendor/qunit.js"></script>
-
- <!-- Application libs -->
- <script src="../../assets/js/libs/jquery.js"></script>
- <script src="../../assets/js/libs/lodash.js"></script>
- <script src="../../assets/js/libs/backbone.js"></script>
-
- <!-- Load application -->
- <script data-main="../../app/config"
- src="../../assets/js/libs/require.js"></script>
-
- <!-- Declare your test files to be run here -->
- <script>
- // Ensure you point to where your tests are, base directory is app/, which
- // is why ../test is necessary
- require({ paths: { tests: "../test/qunit/tests" } }, [
-
- // Load the example tests, replace this and add your own tests
- "tests/example"
-
- ]);
- </script>
-</body>
-</html>
diff --git a/src/fauxton/test/qunit/tests/example.js b/src/fauxton/test/qunit/tests/example.js
deleted file mode 100644
index 4c1242f81..000000000
--- a/src/fauxton/test/qunit/tests/example.js
+++ /dev/null
@@ -1,54 +0,0 @@
-test("one tautology", function() {
- ok(true);
-});
-
-module("simple tests");
-
-test("increments", function() {
- var mike = 0;
-
- ok(mike++ === 0);
- ok(mike === 1);
-});
-
-test("increments (improved)", function() {
- var mike = 0;
-
- equal(mike++, 0);
- equal(mike, 1);
-});
-
-
-module("setUp/tearDown", {
- setup: function() {
- //console.log("Before");
- },
-
- teardown: function() {
- //console.log("After");
- }
-});
-
-test("example", function() {
- //console.log("During");
-});
-
-module("async");
-
-test("multiple async", function() {
- expect(2);
-
- stop();
-
- setTimeout( function( ) {
- ok(true, "async operation completed");
- start();
- }, 500);
-
- stop();
-
- setTimeout(function() {
- ok(true, "async operation completed");
- start();
- }, 500);
-});
diff --git a/src/fauxton/test/qunit/vendor/qunit.css b/src/fauxton/test/qunit/vendor/qunit.css
deleted file mode 100644
index 861236512..000000000
--- a/src/fauxton/test/qunit/vendor/qunit.css
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
- * QUnit 1.2.0pre - A JavaScript Unit Testing Framework
- *
- * http://docs.jquery.com/QUnit
- *
- * Copyright (c) 2011 John Resig, Jörn Zaefferer
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * or GPL (GPL-LICENSE.txt) licenses.
- * Pulled Live from Git Mon Oct 31 14:00:02 UTC 2011
- * Last Commit: ee156923cdb01820e35e6bb579d5cf6bf55736d4
- */
-
-/** Font Family and Sizes */
-
-#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
- font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
-}
-
-#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
-#qunit-tests { font-size: smaller; }
-
-
-/** Resets */
-
-#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
- margin: 0;
- padding: 0;
-}
-
-
-/** Header */
-
-#qunit-header {
- padding: 0.5em 0 0.5em 1em;
-
- color: #8699a4;
- background-color: #0d3349;
-
- font-size: 1.5em;
- line-height: 1em;
- font-weight: normal;
-
- border-radius: 15px 15px 0 0;
- -moz-border-radius: 15px 15px 0 0;
- -webkit-border-top-right-radius: 15px;
- -webkit-border-top-left-radius: 15px;
-}
-
-#qunit-header a {
- text-decoration: none;
- color: #c2ccd1;
-}
-
-#qunit-header a:hover,
-#qunit-header a:focus {
- color: #fff;
-}
-
-#qunit-banner {
- height: 5px;
-}
-
-#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
- color: #5E740B;
- background-color: #eee;
-}
-
-#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
- text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
-}
-
-
-/** Tests: Pass/Fail */
-
-#qunit-tests {
- list-style-position: inside;
-}
-
-#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
- list-style-position: inside;
-}
-
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
- display: none;
-}
-
-#qunit-tests li strong {
- cursor: pointer;
-}
-
-#qunit-tests li a {
- padding: 0.5em;
- color: #c2ccd1;
- text-decoration: none;
-}
-#qunit-tests li a:hover,
-#qunit-tests li a:focus {
- color: #000;
-}
-
-#qunit-tests ol {
- margin-top: 0.5em;
- padding: 0.5em;
-
- background-color: #fff;
-
- border-radius: 15px;
- -moz-border-radius: 15px;
- -webkit-border-radius: 15px;
-
- box-shadow: inset 0px 2px 13px #999;
- -moz-box-shadow: inset 0px 2px 13px #999;
- -webkit-box-shadow: inset 0px 2px 13px #999;
-}
-
-#qunit-tests table {
- border-collapse: collapse;
- margin-top: .2em;
-}
-
-#qunit-tests th {
- text-align: right;
- vertical-align: top;
- padding: 0 .5em 0 0;
-}
-
-#qunit-tests td {
- vertical-align: top;
-}
-
-#qunit-tests pre {
- margin: 0;
- white-space: pre-wrap;
- word-wrap: break-word;
-}
-
-#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
- text-decoration: none;
-}
-
-#qunit-tests ins {
- background-color: #ffcaca;
- color: #500;
- text-decoration: none;
-}
-
-/*** Test Counts */
-
-#qunit-tests b.counts { color: black; }
-#qunit-tests b.passed { color: #5E740B; }
-#qunit-tests b.failed { color: #710909; }
-
-#qunit-tests li li {
- margin: 0.5em;
- padding: 0.4em 0.5em 0.4em 0.5em;
- background-color: #fff;
- border-bottom: none;
- list-style-position: inside;
-}
-
-/*** Passing Styles */
-
-#qunit-tests li li.pass {
- color: #5E740B;
- background-color: #fff;
- border-left: 26px solid #C6E746;
-}
-
-#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
-#qunit-tests .pass .test-name { color: #366097; }
-
-#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
-
-#qunit-banner.qunit-pass { background-color: #C6E746; }
-
-/*** Failing Styles */
-
-#qunit-tests li li.fail {
- color: #710909;
- background-color: #fff;
- border-left: 26px solid #EE5757;
- white-space: pre;
-}
-
-#qunit-tests > li:last-child {
- border-radius: 0 0 15px 15px;
- -moz-border-radius: 0 0 15px 15px;
- -webkit-border-bottom-right-radius: 15px;
- -webkit-border-bottom-left-radius: 15px;
-}
-
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
-#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
-
-#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
-
-#qunit-banner.qunit-fail { background-color: #EE5757; }
-
-
-/** Result */
-
-#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
-
- color: #2b81af;
- background-color: #D2E0E6;
-
- border-bottom: 1px solid white;
-}
-
-/** Fixture */
-
-#qunit-fixture {
- position: absolute;
- top: -10000px;
- left: -10000px;
-}
diff --git a/src/fauxton/test/qunit/vendor/qunit.js b/src/fauxton/test/qunit/vendor/qunit.js
deleted file mode 100644
index a6339f473..000000000
--- a/src/fauxton/test/qunit/vendor/qunit.js
+++ /dev/null
@@ -1,1589 +0,0 @@
-/**
- * QUnit 1.2.0pre - A JavaScript Unit Testing Framework
- *
- * http://docs.jquery.com/QUnit
- *
- * Copyright (c) 2011 John Resig, Jörn Zaefferer
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * or GPL (GPL-LICENSE.txt) licenses.
- * Pulled Live from Git Mon Oct 31 14:00:02 UTC 2011
- * Last Commit: ee156923cdb01820e35e6bb579d5cf6bf55736d4
- */
-
-(function(window) {
-
-var defined = {
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- try {
- return !!sessionStorage.getItem;
- } catch(e) {
- return false;
- }
- })()
-};
-
-var testId = 0,
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty;
-
-var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
- this.name = name;
- this.testName = testName;
- this.expected = expected;
- this.testEnvironmentArg = testEnvironmentArg;
- this.async = async;
- this.callback = callback;
- this.assertions = [];
-};
-Test.prototype = {
- init: function() {
- var tests = id("qunit-tests");
- if (tests) {
- var b = document.createElement("strong");
- b.innerHTML = "Running " + this.name;
- var li = document.createElement("li");
- li.appendChild( b );
- li.className = "running";
- li.id = this.id = "test-output" + testId++;
- tests.appendChild( li );
- }
- },
- setup: function() {
- if (this.module != config.previousModule) {
- if ( config.previousModule ) {
- runLoggingCallbacks('moduleDone', QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- } );
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( 'moduleStart', QUnit, {
- name: this.module
- } );
- }
-
- config.current = this;
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment);
- if (this.testEnvironmentArg) {
- extend(this.testEnvironment, this.testEnvironmentArg);
- }
-
- runLoggingCallbacks( 'testStart', QUnit, {
- name: this.testName,
- module: this.module
- });
-
- // allow utility functions to access the current test environment
- // TODO why??
- QUnit.current_testEnvironment = this.testEnvironment;
-
- try {
- if ( !config.pollution ) {
- saveGlobal();
- }
-
- this.testEnvironment.setup.call(this.testEnvironment);
- } catch(e) {
- QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
- }
- },
- run: function() {
- config.current = this;
- if ( this.async ) {
- QUnit.stop();
- }
-
- if ( config.notrycatch ) {
- this.callback.call(this.testEnvironment);
- return;
- }
- try {
- this.callback.call(this.testEnvironment);
- } catch(e) {
- fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
- QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- try {
- this.testEnvironment.teardown.call(this.testEnvironment);
- checkPollution();
- } catch(e) {
- QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
- }
- },
- finish: function() {
- config.current = this;
- if ( this.expected != null && this.expected != this.assertions.length ) {
- QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
- }
-
- var good = 0, bad = 0,
- tests = id("qunit-tests");
-
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- var ol = document.createElement("ol");
-
- for ( var i = 0; i < this.assertions.length; i++ ) {
- var assertion = this.assertions[i];
-
- var li = document.createElement("li");
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if (bad) {
- sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
- } else {
- sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
- }
- }
-
- if (bad == 0) {
- ol.style.display = "none";
- }
-
- var b = document.createElement("strong");
- b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
-
- var a = document.createElement("a");
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
-
- addEvent(b, "click", function() {
- var next = b.nextSibling.nextSibling,
- display = next.style.display;
- next.style.display = display === "none" ? "block" : "none";
- });
-
- addEvent(b, "dblclick", function(e) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
- }
- });
-
- var li = id(this.id);
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( ol );
-
- } else {
- for ( var i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- try {
- QUnit.reset();
- } catch(e) {
- fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
- }
-
- runLoggingCallbacks( 'testDone', QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length
- } );
- },
-
- queue: function() {
- var test = this;
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
- // defer when previous test run passed, if storage is available
- var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
- if (bad) {
- run();
- } else {
- synchronize(run, true);
- };
- }
-
-};
-
-var QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function(name, testEnvironment) {
- config.currentModule = name;
- config.currentModuleTestEnviroment = testEnvironment;
- },
-
- asyncTest: function(testName, expected, callback) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test(testName, expected, callback, true);
- },
-
- test: function(testName, expected, callback, async) {
- var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
- // is 2nd argument a testEnvironment?
- if ( expected && typeof expected === 'object') {
- testEnvironmentArg = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
- }
-
- if ( !validTest(config.currentModule + ": " + testName) ) {
- return;
- }
-
- var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
- test.module = config.currentModule;
- test.moduleTestEnvironment = config.currentModuleTestEnviroment;
- test.queue();
- },
-
- /**
- * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
- */
- expect: function(asserts) {
- config.current.expected = asserts;
- },
-
- /**
- * Asserts true.
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function(a, msg) {
- a = !!a;
- var details = {
- result: a,
- message: msg
- };
- msg = escapeInnerText(msg);
- runLoggingCallbacks( 'log', QUnit, details );
- config.current.assertions.push({
- result: a,
- message: msg
- });
- },
-
- /**
- * Checks that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- *
- * Prefered to ok( actual == expected, message )
- *
- * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
- *
- * @param Object actual
- * @param Object expected
- * @param String message (optional)
- */
- equal: function(actual, expected, message) {
- QUnit.push(expected == actual, actual, expected, message);
- },
-
- notEqual: function(actual, expected, message) {
- QUnit.push(expected != actual, actual, expected, message);
- },
-
- deepEqual: function(actual, expected, message) {
- QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
- },
-
- notDeepEqual: function(actual, expected, message) {
- QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
- },
-
- strictEqual: function(actual, expected, message) {
- QUnit.push(expected === actual, actual, expected, message);
- },
-
- notStrictEqual: function(actual, expected, message) {
- QUnit.push(expected !== actual, actual, expected, message);
- },
-
- raises: function(block, expected, message) {
- var actual, ok = false;
-
- if (typeof expected === 'string') {
- message = expected;
- expected = null;
- }
-
- try {
- block();
- } catch (e) {
- actual = e;
- }
-
- if (actual) {
- // we don't want to validate thrown error
- if (!expected) {
- ok = true;
- // expected is a regexp
- } else if (QUnit.objectType(expected) === "regexp") {
- ok = expected.test(actual);
- // expected is a constructor
- } else if (actual instanceof expected) {
- ok = true;
- // expected is a validation function which returns true is validation passed
- } else if (expected.call({}, actual) === true) {
- ok = true;
- }
- }
-
- QUnit.ok(ok, message);
- },
-
- start: function(count) {
- config.semaphore -= count || 1;
- if (config.semaphore > 0) {
- // don't start until equal number of stop-calls
- return;
- }
- if (config.semaphore < 0) {
- // ignore if start is called more often then stop
- config.semaphore = 0;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- window.setTimeout(function() {
- if (config.semaphore > 0) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout(config.timeout);
- }
-
- config.blocking = false;
- process(true);
- }, 13);
- } else {
- config.blocking = false;
- process(true);
- }
- },
-
- stop: function(count) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout(config.timeout);
- config.timeout = window.setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout);
- }
- }
-};
-
-//We want access to the constructor's prototype
-(function() {
- function F(){};
- F.prototype = QUnit;
- QUnit = new F();
- //Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-})();
-
-// Backwards compatibility, deprecated
-QUnit.equals = QUnit.equal;
-QUnit.same = QUnit.deepEqual;
-
-// Maintain internal state
-var config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- urlConfig: ['noglobals', 'notrycatch'],
-
- //logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Load paramaters
-(function() {
- var location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {},
- current;
-
- if ( params[ 0 ] ) {
- for ( var i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
-
- QUnit.urlParams = urlParams;
- config.filter = urlParams.filter;
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = !!(location.protocol === 'file:');
-})();
-
-// Expose the API as global variables, unless an 'exports'
-// object exists, in that case we assume we're in CommonJS
-if ( typeof exports === "undefined" || typeof require === "undefined" ) {
- extend(window, QUnit);
- window.QUnit = QUnit;
-} else {
- extend(exports, QUnit);
- exports.QUnit = QUnit;
-}
-
-// define these after exposing globals to keep them in these QUnit namespace only
-extend(QUnit, {
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend(config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date,
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 0
- });
-
- var tests = id( "qunit-tests" ),
- banner = id( "qunit-banner" ),
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = 'Running...<br/>&nbsp;';
- }
- },
-
- /**
- * Resets the test setup. Useful for tests that modify the DOM.
- *
- * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
- */
- reset: function() {
- if ( window.jQuery ) {
- jQuery( "#qunit-fixture" ).html( config.fixture );
- } else {
- var main = id( 'qunit-fixture' );
- if ( main ) {
- main.innerHTML = config.fixture;
- }
- }
- },
-
- /**
- * Trigger an event on an element.
- *
- * @example triggerEvent( document.body, "click" );
- *
- * @param DOMElement elem
- * @param String type
- */
- triggerEvent: function( elem, type, event ) {
- if ( document.createEvent ) {
- event = document.createEvent("MouseEvents");
- event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
- 0, 0, 0, 0, 0, false, false, false, false, 0, null);
- elem.dispatchEvent( event );
-
- } else if ( elem.fireEvent ) {
- elem.fireEvent("on"+type);
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) == type;
- },
-
- objectType: function( obj ) {
- if (typeof obj === "undefined") {
- return "undefined";
-
- // consider: typeof null === object
- }
- if (obj === null) {
- return "null";
- }
-
- var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || '';
-
- switch (type) {
- case 'Number':
- if (isNaN(obj)) {
- return "nan";
- } else {
- return "number";
- }
- case 'String':
- case 'Boolean':
- case 'Array':
- case 'Date':
- case 'RegExp':
- case 'Function':
- return type.toLowerCase();
- }
- if (typeof obj === "object") {
- return "object";
- }
- return undefined;
- },
-
- push: function(result, actual, expected, message) {
- var details = {
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeInnerText(message) || (result ? "okay" : "failed");
- message = '<span class="test-message">' + message + "</span>";
- expected = escapeInnerText(QUnit.jsDump.parse(expected));
- actual = escapeInnerText(QUnit.jsDump.parse(actual));
- var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
- if (actual != expected) {
- output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
- output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
- }
- if (!result) {
- var source = sourceFromStacktrace();
- if (source) {
- details.source = source;
- output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>';
- }
- }
- output += "</table>";
-
- runLoggingCallbacks( 'log', QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var querystring = "?",
- key;
- for ( key in params ) {
- if ( !hasOwn.call( params, key ) ) {
- continue;
- }
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- return window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent
-});
-
-//QUnit.constructor is set to the empty F() above so that we can add to it's prototype later
-//Doing this allows us to tell if the following methods have been overwritten on the actual
-//QUnit object, which is a deprecated way of using the callbacks.
-extend(QUnit.constructor.prototype, {
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback('begin'),
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback('done'),
- // log: { result, actual, expected, message }
- log: registerLoggingCallback('log'),
- // testStart: { name }
- testStart: registerLoggingCallback('testStart'),
- // testDone: { name, failed, passed, total }
- testDone: registerLoggingCallback('testDone'),
- // moduleStart: { name }
- moduleStart: registerLoggingCallback('moduleStart'),
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback('moduleDone')
-});
-
-if ( typeof document === "undefined" || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( 'begin', QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var oldconfig = extend({}, config);
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- var urlConfigHtml = '', len = config.urlConfig.length;
- for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
- config[val] = QUnit.urlParams[val];
- urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
- }
-
- var userAgent = id("qunit-userAgent");
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
- var banner = id("qunit-header");
- if ( banner ) {
- banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' + urlConfigHtml;
- addEvent( banner, "change", function( event ) {
- var params = {};
- params[ event.target.name ] = event.target.checked ? true : undefined;
- window.location = QUnit.url( params );
- });
- }
-
- var toolbar = id("qunit-testrunner-toolbar");
- if ( toolbar ) {
- var filter = document.createElement("input");
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
- addEvent( filter, "click", function() {
- var ol = document.getElementById("qunit-tests");
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace(/ hidepass /, " ");
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem("qunit-filter-passed-tests", "true");
- } else {
- sessionStorage.removeItem("qunit-filter-passed-tests");
- }
- }
- });
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
- filter.checked = true;
- var ol = document.getElementById("qunit-tests");
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- var label = document.createElement("label");
- label.setAttribute("for", "qunit-filter-pass");
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
- }
-
- var main = id('qunit-fixture');
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if (config.autostart) {
- QUnit.start();
- }
-};
-
-addEvent(window, "load", QUnit.load);
-
-// addEvent(window, "error") gives us a useless event object
-window.onerror = function( message, file, line ) {
- if ( QUnit.config.current ) {
- ok( false, message + ", " + file + ":" + line );
- } else {
- test( "global failure", function() {
- ok( false, message + ", " + file + ":" + line );
- });
- }
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.currentModule ) {
- runLoggingCallbacks( 'moduleDone', QUnit, {
- name: config.currentModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- } );
- }
-
- var banner = id("qunit-banner"),
- tests = id("qunit-tests"),
- runtime = +new Date - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- 'Tests completed in ',
- runtime,
- ' milliseconds.<br/>',
- '<span class="passed">',
- passed,
- '</span> tests of <span class="total">',
- config.stats.all,
- '</span> passed, <span class="failed">',
- config.stats.bad,
- '</span> failed.'
- ].join('');
-
- if ( banner ) {
- banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && typeof document !== "undefined" && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- (config.stats.bad ? "\u2716" : "\u2714"),
- document.title.replace(/^[\u2714\u2716] /i, "")
- ].join(" ");
- }
-
- runLoggingCallbacks( 'done', QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- } );
-}
-
-function validTest( name ) {
- var filter = config.filter,
- run = false;
-
- if ( !filter ) {
- return true;
- }
-
- var not = filter.charAt( 0 ) === "!";
- if ( not ) {
- filter = filter.slice( 1 );
- }
-
- if ( name.indexOf( filter ) !== -1 ) {
- return !not;
- }
-
- if ( not ) {
- run = true;
- }
-
- return run;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy)
-// could be extended in the future to use something like https://github.com/csnover/TraceKit
-function sourceFromStacktrace() {
- try {
- throw new Error();
- } catch ( e ) {
- if (e.stacktrace) {
- // Opera
- return e.stacktrace.split("\n")[6];
- } else if (e.stack) {
- // Firefox, Chrome
- return e.stack.split("\n")[4];
- } else if (e.sourceURL) {
- // Safari, PhantomJS
- // TODO sourceURL points at the 'throw new Error' line above, useless
- //return e.sourceURL + ":" + e.line;
- }
- }
-}
-
-function escapeInnerText(s) {
- if (!s) {
- return "";
- }
- s = s + "";
- return s.replace(/[\&<>]/g, function(s) {
- switch(s) {
- case "&": return "&amp;";
- case "<": return "&lt;";
- case ">": return "&gt;";
- default: return s;
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process(last);
- }
-}
-
-function process( last ) {
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- window.setTimeout( function(){
- process( last );
- }, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- if ( !hasOwn.call( window, key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
-}
-
-function checkPollution( name ) {
- var old = config.pollution;
- saveGlobal();
-
- var newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- var deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var result = a.slice();
- for ( var i = 0; i < result.length; i++ ) {
- for ( var j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice(i, 1);
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function fail(message, exception, callback) {
- if ( typeof console !== "undefined" && console.error && console.warn ) {
- console.error(message);
- console.error(exception);
- console.warn(callback.toString());
-
- } else if ( window.opera && opera.postError ) {
- opera.postError(message, exception, callback.toString);
- }
-}
-
-function extend(a, b) {
- for ( var prop in b ) {
- if ( b[prop] === undefined ) {
- delete a[prop];
-
- // Avoid "Member not found" error in IE8 caused by setting window.constructor
- } else if ( prop !== "constructor" || a !== window ) {
- a[prop] = b[prop];
- }
- }
-
- return a;
-}
-
-function addEvent(elem, type, fn) {
- if ( elem.addEventListener ) {
- elem.addEventListener( type, fn, false );
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, fn );
- } else {
- fn();
- }
-}
-
-function id(name) {
- return !!(typeof document !== "undefined" && document && document.getElementById) &&
- document.getElementById( name );
-}
-
-function registerLoggingCallback(key){
- return function(callback){
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks(key, scope, args) {
- //debugger;
- var callbacks;
- if ( QUnit.hasOwnProperty(key) ) {
- QUnit[key].call(scope, args);
- } else {
- callbacks = config[key];
- for( var i = 0; i < callbacks.length; i++ ) {
- callbacks[i].call( scope, args );
- }
- }
-}
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé <prathe@gmail.com>
-QUnit.equiv = function () {
-
- var innerEquiv; // the real equiv function
- var callers = []; // stack to decide between skip/abort functions
- var parents = []; // stack to avoiding loops from circular referencing
-
- // Call the o related callback with the given arguments.
- function bindCallbacks(o, callbacks, args) {
- var prop = QUnit.objectType(o);
- if (prop) {
- if (QUnit.objectType(callbacks[prop]) === "function") {
- return callbacks[prop].apply(callbacks, args);
- } else {
- return callbacks[prop]; // or undefined
- }
- }
- }
-
- var callbacks = function () {
-
- // for string, boolean, number and null
- function useStrictEquality(b, a) {
- if (b instanceof a.constructor || a instanceof b.constructor) {
- // to catch short annotaion VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string" : useStrictEquality,
- "boolean" : useStrictEquality,
- "number" : useStrictEquality,
- "null" : useStrictEquality,
- "undefined" : useStrictEquality,
-
- "nan" : function(b) {
- return isNaN(b);
- },
-
- "date" : function(b, a) {
- return QUnit.objectType(b) === "date"
- && a.valueOf() === b.valueOf();
- },
-
- "regexp" : function(b, a) {
- return QUnit.objectType(b) === "regexp"
- && a.source === b.source && // the regex itself
- a.global === b.global && // and its modifers
- // (gmi) ...
- a.ignoreCase === b.ignoreCase
- && a.multiline === b.multiline;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function" : function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array" : function(b, a) {
- var i, j, loop;
- var len;
-
- // b could be an object literal here
- if (!(QUnit.objectType(b) === "array")) {
- return false;
- }
-
- len = a.length;
- if (len !== b.length) { // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push(a);
- for (i = 0; i < len; i++) {
- loop = false;
- for (j = 0; j < parents.length; j++) {
- if (parents[j] === a[i]) {
- loop = true;// dont rewalk array
- }
- }
- if (!loop && !innerEquiv(a[i], b[i])) {
- parents.pop();
- return false;
- }
- }
- parents.pop();
- return true;
- },
-
- "object" : function(b, a) {
- var i, j, loop;
- var eq = true; // unless we can proove it
- var aProperties = [], bProperties = []; // collection of
- // strings
-
- // comparing constructors is more strict than using
- // instanceof
- if (a.constructor !== b.constructor) {
- return false;
- }
-
- // stack constructor before traversing properties
- callers.push(a.constructor);
- // track reference to avoid circular references
- parents.push(a);
-
- for (i in a) { // be strict: don't ensures hasOwnProperty
- // and go deep
- loop = false;
- for (j = 0; j < parents.length; j++) {
- if (parents[j] === a[i])
- loop = true; // don't go down the same path
- // twice
- }
- aProperties.push(i); // collect a's properties
-
- if (!loop && !innerEquiv(a[i], b[i])) {
- eq = false;
- break;
- }
- }
-
- callers.pop(); // unstack, we are done
- parents.pop();
-
- for (i in b) {
- bProperties.push(i); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq
- && innerEquiv(aProperties.sort(), bProperties
- .sort());
- }
- };
- }();
-
- innerEquiv = function() { // can take multiple arguments
- var args = Array.prototype.slice.apply(arguments);
- if (args.length < 2) {
- return true; // end transition
- }
-
- return (function(a, b) {
- if (a === b) {
- return true; // catch the most you can
- } else if (a === null || b === null || typeof a === "undefined"
- || typeof b === "undefined"
- || QUnit.objectType(a) !== QUnit.objectType(b)) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- })(args[0], args[1])
- && arguments.callee.apply(this, args.splice(1,
- args.length - 1));
- };
-
- return innerEquiv;
-
-}();
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return '"' + str.toString().replace(/"/g, '\\"') + '"';
- };
- function literal( o ) {
- return o + '';
- };
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join )
- arr = arr.join( ',' + s + inner );
- if ( !arr )
- return pre + post;
- return [ pre, inner + arr, base + post ].join(s);
- };
- function array( arr, stack ) {
- var i = arr.length, ret = Array(i);
- this.up();
- while ( i-- )
- ret[i] = this.parse( arr[i] , undefined , stack);
- this.down();
- return join( '[', ret, ']' );
- };
-
- var reName = /^function (\w+)/;
-
- var jsDump = {
- parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
- stack = stack || [ ];
- var parser = this.parsers[ type || this.typeOf(obj) ];
- type = typeof parser;
- var inStack = inArray(obj, stack);
- if (inStack != -1) {
- return 'recursion('+(inStack - stack.length)+')';
- }
- //else
- if (type == 'function') {
- stack.push(obj);
- var res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- // else
- return (type == 'string') ? parser : this.parsers.error;
- },
- typeOf:function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if (typeof obj === "undefined") {
- type = "undefined";
- } else if (QUnit.is("RegExp", obj)) {
- type = "regexp";
- } else if (QUnit.is("Date", obj)) {
- type = "date";
- } else if (QUnit.is("Function", obj)) {
- type = "function";
- } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
- type = "window";
- } else if (obj.nodeType === 9) {
- type = "document";
- } else if (obj.nodeType) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator:function() {
- return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
- },
- indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
- if ( !this.multiline )
- return '';
- var chr = this.indentChar;
- if ( this.HTML )
- chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
- return Array( this._depth_ + (extra||0) ).join(chr);
- },
- up:function( a ) {
- this._depth_ += a || 1;
- },
- down:function( a ) {
- this._depth_ -= a || 1;
- },
- setParser:function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote:quote,
- literal:literal,
- join:join,
- //
- _depth_: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers:{
- window: '[Window]',
- document: '[Document]',
- error:'[ERROR]', //when no parser is found, shouldn't happen
- unknown: '[Unknown]',
- 'null':'null',
- 'undefined':'undefined',
- 'function':function( fn ) {
- var ret = 'function',
- name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
- if ( name )
- ret += ' ' + name;
- ret += '(';
-
- ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
- return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
- },
- array: array,
- nodelist: array,
- arguments: array,
- object:function( map, stack ) {
- var ret = [ ];
- QUnit.jsDump.up();
- for ( var key in map ) {
- var val = map[key];
- ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
- }
- QUnit.jsDump.down();
- return join( '{', ret, '}' );
- },
- node:function( node ) {
- var open = QUnit.jsDump.HTML ? '&lt;' : '<',
- close = QUnit.jsDump.HTML ? '&gt;' : '>';
-
- var tag = node.nodeName.toLowerCase(),
- ret = open + tag;
-
- for ( var a in QUnit.jsDump.DOMAttrs ) {
- var val = node[QUnit.jsDump.DOMAttrs[a]];
- if ( val )
- ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
- }
- return ret + close + open + '/' + tag + close;
- },
- functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
- var l = fn.length;
- if ( !l ) return '';
-
- var args = Array(l);
- while ( l-- )
- args[l] = String.fromCharCode(97+l);//97 is 'a'
- return ' ' + args.join(', ') + ' ';
- },
- key:quote, //object calls it internally, the key part of an item in a map
- functionCode:'[code]', //function calls it internally, it's the content of the function
- attribute:quote, //node calls it internally, it's an html attribute value
- string:quote,
- date:quote,
- regexp:literal, //regex
- number:literal,
- 'boolean':literal
- },
- DOMAttrs:{//attributes to dump from nodes, name=>realName
- id:'id',
- name:'name',
- 'class':'className'
- },
- HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
- indentChar:' ',//indentation unit
- multiline:true //if true, items in a collection, are separated by a \n, else just a space.
- };
-
- return jsDump;
-})();
-
-// from Sizzle.js
-function getText( elems ) {
- var ret = "", elem;
-
- for ( var i = 0; elems[i]; i++ ) {
- elem = elems[i];
-
- // Get the text from text nodes and CDATA nodes
- if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
- ret += elem.nodeValue;
-
- // Traverse everything else, except comment nodes
- } else if ( elem.nodeType !== 8 ) {
- ret += getText( elem.childNodes );
- }
- }
-
- return ret;
-};
-
-//from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
- */
-QUnit.diff = (function() {
- function diff(o, n) {
- var ns = {};
- var os = {};
-
- for (var i = 0; i < n.length; i++) {
- if (ns[n[i]] == null)
- ns[n[i]] = {
- rows: [],
- o: null
- };
- ns[n[i]].rows.push(i);
- }
-
- for (var i = 0; i < o.length; i++) {
- if (os[o[i]] == null)
- os[o[i]] = {
- rows: [],
- n: null
- };
- os[o[i]].rows.push(i);
- }
-
- for (var i in ns) {
- if ( !hasOwn.call( ns, i ) ) {
- continue;
- }
- if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
- n[ns[i].rows[0]] = {
- text: n[ns[i].rows[0]],
- row: os[i].rows[0]
- };
- o[os[i].rows[0]] = {
- text: o[os[i].rows[0]],
- row: ns[i].rows[0]
- };
- }
- }
-
- for (var i = 0; i < n.length - 1; i++) {
- if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
- n[i + 1] == o[n[i].row + 1]) {
- n[i + 1] = {
- text: n[i + 1],
- row: n[i].row + 1
- };
- o[n[i].row + 1] = {
- text: o[n[i].row + 1],
- row: i + 1
- };
- }
- }
-
- for (var i = n.length - 1; i > 0; i--) {
- if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
- n[i - 1] == o[n[i].row - 1]) {
- n[i - 1] = {
- text: n[i - 1],
- row: n[i].row - 1
- };
- o[n[i].row - 1] = {
- text: o[n[i].row - 1],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function(o, n) {
- o = o.replace(/\s+$/, '');
- n = n.replace(/\s+$/, '');
- var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
-
- var str = "";
-
- var oSpace = o.match(/\s+/g);
- if (oSpace == null) {
- oSpace = [" "];
- }
- else {
- oSpace.push(" ");
- }
- var nSpace = n.match(/\s+/g);
- if (nSpace == null) {
- nSpace = [" "];
- }
- else {
- nSpace.push(" ");
- }
-
- if (out.n.length == 0) {
- for (var i = 0; i < out.o.length; i++) {
- str += '<del>' + out.o[i] + oSpace[i] + "</del>";
- }
- }
- else {
- if (out.n[0].text == null) {
- for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
- str += '<del>' + out.o[n] + oSpace[n] + "</del>";
- }
- }
-
- for (var i = 0; i < out.n.length; i++) {
- if (out.n[i].text == null) {
- str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
- }
- else {
- var pre = "";
-
- for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
- pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-})();
-
-})(this);
diff --git a/src/fauxton/test/runner.html b/src/fauxton/test/runner.html
new file mode 100644
index 000000000..5a29ef166
--- /dev/null
+++ b/src/fauxton/test/runner.html
@@ -0,0 +1,16 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>testrunnner Fauxton</title>
+ <link rel="stylesheet" href="mocha/mocha.css" />
+ </head>
+ <body>
+ <div id="mocha"></div>
+ <script type="text/javascript" src="mocha/mocha.js"></script>
+ <script type="text/javascript">
+ // MOCHA SETUP
+ mocha.setup('bdd');
+ </script>
+ <script data-main="./test.config.js" src="../assets/js/libs/require.js"></script>
+ </body>
+</html>
diff --git a/src/fauxton/test/test.config.js b/src/fauxton/test/test.config.js
new file mode 100644
index 000000000..7e6e4874c
--- /dev/null
+++ b/src/fauxton/test/test.config.js
@@ -0,0 +1,67 @@
+// vim: set ft=javascript:
+// Set the require.js configuration for your test setup.
+require.config(
+{
+ "paths": {
+ "libs": "../assets/js/libs",
+ "plugins": "../assets/js/plugins",
+ "jquery": "../assets/js/libs/jquery",
+ "lodash": "../assets/js/libs/lodash",
+ "backbone": "../assets/js/libs/backbone",
+ "bootstrap": "../assets/js/libs/bootstrap",
+ "codemirror": "../assets/js/libs/codemirror",
+ "jshint": "../assets/js/libs/jshint",
+ "d3": "../assets/js/libs/d3",
+ "nv.d3": "../assets/js/libs/nv.d3",
+ "chai": "../test/mocha/chai"
+ },
+ "baseUrl": "../app",
+ "shim": {
+ "backbone": {
+ "deps": [
+ "lodash",
+ "jquery"
+ ],
+ "exports": "Backbone"
+ },
+ "bootstrap": {
+ "deps": [
+ "jquery"
+ ],
+ "exports": "Bootstrap"
+ },
+ "codemirror": {
+ "deps": [
+ "jquery"
+ ],
+ "exports": "CodeMirror"
+ },
+ "jshint": {
+ "deps": [
+ "jquery"
+ ],
+ "exports": "JSHINT"
+ },
+ "plugins/backbone.layoutmanager": [
+ "backbone"
+ ],
+ "plugins/codemirror-javascript": [
+ "codemirror"
+ ],
+ "plugins/prettify": [],
+ "plugins/jquery.form": [
+ "jquery"
+ ]
+ }
+}
+);
+
+require([
+
+ '.././app/addons/logs/tests/logSpec.js',
+
+], function() {
+ if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
+ else { mocha.run(); }
+});
+
diff --git a/src/fauxton/test/test.config.underscore b/src/fauxton/test/test.config.underscore
new file mode 100644
index 000000000..dda16f275
--- /dev/null
+++ b/src/fauxton/test/test.config.underscore
@@ -0,0 +1,15 @@
+// vim: set ft=javascript:
+// Set the require.js configuration for your test setup.
+require.config(
+<%= JSON.stringify(configInfo, null, '\t') %>
+);
+
+require([
+ <% _.each(testFiles, function (test) {%>
+ '../<%= test %>',
+ <% }) %>
+], function() {
+ if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
+ else { mocha.run(); }
+});
+