Nettoyage exemple tests-unitaires

This commit is contained in:
wpetit 2015-04-03 10:34:09 +02:00
parent f4e96ea040
commit bbcccf4586
538 changed files with 21 additions and 46985 deletions

View File

@ -0,0 +1,6 @@
# Tests unitiaires, exemple NodeUnit
```
npm install
./node_modules/.bin/nodeunit math-suite.js
```

View File

@ -1 +0,0 @@
../nodeunit/bin/nodeunit

View File

@ -1,3 +0,0 @@
dist
stamp-build
test/fixtures/dir2

View File

@ -1,68 +0,0 @@
Nodeunit contributors (sorted alphabeticaly)
============================================
* **[Alex Gorbatchev](https://github.com/alexgorbatchev)**
* Deeper default object inspection
* Timeout to ensure flushing of console output (default reporter)
* **[Alex Wolfe](https://github.com/alexkwolfe)**
* HTML test reporter
* **[Caolan McMahon](https://github.com/caolan)**
* Author and maintainer
* Most features develpopment
* **[Carl Fürstenberg](https://github.com/azatoth)**
* Debian-friendly Makefile, supports both 'node' and 'nodejs' executables
* Sandbox utility
* Minimal test reporter
* **[Gerad Suyderhoud](https://github.com/gerad)**
* First comand-line tool
* **[Kadir Pekel](https://github.com/kadirpekel)**
* Improvements to default test reporter
* HTTP test utility
* **[Λlisue](https://github.com/lambdalisue)**
* Add machineout reporter
* **[Matthias Lübken](https://github.com/luebken)**
* Utility functions for tracking incomplete tests on exit
* **[Oleg Efimov](https://github.com/Sannis)**
* Adding 'make lint' and fixing nodelint errors
* Option parsing, --help text and config file support
* Reporters option for command-line tool
* **[Orlando Vazquez](https://github.com/orlandov)**
* Added jUnit XML reporter
* **[Ryan Dahl](https://github.com/ry)**
* Add package.json
* **[Sam Stephenson](https://github.com/sstephenson)**
* Coffee-script support
* **[Thomas Mayfield](https://github.com/thegreatape)**
* Async setUp and tearDown support for testCase
* **[Maciej Małecki](https://github.com/mmalecki)**
* Removal of `testCase`
**[Full contributors list](https://github.com/caolan/nodeunit/contributors).**

View File

@ -1,19 +0,0 @@
Copyright (c) 2010 Caolan McMahon
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.

View File

@ -1,177 +0,0 @@
PACKAGE = nodeunit
NODEJS = $(if $(shell test -f /usr/bin/nodejs && echo "true"),nodejs,node)
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
DATADIR ?= $(PREFIX)/share
MANDIR ?= $(PREFIX)/share/man
LIBDIR ?= $(PREFIX)/lib
NODEJSLIBDIR ?= $(LIBDIR)/$(NODEJS)
BUILDDIR = dist
DOCS = $(shell find doc -name '*.md' \
|sed 's|.md|.1|g' \
|sed 's|doc/|man1/|g' \
)
$(shell if [ ! -d $(BUILDDIR) ]; then mkdir $(BUILDDIR); fi)
all: build doc
browser:
# super hacky build script for browser version!
mkdir -p $(BUILDDIR)/browser
rm -rf $(BUILDDIR)/browser/*
# build browser version of nodeunit.js
cat share/license.js >> $(BUILDDIR)/browser/nodeunit.js
echo "nodeunit = (function(){" >> $(BUILDDIR)/browser/nodeunit.js
cat deps/json2.js >> $(BUILDDIR)/browser/nodeunit.js
# make assert global
echo "var assert = this.assert = {};" >> $(BUILDDIR)/browser/nodeunit.js
echo "var types = {};" >> $(BUILDDIR)/browser/nodeunit.js
echo "var core = {};" >> $(BUILDDIR)/browser/nodeunit.js
echo "var nodeunit = {};" >> $(BUILDDIR)/browser/nodeunit.js
echo "var reporter = {};" >> $(BUILDDIR)/browser/nodeunit.js
cat deps/async.js >> $(BUILDDIR)/browser/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js
cat lib/assert.js >> $(BUILDDIR)/browser/nodeunit.js
echo "})(assert);" >> $(BUILDDIR)/browser/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js
cat lib/types.js >> $(BUILDDIR)/browser/nodeunit.js
echo "})(types);" >> $(BUILDDIR)/browser/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js
cat lib/core.js >> $(BUILDDIR)/browser/nodeunit.js
echo "})(core);" >> $(BUILDDIR)/browser/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/browser/nodeunit.js
cat lib/reporters/browser.js >> $(BUILDDIR)/browser/nodeunit.js
echo "})(reporter);" >> $(BUILDDIR)/browser/nodeunit.js
echo "nodeunit = core;" >> $(BUILDDIR)/browser/nodeunit.js
echo "nodeunit.assert = assert;" >> $(BUILDDIR)/browser/nodeunit.js
echo "nodeunit.reporter = reporter;" >> $(BUILDDIR)/browser/nodeunit.js
echo "nodeunit.run = reporter.run;" >> $(BUILDDIR)/browser/nodeunit.js
echo "return nodeunit; })();" >> $(BUILDDIR)/browser/nodeunit.js
cp $(BUILDDIR)/browser/nodeunit.js $(BUILDDIR)/browser/.nodeunit.js
sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.nodeunit.js > $(BUILDDIR)/browser/nodeunit.js
rm $(BUILDDIR)/browser/.nodeunit.js
# copy nodeunit.css
cp share/nodeunit.css $(BUILDDIR)/browser/nodeunit.css
# create nodeunit.min.js
node_modules/uglify-js/bin/uglifyjs $(BUILDDIR)/browser/nodeunit.js > $(BUILDDIR)/browser/nodeunit.min.js
# create test scripts
mkdir -p $(BUILDDIR)/browser/test
cp test/test.html $(BUILDDIR)/browser/test/test.html
# test-base.js
echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-base.js
cat test/test-base.js >> $(BUILDDIR)/browser/test/test-base.js
echo "})(this.test_base = {});" >> $(BUILDDIR)/browser/test/test-base.js
cp $(BUILDDIR)/browser/test/test-base.js $(BUILDDIR)/browser/.test-base.js
sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-base.js > $(BUILDDIR)/browser/test/test-base.js
rm $(BUILDDIR)/browser/.test-base.js
# test-runmodule.js
echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-runmodule.js
cat test/test-runmodule.js >> $(BUILDDIR)/browser/test/test-runmodule.js
echo "})(this.test_runmodule = {});" >> $(BUILDDIR)/browser/test/test-runmodule.js
cp $(BUILDDIR)/browser/test/test-runmodule.js $(BUILDDIR)/browser/.test-runmodule.js
sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-runmodule.js > $(BUILDDIR)/browser/test/test-runmodule.js
rm $(BUILDDIR)/browser/.test-runmodule.js
# test-runtest.js
echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-runtest.js
cat test/test-runtest.js >> $(BUILDDIR)/browser/test/test-runtest.js
echo "})(this.test_runtest = {});" >> $(BUILDDIR)/browser/test/test-runtest.js
cp $(BUILDDIR)/browser/test/test-runtest.js $(BUILDDIR)/browser/.test-runtest.js
sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-runtest.js > $(BUILDDIR)/browser/test/test-runtest.js
rm $(BUILDDIR)/browser/.test-runtest.js
# test-testcase.js
echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-testcase.js
cat test/test-testcase.js >> $(BUILDDIR)/browser/test/test-testcase.js
echo "})(this.test_testcase = {});" >> $(BUILDDIR)/browser/test/test-testcase.js
cp $(BUILDDIR)/browser/test/test-testcase.js $(BUILDDIR)/browser/.test-testcase.js
sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-testcase.js > $(BUILDDIR)/browser/test/test-testcase.js
rm $(BUILDDIR)/browser/.test-testcase.js
# test-testcase-legacy.js
echo "(function (exports) {" > $(BUILDDIR)/browser/test/test-testcase-legacy.js
cat test/test-testcase-legacy.js >> $(BUILDDIR)/browser/test/test-testcase-legacy.js
echo "})(this.test_testcase_legacy = {});" >> $(BUILDDIR)/browser/test/test-testcase-legacy.js
cp $(BUILDDIR)/browser/test/test-testcase-legacy.js $(BUILDDIR)/browser/.test-testcase-legacy.js
sed "/\@REMOVE_LINE_FOR_BROWSER/d" <$(BUILDDIR)/browser/.test-testcase-legacy.js > $(BUILDDIR)/browser/test/test-testcase-legacy.js
rm $(BUILDDIR)/browser/.test-testcase-legacy.js
# copy nodeunit.js to dist/browser/test to make it easier for me to host and
# run on windows VMs with IE
cp $(BUILDDIR)/browser/nodeunit.js $(BUILDDIR)/browser/test/nodeunit.js
cp $(BUILDDIR)/browser/nodeunit.css $(BUILDDIR)/browser/test/nodeunit.css
commonjs:
# super hacky build script for browser commonjs version!
##### make commonjs browser module ######
mkdir -p $(BUILDDIR)/commonjs
rm -rf $(BUILDDIR)/commonjs/*
mkdir -p $(BUILDDIR)/commonjs/deps
cp deps/json2.js $(BUILDDIR)/commonjs/deps
cp deps/async.js $(BUILDDIR)/commonjs/deps
echo "var async = require('async');" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "var assert = {};" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "var types = {};" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "var core = {};" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "var nodeunit = {};" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "var reporter = {};" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/commonjs/nodeunit.js
cat lib/assert.js >> $(BUILDDIR)/commonjs/nodeunit.js
echo "})(assert);" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/commonjs/nodeunit.js
cat lib/types.js >> $(BUILDDIR)/commonjs/nodeunit.js
echo "})(types);" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "(function(exports){" >> $(BUILDDIR)/commonjs/nodeunit.js
cat lib/core.js >> $(BUILDDIR)/commonjs/nodeunit.js
echo "})(core);" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "module.exports = core;" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "(function(exports, nodeunit){" >> $(BUILDDIR)/commonjs/nodeunit.js
cat lib/reporters/browser.js >> $(BUILDDIR)/commonjs/nodeunit.js
echo "})(reporter, module.exports);" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "module.exports.assert = assert;" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "module.exports.reporter = reporter;" >> $(BUILDDIR)/commonjs/nodeunit.js
echo "module.exports.run = reporter.run;" >> $(BUILDDIR)/commonjs/nodeunit.js
sed -i "/\@REMOVE_LINE_FOR_BROWSER/d" $(BUILDDIR)/commonjs/nodeunit.js
sed -i "/\@REMOVE_LINE_FOR_COMMONJS/d" $(BUILDDIR)/commonjs/nodeunit.js
##### end of commonjs browser module #####
build: stamp-build
stamp-build: $(wildcard deps/* lib/*.js)
touch $@;
mkdir -p $(BUILDDIR)/nodeunit
cp -R bin node_modules deps index.js lib package.json share $(BUILDDIR)/nodeunit
printf '#!/bin/sh\n$(NODEJS) $(NODEJSLIBDIR)/$(PACKAGE)/bin/nodeunit $$@' > $(BUILDDIR)/nodeunit.sh
test:
$(NODEJS) ./bin/nodeunit test
install: build
install -d $(NODEJSLIBDIR)
cp -a $(BUILDDIR)/nodeunit $(NODEJSLIBDIR)
install -m 0755 $(BUILDDIR)/nodeunit.sh $(BINDIR)/nodeunit
install -d $(MANDIR)/man1/
cp -a man1/nodeunit.1 $(MANDIR)/man1/
uninstall:
rm -rf $(NODEJSLIBDIR)/nodeunit $(NODEJSLIBDIR)/nodeunit.js $(BINDIR)/nodeunit
rm -rf $(MANDIR)/man1/nodeunit.1
clean:
rm -rf $(BUILDDIR) stamp-build
lint:
nodelint --config nodelint.cfg ./index.js ./bin/nodeunit ./bin/nodeunit.json ./lib/*.js ./lib/reporters/*.js ./test/*.js
doc: man1 $(DOCS)
@true
man1:
@if ! test -d man1 ; then mkdir -p man1 ; fi
# use `npm install ronn` for this to work.
man1/%.1: doc/%.md
ronn --roff $< > $@
.PHONY: browser test install uninstall build all

View File

@ -1,468 +0,0 @@
Nodeunit
========
Simple syntax, powerful tools. Nodeunit provides easy async unit testing for
node.js and the browser.
* Simple to use
* Just export the tests from a module
* Works with node.js and in the browser
* Helps you avoid common pitfalls when testing asynchronous code
* Easy to add test cases with setUp and tearDown functions if you wish
* Flexible reporters for custom output, built-in support for HTML and jUnit XML
* Allows the use of mocks and stubs
__Contributors__
* [alexgorbatchev](https://github.com/alexgorbatchev)
* [alexkwolfe](https://github.com/alexkwolfe)
* [azatoth](https://github.com/azatoth)
* [kadirpekel](https://github.com/kadirpekel)
* [lambdalisue](https://github.com/lambdalisue)
* [luebken](https://github.com/luebken)
* [orlandov](https://github.com/orlandov)
* [Sannis](https://github.com/Sannis)
* [sstephenson](https://github.com/sstephenson)
* [thegreatape](https://github.com/thegreatape)
* [mmalecki](https://github.com/mmalecki)
* and thanks to [cjohansen](https://github.com/cjohansen) for input and advice
on implementing setUp and tearDown functions. See
[cjohansen's fork](https://github.com/cjohansen/nodeunit).
Also, check out gerad's [nodeunit-dsl](https://github.com/gerad/nodeunit-dsl)
project, which implements a 'pretty dsl on top of nodeunit'.
More contributor information can be found in the
[CONTRIBUTORS.md](https://github.com/caolan/nodeunit/blob/master/CONTRIBUTORS.md)
file.
Usage
-----
Here is an example unit test module:
exports.testSomething = function(test){
test.expect(1);
test.ok(true, "this assertion should pass");
test.done();
};
exports.testSomethingElse = function(test){
test.ok(false, "this assertion should fail");
test.done();
};
When run using the included test runner, this will output the following:
<img src="https://github.com/caolan/nodeunit/raw/master/img/example_fail.png" />
Installation
------------
There are two options for installing nodeunit:
1. Clone / download nodeunit from [github](https://github.com/caolan/nodeunit),
then:
make && sudo make install
2. Install via npm:
npm install nodeunit -g
API Documentation
-----------------
Nodeunit uses the functions available in the node.js
[assert module](http://nodejs.org/docs/v0.4.2/api/assert.html):
* __ok(value, [message])__ - Tests if value is a true value.
* __equal(actual, expected, [message])__ - Tests shallow, coercive equality
with the equal comparison operator ( == ).
* __notEqual(actual, expected, [message])__ - Tests shallow, coercive
non-equality with the not equal comparison operator ( != ).
* __deepEqual(actual, expected, [message])__ - Tests for deep equality.
* __notDeepEqual(actual, expected, [message])__ - Tests for any deep
inequality.
* __strictEqual(actual, expected, [message])__ - Tests strict equality, as
determined by the strict equality operator ( === )
* __notStrictEqual(actual, expected, [message])__ - Tests strict non-equality,
as determined by the strict not equal operator ( !== )
* __throws(block, [error], [message])__ - Expects block to throw an error.
* __doesNotThrow(block, [error], [message])__ - Expects block not to throw an
error.
* __ifError(value)__ - Tests if value is not a false value, throws if it is a
true value. Useful when testing the first argument, error in callbacks.
Nodeunit also provides the following functions within tests:
* __expect(amount)__ - Specify how many assertions are expected to run within a
test. Very useful for ensuring that all your callbacks and assertions are
run.
* __done()__ - Finish the current test function, and move on to the next. ALL
tests should call this!
Nodeunit aims to be simple and easy to learn. This is achieved through using
existing structures (such as node.js modules) to maximum effect, and reducing
the API where possible, to make it easier to digest.
Tests are simply exported from a module, but they are still run in the order
they are defined.
__Note:__ Users of old nodeunit versions may remember using `ok`, `equals` and
`same` in the style of qunit, instead of the assert functions above. These
functions still exist for backwards compatibility, and are simply aliases to
their assert module counterparts.
Asynchronous Testing
--------------------
When testing asynchronous code, there are a number of sharp edges to watch out
for. Thankfully, nodeunit is designed to help you avoid as many of these
pitfalls as possible. For the most part, testing asynchronous code in nodeunit
_just works_.
### Tests run in series
While running tests in parallel seems like a good idea for speeding up your
test suite, in practice I've found it means writing much more complicated
tests. Because of node's module cache, running tests in parallel means mocking
and stubbing is pretty much impossible. One of the nicest things about testing
in javascript is the ease of doing stubs:
var _readFile = fs.readFile;
fs.readFile = function(path, callback){
// it's a stub!
};
// test function that uses fs.readFile
// we're done
fs.readFile = _readFile;
You cannot do this when running tests in parallel. In order to keep testing as
simple as possible, nodeunit avoids it. Thankfully, most unit-test suites run
fast anyway.
### Explicit ending of tests
When testing async code it's important that tests end at the correct point, not
just after a given number of assertions. Otherwise your tests can run short,
ending before all assertions have completed. It's important to detect too
many assertions as well as too few. Combining explicit ending of tests with
an expected number of assertions helps to avoid false test passes, so be sure
to use the `test.expect()` method at the start of your test functions, and
`test.done()` when finished.
Groups, setUp and tearDown
--------------------------
Nodeunit allows the nesting of test functions:
exports.test1 = function (test) {
...
}
exports.group = {
test2: function (test) {
...
},
test3: function (test) {
...
}
}
This would be run as:
test1
group - test2
group - test3
Using these groups, Nodeunit allows you to define a `setUp` function, which is
run before each test, and a `tearDown` function, which is run after each test
calls `test.done()`:
module.exports = {
setUp: function (callback) {
this.foo = 'bar';
callback();
},
tearDown: function (callback) {
// clean up
callback();
},
test1: function (test) {
test.equals(this.foo, 'bar');
test.done();
}
};
In this way, it's possible to have multiple groups of tests in a module, each
group with its own setUp and tearDown functions.
Running Tests
-------------
Nodeunit comes with a basic command-line test runner, which can be installed
using `sudo make install`. Example usage:
nodeunit testmodule1.js testfolder [...]
If no entry file specified, `test` defaults.
The default test reporter uses color output, because I think that's more fun :) I
intend to add a no-color option in future. To give you a feeling of the fun you'll
be having writing tests, lets fix the example at the start of the README:
<img src="https://github.com/caolan/nodeunit/raw/master/img/example_pass.png" />
Ahhh, Doesn't that feel better?
When using the included test runner, it will exit using the failed number of
assertions as the exit code. This means it exits with 0 when all tests pass.
### Command-line Options
* __--reporter FILE__ - you can set the test reporter to a custom module or
on of the modules in nodeunit/lib/reporters, when omitted, the default test runner
is used.
* __--list-reporters__ - list available built-in reporters.
* __--config FILE__ - load config options from a JSON file, allows
the customisation of color schemes for the default test reporter etc. See
bin/nodeunit.json for current available options.
* __-t testName__ - run specifc test only.
* __-f fullTestName__ - run specific test only. fullTestName is built so: "outerGroup - .. - innerGroup - testName".
* __--version__ or __-v__ - report nodeunit version
* __--help__ - show nodeunit help
Running tests in the browser
----------------------------
Nodeunit tests can also be run inside the browser. For example usage, see
the examples/browser folder. The basic syntax is as follows:
__test.html__
<html>
<head>
<title>Example Test Suite</title>
<link rel="stylesheet" href="nodeunit.css" type="text/css" />
<script src="nodeunit.js"></script>
<script src="suite1.js"></script>
<script src="suite2.js"></script>
</head>
<body>
<h1 id="nodeunit-header">Example Test Suite</h1>
<script>
nodeunit.run({
'Suite One': suite1,
'Suite Two': suite2
});
</script>
</body>
</html>
Here, `suite1` and `suite2` are just object literals containing test functions
or groups, as would be returned if you did `require('test-suite')` in node.js:
__suite1.js__
this.suite1 = {
'example test': function (test) {
test.ok(true, 'everything is ok');
test.done();
}
};
If you wish to use a commonjs format for your test suites (using exports), it is
up to you to define the commonjs tools for the browser. There are a number of
alternatives and it's important it fits with your existing code, which is
why nodeunit does not currently provide this out of the box.
In the example above, the tests will run when the page is loaded.
The browser-version of nodeunit.js is created in dist/browser when you do, `make
browser`. You'll need [UglifyJS](https://github.com/mishoo/UglifyJS) installed in
order for it to automatically create nodeunit.min.js.
Adding nodeunit to Your Projects
--------------------------------
If you don't want people to have to install the nodeunit command-line tool,
you'll want to create a script that runs the tests for your project with the
correct require paths set up. Here's an example test script, that assumes you
have nodeunit in a suitably located node_modules directory.
#!/usr/bin/env node
var reporter = require('nodeunit').reporters.default;
reporter.run(['test']);
If you're using git, you might find it useful to include nodeunit as a
submodule. Using submodules makes it easy for developers to download nodeunit
and run your test suite, without cluttering up your repository with
the source code. To add nodeunit as a git submodule do the following:
git submodule add git://github.com/caolan/nodeunit.git node_modules/nodeunit
This will add nodeunit to the node_modules folder of your project. Now, when
cloning the repository, nodeunit can be downloaded by doing the following:
git submodule init
git submodule update
Let's update the test script above with a helpful hint on how to get nodeunit,
if it's missing:
#!/usr/bin/env node
try {
var reporter = require('nodeunit').reporters.default;
}
catch(e) {
console.log("Cannot find nodeunit module.");
console.log("You can download submodules for this project by doing:");
console.log("");
console.log(" git submodule init");
console.log(" git submodule update");
console.log("");
process.exit();
}
process.chdir(__dirname);
reporter.run(['test']);
Now if someone attempts to run your test suite without nodeunit installed they
will be prompted to download the submodules for your project.
Built-in Test Reporters
-----------------------
* __default__ - The standard reporter seen in the nodeunit screenshots
* __minimal__ - Pretty, minimal output, shows errors and progress only
* __html__ - Outputs a HTML report to stdout
* __junit__ - Creates jUnit compatible XML reports, which can be used with
continuous integration tools such as [Hudson](http://hudson-ci.org/).
* __machineout__ - Simple reporter for machine analysis. There is
[nodeunit.vim](https://github.com/lambdalisue/nodeunit.vim) which is useful for TDD on VIM.
Writing a Test Reporter
---------------------
Nodeunit exports runTest(fn, options), runModule(mod, options) and
runFiles(paths, options). You'll most likely want to run test suites from
files, which can be done using the latter function. The _options_ argument can
contain callbacks which run during testing. Nodeunit provides the following
callbacks:
* __moduleStart(name)__ - called before a module is tested
* __moduleDone(name, assertions)__ - called once all test functions within the
module have completed (see assertions object reference below)
ALL tests within the module
* __testStart(name)__ - called before a test function is run
* __testReady(test)__ - called before a test function is run with the test object that will be passed to the test function
* __testDone(name, assertions)__ - called once a test function has completed
(by calling test.done())
* __log(assertion)__ - called whenever an assertion is made (see assertion
object reference below)
* __done(assertions)__ - called after all tests/modules are complete
The __assertion__ object:
* __passed()__ - did the assertion pass?
* __failed()__ - did the assertion fail?
* __error__ - the AssertionError if the assertion failed
* __method__ - the nodeunit assertion method used (ok, same, equals...)
* __message__ - the message the assertion method was called with (optional)
The __assertionList__ object:
* An array-like object with the following new attributes:
* __failures()__ - the number of assertions which failed
* __duration__ - the time taken for the test to complete in msecs
For a reference implementation of a test reporter, see lib/reporters/default.js in
the nodeunit project directory.
Sandbox utility
---------------
This is a function which evaluates JavaScript files in a sandbox and returns the
context. The sandbox function can be used for testing client-side code or private
un-exported functions within a module.
var sandbox = require('nodeunit').utils.sandbox;
var example = sandbox('example.js');
__sandbox(files, sandbox)__ - Evaluates JavaScript files in a sandbox, returning
the context. The first argument can either be a single filename or an array of
filenames. If multiple filenames are given their contents are concatenated before
evaluation. The second argument is an optional context to use for the sandbox.
Note: When working with the sandbox if your script depends on outside sources
(i.e. using `require`) then you will want to pass that into the optional
context when setting up the sandbox.
var sandbox = require('nodeunit').utils.sandbox;
// pass in some node globals
var box_globals = {
// Passing module.exports into the sandbox will give your code access to it.
module: {exports: exports},
// Passing require into the sandbox will give your code access to use it AND
// will share the cache with modules already required from outside the sandbox.
require: require,
// Passing console into the sandbox will give your code access to it
console: console
};
var example = sandbox('example.js', box_globals);
Running the nodeunit Tests
--------------------------
The tests for nodeunit are written using nodeunit itself as the test framework.
However, the module test-base.js first does some basic tests using the assert
module to ensure that test functions are actually run, and a basic level of
nodeunit functionality is available.
To run the nodeunit tests do:
make test
__Note:__ There was a bug in node v0.2.0 causing the tests to hang, upgrading
to v0.2.1 fixes this.
__machineout__ reporter
----------------------------------------------
The default reporter is readable for human but not for machine analysis.
When you want to analyze the output of nodeunit, use __machineout__ reporter and you will get
<img src="https://github.com/caolan/nodeunit/raw/master/img/example_machineout.png" />
nodeunit with vim
----------------------------------
There is [nodeunit.vim](https://github.com/lambdalisue/nodeunit.vim) so you can use
nodeunit with VIM.
That compiler uses __machineout__ reporter and it is useful to use
with [vim-makegreen](https://github.com/reinh/vim-makegreen).
Contributing
------------
Contributions to the project are most welcome, so feel free to fork and improve.
When submitting a pull request, please run `make lint` first to ensure
we're following a consistent coding style.

View File

@ -1,132 +0,0 @@
#!/usr/bin/env node
var
fs = require('fs'),
path = require('path');
// TODO: remove this when https://github.com/joyent/node/pull/1312
// lands in core.
//
// Until then, use console.log from npm (https://gist.github.com/1077544)
require('../deps/console.log');
//require.paths.push(process.cwd());
var args = (process.ARGV || process.argv).slice(2);
var files = [];
var testrunner,
config_file,
config_param_found = false,
output_param_found = false,
reporter_file = 'default',
reporter_param_found = false,
testspec_param_found = false;
testFullSpec_param_found = false;
var usage = "Usage: nodeunit [options] testmodule1.js testfolder [...] \n" +
"Options:\n\n" +
" --config FILE the path to a JSON file with options\n" +
" --reporter FILE optional path to a reporter file to customize the output\n" +
" --list-reporters list available build-in reporters\n" +
" -t testName, specify a test to run\n" +
" -f fullTestName, specify a specific test to run. fullTestName is built so: \"outerGroup - .. - innerGroup - testName\"\n" +
" -h, --help display this help and exit\n" +
" -v, --version output version information and exit";
// load default options
var content = fs.readFileSync(__dirname + '/nodeunit.json', 'utf8');
var options = JSON.parse(content);
// a very basic pseudo --options parser
args.forEach(function (arg) {
if (arg.slice(0, 9) === "--config=") {
config_file = arg.slice(9);
} else if (arg === '--config') {
config_param_found = true;
} else if (config_param_found) {
config_file = arg;
config_param_found = false;
} else if (arg.slice(0, 9) === "--output=") {
options.output = arg.slice(9);
} else if (arg === '--output') {
output_param_found = true;
} else if (output_param_found) {
options.output = arg;
output_param_found = false;
} else if (arg.slice(0, 11) === "--reporter=") {
reporter_file = arg.slice(11);
} else if (arg === '--reporter') {
reporter_param_found = true;
} else if (reporter_param_found) {
reporter_file = arg;
reporter_param_found = false;
} else if (arg === '-t') {
testspec_param_found = true;
} else if (testspec_param_found) {
options.testspec = arg;
testspec_param_found = false;
} else if (arg === '-f') {
testFullSpec_param_found = true;
} else if (testFullSpec_param_found) {
options.testFullSpec= arg;
testFullSpec_param_found = false;
} else if (arg === '--list-reporters') {
var reporters = fs.readdirSync(__dirname + '/../lib/reporters');
reporters = reporters.filter(function (reporter_file) {
return (/\.js$/).test(reporter_file);
}).map(function (reporter_file) {
return reporter_file.replace(/\.js$/, '');
}).filter(function (reporter_file) {
return reporter_file !== 'index';
});
console.log('Build-in reporters: ');
reporters.forEach(function (reporter_file) {
var reporter = require('../lib/reporters/' + reporter_file);
console.log(' * ' + reporter_file + (reporter.info ? ': ' + reporter.info : ''));
});
process.exit(0);
} else if ((arg === '-v') || (arg === '--version')) {
var content = fs.readFileSync(__dirname + '/../package.json', 'utf8');
var pkg = JSON.parse(content);
console.log(pkg.version);
process.exit(0);
} else if ((arg === '-h') || (arg === '--help')) {
console.log(usage);
process.exit(0);
} else {
files.push(arg);
}
});
// defaults to `test`
if (files.length === 0) {
files = ['test'];
}
if (config_file) {
content = fs.readFileSync(config_file, 'utf8');
var custom_options = JSON.parse(content);
for (var option in custom_options) {
if (typeof option === 'string') {
options[option] = custom_options[option];
}
}
}
var builtin_reporters = require(__dirname + '/../lib/reporters');
if (reporter_file in builtin_reporters) {
testrunner = builtin_reporters[reporter_file];
}
else {
testrunner = require(reporter_file);
}
testrunner.run(files, options, function(err) {
if (err) {
process.exit(1);
}
});

View File

@ -1,10 +0,0 @@
{
"error_prefix": "\u001B[31m",
"error_suffix": "\u001B[39m",
"ok_prefix": "\u001B[32m",
"ok_suffix": "\u001B[39m",
"bold_prefix": "\u001B[1m",
"bold_suffix": "\u001B[22m",
"assertion_prefix": "\u001B[35m",
"assertion_suffix": "\u001B[39m"
}

View File

@ -1,628 +0,0 @@
/*global setTimeout: false, console: false */
(function () {
var async = {};
// global on the server, window in the browser
var root = this,
previous_async = root.async;
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
else {
root.async = async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
//// cross-browser compatiblity functions ////
var _forEach = function (arr, iterator) {
if (arr.forEach) {
return arr.forEach(iterator);
}
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
};
var _map = function (arr, iterator) {
if (arr.map) {
return arr.map(iterator);
}
var results = [];
_forEach(arr, function (x, i, a) {
results.push(iterator(x, i, a));
});
return results;
};
var _reduce = function (arr, iterator, memo) {
if (arr.reduce) {
return arr.reduce(iterator, memo);
}
_forEach(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
};
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
var _indexOf = function (arr, item) {
if (arr.indexOf) {
return arr.indexOf(item);
}
for (var i = 0; i < arr.length; i += 1) {
if (arr[i] === item) {
return i;
}
}
return -1;
};
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
if (typeof setImmediate === 'function') {
async.nextTick = function (fn) {
setImmediate(fn);
};
}
else if (typeof process !== 'undefined' && process.nextTick) {
async.nextTick = process.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
}
async.forEach = function (arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
_forEach(arr, function (x) {
iterator(x, function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback();
}
}
});
});
};
async.forEachSeries = function (arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback();
}
else {
iterate();
}
}
});
};
iterate();
};
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.forEach].concat(args));
};
};
var doSeries = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.forEachSeries].concat(args));
};
};
var _asyncMap = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (err, v) {
results[x.index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.reduce = function (arr, memo, iterator, callback) {
async.forEachSeries(arr, function (x, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
// inject alias
async.inject = async.reduce;
// foldl alias
async.foldl = async.reduce;
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
// foldr alias
async.foldr = async.reduceRight;
var _filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.filter = doParallel(_filter);
async.filterSeries = doSeries(_filter);
// select alias
async.select = async.filter;
async.selectSeries = async.filterSeries;
var _reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.reject = doParallel(_reject);
async.rejectSeries = doSeries(_reject);
var _detect = function (eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
}
else {
callback();
}
});
}, function (err) {
main_callback();
});
};
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.some = function (arr, iterator, main_callback) {
async.forEach(arr, function (x, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(false);
});
};
// any alias
async.any = async.some;
async.every = function (arr, iterator, main_callback) {
async.forEach(arr, function (x, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(true);
});
};
// all alias
async.all = async.every;
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
iterator(x, function (err, criteria) {
if (err) {
callback(err);
}
else {
callback(null, {value: x, criteria: criteria});
}
});
}, function (err, results) {
if (err) {
return callback(err);
}
else {
var fn = function (left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
};
callback(null, _map(results.sort(fn), function (x) {
return x.value;
}));
}
});
};
async.auto = function (tasks, callback) {
callback = callback || function () {};
var keys = _keys(tasks);
if (!keys.length) {
return callback(null);
}
var completed = [];
var listeners = [];
var addListener = function (fn) {
listeners.unshift(fn);
};
var removeListener = function (fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
};
var taskComplete = function () {
_forEach(listeners, function (fn) {
fn();
});
};
addListener(function () {
if (completed.length === keys.length) {
callback(null);
}
});
_forEach(keys, function (k) {
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
var taskCallback = function (err) {
if (err) {
callback(err);
// stop subsequent errors hitting callback multiple times
callback = function () {};
}
else {
completed.push(k);
taskComplete();
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && _indexOf(completed, x) !== -1);
}, true);
};
if (ready()) {
task[task.length - 1](taskCallback);
}
else {
var listener = function () {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback);
}
};
addListener(listener);
}
});
};
async.waterfall = function (tasks, callback) {
if (!tasks.length) {
return callback();
}
callback = callback || function () {};
var wrapIterator = function (iterator) {
return function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.nextTick(function () {
iterator.apply(null, args);
});
}
};
};
wrapIterator(async.iterator(tasks))();
};
async.parallel = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.map(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args || null);
});
}
}, callback);
}
else {
var results = {};
async.forEach(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.series = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args || null);
});
}
}, callback);
}
else {
var results = {};
async.forEachSeries(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
async.apply = function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(
null, args.concat(Array.prototype.slice.call(arguments))
);
};
};
var _concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
if (test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
});
}
else {
callback();
}
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback();
}
};
async.queue = function (worker, concurrency) {
var workers = 0;
var tasks = [];
var q = {
concurrency: concurrency,
push: function (data, callback) {
tasks.push({data: data, callback: callback});
async.nextTick(q.process);
},
process: function () {
if (workers < q.concurrency && tasks.length) {
var task = tasks.splice(0, 1)[0];
workers += 1;
worker(task.data, function () {
workers -= 1;
if (task.callback) {
task.callback.apply(task, arguments);
}
q.process();
});
}
},
length: function () {
return tasks.length;
}
};
return q;
};
var _console_fn = function (name) {
return function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_forEach(args, function (x) {
console[name](x);
});
}
}
}]));
};
};
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
async.warn = _console_fn('warn');
async.error = _console_fn('error');*/
async.memoize = function (fn, hasher) {
var memo = {};
hasher = hasher || function (x) {
return x;
};
return function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
callback.apply(null, memo[key]);
}
else {
fn.apply(null, args.concat([function () {
memo[key] = arguments;
callback.apply(null, arguments);
}]));
}
};
};
}());

View File

@ -1,55 +0,0 @@
/*
A console.log that won't leave you hanging when node exits
90% of this file was ripped from node.js
License: see: https://github.com/joyent/node/blob/master/lib/console.js
*/
// console object
var formatRegExp = /%[sdj]/g;
function format(f) {
var util = require('util');
if (typeof f !== 'string') {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(util.inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var str = String(f).replace(formatRegExp, function(x) {
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j': return JSON.stringify(args[i++]);
default:
return x;
}
});
for (var len = args.length, x = args[i]; i < len; x = args[++i]) {
if (x === null || typeof x !== 'object') {
str += ' ' + x;
} else {
str += ' ' + util.inspect(x);
}
}
return str;
}
console.log = function() {
var res = process.stdout.write(format.apply(this, arguments) + '\n');
// this is the first time stdout got backed up
if (!res && !process.stdout.pendingWrite) {
process.stdout.pendingWrite = true;
// magic sauce: keep node alive until stdout has flushed
process.stdout.once('drain', function () {
process.stdout.draining = false;
});
}
};

View File

@ -1,70 +0,0 @@
0.4.3 / 2011-06-20
==================
* Fixed stacktraces line number when used multiline js expressions [Octave]
0.4.2 / 2011-05-11
==================
* Added client side support
0.4.1 / 2011-04-21
==================
* Fixed error context
0.4.0 / 2011-04-21
==================
* Added; ported jade's error reporting to ejs. [slaskis]
0.3.1 / 2011-02-23
==================
* Fixed optional `compile()` options
0.3.0 / 2011-02-14
==================
* Added 'json' filter [Yuriy Bogdanov]
* Use exported version of parse function to allow monkey-patching [Anatoliy Chakkaev]
0.2.1 / 2010-10-07
==================
* Added filter support
* Fixed _cache_ option. ~4x performance increase
0.2.0 / 2010-08-05
==================
* Added support for global tag config
* Added custom tag support. Closes #5
* Fixed whitespace bug. Closes #4
0.1.0 / 2010-08-04
==================
* Faster implementation [ashleydev]
0.0.4 / 2010-08-02
==================
* Fixed single quotes for content outside of template tags. [aniero]
* Changed; `exports.compile()` now expects only "locals"
0.0.3 / 2010-07-15
==================
* Fixed single quotes
0.0.2 / 2010-07-09
==================
* Fixed newline preservation
0.0.1 / 2010-07-09
==================
* Initial release

View File

@ -1,20 +0,0 @@
SRC = $(shell find lib -name "*.js" -type f)
UGLIFY_FLAGS = --no-mangle
test:
@./node_modules/.bin/expresso test/*.test.js
ejs.js: $(SRC)
@node support/compile.js $^
ejs.min.js: ejs.js
@uglifyjs $(UGLIFY_FLAGS) $< > $@ \
&& du ejs.min.js \
&& du ejs.js
clean:
rm -f ejs.js
rm -f ejs.min.js
.PHONY: test

View File

@ -1,152 +0,0 @@
# EJS
Embedded JavaScript templates.
## Installation
$ npm install ejs
## Features
* Complies with the [Express](http://expressjs.com) view system
* Static caching of intermediate JavaScript
* Unbuffered code for conditionals etc `<% code %>`
* Escapes html by default with `<%= code %>`
* Unescaped buffering with `<%- code %>`
* Supports tag customization
* Filter support for designer-friendly templates
* Client-side support
## Example
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>
## Usage
ejs.compile(str, options);
// => Function
ejs.render(str, options);
// => str
## Options
- `locals` Local variables object
- `cache` Compiled functions are cached, requires `filename`
- `filename` Used by `cache` to key caches
- `scope` Function execution context
- `debug` Output generated function body
- `open` Open tag, defaulting to "<%"
- `close` Closing tag, defaulting to "%>"
## Custom tags
Custom tags can also be applied globally:
var ejs = require('ejs');
ejs.open = '{{';
ejs.close = '}}';
Which would make the following a valid template:
<h1>{{= title }}</h1>
## Filters
EJS conditionally supports the concept of "filters". A "filter chain"
is a designer friendly api for manipulating data, without writing JavaScript.
Filters can be applied by supplying the _:_ modifier, so for example if we wish to take the array `[{ name: 'tj' }, { name: 'mape' }, { name: 'guillermo' }]` and output a list of names we can do this simply with filters:
Template:
<p><%=: users | map:'name' | join %></p>
Output:
<p>Tj, Mape, Guillermo</p>
Render call:
ejs.render(str, {
locals: {
users: [
{ name: 'tj' },
{ name: 'mape' },
{ name: 'guillermo' }
]
}
});
Or perhaps capitalize the first user's name for display:
<p><%=: users | first | capitalize %></p>
## Filter list
Currently these filters are available:
- first
- last
- capitalize
- downcase
- upcase
- sort
- sort_by:'prop'
- size
- length
- plus:n
- minus:n
- times:n
- divided_by:n
- join:'val'
- truncate:n
- truncate_words:n
- replace:pattern,substitution
- prepend:val
- append:val
- map:'prop'
- reverse
- get:'prop'
## Adding filters
To add a filter simply add a method to the `.filters` object:
```js
ejs.filters.last = function(obj) {
return obj[obj.length - 1];
};
```
## client-side support
include `./ejs.js` or `./ejs.min.js` and `require("ejs").compile(str)`.
## License
(The MIT License)
Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
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.

View File

@ -1,14 +0,0 @@
var ejs = require('./lib/ejs'),
str = '<% if (foo) { %><p><%= foo %></p><% } %>',
times = 50000;
console.log('rendering ' + times + ' times');
var start = new Date;
while (times--) {
ejs.render(str, { cache: true, filename: 'test', locals: { foo: 'bar' }});
}
console.log('took ' + (new Date - start) + 'ms');

View File

@ -1,531 +0,0 @@
// CommonJS require()
function require(p){
var path = require.resolve(p)
, mod = require.modules[path];
if (!mod) throw new Error('failed to require "' + p + '"');
if (!mod.exports) {
mod.exports = {};
mod.call(mod.exports, mod, mod.exports, require.relative(path));
}
return mod.exports;
}
require.modules = {};
require.resolve = function (path){
var orig = path
, reg = path + '.js'
, index = path + '/index.js';
return require.modules[reg] && reg
|| require.modules[index] && index
|| orig;
};
require.register = function (path, fn){
require.modules[path] = fn;
};
require.relative = function (parent) {
return function(p){
if ('.' != p[0]) return require(p);
var path = parent.split('/')
, segs = p.split('/');
path.pop();
for (var i = 0; i < segs.length; i++) {
var seg = segs[i];
if ('..' == seg) path.pop();
else if ('.' != seg) path.push(seg);
}
return require(path.join('/'));
};
};
require.register("ejs.js", function(module, exports, require){
/*!
* EJS
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('./utils');
/**
* Library version.
*/
exports.version = '0.4.2';
/**
* Filters.
*
* @type Object
*/
var filters = exports.filters = require('./filters');
/**
* Intermediate js cache.
*
* @type Object
*/
var cache = {};
/**
* Clear intermediate js cache.
*
* @api public
*/
exports.clearCache = function(){
cache = {};
};
/**
* Translate filtered code into function calls.
*
* @param {String} js
* @return {String}
* @api private
*/
function filtered(js) {
return js.substr(1).split('|').reduce(function(js, filter){
var parts = filter.split(':')
, name = parts.shift()
, args = parts.shift() || '';
if (args) args = ', ' + args;
return 'filters.' + name + '(' + js + args + ')';
});
};
/**
* Re-throw the given `err` in context to the
* `str` of ejs, `filename`, and `lineno`.
*
* @param {Error} err
* @param {String} str
* @param {String} filename
* @param {String} lineno
* @api private
*/
function rethrow(err, str, filename, lineno){
var lines = str.split('\n')
, start = Math.max(lineno - 3, 0)
, end = Math.min(lines.length, lineno + 3);
// Error context
var context = lines.slice(start, end).map(function(line, i){
var curr = i + start + 1;
return (curr == lineno ? ' >> ' : ' ')
+ curr
+ '| '
+ line;
}).join('\n');
// Alter exception message
err.path = filename;
err.message = (filename || 'ejs') + ':'
+ lineno + '\n'
+ context + '\n\n'
+ err.message;
throw err;
}
/**
* Parse the given `str` of ejs, returning the function body.
*
* @param {String} str
* @return {String}
* @api public
*/
var parse = exports.parse = function(str, options){
var options = options || {}
, open = options.open || exports.open || '<%'
, close = options.close || exports.close || '%>';
var buf = [
"var buf = [];"
, "\nwith (locals) {"
, "\n buf.push('"
];
var lineno = 1;
for (var i = 0, len = str.length; i < len; ++i) {
if (str.slice(i, open.length + i) == open) {
i += open.length
var prefix, postfix, line = '__stack.lineno=' + lineno;
switch (str[i]) {
case '=':
prefix = "', escape((" + line + ', ';
postfix = ")), '";
++i;
break;
case '-':
prefix = "', (" + line + ', ';
postfix = "), '";
++i;
break;
default:
prefix = "');" + line + ';';
postfix = "; buf.push('";
}
var start = i;
var end = str.indexOf(close, i);
var js = str.substring(i, end);
var n = 0;
while ((n = js.indexOf("\n", n)) > -1) {
n++;
lineno++;
}
if (js[0] == ':') js = filtered(js);
buf.push(prefix, js, postfix);
i += end - start + close.length - 1;
} else if (str[i] == "\\") {
buf.push("\\\\");
} else if (str[i] == "'") {
buf.push("\\'");
} else if (str[i] == "\r") {
buf.push(" ");
} else if (str[i] == "\n") {
buf.push("\\n");
lineno++;
} else {
buf.push(str[i]);
}
}
buf.push("');\n}\nreturn buf.join('');");
return buf.join('');
};
/**
* Compile the given `str` of ejs into a `Function`.
*
* @param {String} str
* @param {Object} options
* @return {Function}
* @api public
*/
var compile = exports.compile = function(str, options){
options = options || {};
var input = JSON.stringify(str)
, filename = options.filename
? JSON.stringify(options.filename)
: 'undefined';
// Adds the fancy stack trace meta info
str = [
'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
rethrow.toString(),
'try {',
exports.parse(str, options),
'} catch (err) {',
' rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
'}'
].join("\n");
if (options.debug) console.log(str);
var fn = new Function('locals, filters, escape', str);
return function(locals){
return fn.call(this, locals, filters, utils.escape);
}
};
/**
* Render the given `str` of ejs.
*
* Options:
*
* - `locals` Local variables object
* - `cache` Compiled functions are cached, requires `filename`
* - `filename` Used by `cache` to key caches
* - `scope` Function execution context
* - `debug` Output generated function body
* - `open` Open tag, defaulting to "<%"
* - `close` Closing tag, defaulting to "%>"
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api public
*/
exports.render = function(str, options){
var fn
, options = options || {};
if (options.cache) {
if (options.filename) {
fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
} else {
throw new Error('"cache" option requires "filename".');
}
} else {
fn = compile(str, options);
}
return fn.call(options.scope, options.locals || {});
};
/**
* Expose to require().
*/
if (require.extensions) {
require.extensions['.ejs'] = function(module, filename) {
source = require('fs').readFileSync(filename, 'utf-8');
module._compile(compile(source, {}), filename);
};
} else if (require.registerExtension) {
require.registerExtension('.ejs', function(src) {
return compile(src, {});
});
}
}); // module: ejs.js
require.register("filters.js", function(module, exports, require){
/*!
* EJS - Filters
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* First element of the target `obj`.
*/
exports.first = function(obj) {
return obj[0];
};
/**
* Last element of the target `obj`.
*/
exports.last = function(obj) {
return obj[obj.length - 1];
};
/**
* Capitalize the first letter of the target `str`.
*/
exports.capitalize = function(str){
str = String(str);
return str[0].toUpperCase() + str.substr(1, str.length);
};
/**
* Downcase the target `str`.
*/
exports.downcase = function(str){
return String(str).toLowerCase();
};
/**
* Uppercase the target `str`.
*/
exports.upcase = function(str){
return String(str).toUpperCase();
};
/**
* Sort the target `obj`.
*/
exports.sort = function(obj){
return Object.create(obj).sort();
};
/**
* Sort the target `obj` by the given `prop` ascending.
*/
exports.sort_by = function(obj, prop){
return Object.create(obj).sort(function(a, b){
a = a[prop], b = b[prop];
if (a > b) return 1;
if (a < b) return -1;
return 0;
});
};
/**
* Size or length of the target `obj`.
*/
exports.size = exports.length = function(obj) {
return obj.length;
};
/**
* Add `a` and `b`.
*/
exports.plus = function(a, b){
return Number(a) + Number(b);
};
/**
* Subtract `b` from `a`.
*/
exports.minus = function(a, b){
return Number(a) - Number(b);
};
/**
* Multiply `a` by `b`.
*/
exports.times = function(a, b){
return Number(a) * Number(b);
};
/**
* Divide `a` by `b`.
*/
exports.divided_by = function(a, b){
return Number(a) / Number(b);
};
/**
* Join `obj` with the given `str`.
*/
exports.join = function(obj, str){
return obj.join(str || ', ');
};
/**
* Truncate `str` to `len`.
*/
exports.truncate = function(str, len){
str = String(str);
return str.substr(0, len);
};
/**
* Truncate `str` to `n` words.
*/
exports.truncate_words = function(str, n){
var str = String(str)
, words = str.split(/ +/);
return words.slice(0, n).join(' ');
};
/**
* Replace `pattern` with `substitution` in `str`.
*/
exports.replace = function(str, pattern, substitution){
return String(str).replace(pattern, substitution || '');
};
/**
* Prepend `val` to `obj`.
*/
exports.prepend = function(obj, val){
return Array.isArray(obj)
? [val].concat(obj)
: val + obj;
};
/**
* Append `val` to `obj`.
*/
exports.append = function(obj, val){
return Array.isArray(obj)
? obj.concat(val)
: obj + val;
};
/**
* Map the given `prop`.
*/
exports.map = function(arr, prop){
return arr.map(function(obj){
return obj[prop];
});
};
/**
* Reverse the given `obj`.
*/
exports.reverse = function(obj){
return Array.isArray(obj)
? obj.reverse()
: String(obj).split('').reverse().join('');
};
/**
* Get `prop` of the given `obj`.
*/
exports.get = function(obj, prop){
return obj[prop];
};
/**
* Packs the given `obj` into json string
*/
exports.json = function(obj){
return JSON.stringify(obj);
};
}); // module: filters.js
require.register("utils.js", function(module, exports, require){
/*!
* EJS
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Escape the given string of `html`.
*
* @param {String} html
* @return {String}
* @api private
*/
exports.escape = function(html){
return String(html)
.replace(/&(?!\w+;)/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
}); // module: utils.js

File diff suppressed because one or more lines are too long

View File

@ -1,5 +0,0 @@
<html>
<head>
<script src="../ejs.js"></script>
</head>
</html>

View File

@ -1,7 +0,0 @@
<% if (names.length) { %>
<ul>
<% names.forEach(function(name){ %>
<li><%= name %></li>
<% }) %>
</ul>
<% } %>

View File

@ -1,16 +0,0 @@
/**
* Module dependencies.
*/
var ejs = require('../')
, fs = require('fs')
, str = fs.readFileSync(__dirname + '/list.ejs', 'utf8');
var ret = ejs.render(str, {
locals: {
names: ['foo', 'bar', 'baz']
}
});
console.log(ret);

View File

@ -1,2 +0,0 @@
module.exports = require('./lib/ejs');

View File

@ -1,251 +0,0 @@
/*!
* EJS
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('./utils');
/**
* Library version.
*/
exports.version = '0.4.3';
/**
* Filters.
*
* @type Object
*/
var filters = exports.filters = require('./filters');
/**
* Intermediate js cache.
*
* @type Object
*/
var cache = {};
/**
* Clear intermediate js cache.
*
* @api public
*/
exports.clearCache = function(){
cache = {};
};
/**
* Translate filtered code into function calls.
*
* @param {String} js
* @return {String}
* @api private
*/
function filtered(js) {
return js.substr(1).split('|').reduce(function(js, filter){
var parts = filter.split(':')
, name = parts.shift()
, args = parts.shift() || '';
if (args) args = ', ' + args;
return 'filters.' + name + '(' + js + args + ')';
});
};
/**
* Re-throw the given `err` in context to the
* `str` of ejs, `filename`, and `lineno`.
*
* @param {Error} err
* @param {String} str
* @param {String} filename
* @param {String} lineno
* @api private
*/
function rethrow(err, str, filename, lineno){
var lines = str.split('\n')
, start = Math.max(lineno - 3, 0)
, end = Math.min(lines.length, lineno + 3);
// Error context
var context = lines.slice(start, end).map(function(line, i){
var curr = i + start + 1;
return (curr == lineno ? ' >> ' : ' ')
+ curr
+ '| '
+ line;
}).join('\n');
// Alter exception message
err.path = filename;
err.message = (filename || 'ejs') + ':'
+ lineno + '\n'
+ context + '\n\n'
+ err.message;
throw err;
}
/**
* Parse the given `str` of ejs, returning the function body.
*
* @param {String} str
* @return {String}
* @api public
*/
var parse = exports.parse = function(str, options){
var options = options || {}
, open = options.open || exports.open || '<%'
, close = options.close || exports.close || '%>';
var buf = [
"var buf = [];"
, "\nwith (locals) {"
, "\n buf.push('"
];
var lineno = 1;
for (var i = 0, len = str.length; i < len; ++i) {
if (str.slice(i, open.length + i) == open) {
i += open.length
var prefix, postfix, line = '__stack.lineno=' + lineno;
switch (str.substr(i, 1)) {
case '=':
prefix = "', escape((" + line + ', ';
postfix = ")), '";
++i;
break;
case '-':
prefix = "', (" + line + ', ';
postfix = "), '";
++i;
break;
default:
prefix = "');" + line + ';';
postfix = "; buf.push('";
}
var end = str.indexOf(close, i)
, js = str.substring(i, end)
, start = i
, n = 0;
while (~(n = js.indexOf("\n", n))) n++, lineno++;
if (js.substr(0, 1) == ':') js = filtered(js);
buf.push(prefix, js, postfix);
i += end - start + close.length - 1;
} else if (str.substr(i, 1) == "\\") {
buf.push("\\\\");
} else if (str.substr(i, 1) == "'") {
buf.push("\\'");
} else if (str.substr(i, 1) == "\r") {
buf.push(" ");
} else if (str.substr(i, 1) == "\n") {
buf.push("\\n");
lineno++;
} else {
buf.push(str.substr(i, 1));
}
}
buf.push("');\n}\nreturn buf.join('');");
return buf.join('');
};
/**
* Compile the given `str` of ejs into a `Function`.
*
* @param {String} str
* @param {Object} options
* @return {Function}
* @api public
*/
var compile = exports.compile = function(str, options){
options = options || {};
var input = JSON.stringify(str)
, filename = options.filename
? JSON.stringify(options.filename)
: 'undefined';
// Adds the fancy stack trace meta info
str = [
'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
rethrow.toString(),
'try {',
exports.parse(str, options),
'} catch (err) {',
' rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
'}'
].join("\n");
if (options.debug) console.log(str);
var fn = new Function('locals, filters, escape', str);
return function(locals){
return fn.call(this, locals, filters, utils.escape);
}
};
/**
* Render the given `str` of ejs.
*
* Options:
*
* - `locals` Local variables object
* - `cache` Compiled functions are cached, requires `filename`
* - `filename` Used by `cache` to key caches
* - `scope` Function execution context
* - `debug` Output generated function body
* - `open` Open tag, defaulting to "<%"
* - `close` Closing tag, defaulting to "%>"
*
* @param {String} str
* @param {Object} options
* @return {String}
* @api public
*/
exports.render = function(str, options){
var fn
, options = options || {};
if (options.cache) {
if (options.filename) {
fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
} else {
throw new Error('"cache" option requires "filename".');
}
} else {
fn = compile(str, options);
}
return fn.call(options.scope, options.locals || {});
};
/**
* Expose to require().
*/
if (require.extensions) {
require.extensions['.ejs'] = function(module, filename) {
source = require('fs').readFileSync(filename, 'utf-8');
module._compile(compile(source, {}), filename);
};
} else if (require.registerExtension) {
require.registerExtension('.ejs', function(src) {
return compile(src, {});
});
}

View File

@ -1,198 +0,0 @@
/*!
* EJS - Filters
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* First element of the target `obj`.
*/
exports.first = function(obj) {
return obj[0];
};
/**
* Last element of the target `obj`.
*/
exports.last = function(obj) {
return obj[obj.length - 1];
};
/**
* Capitalize the first letter of the target `str`.
*/
exports.capitalize = function(str){
str = String(str);
return str[0].toUpperCase() + str.substr(1, str.length);
};
/**
* Downcase the target `str`.
*/
exports.downcase = function(str){
return String(str).toLowerCase();
};
/**
* Uppercase the target `str`.
*/
exports.upcase = function(str){
return String(str).toUpperCase();
};
/**
* Sort the target `obj`.
*/
exports.sort = function(obj){
return Object.create(obj).sort();
};
/**
* Sort the target `obj` by the given `prop` ascending.
*/
exports.sort_by = function(obj, prop){
return Object.create(obj).sort(function(a, b){
a = a[prop], b = b[prop];
if (a > b) return 1;
if (a < b) return -1;
return 0;
});
};
/**
* Size or length of the target `obj`.
*/
exports.size = exports.length = function(obj) {
return obj.length;
};
/**
* Add `a` and `b`.
*/
exports.plus = function(a, b){
return Number(a) + Number(b);
};
/**
* Subtract `b` from `a`.
*/
exports.minus = function(a, b){
return Number(a) - Number(b);
};
/**
* Multiply `a` by `b`.
*/
exports.times = function(a, b){
return Number(a) * Number(b);
};
/**
* Divide `a` by `b`.
*/
exports.divided_by = function(a, b){
return Number(a) / Number(b);
};
/**
* Join `obj` with the given `str`.
*/
exports.join = function(obj, str){
return obj.join(str || ', ');
};
/**
* Truncate `str` to `len`.
*/
exports.truncate = function(str, len){
str = String(str);
return str.substr(0, len);
};
/**
* Truncate `str` to `n` words.
*/
exports.truncate_words = function(str, n){
var str = String(str)
, words = str.split(/ +/);
return words.slice(0, n).join(' ');
};
/**
* Replace `pattern` with `substitution` in `str`.
*/
exports.replace = function(str, pattern, substitution){
return String(str).replace(pattern, substitution || '');
};
/**
* Prepend `val` to `obj`.
*/
exports.prepend = function(obj, val){
return Array.isArray(obj)
? [val].concat(obj)
: val + obj;
};
/**
* Append `val` to `obj`.
*/
exports.append = function(obj, val){
return Array.isArray(obj)
? obj.concat(val)
: obj + val;
};
/**
* Map the given `prop`.
*/
exports.map = function(arr, prop){
return arr.map(function(obj){
return obj[prop];
});
};
/**
* Reverse the given `obj`.
*/
exports.reverse = function(obj){
return Array.isArray(obj)
? obj.reverse()
: String(obj).split('').reverse().join('');
};
/**
* Get `prop` of the given `obj`.
*/
exports.get = function(obj, prop){
return obj[prop];
};
/**
* Packs the given `obj` into json string
*/
exports.json = function(obj){
return JSON.stringify(obj);
};

View File

@ -1,23 +0,0 @@
/*!
* EJS
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
* Escape the given string of `html`.
*
* @param {String} html
* @return {String}
* @api private
*/
exports.escape = function(html){
return String(html)
.replace(/&(?!\w+;)/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};

View File

@ -1,11 +0,0 @@
{
"name": "ejs",
"description": "Embedded JavaScript templates",
"version": "0.4.3",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"keywords": ["template", "engine", "ejs"],
"devDependencies": {
"expresso": "0.9.2"
},
"main": "./lib/ejs.js"
}

View File

@ -1,173 +0,0 @@
/**
* Module dependencies.
*/
var fs = require('fs');
/**
* Arguments.
*/
var args = process.argv.slice(2)
, pending = args.length
, files = {};
console.log('');
// parse arguments
args.forEach(function(file){
var mod = file.replace('lib/', '');
fs.readFile(file, 'utf8', function(err, js){
if (err) throw err;
console.log(' \033[90mcompile : \033[0m\033[36m%s\033[0m', file);
files[file] = parse(js);
--pending || compile();
});
});
/**
* Parse the given `js`.
*/
function parse(js) {
return parseInheritance(parseConditionals(js));
}
/**
* Parse __proto__.
*/
function parseInheritance(js) {
return js
.replace(/^ *(\w+)\.prototype\.__proto__ * = *(\w+)\.prototype *;?/gm, function(_, child, parent){
return child + '.prototype = new ' + parent + ';\n'
+ child + '.prototype.constructor = '+ child + ';\n';
});
}
/**
* Parse the given `js`, currently supporting:
*
* 'if' ['node' | 'browser']
* 'end'
*
*/
function parseConditionals(js) {
var lines = js.split('\n')
, len = lines.length
, buffer = true
, browser = false
, buf = []
, line
, cond;
for (var i = 0; i < len; ++i) {
line = lines[i];
if (/^ *\/\/ *if *(node|browser)/gm.exec(line)) {
cond = RegExp.$1;
buffer = browser = 'browser' == cond;
} else if (/^ *\/\/ *end/.test(line)) {
buffer = true;
browser = false;
} else if (browser) {
buf.push(line.replace(/^( *)\/\//, '$1'));
} else if (buffer) {
buf.push(line);
}
}
return buf.join('\n');
}
/**
* Compile the files.
*/
function compile() {
var buf = '';
buf += '\n// CommonJS require()\n\n';
buf += browser.require + '\n\n';
buf += 'require.modules = {};\n\n';
buf += 'require.resolve = ' + browser.resolve + ';\n\n';
buf += 'require.register = ' + browser.register + ';\n\n';
buf += 'require.relative = ' + browser.relative + ';\n\n';
args.forEach(function(file){
var js = files[file];
file = file.replace('lib/', '');
buf += '\nrequire.register("' + file + '", function(module, exports, require){\n';
buf += js;
buf += '\n}); // module: ' + file + '\n';
});
fs.writeFile('ejs.js', buf, function(err){
if (err) throw err;
console.log(' \033[90m create : \033[0m\033[36m%s\033[0m', 'ejs.js');
console.log();
});
}
// refactored version of weepy's
// https://github.com/weepy/brequire/blob/master/browser/brequire.js
var browser = {
/**
* Require a module.
*/
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;
},
/**
* Resolve module path.
*/
resolve: function(path){
var orig = path
, reg = path + '.js'
, index = path + '/index.js';
return require.modules[reg] && reg
|| require.modules[index] && index
|| orig;
},
/**
* Return relative require().
*/
relative: function(parent) {
return function(p){
if ('.' != p.substr(0, 1)) 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('/'));
};
},
/**
* Register a module.
*/
register: function(path, fn){
require.modules[path] = fn;
}
};

View File

@ -1,269 +0,0 @@
/**
* Module dependencies.
*/
var ejs = require('../')
, assert = require('assert');
module.exports = {
'test .version': function(){
assert.ok(/^\d+\.\d+\.\d+$/.test(ejs.version), 'Test .version format');
},
'test html': function(){
assert.equal('<p>yay</p>', ejs.render('<p>yay</p>'));
},
'test buffered code': function(){
var html = '<p>tj</p>',
str = '<p><%= name %></p>',
locals = { name: 'tj' };
assert.equal(html, ejs.render(str, { locals: locals }));
},
'test unbuffered code': function(){
var html = '<p>tj</p>',
str = '<% if (name) { %><p><%= name %></p><% } %>',
locals = { name: 'tj' };
assert.equal(html, ejs.render(str, { locals: locals }));
},
'test `scope` option': function(){
var html = '<p>tj</p>',
str = '<p><%= this %></p>';
assert.equal(html, ejs.render(str, { scope: 'tj' }));
},
'test escaping': function(){
assert.equal('&lt;script&gt;', ejs.render('<%= "<script>" %>'));
assert.equal('<script>', ejs.render('<%- "<script>" %>'));
},
'test newlines': function(){
var html = '\n<p>tj</p>\n<p>tj@sencha.com</p>',
str = '<% if (name) { %>\n<p><%= name %></p>\n<p><%= email %></p><% } %>',
locals = { name: 'tj', email: 'tj@sencha.com' };
assert.equal(html, ejs.render(str, { locals: locals }));
},
'test single quotes': function(){
var html = '<p>WAHOO</p>',
str = "<p><%= up('wahoo') %></p>",
locals = { up: function(str){ return str.toUpperCase(); }};
assert.equal(html, ejs.render(str, { locals: locals }));
},
'test single quotes in the html': function(){
var html = '<p>WAHOO that\'s cool</p>',
str = '<p><%= up(\'wahoo\') %> that\'s cool</p>',
locals = { up: function(str){ return str.toUpperCase(); }};
assert.equal(html, ejs.render(str, { locals: locals }));
},
'test multiple single quotes': function() {
var html = "<p>couldn't shouldn't can't</p>",
str = "<p>couldn't shouldn't can't</p>";
assert.equal(html, ejs.render(str));
},
'test single quotes inside tags': function() {
var html = '<p>string</p>',
str = "<p><%= 'string' %></p>";
assert.equal(html, ejs.render(str));
},
'test back-slashes in the document': function() {
var html = "<p>backslash: '\\'</p>",
str = "<p>backslash: '\\'</p>";
assert.equal(html, ejs.render(str));
},
'test double quotes': function(){
var html = '<p>WAHOO</p>',
str = '<p><%= up("wahoo") %></p>',
locals = { up: function(str){ return str.toUpperCase(); }};
assert.equal(html, ejs.render(str, { locals: locals }));
},
'test multiple double quotes': function() {
var html = '<p>just a "test" wahoo</p>',
str = '<p>just a "test" wahoo</p>';
assert.equal(html, ejs.render(str));
},
'test whitespace': function(){
var html = '<p>foo</p>',
str = '<p><%="foo"%></p>';
assert.equal(html, ejs.render(str));
var html = '<p>foo</p>',
str = '<p><%=bar%></p>';
assert.equal(html, ejs.render(str, { locals: { bar: 'foo' }}));
},
'test custom tags': function(){
var html = '<p>foo</p>',
str = '<p>{{= "foo" }}</p>';
assert.equal(html, ejs.render(str, {
open: '{{',
close: '}}'
}));
var html = '<p>foo</p>',
str = '<p><?= "foo" ?></p>';
assert.equal(html, ejs.render(str, {
open: '<?',
close: '?>'
}));
},
'test custom tags over 2 chars': function(){
var html = '<p>foo</p>',
str = '<p>{{{{= "foo" }>>}</p>';
assert.equal(html, ejs.render(str, {
open: '{{{{',
close: '}>>}'
}));
var html = '<p>foo</p>',
str = '<p><??= "foo" ??></p>';
assert.equal(html, ejs.render(str, {
open: '<??',
close: '??>'
}));
},
'test global custom tags': function(){
var html = '<p>foo</p>',
str = '<p>{{= "foo" }}</p>';
ejs.open = '{{';
ejs.close = '}}';
assert.equal(html, ejs.render(str));
delete ejs.open;
delete ejs.close;
},
'test iteration': function(){
var html = '<p>foo</p>',
str = '<% for (var key in items) { %>'
+ '<p><%= items[key] %></p>'
+ '<% } %>';
assert.equal(html, ejs.render(str, {
locals: {
items: ['foo']
}
}));
var html = '<p>foo</p>',
str = '<% items.forEach(function(item){ %>'
+ '<p><%= item %></p>'
+ '<% }) %>';
assert.equal(html, ejs.render(str, {
locals: {
items: ['foo']
}
}));
},
'test filter support': function(){
var html = 'Zab',
str = '<%=: items | reverse | first | reverse | capitalize %>';
assert.equal(html, ejs.render(str, {
locals: {
items: ['foo', 'bar', 'baz']
}
}));
},
'test filter argument support': function(){
var html = 'tj, guillermo',
str = '<%=: users | map:"name" | join:", " %>';
assert.equal(html, ejs.render(str, {
locals: {
users: [
{ name: 'tj' },
{ name: 'guillermo' }
]
}
}));
},
'test sort_by filter': function(){
var html = 'tj',
str = '<%=: users | sort_by:"name" | last | get:"name" %>';
assert.equal(html, ejs.render(str, {
locals: {
users: [
{ name: 'guillermo' },
{ name: 'tj' },
{ name: 'mape' }
]
}
}));
},
'test custom filters': function(){
var html = 'Welcome Tj Holowaychuk',
str = '<%=: users | first | greeting %>';
ejs.filters.greeting = function(user){
return 'Welcome ' + user.first + ' ' + user.last + '';
};
assert.equal(html, ejs.render(str, {
locals: {
users: [
{ first: 'Tj', last: 'Holowaychuk' }
]
}
}));
},
'test useful stack traces': function(){
var str = [
"A little somethin'",
"somethin'",
"<% if (name) { %>", // Failing line
" <p><%= name %></p>",
" <p><%= email %></p>",
"<% } %>"
].join("\n");
try {
ejs.render(str)
} catch( err ){
assert.includes(err.message,"name is not defined");
assert.eql(err.name,"ReferenceError");
var lineno = parseInt(err.toString().match(/ejs:(\d+)\n/)[1]);
assert.eql(lineno,3,"Error should been thrown on line 3, was thrown on line "+lineno);
}
},
'test useful stack traces multiline': function(){
var str = [
"A little somethin'",
"somethin'",
"<% var some = 'pretty';",
" var multiline = 'javascript';",
"%>",
"<% if (name) { %>", // Failing line
" <p><%= name %></p>",
" <p><%= email %></p>",
"<% } %>"
].join("\n");
try {
ejs.render(str)
} catch( err ){
assert.includes(err.message,"name is not defined");
assert.eql(err.name,"ReferenceError");
var lineno = parseInt(err.toString().match(/ejs:(\d+)\n/)[1]);
assert.eql(lineno,6,"Error should been thrown on line 3, was thrown on line "+lineno);
}
}
};

View File

@ -1,481 +0,0 @@
/*
http://www.JSON.org/json2.js
2010-11-17
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false, regexp: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON = {};
(function () {
"use strict";
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

View File

@ -1,70 +0,0 @@
/*!
* Styles taken from qunit.css
*/
h1#nodeunit-header, h1.nodeunit-header {
padding: 15px;
font-size: large;
background-color: #06b;
color: white;
font-family: 'trebuchet ms', verdana, arial;
margin: 0;
}
h1#nodeunit-header a {
color: white;
}
h2#nodeunit-banner {
height: 2em;
border-bottom: 1px solid white;
background-color: #eee;
margin: 0;
font-family: 'trebuchet ms', verdana, arial;
}
h2#nodeunit-banner.pass {
background-color: green;
}
h2#nodeunit-banner.fail {
background-color: red;
}
h2#nodeunit-userAgent, h2.nodeunit-userAgent {
padding: 10px;
background-color: #eee;
color: black;
margin: 0;
font-size: small;
font-weight: normal;
font-family: 'trebuchet ms', verdana, arial;
font-size: 10pt;
}
div#nodeunit-testrunner-toolbar {
background: #eee;
border-top: 1px solid black;
padding: 10px;
font-family: 'trebuchet ms', verdana, arial;
margin: 0;
font-size: 10pt;
}
ol#nodeunit-tests {
font-family: 'trebuchet ms', verdana, arial;
font-size: 10pt;
}
ol#nodeunit-tests li strong {
cursor:pointer;
}
ol#nodeunit-tests .pass {
color: green;
}
ol#nodeunit-tests .fail {
color: red;
}
p#nodeunit-testresult {
margin-left: 1em;
font-size: 10pt;
font-family: 'trebuchet ms', verdana, arial;
}

View File

@ -1,2117 +0,0 @@
/*!
* Nodeunit
* https://github.com/caolan/nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* json2.js
* http://www.JSON.org/json2.js
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
nodeunit = (function(){
/*
http://www.JSON.org/json2.js
2010-11-17
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false, regexp: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON = {};
(function () {
"use strict";
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
var assert = this.assert = {};
var types = {};
var core = {};
var nodeunit = {};
var reporter = {};
/*global setTimeout: false, console: false */
(function () {
var async = {};
// global on the server, window in the browser
var root = this,
previous_async = root.async;
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
else {
root.async = async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
//// cross-browser compatiblity functions ////
var _forEach = function (arr, iterator) {
if (arr.forEach) {
return arr.forEach(iterator);
}
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
};
var _map = function (arr, iterator) {
if (arr.map) {
return arr.map(iterator);
}
var results = [];
_forEach(arr, function (x, i, a) {
results.push(iterator(x, i, a));
});
return results;
};
var _reduce = function (arr, iterator, memo) {
if (arr.reduce) {
return arr.reduce(iterator, memo);
}
_forEach(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
};
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
var _indexOf = function (arr, item) {
if (arr.indexOf) {
return arr.indexOf(item);
}
for (var i = 0; i < arr.length; i += 1) {
if (arr[i] === item) {
return i;
}
}
return -1;
};
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
if (typeof setImmediate === 'function') {
async.nextTick = function (fn) {
setImmediate(fn);
};
}
else if (typeof process !== 'undefined' && process.nextTick) {
async.nextTick = process.nextTick;
}
else {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
}
async.forEach = function (arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
_forEach(arr, function (x) {
iterator(x, function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback();
}
}
});
});
};
async.forEachSeries = function (arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback();
}
else {
iterate();
}
}
});
};
iterate();
};
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.forEach].concat(args));
};
};
var doSeries = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.forEachSeries].concat(args));
};
};
var _asyncMap = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (err, v) {
results[x.index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.reduce = function (arr, memo, iterator, callback) {
async.forEachSeries(arr, function (x, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
// inject alias
async.inject = async.reduce;
// foldl alias
async.foldl = async.reduce;
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
// foldr alias
async.foldr = async.reduceRight;
var _filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.filter = doParallel(_filter);
async.filterSeries = doSeries(_filter);
// select alias
async.select = async.filter;
async.selectSeries = async.filterSeries;
var _reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.reject = doParallel(_reject);
async.rejectSeries = doSeries(_reject);
var _detect = function (eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
}
else {
callback();
}
});
}, function (err) {
main_callback();
});
};
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.some = function (arr, iterator, main_callback) {
async.forEach(arr, function (x, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(false);
});
};
// any alias
async.any = async.some;
async.every = function (arr, iterator, main_callback) {
async.forEach(arr, function (x, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(true);
});
};
// all alias
async.all = async.every;
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
iterator(x, function (err, criteria) {
if (err) {
callback(err);
}
else {
callback(null, {value: x, criteria: criteria});
}
});
}, function (err, results) {
if (err) {
return callback(err);
}
else {
var fn = function (left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
};
callback(null, _map(results.sort(fn), function (x) {
return x.value;
}));
}
});
};
async.auto = function (tasks, callback) {
callback = callback || function () {};
var keys = _keys(tasks);
if (!keys.length) {
return callback(null);
}
var completed = [];
var listeners = [];
var addListener = function (fn) {
listeners.unshift(fn);
};
var removeListener = function (fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
};
var taskComplete = function () {
_forEach(listeners, function (fn) {
fn();
});
};
addListener(function () {
if (completed.length === keys.length) {
callback(null);
}
});
_forEach(keys, function (k) {
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
var taskCallback = function (err) {
if (err) {
callback(err);
// stop subsequent errors hitting callback multiple times
callback = function () {};
}
else {
completed.push(k);
taskComplete();
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && _indexOf(completed, x) !== -1);
}, true);
};
if (ready()) {
task[task.length - 1](taskCallback);
}
else {
var listener = function () {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback);
}
};
addListener(listener);
}
});
};
async.waterfall = function (tasks, callback) {
if (!tasks.length) {
return callback();
}
callback = callback || function () {};
var wrapIterator = function (iterator) {
return function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.nextTick(function () {
iterator.apply(null, args);
});
}
};
};
wrapIterator(async.iterator(tasks))();
};
async.parallel = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.map(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args || null);
});
}
}, callback);
}
else {
var results = {};
async.forEach(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.series = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args || null);
});
}
}, callback);
}
else {
var results = {};
async.forEachSeries(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
async.apply = function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(
null, args.concat(Array.prototype.slice.call(arguments))
);
};
};
var _concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
if (test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
});
}
else {
callback();
}
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback();
}
};
async.queue = function (worker, concurrency) {
var workers = 0;
var tasks = [];
var q = {
concurrency: concurrency,
push: function (data, callback) {
tasks.push({data: data, callback: callback});
async.nextTick(q.process);
},
process: function () {
if (workers < q.concurrency && tasks.length) {
var task = tasks.splice(0, 1)[0];
workers += 1;
worker(task.data, function () {
workers -= 1;
if (task.callback) {
task.callback.apply(task, arguments);
}
q.process();
});
}
},
length: function () {
return tasks.length;
}
};
return q;
};
var _console_fn = function (name) {
return function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_forEach(args, function (x) {
console[name](x);
});
}
}
}]));
};
};
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
async.warn = _console_fn('warn');
async.error = _console_fn('error');*/
async.memoize = function (fn, hasher) {
var memo = {};
hasher = hasher || function (x) {
return x;
};
return function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
callback.apply(null, memo[key]);
}
else {
fn.apply(null, args.concat([function () {
memo[key] = arguments;
callback.apply(null, arguments);
}]));
}
};
};
}());
(function(exports){
/**
* This file is based on the node.js assert module, but with some small
* changes for browser-compatibility
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
*/
/**
* Added for browser compatibility
*/
var _keys = function(obj){
if(Object.keys) return Object.keys(obj);
if (typeof obj != 'object' && typeof obj != 'function') {
throw new TypeError('-');
}
var keys = [];
for(var k in obj){
if(obj.hasOwnProperty(k)) keys.push(k);
}
return keys;
};
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var pSlice = Array.prototype.slice;
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = exports;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({message: message, actual: actual, expected: expected})
assert.AssertionError = function AssertionError (options) {
this.name = "AssertionError";
this.message = options.message;
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
}
};
// code from util.inherits in node
assert.AssertionError.super_ = Error;
// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call
// TODO: test what effect this may have
var ctor = function () { this.constructor = assert.AssertionError; };
ctor.prototype = Error.prototype;
assert.AssertionError.prototype = new ctor();
assert.AssertionError.prototype.toString = function() {
if (this.message) {
return [this.name+":", this.message].join(' ');
} else {
return [ this.name+":"
, typeof this.expected !== 'undefined' ? JSON.stringify(this.expected) : 'undefined'
, this.operator
, typeof this.actual !== 'undefined' ? JSON.stringify(this.actual) : 'undefined'
].join(" ");
}
};
// assert.AssertionError instanceof Error
assert.AssertionError.__proto__ = Error.prototype;
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
assert.ok = function ok(value, message) {
if (!!!value) fail(value, true, message, "==", assert.ok);
};
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, "==", assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, "!=", assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected)) {
fail(actual, expected, message, "deepEqual", assert.deepEqual);
}
};
var Buffer = null;
if (typeof require !== 'undefined' && typeof process !== 'undefined') {
try {
Buffer = require('buffer').Buffer;
}
catch (e) {
// May be a CommonJS environment other than Node.js
Buffer = null;
}
}
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();
// 7.2.1 If the expcted value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object that refers to the same source and options
} else if (actual instanceof RegExp && expected instanceof RegExp) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.ignoreCase === expected.ignoreCase &&
actual.multiline === expected.multiline;
} else if (Buffer && actual instanceof Buffer && expected instanceof Buffer) {
return (function() {
var i, len;
for (i = 0, len = expected.length; i < len; i++) {
if (actual[i] !== expected[i]) {
return false;
}
}
return actual.length === expected.length;
})();
// 7.3. Other pairs that do not both pass typeof value == "object",
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return actual == expected;
// 7.4. For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical "prototype" property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isUndefinedOrNull (value) {
return value === null || value === undefined;
}
function isArguments (object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv (a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
return false;
// an identical "prototype" property.
if (a.prototype !== b.prototype) return false;
//~~~I've managed to break Object.keys through screwy arguments passing.
// Converting to array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
try{
var ka = _keys(a),
kb = _keys(b),
key, i;
} catch (e) {//happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key] ))
return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected)) {
fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual);
}
};
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, "===", assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as determined by !==.
// assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, "!==", assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (expected instanceof RegExp) {
return expected.test(actual.message || actual);
} else if (actual instanceof expected) {
return true;
} else if (expected.call({}, actual) === true) {
return true;
}
return false;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof expected === 'string') {
message = expected;
expected = null;
}
try {
block();
} catch (e) {
actual = e;
}
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail('Missing expected exception' + message);
}
if (!shouldThrow && expectedException(actual, expected)) {
fail('Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [true].concat(pSlice.call(arguments)));
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [false].concat(pSlice.call(arguments)));
};
assert.ifError = function (err) { if (err) {throw err;}};
})(assert);
(function(exports){
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* Only code on that line will be removed, it's mostly to avoid requiring code
* that is node specific
*/
/**
* Module dependencies
*/
/**
* Creates assertion objects representing the result of an assert call.
* Accepts an object or AssertionError as its argument.
*
* @param {object} obj
* @api public
*/
exports.assertion = function (obj) {
return {
method: obj.method || '',
message: obj.message || (obj.error && obj.error.message) || '',
error: obj.error,
passed: function () {
return !this.error;
},
failed: function () {
return Boolean(this.error);
}
};
};
/**
* Creates an assertion list object representing a group of assertions.
* Accepts an array of assertion objects.
*
* @param {Array} arr
* @param {Number} duration
* @api public
*/
exports.assertionList = function (arr, duration) {
var that = arr || [];
that.failures = function () {
var failures = 0;
for (var i = 0; i < this.length; i += 1) {
if (this[i].failed()) {
failures += 1;
}
}
return failures;
};
that.passes = function () {
return that.length - that.failures();
};
that.duration = duration || 0;
return that;
};
/**
* Create a wrapper function for assert module methods. Executes a callback
* after it's complete with an assertion object representing the result.
*
* @param {Function} callback
* @api private
*/
var assertWrapper = function (callback) {
return function (new_method, assert_method, arity) {
return function () {
var message = arguments[arity - 1];
var a = exports.assertion({method: new_method, message: message});
try {
assert[assert_method].apply(null, arguments);
}
catch (e) {
a.error = e;
}
callback(a);
};
};
};
/**
* Creates the 'test' object that gets passed to every test function.
* Accepts the name of the test function as its first argument, followed by
* the start time in ms, the options object and a callback function.
*
* @param {String} name
* @param {Number} start
* @param {Object} options
* @param {Function} callback
* @api public
*/
exports.test = function (name, start, options, callback) {
var expecting;
var a_list = [];
var wrapAssert = assertWrapper(function (a) {
a_list.push(a);
if (options.log) {
async.nextTick(function () {
options.log(a);
});
}
});
var test = {
done: function (err) {
if (expecting !== undefined && expecting !== a_list.length) {
var e = new Error(
'Expected ' + expecting + ' assertions, ' +
a_list.length + ' ran'
);
var a1 = exports.assertion({method: 'expect', error: e});
a_list.push(a1);
if (options.log) {
async.nextTick(function () {
options.log(a1);
});
}
}
if (err) {
var a2 = exports.assertion({error: err});
a_list.push(a2);
if (options.log) {
async.nextTick(function () {
options.log(a2);
});
}
}
var end = new Date().getTime();
async.nextTick(function () {
var assertion_list = exports.assertionList(a_list, end - start);
options.testDone(name, assertion_list);
callback(null, a_list);
});
},
ok: wrapAssert('ok', 'ok', 2),
same: wrapAssert('same', 'deepEqual', 3),
equals: wrapAssert('equals', 'equal', 3),
expect: function (num) {
expecting = num;
},
_assertion_list: a_list
};
// add all functions from the assert module
for (var k in assert) {
if (assert.hasOwnProperty(k)) {
test[k] = wrapAssert(k, k, assert[k].length);
}
}
return test;
};
/**
* Ensures an options object has all callbacks, adding empty callback functions
* if any are missing.
*
* @param {Object} opt
* @return {Object}
* @api public
*/
exports.options = function (opt) {
var optionalCallback = function (name) {
opt[name] = opt[name] || function () {};
};
optionalCallback('moduleStart');
optionalCallback('moduleDone');
optionalCallback('testStart');
optionalCallback('testReady');
optionalCallback('testDone');
//optionalCallback('log');
// 'done' callback is not optional.
return opt;
};
})(types);
(function(exports){
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* Only code on that line will be removed, it's mostly to avoid requiring code
* that is node specific
*/
/**
* Module dependencies
*/
/**
* Added for browser compatibility
*/
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
var _copy = function (obj) {
var nobj = {};
var keys = _keys(obj);
for (var i = 0; i < keys.length; i += 1) {
nobj[keys[i]] = obj[keys[i]];
}
return nobj;
};
/**
* Runs a test function (fn) from a loaded module. After the test function
* calls test.done(), the callback is executed with an assertionList as its
* second argument.
*
* @param {String} name
* @param {Function} fn
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runTest = function (name, fn, opt, callback) {
var options = types.options(opt);
options.testStart(name);
var start = new Date().getTime();
var test = types.test(name, start, options, callback);
options.testReady(test);
try {
fn(test);
}
catch (e) {
test.done(e);
}
};
/**
* Takes an object containing test functions or other test suites as properties
* and runs each in series. After all tests have completed, the callback is
* called with a list of all assertions as the second argument.
*
* If a name is passed to this function it is prepended to all test and suite
* names that run within it.
*
* @param {String} name
* @param {Object} suite
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runSuite = function (name, suite, opt, callback) {
suite = wrapGroup(suite);
var keys = _keys(suite);
async.concatSeries(keys, function (k, cb) {
var prop = suite[k], _name;
_name = name ? [].concat(name, k) : [k];
_name.toString = function () {
// fallback for old one
return this.join(' - ');
};
if (typeof prop === 'function') {
var in_name = false,
in_specific_test = (_name.toString() === opt.testFullSpec) ? true : false;
for (var i = 0; i < _name.length; i += 1) {
if (_name[i] === opt.testspec) {
in_name = true;
}
}
if ((!opt.testFullSpec || in_specific_test) && (!opt.testspec || in_name)) {
if (opt.moduleStart) {
opt.moduleStart();
}
exports.runTest(_name, suite[k], opt, cb);
}
else {
return cb();
}
}
else {
exports.runSuite(_name, suite[k], opt, cb);
}
}, callback);
};
/**
* Run each exported test function or test suite from a loaded module.
*
* @param {String} name
* @param {Object} mod
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runModule = function (name, mod, opt, callback) {
var options = _copy(types.options(opt));
var _run = false;
var _moduleStart = options.moduleStart;
mod = wrapGroup(mod);
function run_once() {
if (!_run) {
_run = true;
_moduleStart(name);
}
}
options.moduleStart = run_once;
var start = new Date().getTime();
exports.runSuite(null, mod, options, function (err, a_list) {
var end = new Date().getTime();
var assertion_list = types.assertionList(a_list, end - start);
options.moduleDone(name, assertion_list);
if (nodeunit.complete) {
nodeunit.complete(name, assertion_list);
}
callback(null, a_list);
});
};
/**
* Treats an object literal as a list of modules keyed by name. Runs each
* module and finished with calling 'done'. You can think of this as a browser
* safe alternative to runFiles in the nodeunit module.
*
* @param {Object} modules
* @param {Object} opt
* @api public
*/
// TODO: add proper unit tests for this function
exports.runModules = function (modules, opt) {
var all_assertions = [];
var options = types.options(opt);
var start = new Date().getTime();
async.concatSeries(_keys(modules), function (k, cb) {
exports.runModule(k, modules[k], options, cb);
},
function (err, all_assertions) {
var end = new Date().getTime();
options.done(types.assertionList(all_assertions, end - start));
});
};
/**
* Wraps a test function with setUp and tearDown functions.
* Used by testCase.
*
* @param {Function} setUp
* @param {Function} tearDown
* @param {Function} fn
* @api private
*/
var wrapTest = function (setUp, tearDown, fn) {
return function (test) {
var context = {};
if (tearDown) {
var done = test.done;
test.done = function (err) {
try {
tearDown.call(context, function (err2) {
if (err && err2) {
test._assertion_list.push(
types.assertion({error: err})
);
return done(err2);
}
done(err || err2);
});
}
catch (e) {
done(e);
}
};
}
if (setUp) {
setUp.call(context, function (err) {
if (err) {
return test.done(err);
}
fn.call(context, test);
});
}
else {
fn.call(context, test);
}
};
};
/**
* Returns a serial callback from two functions.
*
* @param {Function} funcFirst
* @param {Function} funcSecond
* @api private
*/
var getSerialCallback = function (fns) {
if (!fns.length) {
return null;
}
return function (callback) {
var that = this;
var bound_fns = [];
for (var i = 0, len = fns.length; i < len; i++) {
(function (j) {
bound_fns.push(function () {
return fns[j].apply(that, arguments);
});
})(i);
}
return async.series(bound_fns, callback);
};
};
/**
* Wraps a group of tests with setUp and tearDown functions.
* Used by testCase.
*
* @param {Object} group
* @param {Array} setUps - parent setUp functions
* @param {Array} tearDowns - parent tearDown functions
* @api private
*/
var wrapGroup = function (group, setUps, tearDowns) {
var tests = {};
var setUps = setUps ? setUps.slice(): [];
var tearDowns = tearDowns ? tearDowns.slice(): [];
if (group.setUp) {
setUps.push(group.setUp);
delete group.setUp;
}
if (group.tearDown) {
tearDowns.unshift(group.tearDown);
delete group.tearDown;
}
var keys = _keys(group);
for (var i = 0; i < keys.length; i += 1) {
var k = keys[i];
if (typeof group[k] === 'function') {
tests[k] = wrapTest(
getSerialCallback(setUps),
getSerialCallback(tearDowns),
group[k]
);
}
else if (typeof group[k] === 'object') {
tests[k] = wrapGroup(group[k], setUps, tearDowns);
}
}
return tests;
};
/**
* Backwards compatibility for test suites using old testCase API
*/
exports.testCase = function (suite) {
return suite;
};
})(core);
(function(exports){
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* Only code on that line will be removed, its mostly to avoid requiring code
* that is node specific
*/
/**
* NOTE: this test runner is not listed in index.js because it cannot be
* used with the command-line tool, only inside the browser.
*/
/**
* Reporter info string
*/
exports.info = "Browser-based test reporter";
/**
* Run all tests within each module, reporting the results
*
* @param {Array} files
* @api public
*/
exports.run = function (modules, options, callback) {
var start = new Date().getTime(), div;
options = options || {};
div = options.div || document.body;
function setText(el, txt) {
if ('innerText' in el) {
el.innerText = txt;
}
else if ('textContent' in el){
el.textContent = txt;
}
}
function getOrCreate(tag, id) {
var el = document.getElementById(id);
if (!el) {
el = document.createElement(tag);
el.id = id;
div.appendChild(el);
}
return el;
};
var header = getOrCreate('h1', 'nodeunit-header');
var banner = getOrCreate('h2', 'nodeunit-banner');
var userAgent = getOrCreate('h2', 'nodeunit-userAgent');
var tests = getOrCreate('ol', 'nodeunit-tests');
var result = getOrCreate('p', 'nodeunit-testresult');
setText(userAgent, navigator.userAgent);
nodeunit.runModules(modules, {
moduleStart: function (name) {
/*var mheading = document.createElement('h2');
mheading.innerText = name;
results.appendChild(mheading);
module = document.createElement('ol');
results.appendChild(module);*/
},
testDone: function (name, assertions) {
var test = document.createElement('li');
var strong = document.createElement('strong');
strong.innerHTML = name + ' <b style="color: black;">(' +
'<b class="fail">' + assertions.failures() + '</b>, ' +
'<b class="pass">' + assertions.passes() + '</b>, ' +
assertions.length +
')</b>';
test.className = assertions.failures() ? 'fail': 'pass';
test.appendChild(strong);
var aList = document.createElement('ol');
aList.style.display = 'none';
test.onclick = function () {
var d = aList.style.display;
aList.style.display = (d == 'none') ? 'block': 'none';
};
for (var i=0; i<assertions.length; i++) {
var li = document.createElement('li');
var a = assertions[i];
if (a.failed()) {
li.innerHTML = (a.message || a.method || 'no message') +
'<pre>' + (a.error.stack || a.error) + '</pre>';
li.className = 'fail';
}
else {
li.innerHTML = a.message || a.method || 'no message';
li.className = 'pass';
}
aList.appendChild(li);
}
test.appendChild(aList);
tests.appendChild(test);
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
var failures = assertions.failures();
banner.className = failures ? 'fail': 'pass';
result.innerHTML = 'Tests completed in ' + duration +
' milliseconds.<br/><span class="passed">' +
assertions.passes() + '</span> assertions of ' +
'<span class="all">' + assertions.length + '<span> passed, ' +
assertions.failures() + ' failed.';
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
});
};
})(reporter);
nodeunit = core;
nodeunit.assert = assert;
nodeunit.reporter = reporter;
nodeunit.run = reporter.run;
return nodeunit; })();

View File

@ -1,66 +0,0 @@
nodeunit(1) -- simple node.js unit testing tool
===============================================
## SYNOPSIS
nodeunit [options] <file-or-directory> [<file-or-directory> ...]
## DESCRIPTION
Nodeunit is a simple unit testing tool based on the node.js assert module.
* Simple to use
* Just export the tests from a module
* Helps you avoid common pitfalls when testing asynchronous code
* Easy to add test cases with setUp and tearDown functions if you wish
* Allows the use of mocks and stubs
## OPTIONS
__--config FILE__:
Load config options from a JSON file, allows the customisation
of color schemes for the default test reporter etc.
See bin/nodeunit.json for current available options.
__--reporter FILE__:
You can set the test reporter to a custom module or on of the modules
in nodeunit/lib/reporters, when omitted, the default test runner is used.
__--list-reporters__:
List available build-in reporters.
__-t testName__:
Run specifc test only.
__-f fullTestName__:
Run specific test only. fullTestName is built so: "outerGroup - .. - innerGroup - testName".
__-h__, __--help__:
Display the help and exit.
__-v__, __--version__:
Output version information and exit.
__<file-or-directory>__:
You can run nodeunit on specific files or on all *\*.js* files inside
a directory.
## AUTHORS
Written by Caolan McMahon and other nodeunit contributors.
Contributors list: <http://github.com/caolan/nodeunit/contributors>.
## REPORTING BUGS
Report nodeunit bugs to <http://github.com/caolan/nodeunit/issues>.
## COPYRIGHT
Copyright © 2010 Caolan McMahon.
Nodeunit has been released under the MIT license:
<http://github.com/caolan/nodeunit/raw/master/LICENSE>.
## SEE ALSO
node(1)

View File

@ -1,2034 +0,0 @@
/*!
* Nodeunit
* https://github.com/caolan/nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* json2.js
* http://www.JSON.org/json2.js
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
nodeunit = (function(){
/*
http://www.JSON.org/json2.js
2010-11-17
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
*/
/*jslint evil: true, strict: false, regexp: false */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
var JSON = {};
(function () {
"use strict";
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/
.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());
var assert = this.assert = {};
var types = {};
var core = {};
var nodeunit = {};
var reporter = {};
/*global setTimeout: false, console: false */
(function () {
var async = {};
// global on the server, window in the browser
var root = this,
previous_async = root.async;
if (typeof module !== 'undefined' && module.exports) {
module.exports = async;
}
else {
root.async = async;
}
async.noConflict = function () {
root.async = previous_async;
return async;
};
//// cross-browser compatiblity functions ////
var _forEach = function (arr, iterator) {
if (arr.forEach) {
return arr.forEach(iterator);
}
for (var i = 0; i < arr.length; i += 1) {
iterator(arr[i], i, arr);
}
};
var _map = function (arr, iterator) {
if (arr.map) {
return arr.map(iterator);
}
var results = [];
_forEach(arr, function (x, i, a) {
results.push(iterator(x, i, a));
});
return results;
};
var _reduce = function (arr, iterator, memo) {
if (arr.reduce) {
return arr.reduce(iterator, memo);
}
_forEach(arr, function (x, i, a) {
memo = iterator(memo, x, i, a);
});
return memo;
};
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
var _indexOf = function (arr, item) {
if (arr.indexOf) {
return arr.indexOf(item);
}
for (var i = 0; i < arr.length; i += 1) {
if (arr[i] === item) {
return i;
}
}
return -1;
};
//// exported async module functions ////
//// nextTick implementation with browser-compatible fallback ////
if (typeof process === 'undefined' || !(process.nextTick)) {
async.nextTick = function (fn) {
setTimeout(fn, 0);
};
}
else {
async.nextTick = process.nextTick;
}
async.forEach = function (arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
_forEach(arr, function (x) {
iterator(x, function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback();
}
}
});
});
};
async.forEachSeries = function (arr, iterator, callback) {
if (!arr.length) {
return callback();
}
var completed = 0;
var iterate = function () {
iterator(arr[completed], function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
completed += 1;
if (completed === arr.length) {
callback();
}
else {
iterate();
}
}
});
};
iterate();
};
var doParallel = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.forEach].concat(args));
};
};
var doSeries = function (fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return fn.apply(null, [async.forEachSeries].concat(args));
};
};
var _asyncMap = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (err, v) {
results[x.index] = v;
callback(err);
});
}, function (err) {
callback(err, results);
});
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);
// reduce only has a series version, as doing reduce in parallel won't
// work in many situations.
async.reduce = function (arr, memo, iterator, callback) {
async.forEachSeries(arr, function (x, callback) {
iterator(memo, x, function (err, v) {
memo = v;
callback(err);
});
}, function (err) {
callback(err, memo);
});
};
// inject alias
async.inject = async.reduce;
// foldl alias
async.foldl = async.reduce;
async.reduceRight = function (arr, memo, iterator, callback) {
var reversed = _map(arr, function (x) {
return x;
}).reverse();
async.reduce(reversed, memo, iterator, callback);
};
// foldr alias
async.foldr = async.reduceRight;
var _filter = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.filter = doParallel(_filter);
async.filterSeries = doSeries(_filter);
// select alias
async.select = async.filter;
async.selectSeries = async.filterSeries;
var _reject = function (eachfn, arr, iterator, callback) {
var results = [];
arr = _map(arr, function (x, i) {
return {index: i, value: x};
});
eachfn(arr, function (x, callback) {
iterator(x.value, function (v) {
if (!v) {
results.push(x);
}
callback();
});
}, function (err) {
callback(_map(results.sort(function (a, b) {
return a.index - b.index;
}), function (x) {
return x.value;
}));
});
};
async.reject = doParallel(_reject);
async.rejectSeries = doSeries(_reject);
var _detect = function (eachfn, arr, iterator, main_callback) {
eachfn(arr, function (x, callback) {
iterator(x, function (result) {
if (result) {
main_callback(x);
}
else {
callback();
}
});
}, function (err) {
main_callback();
});
};
async.detect = doParallel(_detect);
async.detectSeries = doSeries(_detect);
async.some = function (arr, iterator, main_callback) {
async.forEach(arr, function (x, callback) {
iterator(x, function (v) {
if (v) {
main_callback(true);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(false);
});
};
// any alias
async.any = async.some;
async.every = function (arr, iterator, main_callback) {
async.forEach(arr, function (x, callback) {
iterator(x, function (v) {
if (!v) {
main_callback(false);
main_callback = function () {};
}
callback();
});
}, function (err) {
main_callback(true);
});
};
// all alias
async.all = async.every;
async.sortBy = function (arr, iterator, callback) {
async.map(arr, function (x, callback) {
iterator(x, function (err, criteria) {
if (err) {
callback(err);
}
else {
callback(null, {value: x, criteria: criteria});
}
});
}, function (err, results) {
if (err) {
return callback(err);
}
else {
var fn = function (left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
};
callback(null, _map(results.sort(fn), function (x) {
return x.value;
}));
}
});
};
async.auto = function (tasks, callback) {
callback = callback || function () {};
var keys = _keys(tasks);
if (!keys.length) {
return callback(null);
}
var completed = [];
var listeners = [];
var addListener = function (fn) {
listeners.unshift(fn);
};
var removeListener = function (fn) {
for (var i = 0; i < listeners.length; i += 1) {
if (listeners[i] === fn) {
listeners.splice(i, 1);
return;
}
}
};
var taskComplete = function () {
_forEach(listeners, function (fn) {
fn();
});
};
addListener(function () {
if (completed.length === keys.length) {
callback(null);
}
});
_forEach(keys, function (k) {
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
var taskCallback = function (err) {
if (err) {
callback(err);
// stop subsequent errors hitting callback multiple times
callback = function () {};
}
else {
completed.push(k);
taskComplete();
}
};
var requires = task.slice(0, Math.abs(task.length - 1)) || [];
var ready = function () {
return _reduce(requires, function (a, x) {
return (a && _indexOf(completed, x) !== -1);
}, true);
};
if (ready()) {
task[task.length - 1](taskCallback);
}
else {
var listener = function () {
if (ready()) {
removeListener(listener);
task[task.length - 1](taskCallback);
}
};
addListener(listener);
}
});
};
async.waterfall = function (tasks, callback) {
if (!tasks.length) {
return callback();
}
callback = callback || function () {};
var wrapIterator = function (iterator) {
return function (err) {
if (err) {
callback(err);
callback = function () {};
}
else {
var args = Array.prototype.slice.call(arguments, 1);
var next = iterator.next();
if (next) {
args.push(wrapIterator(next));
}
else {
args.push(callback);
}
async.nextTick(function () {
iterator.apply(null, args);
});
}
};
};
wrapIterator(async.iterator(tasks))();
};
async.parallel = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.map(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args || null);
});
}
}, callback);
}
else {
var results = {};
async.forEach(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.series = function (tasks, callback) {
callback = callback || function () {};
if (tasks.constructor === Array) {
async.mapSeries(tasks, function (fn, callback) {
if (fn) {
fn(function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
callback.call(null, err, args || null);
});
}
}, callback);
}
else {
var results = {};
async.forEachSeries(_keys(tasks), function (k, callback) {
tasks[k](function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (args.length <= 1) {
args = args[0];
}
results[k] = args;
callback(err);
});
}, function (err) {
callback(err, results);
});
}
};
async.iterator = function (tasks) {
var makeCallback = function (index) {
var fn = function () {
if (tasks.length) {
tasks[index].apply(null, arguments);
}
return fn.next();
};
fn.next = function () {
return (index < tasks.length - 1) ? makeCallback(index + 1): null;
};
return fn;
};
return makeCallback(0);
};
async.apply = function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
return fn.apply(
null, args.concat(Array.prototype.slice.call(arguments))
);
};
};
var _concat = function (eachfn, arr, fn, callback) {
var r = [];
eachfn(arr, function (x, cb) {
fn(x, function (err, y) {
r = r.concat(y || []);
cb(err);
});
}, function (err) {
callback(err, r);
});
};
async.concat = doParallel(_concat);
async.concatSeries = doSeries(_concat);
async.whilst = function (test, iterator, callback) {
if (test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.whilst(test, iterator, callback);
});
}
else {
callback();
}
};
async.until = function (test, iterator, callback) {
if (!test()) {
iterator(function (err) {
if (err) {
return callback(err);
}
async.until(test, iterator, callback);
});
}
else {
callback();
}
};
async.queue = function (worker, concurrency) {
var workers = 0;
var tasks = [];
var q = {
concurrency: concurrency,
push: function (data, callback) {
tasks.push({data: data, callback: callback});
async.nextTick(q.process);
},
process: function () {
if (workers < q.concurrency && tasks.length) {
var task = tasks.splice(0, 1)[0];
workers += 1;
worker(task.data, function () {
workers -= 1;
if (task.callback) {
task.callback.apply(task, arguments);
}
q.process();
});
}
},
length: function () {
return tasks.length;
}
};
return q;
};
var _console_fn = function (name) {
return function (fn) {
var args = Array.prototype.slice.call(arguments, 1);
fn.apply(null, args.concat([function (err) {
var args = Array.prototype.slice.call(arguments, 1);
if (typeof console !== 'undefined') {
if (err) {
if (console.error) {
console.error(err);
}
}
else if (console[name]) {
_forEach(args, function (x) {
console[name](x);
});
}
}
}]));
};
};
async.log = _console_fn('log');
async.dir = _console_fn('dir');
/*async.info = _console_fn('info');
async.warn = _console_fn('warn');
async.error = _console_fn('error');*/
async.memoize = function (fn, hasher) {
var memo = {};
hasher = hasher || function (x) {
return x;
};
return function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
var key = hasher.apply(null, args);
if (key in memo) {
callback.apply(null, memo[key]);
}
else {
fn.apply(null, args.concat([function () {
memo[key] = arguments;
callback.apply(null, arguments);
}]));
}
};
};
}());
(function(exports){
/**
* This file is based on the node.js assert module, but with some small
* changes for browser-compatibility
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
*/
/**
* Added for browser compatibility
*/
var _keys = function(obj){
if(Object.keys) return Object.keys(obj);
if (typeof obj != 'object' && typeof obj != 'function') {
throw new TypeError('-');
}
var keys = [];
for(var k in obj){
if(obj.hasOwnProperty(k)) keys.push(k);
}
return keys;
};
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var pSlice = Array.prototype.slice;
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = exports;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({message: message, actual: actual, expected: expected})
assert.AssertionError = function AssertionError (options) {
this.name = "AssertionError";
this.message = options.message;
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
}
};
// code from util.inherits in node
assert.AssertionError.super_ = Error;
// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call
// TODO: test what effect this may have
var ctor = function () { this.constructor = assert.AssertionError; };
ctor.prototype = Error.prototype;
assert.AssertionError.prototype = new ctor();
assert.AssertionError.prototype.toString = function() {
if (this.message) {
return [this.name+":", this.message].join(' ');
} else {
return [ this.name+":"
, JSON.stringify(this.expected )
, this.operator
, JSON.stringify(this.actual)
].join(" ");
}
};
// assert.AssertionError instanceof Error
assert.AssertionError.__proto__ = Error.prototype;
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
assert.ok = function ok(value, message) {
if (!!!value) fail(value, true, message, "==", assert.ok);
};
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, "==", assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, "!=", assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected)) {
fail(actual, expected, message, "deepEqual", assert.deepEqual);
}
};
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();
// 7.3. Other pairs that do not both pass typeof value == "object",
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return actual == expected;
// 7.4. For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical "prototype" property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isUndefinedOrNull (value) {
return value === null || value === undefined;
}
function isArguments (object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv (a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
return false;
// an identical "prototype" property.
if (a.prototype !== b.prototype) return false;
//~~~I've managed to break Object.keys through screwy arguments passing.
// Converting to array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
try{
var ka = _keys(a),
kb = _keys(b),
key, i;
} catch (e) {//happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key] ))
return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected)) {
fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual);
}
};
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, "===", assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as determined by !==.
// assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, "!==", assert.notStrictEqual);
}
};
function _throws (shouldThrow, block, err, message) {
var exception = null,
threw = false,
typematters = true;
message = message || "";
//handle optional arguments
if (arguments.length == 3) {
if (typeof(err) == "string") {
message = err;
typematters = false;
}
} else if (arguments.length == 2) {
typematters = false;
}
try {
block();
} catch (e) {
threw = true;
exception = e;
}
if (shouldThrow && !threw) {
fail( "Missing expected exception"
+ (err && err.name ? " ("+err.name+")." : '.')
+ (message ? " " + message : "")
);
}
if (!shouldThrow && threw && typematters && exception instanceof err) {
fail( "Got unwanted exception"
+ (err && err.name ? " ("+err.name+")." : '.')
+ (message ? " " + message : "")
);
}
if ((shouldThrow && threw && typematters && !(exception instanceof err)) ||
(!shouldThrow && threw)) {
throw exception;
}
};
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [true].concat(pSlice.call(arguments)));
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [false].concat(pSlice.call(arguments)));
};
assert.ifError = function (err) { if (err) {throw err;}};
})(assert);
(function(exports){
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
* Only code on that line will be removed, its mostly to avoid requiring code
* that is node specific
*/
/**
* Module dependencies
*/
//var assert = require('./assert'), //@REMOVE_LINE_FOR_BROWSER
// async = require('../deps/async'); //@REMOVE_LINE_FOR_BROWSER
/**
* Creates assertion objects representing the result of an assert call.
* Accepts an object or AssertionError as its argument.
*
* @param {object} obj
* @api public
*/
exports.assertion = function (obj) {
return {
method: obj.method || '',
message: obj.message || (obj.error && obj.error.message) || '',
error: obj.error,
passed: function () {
return !this.error;
},
failed: function () {
return Boolean(this.error);
}
};
};
/**
* Creates an assertion list object representing a group of assertions.
* Accepts an array of assertion objects.
*
* @param {Array} arr
* @param {Number} duration
* @api public
*/
exports.assertionList = function (arr, duration) {
var that = arr || [];
that.failures = function () {
var failures = 0;
for (var i = 0; i < this.length; i += 1) {
if (this[i].failed()) {
failures += 1;
}
}
return failures;
};
that.passes = function () {
return that.length - that.failures();
};
that.duration = duration || 0;
return that;
};
/**
* Create a wrapper function for assert module methods. Executes a callback
* after the it's complete with an assertion object representing the result.
*
* @param {Function} callback
* @api private
*/
var assertWrapper = function (callback) {
return function (new_method, assert_method, arity) {
return function () {
var message = arguments[arity - 1];
var a = exports.assertion({method: new_method, message: message});
try {
assert[assert_method].apply(null, arguments);
}
catch (e) {
a.error = e;
}
callback(a);
};
};
};
/**
* Creates the 'test' object that gets passed to every test function.
* Accepts the name of the test function as its first argument, followed by
* the start time in ms, the options object and a callback function.
*
* @param {String} name
* @param {Number} start
* @param {Object} options
* @param {Function} callback
* @api public
*/
exports.test = function (name, start, options, callback) {
var expecting;
var a_list = [];
var wrapAssert = assertWrapper(function (a) {
a_list.push(a);
if (options.log) {
async.nextTick(function () {
options.log(a);
});
}
});
var test = {
done: function (err) {
if (expecting !== undefined && expecting !== a_list.length) {
var e = new Error(
'Expected ' + expecting + ' assertions, ' +
a_list.length + ' ran'
);
var a1 = exports.assertion({method: 'expect', error: e});
a_list.push(a1);
if (options.log) {
async.nextTick(function () {
options.log(a1);
});
}
}
if (err) {
var a2 = exports.assertion({error: err});
a_list.push(a2);
if (options.log) {
async.nextTick(function () {
options.log(a2);
});
}
}
var end = new Date().getTime();
async.nextTick(function () {
var assertion_list = exports.assertionList(a_list, end - start);
options.testDone(name, assertion_list);
callback(null, a_list);
});
},
ok: wrapAssert('ok', 'ok', 2),
same: wrapAssert('same', 'deepEqual', 3),
equals: wrapAssert('equals', 'equal', 3),
expect: function (num) {
expecting = num;
},
_assertion_list: a_list
};
// add all functions from the assert module
for (var k in assert) {
if (assert.hasOwnProperty(k)) {
test[k] = wrapAssert(k, k, assert[k].length);
}
}
return test;
};
/**
* Ensures an options object has all callbacks, adding empty callback functions
* if any are missing.
*
* @param {Object} opt
* @return {Object}
* @api public
*/
exports.options = function (opt) {
var optionalCallback = function (name) {
opt[name] = opt[name] || function () {};
};
optionalCallback('moduleStart');
optionalCallback('moduleDone');
optionalCallback('testStart');
optionalCallback('testDone');
//optionalCallback('log');
// 'done' callback is not optional.
return opt;
};
})(types);
(function(exports){
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
* Only code on that line will be removed, its mostly to avoid requiring code
* that is node specific
*/
/**
* Module dependencies
*/
//var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER
// types = require('./types'); //@REMOVE_LINE_FOR_BROWSER
/**
* Added for browser compatibility
*/
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
var _copy = function (obj) {
var nobj = {};
var keys = _keys(obj);
for (var i = 0; i < keys.length; i += 1) {
nobj[keys[i]] = obj[keys[i]];
}
return nobj;
};
/**
* Runs a test function (fn) from a loaded module. After the test function
* calls test.done(), the callback is executed with an assertionList as its
* second argument.
*
* @param {String} name
* @param {Function} fn
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runTest = function (name, fn, opt, callback) {
var options = types.options(opt);
options.testStart(name);
var start = new Date().getTime();
var test = types.test(name, start, options, callback);
try {
fn(test);
}
catch (e) {
test.done(e);
}
};
/**
* Takes an object containing test functions or other test suites as properties
* and runs each in series. After all tests have completed, the callback is
* called with a list of all assertions as the second argument.
*
* If a name is passed to this function it is prepended to all test and suite
* names that run within it.
*
* @param {String} name
* @param {Object} suite
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runSuite = function (name, suite, opt, callback) {
var keys = _keys(suite);
async.concatSeries(keys, function (k, cb) {
var prop = suite[k], _name;
_name = name ? [].concat(name, k) : [k];
_name.toString = function () {
// fallback for old one
return this.join(' - ');
};
if (typeof prop === 'function') {
var in_name = false;
for (var i = 0; i < _name.length; i += 1) {
if (_name[i] === opt.testspec) {
in_name = true;
}
}
if (!opt.testspec || in_name) {
if (opt.moduleStart) {
opt.moduleStart();
}
exports.runTest(_name, suite[k], opt, cb);
}
else {
return cb();
}
}
else {
exports.runSuite(_name, suite[k], opt, cb);
}
}, callback);
};
/**
* Run each exported test function or test suite from a loaded module.
*
* @param {String} name
* @param {Object} mod
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runModule = function (name, mod, opt, callback) {
var options = _copy(types.options(opt));
var _run = false;
var _moduleStart = options.moduleStart;
function run_once() {
if (!_run) {
_run = true;
_moduleStart(name);
}
}
options.moduleStart = run_once;
var start = new Date().getTime();
exports.runSuite(null, mod, options, function (err, a_list) {
var end = new Date().getTime();
var assertion_list = types.assertionList(a_list, end - start);
options.moduleDone(name, assertion_list);
callback(null, a_list);
});
};
/**
* Treats an object literal as a list of modules keyed by name. Runs each
* module and finished with calling 'done'. You can think of this as a browser
* safe alternative to runFiles in the nodeunit module.
*
* @param {Object} modules
* @param {Object} opt
* @api public
*/
// TODO: add proper unit tests for this function
exports.runModules = function (modules, opt) {
var all_assertions = [];
var options = types.options(opt);
var start = new Date().getTime();
async.concatSeries(_keys(modules), function (k, cb) {
exports.runModule(k, modules[k], options, cb);
},
function (err, all_assertions) {
var end = new Date().getTime();
options.done(types.assertionList(all_assertions, end - start));
});
};
/**
* Wraps a test function with setUp and tearDown functions.
* Used by testCase.
*
* @param {Function} setUp
* @param {Function} tearDown
* @param {Function} fn
* @api private
*/
var wrapTest = function (setUp, tearDown, fn) {
return function (test) {
var context = {};
if (tearDown) {
var done = test.done;
test.done = function (err) {
try {
tearDown.call(context, function (err2) {
if (err && err2) {
test._assertion_list.push(
types.assertion({error: err})
);
return done(err2);
}
done(err || err2);
});
}
catch (e) {
done(e);
}
};
}
if (setUp) {
setUp.call(context, function (err) {
if (err) {
return test.done(err);
}
fn.call(context, test);
});
}
else {
fn.call(context, test);
}
};
};
/**
* Wraps a group of tests with setUp and tearDown functions.
* Used by testCase.
*
* @param {Function} setUp
* @param {Function} tearDown
* @param {Object} group
* @api private
*/
var wrapGroup = function (setUp, tearDown, group) {
var tests = {};
var keys = _keys(group);
for (var i = 0; i < keys.length; i += 1) {
var k = keys[i];
if (typeof group[k] === 'function') {
tests[k] = wrapTest(setUp, tearDown, group[k]);
}
else if (typeof group[k] === 'object') {
tests[k] = wrapGroup(setUp, tearDown, group[k]);
}
}
return tests;
};
/**
* Utility for wrapping a suite of test functions with setUp and tearDown
* functions.
*
* @param {Object} suite
* @return {Object}
* @api public
*/
exports.testCase = function (suite) {
var setUp = suite.setUp;
var tearDown = suite.tearDown;
delete suite.setUp;
delete suite.tearDown;
return wrapGroup(setUp, tearDown, suite);
};
})(core);
(function(exports){
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
* Only code on that line will be removed, its mostly to avoid requiring code
* that is node specific
*/
/**
* NOTE: this test runner is not listed in index.js because it cannot be
* used with the command-line tool, only inside the browser.
*/
/**
* Reporter info string
*/
exports.info = "Browser-based test reporter";
/**
* Run all tests within each module, reporting the results
*
* @param {Array} files
* @api public
*/
exports.run = function (modules, options) {
var start = new Date().getTime();
function setText(el, txt) {
if ('innerText' in el) {
el.innerText = txt;
}
else if ('textContent' in el){
el.textContent = txt;
}
}
function getOrCreate(tag, id) {
var el = document.getElementById(id);
if (!el) {
el = document.createElement(tag);
el.id = id;
document.body.appendChild(el);
}
return el;
};
var header = getOrCreate('h1', 'nodeunit-header');
var banner = getOrCreate('h2', 'nodeunit-banner');
var userAgent = getOrCreate('h2', 'nodeunit-userAgent');
var tests = getOrCreate('ol', 'nodeunit-tests');
var result = getOrCreate('p', 'nodeunit-testresult');
setText(userAgent, navigator.userAgent);
nodeunit.runModules(modules, {
moduleStart: function (name) {
/*var mheading = document.createElement('h2');
mheading.innerText = name;
results.appendChild(mheading);
module = document.createElement('ol');
results.appendChild(module);*/
},
testDone: function (name, assertions) {
var test = document.createElement('li');
var strong = document.createElement('strong');
strong.innerHTML = name + ' <b style="color: black;">(' +
'<b class="fail">' + assertions.failures() + '</b>, ' +
'<b class="pass">' + assertions.passes() + '</b>, ' +
assertions.length +
')</b>';
test.className = assertions.failures() ? 'fail': 'pass';
test.appendChild(strong);
var aList = document.createElement('ol');
aList.style.display = 'none';
test.onclick = function () {
var d = aList.style.display;
aList.style.display = (d == 'none') ? 'block': 'none';
};
for (var i=0; i<assertions.length; i++) {
var li = document.createElement('li');
var a = assertions[i];
if (a.failed()) {
li.innerHTML = (a.message || a.method || 'no message') +
'<pre>' + (a.error.stack || a.error) + '</pre>';
li.className = 'fail';
}
else {
li.innerHTML = a.message || a.method || 'no message';
li.className = 'pass';
}
aList.appendChild(li);
}
test.appendChild(aList);
tests.appendChild(test);
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
var failures = assertions.failures();
banner.className = failures ? 'fail': 'pass';
result.innerHTML = 'Tests completed in ' + duration +
' milliseconds.<br/><span class="passed">' +
assertions.passes() + '</span> assertions of ' +
'<span class="all">' + assertions.length + '<span> passed, ' +
assertions.failures() + ' failed.';
}
});
};
})(reporter);
nodeunit = core;
nodeunit.assert = assert;
nodeunit.reporter = reporter;
nodeunit.run = reporter.run;
return nodeunit; })();

View File

@ -1,12 +0,0 @@
this.suite1 = {
'test one': function (test) {
test.ok(true, 'everythings ok');
setTimeout(function () {
test.done();
}, 10);
},
'apples and oranges': function (test) {
test.equal('apples', 'oranges', 'comparing apples and oranges');
test.done();
}
};

View File

@ -1,13 +0,0 @@
this.suite2 = {
'another test': function (test) {
setTimeout(function () {
// lots of assertions
test.ok(true, 'everythings ok');
test.ok(true, 'everythings ok');
test.ok(true, 'everythings ok');
test.ok(true, 'everythings ok');
test.ok(true, 'everythings ok');
test.done();
}, 10);
}
};

View File

@ -1,7 +0,0 @@
this.suite3 = {
'test for ie6,7,8': function (test) {
test.deepEqual(["test"], ["test"]);
test.notDeepEqual(["a"], ["b"]);
test.done();
}
};

View File

@ -1,18 +0,0 @@
<html>
<head>
<title>Example tests</title>
<script src="nodeunit.js"></script>
<script src="suite1.js"></script>
<script src="suite2.js"></script>
<script src="suite3.js"></script>
</head>
<body>
<script>
nodeunit.run({
'suite1': suite1,
'suite2': suite2,
'suite3': suite3
});
</script>
</body>
</html>

View File

@ -1,94 +0,0 @@
var testCase = require('nodeunit').testCase;
/*
This is an example test suite to demonstrate the nested test reporter.
Run with --reporter nested, e.g.,
nodeunit --reporter nested nested_reporter_test.unit.js
The test output should be something like:
nested_reporter_test.unit.js
Test 0.1 (pass)
TC 1
TC 1.1
Test 1.1.1 (pass)
TC 2
TC 2.1
TC 2.1.1
Test 2.1.1.1 (pass)
Test 2.1.1.2 (pass)
TC 2.2.1
Test 2.2.1.1 (pass)
TC 2.2.1.1
Test 2.2.1.1.1 (pass)
Test 2.2.1.2 (pass)
TC 3
TC 3.1
TC 3.1.1
Test 3.1.1.1 (should fail) (fail)
AssertionError: false == true
// stack trace here.
FAILURES: 1/8 assertions failed (6ms)
*/
module.exports = testCase({
"Test 0.1": function(test) {
test.ok(true);
test.done();
},
"TC 1": testCase({
"TC 1.1": testCase({
"Test 1.1.1": function(test) {
test.ok(true);
test.done();
}
})
}),
"TC 2": testCase({
"TC 2.1": testCase({
"TC 2.1.1": testCase({
"Test 2.1.1.1": function(test) {
test.ok(true);
test.done();
},
"Test 2.1.1.2": function(test) {
test.ok(true);
test.done();
}
}),
"TC 2.2.1": testCase({
"Test 2.2.1.1": function(test) {
test.ok(true);
test.done();
},
"TC 2.2.1.1": testCase({
"Test 2.2.1.1.1": function(test) {
test.ok(true);
test.done();
},
}),
"Test 2.2.1.2": function(test) {
test.ok(true);
test.done();
}
})
})
}),
"TC 3": testCase({
"TC 3.1": testCase({
"TC 3.1.1": testCase({
"Test 3.1.1.1 (should fail)": function(test) {
test.ok(false);
test.done();
}
})
})
})
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,3 +0,0 @@
// This file is just added for convenience so this repository can be
// directly checked out into a project's deps folder
module.exports = require('./lib/nodeunit');

View File

@ -1,354 +0,0 @@
/**
* This file is based on the node.js assert module, but with some small
* changes for browser-compatibility
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
*/
/**
* Added for browser compatibility
*/
var _keys = function(obj){
if(Object.keys) return Object.keys(obj);
if (typeof obj != 'object' && typeof obj != 'function') {
throw new TypeError('-');
}
var keys = [];
for(var k in obj){
if(obj.hasOwnProperty(k)) keys.push(k);
}
return keys;
};
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
//
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
//
// Originally from narwhal.js (http://narwhaljs.org)
// Copyright (c) 2009 Thomas Robinson <280north.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the 'Software'), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var pSlice = Array.prototype.slice;
// 1. The assert module provides functions that throw
// AssertionError's when particular conditions are not met. The
// assert module must conform to the following interface.
var assert = exports;
// 2. The AssertionError is defined in assert.
// new assert.AssertionError({message: message, actual: actual, expected: expected})
assert.AssertionError = function AssertionError (options) {
this.name = "AssertionError";
this.message = options.message;
this.actual = options.actual;
this.expected = options.expected;
this.operator = options.operator;
var stackStartFunction = options.stackStartFunction || fail;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, stackStartFunction);
}
};
// code from util.inherits in node
assert.AssertionError.super_ = Error;
// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call
// TODO: test what effect this may have
var ctor = function () { this.constructor = assert.AssertionError; };
ctor.prototype = Error.prototype;
assert.AssertionError.prototype = new ctor();
assert.AssertionError.prototype.toString = function() {
if (this.message) {
return [this.name+":", this.message].join(' ');
} else {
return [ this.name+":"
, typeof this.expected !== 'undefined' ? JSON.stringify(this.expected) : 'undefined'
, this.operator
, typeof this.actual !== 'undefined' ? JSON.stringify(this.actual) : 'undefined'
].join(" ");
}
};
// assert.AssertionError instanceof Error
assert.AssertionError.__proto__ = Error.prototype;
// At present only the three keys mentioned above are used and
// understood by the spec. Implementations or sub modules can pass
// other keys to the AssertionError's constructor - they will be
// ignored.
// 3. All of the following functions must throw an AssertionError
// when a corresponding condition is not met, with a message that
// may be undefined if not provided. All assertion methods provide
// both the actual and expected values to the assertion error for
// display purposes.
function fail(actual, expected, message, operator, stackStartFunction) {
throw new assert.AssertionError({
message: message,
actual: actual,
expected: expected,
operator: operator,
stackStartFunction: stackStartFunction
});
}
// EXTENSION! allows for well behaved errors defined elsewhere.
assert.fail = fail;
// 4. Pure assertion tests whether a value is truthy, as determined
// by !!guard.
// assert.ok(guard, message_opt);
// This statement is equivalent to assert.equal(true, guard,
// message_opt);. To test strictly for the value true, use
// assert.strictEqual(true, guard, message_opt);.
assert.ok = function ok(value, message) {
if (!!!value) fail(value, true, message, "==", assert.ok);
};
// 5. The equality assertion tests shallow, coercive equality with
// ==.
// assert.equal(actual, expected, message_opt);
assert.equal = function equal(actual, expected, message) {
if (actual != expected) fail(actual, expected, message, "==", assert.equal);
};
// 6. The non-equality assertion tests for whether two objects are not equal
// with != assert.notEqual(actual, expected, message_opt);
assert.notEqual = function notEqual(actual, expected, message) {
if (actual == expected) {
fail(actual, expected, message, "!=", assert.notEqual);
}
};
// 7. The equivalence assertion tests a deep equality relation.
// assert.deepEqual(actual, expected, message_opt);
assert.deepEqual = function deepEqual(actual, expected, message) {
if (!_deepEqual(actual, expected)) {
fail(actual, expected, message, "deepEqual", assert.deepEqual);
}
};
var Buffer = null;
if (typeof require !== 'undefined' && typeof process !== 'undefined') {
try {
Buffer = require('buffer').Buffer;
}
catch (e) {
// May be a CommonJS environment other than Node.js
Buffer = null;
}
}
function _deepEqual(actual, expected) {
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
// 7.2. If the expected value is a Date object, the actual value is
// equivalent if it is also a Date object that refers to the same time.
} else if (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();
// 7.2.1 If the expcted value is a RegExp object, the actual value is
// equivalent if it is also a RegExp object that refers to the same source and options
} else if (actual instanceof RegExp && expected instanceof RegExp) {
return actual.source === expected.source &&
actual.global === expected.global &&
actual.ignoreCase === expected.ignoreCase &&
actual.multiline === expected.multiline;
} else if (Buffer && actual instanceof Buffer && expected instanceof Buffer) {
return (function() {
var i, len;
for (i = 0, len = expected.length; i < len; i++) {
if (actual[i] !== expected[i]) {
return false;
}
}
return actual.length === expected.length;
})();
// 7.3. Other pairs that do not both pass typeof value == "object",
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return actual == expected;
// 7.4. For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical "prototype" property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected);
}
}
function isUndefinedOrNull (value) {
return value === null || value === undefined;
}
function isArguments (object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
}
function objEquiv (a, b) {
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
return false;
// an identical "prototype" property.
if (a.prototype !== b.prototype) return false;
//~~~I've managed to break Object.keys through screwy arguments passing.
// Converting to array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return _deepEqual(a, b);
}
try{
var ka = _keys(a),
kb = _keys(b),
key, i;
} catch (e) {//happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!_deepEqual(a[key], b[key] ))
return false;
}
return true;
}
// 8. The non-equivalence assertion tests for any deep inequality.
// assert.notDeepEqual(actual, expected, message_opt);
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
if (_deepEqual(actual, expected)) {
fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual);
}
};
// 9. The strict equality assertion tests strict equality, as determined by ===.
// assert.strictEqual(actual, expected, message_opt);
assert.strictEqual = function strictEqual(actual, expected, message) {
if (actual !== expected) {
fail(actual, expected, message, "===", assert.strictEqual);
}
};
// 10. The strict non-equality assertion tests for strict inequality, as determined by !==.
// assert.notStrictEqual(actual, expected, message_opt);
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
if (actual === expected) {
fail(actual, expected, message, "!==", assert.notStrictEqual);
}
};
function expectedException(actual, expected) {
if (!actual || !expected) {
return false;
}
if (expected instanceof RegExp) {
return expected.test(actual.message || actual);
} else if (actual instanceof expected) {
return true;
} else if (expected.call({}, actual) === true) {
return true;
}
return false;
}
function _throws(shouldThrow, block, expected, message) {
var actual;
if (typeof expected === 'string') {
message = expected;
expected = null;
}
try {
block();
} catch (e) {
actual = e;
}
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
(message ? ' ' + message : '.');
if (shouldThrow && !actual) {
fail('Missing expected exception' + message);
}
if (!shouldThrow && expectedException(actual, expected)) {
fail('Got unwanted exception' + message);
}
if ((shouldThrow && actual && expected &&
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
throw actual;
}
}
// 11. Expected to throw an error:
// assert.throws(block, Error_opt, message_opt);
assert.throws = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [true].concat(pSlice.call(arguments)));
};
// EXTENSION! This is annoying to write outside this module.
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
_throws.apply(this, [false].concat(pSlice.call(arguments)));
};
assert.ifError = function (err) { if (err) {throw err;}};

View File

@ -1,319 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
* Only code on that line will be removed, it's mostly to avoid requiring code
* that is node specific
*/
/**
* Module dependencies
*/
var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER
nodeunit = require('./nodeunit'), //@REMOVE_LINE_FOR_BROWSER
types = require('./types'); //@REMOVE_LINE_FOR_BROWSER
/**
* Added for browser compatibility
*/
var _keys = function (obj) {
if (Object.keys) {
return Object.keys(obj);
}
var keys = [];
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
keys.push(k);
}
}
return keys;
};
var _copy = function (obj) {
var nobj = {};
var keys = _keys(obj);
for (var i = 0; i < keys.length; i += 1) {
nobj[keys[i]] = obj[keys[i]];
}
return nobj;
};
/**
* Runs a test function (fn) from a loaded module. After the test function
* calls test.done(), the callback is executed with an assertionList as its
* second argument.
*
* @param {String} name
* @param {Function} fn
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runTest = function (name, fn, opt, callback) {
var options = types.options(opt);
options.testStart(name);
var start = new Date().getTime();
var test = types.test(name, start, options, callback);
options.testReady(test);
try {
fn(test);
}
catch (e) {
test.done(e);
}
};
/**
* Takes an object containing test functions or other test suites as properties
* and runs each in series. After all tests have completed, the callback is
* called with a list of all assertions as the second argument.
*
* If a name is passed to this function it is prepended to all test and suite
* names that run within it.
*
* @param {String} name
* @param {Object} suite
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runSuite = function (name, suite, opt, callback) {
suite = wrapGroup(suite);
var keys = _keys(suite);
async.concatSeries(keys, function (k, cb) {
var prop = suite[k], _name;
_name = name ? [].concat(name, k) : [k];
_name.toString = function () {
// fallback for old one
return this.join(' - ');
};
if (typeof prop === 'function') {
var in_name = false,
in_specific_test = (_name.toString() === opt.testFullSpec) ? true : false;
for (var i = 0; i < _name.length; i += 1) {
if (_name[i] === opt.testspec) {
in_name = true;
}
}
if ((!opt.testFullSpec || in_specific_test) && (!opt.testspec || in_name)) {
if (opt.moduleStart) {
opt.moduleStart();
}
exports.runTest(_name, suite[k], opt, cb);
}
else {
return cb();
}
}
else {
exports.runSuite(_name, suite[k], opt, cb);
}
}, callback);
};
/**
* Run each exported test function or test suite from a loaded module.
*
* @param {String} name
* @param {Object} mod
* @param {Object} opt
* @param {Function} callback
* @api public
*/
exports.runModule = function (name, mod, opt, callback) {
var options = _copy(types.options(opt));
var _run = false;
var _moduleStart = options.moduleStart;
mod = wrapGroup(mod);
function run_once() {
if (!_run) {
_run = true;
_moduleStart(name);
}
}
options.moduleStart = run_once;
var start = new Date().getTime();
exports.runSuite(null, mod, options, function (err, a_list) {
var end = new Date().getTime();
var assertion_list = types.assertionList(a_list, end - start);
options.moduleDone(name, assertion_list);
if (nodeunit.complete) {
nodeunit.complete(name, assertion_list);
}
callback(null, a_list);
});
};
/**
* Treats an object literal as a list of modules keyed by name. Runs each
* module and finished with calling 'done'. You can think of this as a browser
* safe alternative to runFiles in the nodeunit module.
*
* @param {Object} modules
* @param {Object} opt
* @api public
*/
// TODO: add proper unit tests for this function
exports.runModules = function (modules, opt) {
var all_assertions = [];
var options = types.options(opt);
var start = new Date().getTime();
async.concatSeries(_keys(modules), function (k, cb) {
exports.runModule(k, modules[k], options, cb);
},
function (err, all_assertions) {
var end = new Date().getTime();
options.done(types.assertionList(all_assertions, end - start));
});
};
/**
* Wraps a test function with setUp and tearDown functions.
* Used by testCase.
*
* @param {Function} setUp
* @param {Function} tearDown
* @param {Function} fn
* @api private
*/
var wrapTest = function (setUp, tearDown, fn) {
return function (test) {
var context = {};
if (tearDown) {
var done = test.done;
test.done = function (err) {
try {
tearDown.call(context, function (err2) {
if (err && err2) {
test._assertion_list.push(
types.assertion({error: err})
);
return done(err2);
}
done(err || err2);
});
}
catch (e) {
done(e);
}
};
}
if (setUp) {
setUp.call(context, function (err) {
if (err) {
return test.done(err);
}
fn.call(context, test);
});
}
else {
fn.call(context, test);
}
};
};
/**
* Returns a serial callback from two functions.
*
* @param {Function} funcFirst
* @param {Function} funcSecond
* @api private
*/
var getSerialCallback = function (fns) {
if (!fns.length) {
return null;
}
return function (callback) {
var that = this;
var bound_fns = [];
for (var i = 0, len = fns.length; i < len; i++) {
(function (j) {
bound_fns.push(function () {
return fns[j].apply(that, arguments);
});
})(i);
}
return async.series(bound_fns, callback);
};
};
/**
* Wraps a group of tests with setUp and tearDown functions.
* Used by testCase.
*
* @param {Object} group
* @param {Array} setUps - parent setUp functions
* @param {Array} tearDowns - parent tearDown functions
* @api private
*/
var wrapGroup = function (group, setUps, tearDowns) {
var tests = {};
var setUps = setUps ? setUps.slice(): [];
var tearDowns = tearDowns ? tearDowns.slice(): [];
if (group.setUp) {
setUps.push(group.setUp);
delete group.setUp;
}
if (group.tearDown) {
tearDowns.unshift(group.tearDown);
delete group.tearDown;
}
var keys = _keys(group);
for (var i = 0; i < keys.length; i += 1) {
var k = keys[i];
if (typeof group[k] === 'function') {
tests[k] = wrapTest(
getSerialCallback(setUps),
getSerialCallback(tearDowns),
group[k]
);
}
else if (typeof group[k] === 'object') {
tests[k] = wrapGroup(group[k], setUps, tearDowns);
}
}
return tests;
};
/**
* Backwards compatibility for test suites using old testCase API
*/
exports.testCase = function (suite) {
return suite;
};

View File

@ -1,104 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var async = require('../deps/async'),
types = require('./types'),
utils = require('./utils'),
core = require('./core'),
reporters = require('./reporters'),
assert = require('./assert'),
path = require('path'),
events = require('events');
/**
* Export sub-modules.
*/
exports.types = types;
exports.utils = utils;
exports.reporters = reporters;
exports.assert = assert;
// backwards compatibility
exports.testrunner = {
run: function () {
console.log(
'WARNING: nodeunit.testrunner is going to be deprecated, please ' +
'use nodeunit.reporters.default instead!'
);
return reporters['default'].run.apply(this, arguments);
}
};
/**
* Export all core functions
*/
for (var k in core) {
exports[k] = core[k];
};
/**
* Load modules from paths array and run all exported tests in series. If a path
* is a directory, load all supported file types inside it as modules. This only
* reads 1 level deep in the directory and does not recurse through
* sub-directories.
*
* @param {Array} paths
* @param {Object} opt
* @api public
*/
exports.runFiles = function (paths, opt) {
var all_assertions = [];
var options = types.options(opt);
var start = new Date().getTime();
if (!paths.length) {
return options.done(types.assertionList(all_assertions));
}
utils.modulePaths(paths, function (err, files) {
if (err) throw err;
async.concatSeries(files, function (file, cb) {
var name = path.basename(file);
exports.runModule(name, require(file), options, cb);
},
function (err, all_assertions) {
var end = new Date().getTime();
exports.done()
options.done(types.assertionList(all_assertions, end - start));
});
});
};
/* Export all prototypes from events.EventEmitter */
var label;
for (label in events.EventEmitter.prototype) {
exports[label] = events.EventEmitter.prototype[label];
}
/* Emit event 'complete' on completion of a test suite. */
exports.complete = function(name, assertions)
{
exports.emit('complete', name, assertions);
};
/* Emit event 'complete' on completion of all tests. */
exports.done = function()
{
exports.emit('done');
};
module.exports = exports;

View File

@ -1,123 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
* Only code on that line will be removed, its mostly to avoid requiring code
* that is node specific
*/
/**
* NOTE: this test runner is not listed in index.js because it cannot be
* used with the command-line tool, only inside the browser.
*/
/**
* Reporter info string
*/
exports.info = "Browser-based test reporter";
/**
* Run all tests within each module, reporting the results
*
* @param {Array} files
* @api public
*/
exports.run = function (modules, options, callback) {
var start = new Date().getTime(), div;
options = options || {};
div = options.div || document.body;
function setText(el, txt) {
if ('innerText' in el) {
el.innerText = txt;
}
else if ('textContent' in el){
el.textContent = txt;
}
}
function getOrCreate(tag, id) {
var el = document.getElementById(id);
if (!el) {
el = document.createElement(tag);
el.id = id;
div.appendChild(el);
}
return el;
};
var header = getOrCreate('h1', 'nodeunit-header');
var banner = getOrCreate('h2', 'nodeunit-banner');
var userAgent = getOrCreate('h2', 'nodeunit-userAgent');
var tests = getOrCreate('ol', 'nodeunit-tests');
var result = getOrCreate('p', 'nodeunit-testresult');
setText(userAgent, navigator.userAgent);
nodeunit.runModules(modules, {
moduleStart: function (name) {
/*var mheading = document.createElement('h2');
mheading.innerText = name;
results.appendChild(mheading);
module = document.createElement('ol');
results.appendChild(module);*/
},
testDone: function (name, assertions) {
var test = document.createElement('li');
var strong = document.createElement('strong');
strong.innerHTML = name + ' <b style="color: black;">(' +
'<b class="fail">' + assertions.failures() + '</b>, ' +
'<b class="pass">' + assertions.passes() + '</b>, ' +
assertions.length +
')</b>';
test.className = assertions.failures() ? 'fail': 'pass';
test.appendChild(strong);
var aList = document.createElement('ol');
aList.style.display = 'none';
test.onclick = function () {
var d = aList.style.display;
aList.style.display = (d == 'none') ? 'block': 'none';
};
for (var i=0; i<assertions.length; i++) {
var li = document.createElement('li');
var a = assertions[i];
if (a.failed()) {
li.innerHTML = (a.message || a.method || 'no message') +
'<pre>' + (a.error.stack || a.error) + '</pre>';
li.className = 'fail';
}
else {
li.innerHTML = a.message || a.method || 'no message';
li.className = 'pass';
}
aList.appendChild(li);
}
test.appendChild(aList);
tests.appendChild(test);
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
var failures = assertions.failures();
banner.className = failures ? 'fail': 'pass';
result.innerHTML = 'Tests completed in ' + duration +
' milliseconds.<br/><span class="passed">' +
assertions.passes() + '</span> assertions of ' +
'<span class="all">' + assertions.length + '<span> passed, ' +
assertions.failures() + ' failed.';
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
});
};

View File

@ -1,131 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
track = require('../track'),
path = require('path'),
AssertionError = require('../assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Default tests reporter";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
if (!options) {
// load default options
var content = fs.readFileSync(
__dirname + '/../../bin/nodeunit.json', 'utf8'
);
options = JSON.parse(content);
}
var error = function (str) {
return options.error_prefix + str + options.error_suffix;
};
var ok = function (str) {
return options.ok_prefix + str + options.ok_suffix;
};
var bold = function (str) {
return options.bold_prefix + str + options.bold_suffix;
};
var assertion_message = function (str) {
return options.assertion_prefix + str + options.assertion_suffix;
};
var start = new Date().getTime();
var tracker = track.createTracker(function (tracker) {
if (tracker.unfinished()) {
console.log('');
console.log(error(bold(
'FAILURES: Undone tests (or their setups/teardowns): '
)));
var names = tracker.names();
for (var i = 0; i < names.length; i += 1) {
console.log('- ' + names[i]);
}
console.log('');
console.log('To fix this, make sure all tests call test.done()');
process.reallyExit(tracker.unfinished());
}
});
var opts = {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {
console.log('\n' + bold(name));
},
testDone: function (name, assertions) {
tracker.remove(name);
if (!assertions.failures()) {
console.log('✔ ' + name);
}
else {
console.log(error('✖ ' + name) + '\n');
assertions.forEach(function (a) {
if (a.failed()) {
a = utils.betterErrors(a);
if (a.error instanceof AssertionError && a.message) {
console.log(
'Assertion Message: ' +
assertion_message(a.message)
);
}
console.log(a.error.stack + '\n');
}
});
}
},
done: function (assertions, end) {
var end = end || new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'\n' + bold(error('FAILURES: ')) + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
}
else {
console.log(
'\n' + bold(ok('OK: ')) + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
},
testStart: function(name) {
tracker.put(name);
}
};
if (files && files.length) {
var paths = files.map(function (p) {
return path.resolve(p);
});
nodeunit.runFiles(paths, opts);
} else {
nodeunit.runModules(files,opts);
}
};

View File

@ -1,104 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
track = require('../track'),
path = require('path'),
AssertionError = require('../assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Reporter for eclipse plugin";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
var start = new Date().getTime();
var paths = files.map(function (p) {
if (p.indexOf('/') === 0) {
return p;
}
return path.resolve(p);
});
var tracker = track.createTracker(function (tracker) {
if (tracker.unfinished()) {
console.log('');
console.log('FAILURES: Undone tests (or their setups/teardowns): ');
var names = tracker.names();
for (var i = 0; i < names.length; i += 1) {
console.log('- ' + names[i]);
}
console.log('');
console.log('To fix this, make sure all tests call test.done()');
process.reallyExit(tracker.unfinished());
}
});
nodeunit.runFiles(paths, {
testspec: undefined,
moduleStart: function (name) {
console.log('\n' + name);
},
testDone: function (name, assertions) {
tracker.remove(name);
if (!assertions.failures()) {
console.log('✔ ' + name);
}
else {
console.log('✖ ' + name + '\n');
assertions.forEach(function (a) {
if (a.failed()) {
a = utils.betterErrors(a);
if (a.error instanceof AssertionError && a.message) {
console.log(
'Assertion Message: ' + a.message
);
}
console.log(a.error.stack + '\n');
}
});
}
},
done: function (assertions, end) {
var end = end || new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'\n' + 'FAILURES: ' + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
}
else {
console.log(
'\n' + 'OK: ' + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
},
testStart: function (name) {
tracker.put(name);
}
});
};

View File

@ -1,110 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
path = require('path'),
AssertionError = require('assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Report tests result as HTML";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
var start = new Date().getTime();
var paths = files.map(function (p) {
return path.resolve(p);
});
console.log('<html>');
console.log('<head>');
console.log('<title></title>');
console.log('<style type="text/css">');
console.log('body { font: 12px Helvetica Neue }');
console.log('h2 { margin:0 ; padding:0 }');
console.log('pre { font: 11px Andale Mono; margin-left: 1em; padding-left: 1em; margin-top:0; font-size:smaller;}');
console.log('.assertion_message { margin-left: 1em; }');
console.log(' ol {' +
' list-style: none;' +
' margin-left: 1em;' +
' padding-left: 1em;' +
' text-indent: -1em;' +
'}');
console.log(' ol li.pass:before { content: "\\2714 \\0020"; }');
console.log(' ol li.fail:before { content: "\\2716 \\0020"; }');
console.log('</style>');
console.log('</head>');
console.log('<body>');
nodeunit.runFiles(paths, {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {
console.log('<h2>' + name + '</h2>');
console.log('<ol>');
},
testDone: function (name, assertions) {
if (!assertions.failures()) {
console.log('<li class="pass">' + name + '</li>');
}
else {
console.log('<li class="fail">' + name);
assertions.forEach(function (a) {
if (a.failed()) {
a = utils.betterErrors(a);
if (a.error instanceof AssertionError && a.message) {
console.log('<div class="assertion_message">' +
'Assertion Message: ' + a.message +
'</div>');
}
console.log('<pre>');
console.log(a.error.stack);
console.log('</pre>');
}
});
console.log('</li>');
}
},
moduleDone: function () {
console.log('</ol>');
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'<h3>FAILURES: ' + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)</h3>'
);
}
else {
console.log(
'<h3>OK: ' + assertions.length +
' assertions (' + assertions.duration + 'ms)</h3>'
);
}
console.log('</body>');
console.log('</html>');
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
});
};

View File

@ -1,27 +0,0 @@
// This is a hack to make browserify skip tap
var tap;
try {
tap = require('./' + 'tap');
} catch (ex) {
tap = {
run: function() {
throw new Error('Sorry, tap reporter not available');
}
};
}
module.exports = {
'junit': require('./junit'),
'default': require('./default'),
'skip_passed': require('./skip_passed'),
'minimal': require('./minimal'),
'html': require('./html'),
'eclipse': require('./eclipse'),
'machineout': require('./machineout'),
'tap': tap,
'nested': require('./nested'),
'verbose' : require('./verbose'),
'lcov' : require('./lcov')
// browser test reporter is not listed because it cannot be used
// with the command line tool, only inside a browser.
};

View File

@ -1,180 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
path = require('path'),
async = require('../../deps/async'),
AssertionError = require('assert').AssertionError,
child_process = require('child_process'),
ejs = require('../../deps/ejs');
/**
* Reporter info string
*/
exports.info = "jUnit XML test reports";
/**
* Ensures a directory exists using mkdir -p.
*
* @param {String} path
* @param {Function} callback
* @api private
*/
var ensureDir = function (path, callback) {
var mkdir = child_process.spawn('mkdir', ['-p', path]);
mkdir.on('error', function (err) {
callback(err);
callback = function(){};
});
mkdir.on('exit', function (code) {
if (code === 0) callback();
else callback(new Error('mkdir exited with code: ' + code));
});
};
/**
* Returns absolute version of a path. Relative paths are interpreted
* relative to process.cwd() or the cwd parameter. Paths that are already
* absolute are returned unaltered.
*
* @param {String} p
* @param {String} cwd
* @return {String}
* @api public
*/
var abspath = function (p, /*optional*/cwd) {
if (p[0] === '/') return p;
cwd = cwd || process.cwd();
return path.normalize(path.resolve(p));
};
/**
* Run all tests within each module, reporting the results to the command-line,
* then writes out junit-compatible xml documents.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, opts, callback) {
if (!opts.output) {
console.error(
'Error: No output directory defined.\n' +
'\tEither add an "output" property to your nodeunit.json config ' +
'file, or\n\tuse the --output command line option.'
);
return;
}
opts.output = abspath(opts.output);
var error = function (str) {
return opts.error_prefix + str + opts.error_suffix;
};
var ok = function (str) {
return opts.ok_prefix + str + opts.ok_suffix;
};
var bold = function (str) {
return opts.bold_prefix + str + opts.bold_suffix;
};
var start = new Date().getTime();
var paths = files.map(function (p) {
return path.resolve(p);
});
var modules = {}
var curModule;
nodeunit.runFiles(paths, {
testspec: opts.testspec,
testFullSpec: opts.testFullSpec,
moduleStart: function (name) {
curModule = {
errorCount: 0,
failureCount: 0,
tests: 0,
testcases: [],
name: name
};
modules[name] = curModule;
},
testDone: function (name, assertions) {
var testcase = {name: name};
for (var i=0; i<assertions.length; i++) {
var a = assertions[i];
if (a.failed()) {
a = utils.betterErrors(a);
testcase.failure = {
message: a.message,
backtrace: a.error.stack
};
if (a.error instanceof AssertionError) {
curModule.failureCount++;
}
else {
curModule.errorCount++;
}
break;
}
}
curModule.tests++;
curModule.testcases.push(testcase);
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
ensureDir(opts.output, function (err) {
var tmpl = __dirname + "/../../share/junit.xml.ejs";
fs.readFile(tmpl, function (err, data) {
if (err) throw err;
var tmpl = data.toString();
for(var k in modules) {
var module = modules[k];
var rendered = ejs.render(tmpl, {
locals: {suites: [module]}
});
var filename = path.resolve(
opts.output,
module.name + '.xml'
);
console.log('Writing ' + filename);
fs.writeFileSync(filename, rendered, 'utf8');
}
if (assertions.failures()) {
console.log(
'\n' + bold(error('FAILURES: ')) +
assertions.failures() + '/' +
assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
}
else {
console.log(
'\n' + bold(ok('OK: ')) + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
});
});
}
});
}

View File

@ -1,54 +0,0 @@
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
path = require('path');
/**
* Reporter info string
*/
exports.info = 'The LCOV reporter reads JS files instrumented by JSCoverage (http://siliconforks.com/jscoverage/) and outputs coverage data in the LCOV format (http://ltp.sourceforge.net/coverage/lcov/geninfo.1.php)';
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
var paths = files.map(function (p) {
return path.resolve(p);
});
nodeunit.runFiles(paths, {
done: function (assertions) {
var cov = (global || window)._$jscoverage || {};
Object.keys(cov).forEach(function (filename) {
var data = cov[filename];
reportFile(filename, data);
});
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
});
};
function reportFile(filename, data) {
console.log('SF:' + filename);
data.source.forEach(function(line, num) {
// increase the line number, as JS arrays are zero-based
num++;
if (data[num] !== undefined) {
console.log('DA:' + num + ',' + data[num]);
}
});
console.log('end_of_record');
}

View File

@ -1,112 +0,0 @@
/*!
* Nodeunit
*
* @author Alisue (lambdalisue@hashnote.net)
* @url http://hashnote.net/
*
* Copyright (c) 2011 Alisue
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
track = require('../track'),
path = require('path'),
AssertionError = require('../assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Tests reporter for machinally analysis";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
// options doesn't effect
var parseStack = function (stack, delimiter) {
var parseTrace = function (trace) {
var filename, row, column;
pattern1 = /\s{4}at\s\S+\s\(([^:]+):(\d+):(\d+)\)/;
pattern2 = /\s{4}at\s([^:]+):(\d+):(\d+)/;
if (trace.match(pattern1) !== null) {
filename = RegExp.$1;
row = RegExp.$2;
column = RegExp.$3;
} else if (trace.match(pattern2) !== null) {
filename = RegExp.$1;
row = RegExp.$2;
column = RegExp.$3;
} else {
throw new Error("Could not parse a line of stack trace: " + trace);
}
return {filename: filename, row: row, column: column};
};
if (delimiter === undefined) {
delimiter = ':';
}
traceback = stack.split('\n');
firstline = traceback.shift();
trace = parseTrace(traceback[0]);
return {filename: trace.filename, row: trace.row, column: trace.column, message: firstline};
};
var createErrorMessage = function(type, name, filename, row, column, message){
return [type, name, filename, row, column, message].join(":");
};
var paths = files.map(function (p) {
return path.resolve(p);
});
var tracker = track.createTracker(function (tracker) {
if (tracker.unfinished()) {
var names = tracker.names();
for (var i = 0; i < names.length; i += 1) {
console.log(createErrorMessage(
'Error', names[i],
'', '', '',
'Undone tests - To fix this, make sure all tests call test.done()'
));
}
process.reallyExit(tracker.unfinished());
}
});
nodeunit.runFiles(paths, {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {},
testDone: function (name, assertions) {
tracker.remove(name);
if (assertions.failures()) {
assertions.forEach(function (a) {
var stacks, message, filename, row, column;
if (a.failed()) {
stackinfo = parseStack(a.error.stack, ':');
console.log(createErrorMessage(
'Fail', name, stackinfo.filename,
stackinfo.row, stackinfo.column, stackinfo.message));
}
});
}
},
done: function (assertions, end) {
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
},
testStart: function(name) {
tracker.put(name);
}
});
};

View File

@ -1,142 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
path = require('path'),
track = require('../track'),
AssertionError = require('assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Pretty minimal output";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
if (!options) {
// load default options
var content = fs.readFileSync(
__dirname + '/../../bin/nodeunit.json', 'utf8'
);
options = JSON.parse(content);
}
var red = function (str) {
return options.error_prefix + str + options.error_suffix;
};
var green = function (str) {
return options.ok_prefix + str + options.ok_suffix;
};
var magenta = function (str) {
return options.assertion_prefix + str + options.assertion_suffix;
};
var bold = function (str) {
return options.bold_prefix + str + options.bold_suffix;
};
var start = new Date().getTime();
var tracker = track.createTracker(function (tracker) {
if (tracker.unfinished()) {
console.log('');
console.log(bold(red(
'FAILURES: Undone tests (or their setups/teardowns): '
)));
var names = tracker.names();
for (var i = 0; i < names.length; i += 1) {
console.log('- ' + names[i]);
}
console.log('');
console.log('To fix this, make sure all tests call test.done()');
process.reallyExit(tracker.unfinished());
}
});
var opts = {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {
process.stdout.write(bold(name) + ': ');
},
moduleDone: function (name, assertions) {
console.log('');
if (assertions.failures()) {
assertions.forEach(function (a) {
if (a.failed()) {
a = utils.betterErrors(a);
if (a.error instanceof AssertionError && a.message) {
console.log(
'Assertion in test ' + bold(a.testname) + ': ' +
magenta(a.message)
);
}
console.log(a.error.stack + '\n');
}
});
}
},
testStart: function (name) {
tracker.put(name);
},
testDone: function (name, assertions) {
tracker.remove(name);
if (!assertions.failures()) {
process.stdout.write('.');
}
else {
process.stdout.write(red('F'));
assertions.forEach(function (assertion) {
assertion.testname = name;
});
}
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'\n' + bold(red('FAILURES: ')) + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
}
else {
console.log(
'\n' + bold(green('OK: ')) + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
};
if (files && files.length) {
var paths = files.map(function (p) {
return path.resolve(p);
});
nodeunit.runFiles(paths, opts);
} else {
nodeunit.runModules(files,opts);
}
};

View File

@ -1,216 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
track = require('../track'),
path = require('path'),
AssertionError = require('../assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Nested test reporter";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
if (!options) {
// load default options
var content = fs.readFileSync(
__dirname + '/../../bin/nodeunit.json',
'utf8'
);
options = JSON.parse(content);
}
var error = function (str) {
return options.error_prefix + str + options.error_suffix;
};
var ok = function (str) {
return options.ok_prefix + str + options.ok_suffix;
};
var bold = function (str) {
return options.bold_prefix + str + options.bold_suffix;
};
var assertion_message = function (str) {
return options.assertion_prefix + str + options.assertion_suffix;
};
var spaces_per_indent = options.spaces_per_indent || 4;
var start = new Date().getTime();
var paths = files.map(function (p) {
return path.resolve(p);
});
var tracker = track.createTracker(function (tracker) {
var i, names;
if (tracker.unfinished()) {
console.log('');
console.log(error(bold(
'FAILURES: Undone tests (or their setups/teardowns): '
)));
names = tracker.names();
for (i = 0; i < names.length; i += 1) {
console.log('- ' + names[i]);
}
console.log('');
console.log('To fix this, make sure all tests call test.done()');
process.reallyExit(tracker.unfinished());
}
});
// Object to hold status of each 'part' of the testCase/name array,
// i.e., whether this part has been printed yet.
tracker.already_printed = {};
var pass_text = function (txt) {
// Print in bold green.
return bold(ok(txt + " (pass)"));
};
var fail_text = function (txt) {
return bold(error(txt + " (fail) ✖ "));
};
var status_text = function (txt, status) {
if (status === 'pass') {
return pass_text(txt);
} else {
return fail_text(txt);
}
};
/**
* Slices an array, returns a string by joining the sliced elements.
* @example
* > name_slice(['TC1', 'TC1.1', 'mytest'], 1);
* "TC1,TC1.1"
*/
var name_slice = function (name_arr, end_index) {
return name_arr.slice(0, end_index + 1).join(",");
};
var indent = (function () {
var txt = '';
var i;
for (i = 0; i < spaces_per_indent; i++) {
txt += ' ';
}
return txt;
}());
// Indent once for each indent_level
var add_indent = function (txt, indent_level) {
var k;
for (k = 0; k < indent_level; k++) {
txt += indent;
}
return txt;
};
// If it's not the last element of the name_arr, it's a testCase.
var is_testCase = function (name_arr, index) {
return index === name_arr.length - 1 ? false : true;
};
var testCase_line = function (txt) {
return txt + "\n";
};
/**
* Prints (console.log) the nested test status line(s).
*
* @param {Array} name_arr - Array of name elements.
* @param {String} status - either 'pass' or 'fail'.
* @example
* > print_status(['TC1', 'TC1.1', 'mytest'], 'pass');
* TC1
* TC1.1
* mytest (pass)
*/
var print_status = function (name_arr, status) {
var txt = '';
var _name_slice, part, i;
for (i = 0; i < name_arr.length; i++) {
_name_slice = name_slice(name_arr, i);
part = name_arr[i];
if (!tracker.already_printed[_name_slice]) {
txt = add_indent(txt, i);
if (is_testCase(name_arr, i)) {
txt += testCase_line(part);
} else {
txt += status_text(part, status);
}
tracker.already_printed[_name_slice] = true;
}
}
console.log(txt);
};
nodeunit.runFiles(paths, {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {
console.log('\n' + bold(name));
},
testDone: function (name, assertions) {
tracker.remove(name);
if (!assertions.failures()) {
print_status(name, 'pass');
} else {
print_status(name, 'fail');
assertions.forEach(function (a) {
if (a.failed()) {
a = utils.betterErrors(a);
if (a.error instanceof AssertionError && a.message) {
console.log(
'Assertion Message: ' +
assertion_message(a.message)
);
}
console.log(a.error.stack + '\n');
}
});
}
},
done: function (assertions, end) {
end = end || new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'\n' + bold(error('FAILURES: ')) + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
} else {
console.log(
'\n' + bold(ok('OK: ')) + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
},
testStart: function (name) {
tracker.put(name);
}
});
};

View File

@ -1,108 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
path = require('path'),
AssertionError = require('assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Skip passed tests output";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
if (!options) {
// load default options
var content = fs.readFileSync(
__dirname + '/../../bin/nodeunit.json', 'utf8'
);
options = JSON.parse(content);
}
var error = function (str) {
return options.error_prefix + str + options.error_suffix;
};
var ok = function (str) {
return options.ok_prefix + str + options.ok_suffix;
};
var bold = function (str) {
return options.bold_prefix + str + options.bold_suffix;
};
var assertion_message = function (str) {
return options.assertion_prefix + str + options.assertion_suffix;
};
var start = new Date().getTime();
var paths = files.map(function (p) {
return path.resolve(p);
});
nodeunit.runFiles(paths, {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {
console.log('\n' + bold(name));
},
testDone: function (name, assertions) {
if (assertions.failures()) {
console.log(error('✖ ' + name) + '\n');
assertions.forEach(function (a) {
if (a.failed()) {
a = utils.betterErrors(a);
if (a.error instanceof AssertionError && a.message) {
console.log(
'Assertion Message: ' + assertion_message(a.message)
);
}
console.log(a.error.stack + '\n');
}
});
}
},
moduleDone: function (name, assertions) {
if (!assertions.failures()) {
console.log('✔ all tests passed');
}
else {
console.log(error('✖ some tests failed'));
}
},
done: function (assertions) {
var end = new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'\n' + bold(error('FAILURES: ')) + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
}
else {
console.log(
'\n' + bold(ok('OK: ')) + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
});
};

View File

@ -1,67 +0,0 @@
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
path = require('path'),
assert = require('tap').assert,
TapProducer = require('tap').Producer,
fs = require('fs');
/**
* Reporter info string
*/
exports.info = "TAP output";
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
if (!options) {
// load default options
var content = fs.readFileSync(
__dirname + '/../../bin/nodeunit.json', 'utf8'
);
options = JSON.parse(content);
}
var paths = files.map(function (p) {
return path.resolve(p);
});
var output = new TapProducer();
output.pipe(process.stdout);
nodeunit.runFiles(paths, {
testStart: function (name) {
output.write(name.toString());
},
testDone: function (name, assertions) {
assertions.forEach(function (e) {
var extra = {};
if (e.error) {
extra.error = {
name: e.error.name,
message: e.error.message,
stack: e.error.stack.split(/\n/).filter(function (line) {
// exclude line of "types.js"
return ! RegExp(/types.js:83:39/).test(line);
}).join('\n')
};
extra.wanted = e.error.expected;
extra.found = e.error.actual;
}
output.write(assert(e.passed(), e.message, extra));
});
},
done: function (assertions) {
output.end();
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
}
});
};

View File

@ -1,125 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var nodeunit = require('../nodeunit'),
utils = require('../utils'),
fs = require('fs'),
track = require('../track'),
path = require('path');
AssertionError = require('../assert').AssertionError;
/**
* Reporter info string
*/
exports.info = "Verbose tests reporter"
/**
* Run all tests within each module, reporting the results to the command-line.
*
* @param {Array} files
* @api public
*/
exports.run = function (files, options, callback) {
if (!options) {
// load default options
var content = fs.readFileSync(
__dirname + '/../../bin/nodeunit.json', 'utf8'
);
options = JSON.parse(content);
}
var error = function (str) {
return options.error_prefix + str + options.error_suffix;
};
var ok = function (str) {
return options.ok_prefix + str + options.ok_suffix;
};
var bold = function (str) {
return options.bold_prefix + str + options.bold_suffix;
};
var assertion_message = function (str) {
return options.assertion_prefix + str + options.assertion_suffix;
};
var start = new Date().getTime();
var paths = files.map(function (p) {
return path.resolve(p);
});
var tracker = track.createTracker(function (tracker) {
if (tracker.unfinished()) {
console.log('');
console.log(error(bold(
'FAILURES: Undone tests (or their setups/teardowns): '
)));
var names = tracker.names();
for (var i = 0; i < names.length; i += 1) {
console.log('- ' + names[i]);
}
console.log('');
console.log('To fix this, make sure all tests call test.done()');
process.reallyExit(tracker.unfinished());
}
});
nodeunit.runFiles(paths, {
testspec: options.testspec,
testFullSpec: options.testFullSpec,
moduleStart: function (name) {
console.log('\n' + bold(name));
},
testDone: function (name, assertions) {
tracker.remove(name);
if (!assertions.failures()) {
console.log('✔ ' + name);
}
else {
console.log(error('✖ ' + name));
}
// verbose so print everything
assertions.forEach(function (a) {
if (a.failed()) {
console.log(error(' ✖ ' + a.message));
a = utils.betterErrors(a);
console.log(' ' + a.error.stack);
}
else {
console.log(' ✔ ' + a.message);
}
});
},
done: function (assertions, end) {
var end = end || new Date().getTime();
var duration = end - start;
if (assertions.failures()) {
console.log(
'\n' + bold(error('FAILURES: ')) + assertions.failures() +
'/' + assertions.length + ' assertions failed (' +
assertions.duration + 'ms)'
);
}
else {
console.log(
'\n' + bold(ok('OK: ')) + assertions.length +
' assertions (' + assertions.duration + 'ms)'
);
}
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined);
},
testStart: function(name) {
tracker.put(name);
}
});
};

View File

@ -1,48 +0,0 @@
/*!
* Simple util module to track tests. Adds a process.exit hook to print
* the undone tests.
*/
exports.createTracker = function (on_exit) {
var names = {};
var tracker = {
names: function () {
var arr = [];
for (var k in names) {
if (names.hasOwnProperty(k)) {
arr.push(k);
}
}
return arr;
},
unfinished: function () {
return tracker.names().length;
},
put: function (testname) {
names[testname] = testname;
},
remove: function (testname) {
delete names[testname];
}
};
process.on('exit', function() {
on_exit = on_exit || exports.default_on_exit;
on_exit(tracker);
});
return tracker;
};
exports.default_on_exit = function (tracker) {
if (tracker.unfinished()) {
console.log('');
console.log('Undone tests (or their setups/teardowns): ');
var names = tracker.names();
for (var i = 0; i < names.length; i += 1) {
console.log(names[i]);
}
process.reallyExit(tracker.unfinished());
}
};

View File

@ -1,190 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
* Only code on that line will be removed, it's mostly to avoid requiring code
* that is node specific
*/
/**
* Module dependencies
*/
var assert = require('./assert'), //@REMOVE_LINE_FOR_BROWSER
async = require('../deps/async'); //@REMOVE_LINE_FOR_BROWSER
/**
* Creates assertion objects representing the result of an assert call.
* Accepts an object or AssertionError as its argument.
*
* @param {object} obj
* @api public
*/
exports.assertion = function (obj) {
return {
method: obj.method || '',
message: obj.message || (obj.error && obj.error.message) || '',
error: obj.error,
passed: function () {
return !this.error;
},
failed: function () {
return Boolean(this.error);
}
};
};
/**
* Creates an assertion list object representing a group of assertions.
* Accepts an array of assertion objects.
*
* @param {Array} arr
* @param {Number} duration
* @api public
*/
exports.assertionList = function (arr, duration) {
var that = arr || [];
that.failures = function () {
var failures = 0;
for (var i = 0; i < this.length; i += 1) {
if (this[i].failed()) {
failures += 1;
}
}
return failures;
};
that.passes = function () {
return that.length - that.failures();
};
that.duration = duration || 0;
return that;
};
/**
* Create a wrapper function for assert module methods. Executes a callback
* after it's complete with an assertion object representing the result.
*
* @param {Function} callback
* @api private
*/
var assertWrapper = function (callback) {
return function (new_method, assert_method, arity) {
return function () {
var message = arguments[arity - 1];
var a = exports.assertion({method: new_method, message: message});
try {
assert[assert_method].apply(null, arguments);
}
catch (e) {
a.error = e;
}
callback(a);
};
};
};
/**
* Creates the 'test' object that gets passed to every test function.
* Accepts the name of the test function as its first argument, followed by
* the start time in ms, the options object and a callback function.
*
* @param {String} name
* @param {Number} start
* @param {Object} options
* @param {Function} callback
* @api public
*/
exports.test = function (name, start, options, callback) {
var expecting;
var a_list = [];
var wrapAssert = assertWrapper(function (a) {
a_list.push(a);
if (options.log) {
async.nextTick(function () {
options.log(a);
});
}
});
var test = {
done: function (err) {
if (expecting !== undefined && expecting !== a_list.length) {
var e = new Error(
'Expected ' + expecting + ' assertions, ' +
a_list.length + ' ran'
);
var a1 = exports.assertion({method: 'expect', error: e});
a_list.push(a1);
if (options.log) {
async.nextTick(function () {
options.log(a1);
});
}
}
if (err) {
var a2 = exports.assertion({error: err});
a_list.push(a2);
if (options.log) {
async.nextTick(function () {
options.log(a2);
});
}
}
var end = new Date().getTime();
async.nextTick(function () {
var assertion_list = exports.assertionList(a_list, end - start);
options.testDone(name, assertion_list);
callback(null, a_list);
});
},
ok: wrapAssert('ok', 'ok', 2),
same: wrapAssert('same', 'deepEqual', 3),
equals: wrapAssert('equals', 'equal', 3),
expect: function (num) {
expecting = num;
},
_assertion_list: a_list
};
// add all functions from the assert module
for (var k in assert) {
if (assert.hasOwnProperty(k)) {
test[k] = wrapAssert(k, k, assert[k].length);
}
}
return test;
};
/**
* Ensures an options object has all callbacks, adding empty callback functions
* if any are missing.
*
* @param {Object} opt
* @return {Object}
* @api public
*/
exports.options = function (opt) {
var optionalCallback = function (name) {
opt[name] = opt[name] || function () {};
};
optionalCallback('moduleStart');
optionalCallback('moduleDone');
optionalCallback('testStart');
optionalCallback('testReady');
optionalCallback('testDone');
//optionalCallback('log');
// 'done' callback is not optional.
return opt;
};

View File

@ -1,216 +0,0 @@
/*!
* Nodeunit
* Copyright (c) 2010 Caolan McMahon
* MIT Licensed
*/
/**
* Module dependencies
*/
var async = require('../deps/async'),
fs = require('fs'),
util = require('util'),
Script = require('vm').Script,
http = require('http');
/**
* Detect if coffee-script, iced-coffeescript, or streamline are available and
* the respective file extensions to the search filter in modulePaths if it is.
*/
var extensions = [ 'js' ]; // js is always supported: add it unconditionally
var extensionPattern;
try {
require('coffee' + '-script/register');
extensions.push('coffee');
} catch (e) { }
try {
require('iced-coffee' + '-script/register');
extensions.push('iced');
} catch (e) { }
try {
require('stream' + 'line').register();
extensions.push('_coffee');
extensions.push('_js');
} catch (e) { }
extensionPattern = new RegExp('\\.(?:' + extensions.join('|') + ')$');
/**
* Finds all modules at each path in an array, If a path is a directory, it
* returns all supported file types inside it. This only reads 1 level deep in
* the directory and does not recurse through sub-directories.
*
* The extension (.js, .coffee etc) is stripped from the filenames so they can
* simply be require()'ed.
*
* @param {Array} paths
* @param {Function} callback
* @api public
*/
exports.modulePaths = function (paths, callback) {
async.concat(paths, function (p, cb) {
fs.stat(p, function (err, stats) {
if (err) {
return cb(err);
}
if (stats.isFile()) {
return cb(null, [p]);
}
if (stats.isDirectory()) {
fs.readdir(p, function (err, files) {
if (err) {
return cb(err);
}
// filter out any filenames with unsupported extensions
var modules = files.filter(function (filename) {
return extensionPattern.exec(filename);
});
// remove extension from module name and prepend the
// directory path
var fullpaths = modules.map(function (filename) {
var mod_name = filename.replace(extensionPattern, '');
return [p, mod_name].join('/');
});
// sort filenames here, because Array.map changes order
fullpaths.sort();
cb(null, fullpaths);
});
}
});
}, callback);
};
/**
* Evaluates JavaScript files in a sandbox, returning the context. The first
* argument can either be a single filename or an array of filenames. If
* multiple filenames are given their contents are concatenated before
* evalution. The second argument is an optional context to use for the sandbox.
*
* @param files
* @param {Object} sandbox
* @return {Object}
* @api public
*/
exports.sandbox = function (files, /*optional*/sandbox) {
var source, script, result;
if (!(files instanceof Array)) {
files = [files];
}
source = files.map(function (file) {
return fs.readFileSync(file, 'utf8');
}).join('');
if (!sandbox) {
sandbox = {};
}
script = new Script(source);
result = script.runInNewContext(sandbox);
return sandbox;
};
/**
* Provides a http request, response testing environment.
*
* Example:
*
* var httputil = require('nodeunit').utils.httputil
* exports.testSomething = function(test) {
* httputil(function (req, resp) {
* resp.writeHead(200, {});
* resp.end('test data');
* },
* function(server, client) {
* client.fetch('GET', '/', {}, function(resp) {
* test.equal('test data', resp.body);
* server.close();
* test.done();
* })
* });
* };
*
* @param {Function} cgi
* @param {Function} envReady
* @api public
*/
exports.httputil = function (cgi, envReady) {
var hostname = process.env.HOSTNAME || 'localhost';
var port = process.env.PORT || 3000;
var server = http.createServer(cgi);
server.listen(port, hostname);
var client = http.createClient(port, hostname);
client.fetch = function (method, path, headers, respReady) {
var request = this.request(method, path, headers);
request.end();
request.on('response', function (response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
if (response.body) {
response.body += chunk;
} else {
response.body = chunk;
}
});
response.on('end', function () {
if (response.headers['content-type'] === 'application/json') {
response.bodyAsObject = JSON.parse(response.body);
}
respReady(response);
});
});
};
process.nextTick(function () {
if (envReady && typeof envReady === 'function') {
envReady(server, client);
}
});
};
/**
* Improves formatting of AssertionError messages to make deepEqual etc more
* readable.
*
* @param {Object} assertion
* @return {Object}
* @api public
*/
exports.betterErrors = function (assertion) {
if (!assertion.error) {
return assertion;
}
var e = assertion.error;
if (e.actual && e.expected) {
var actual = util.inspect(e.actual, false, 10).replace(/\n$/, '');
var expected = util.inspect(e.expected, false, 10).replace(/\n$/, '');
var multiline = (
actual.indexOf('\n') !== -1 ||
expected.indexOf('\n') !== -1
);
var spacing = (multiline ? '\n' : ' ');
e._message = e.message;
e.stack = (
e.name + ':' + spacing +
actual + spacing + e.operator + spacing +
expected + '\n' +
e.stack.split('\n').slice(1).join('\n')
);
}
return assertion;
};

View File

@ -1,95 +0,0 @@
.\" Generated with Ronnjs/v0.1
.\" http://github.com/kapouer/ronnjs/
.
.TH "NODEUNIT" "1" "October 2010" "" ""
.
.SH "NAME"
\fBnodeunit\fR \-\- simple node\.js unit testing tool
.
.SH "SYNOPSIS"
.
.nf
nodeunit [options] <file\-or\-directory> [<file\-or\-directory> \.\.\.]
.
.fi
.
.SH "DESCRIPTION"
Nodeunit is a simple unit testing tool based on the node\.js assert module\.
.
.IP "\(bu" 4
Simple to use
.
.IP "\(bu" 4
Just export the tests from a module
.
.IP "\(bu" 4
Helps you avoid common pitfalls when testing asynchronous code
.
.IP "\(bu" 4
Easy to add test cases with setUp and tearDown functions if you wish
.
.IP "\(bu" 4
Allows the use of mocks and stubs
.
.IP "" 0
.
.SH "OPTIONS"
\fB\-\-config FILE\fR:
.
.br
Load config options from a JSON file, allows the customisation
of color schemes for the default test reporter etc\.
See bin/nodeunit\.json for current available options\.
.
.P
\fB\-\-reporter FILE\fR:
.
.br
You can set the test reporter to a custom module or on of the modules
in nodeunit/lib/reporters, when omitted, the default test runner is used\.
.
.P
\fB\-\-list\-reporters\fR:
.
.br
List available build\-in reporters\.
.
.P
\fB\-h\fR, \fB\-\-help\fR:
.
.br
Display the help and exit\.
.
.P
\fB\-v\fR, \fB\-\-version\fR:
.
.br
Output version information and exit\.
.
.P
\fB<file\-or\-directory>\fR:
You can run nodeunit on specific files or on all \fI*\.js\fR files inside
.
.br
a directory\.
.
.SH "AUTHORS"
Written by Caolan McMahon and other nodeunit contributors\.
.
.br
Contributors list: \fIhttp://github\.com/caolan/nodeunit/contributors\fR\|\.
.
.SH "REPORTING BUGS"
Report nodeunit bugs to \fIhttp://github\.com/caolan/nodeunit/issues\fR\|\.
.
.SH "COPYRIGHT"
Copyright © 2010 Caolan McMahon\.
.
.br
Nodeunit has been released under the MIT license:
.
.br
\fIhttp://github\.com/caolan/nodeunit/raw/master/LICENSE\fR\|\.
.
.SH "SEE ALSO"
node(1)

View File

@ -1 +0,0 @@
../tap/bin/tap.js

View File

@ -1,11 +0,0 @@
# contributors sorted by whether or not they're me
Isaac Z. Schlueter <i@izs.me>
baudehlo <helpme+github@gmail.com>
James Halliday <mail@substack.net>
Jason Smith (air) <jhs@iriscouch.com>
Pedro P. Candel <kusorbox@gmail.com>
Stein Martin Hustad <stein@hustad.com>
Trent Mick <trentm@gmail.com>
Corey Richardson <kb1pkl@aim.com>
Raynos <raynos2@gmail.com>
Siddharth Mahendraker <siddharth_mahen@me.com>

View File

@ -1,23 +0,0 @@
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
All rights reserved.
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.

View File

@ -1,86 +0,0 @@
This is a mix-and-match set of utilities that you can use to write test
harnesses and frameworks that communicate with one another using the
Test Anything Protocol.
If you don't yet know what TAP is, [you better ask
somebody](http://testanything.org/).
Default Usage:
1. Make a directory. Maybe call it 'test'. That'd be nice and obvious.
2. Put a bunch of test scripts in there. If they're node programs, then
they should be ".js". Anything else is assumed to be some kind of shell
script, which should have a shebang line.
3. `npm install tap`
4. Update package.json scripts.test to include `tap ./test` [example
gist](https://gist.github.com/4469613)
5. `npm test`
The output will be TAP-compliant.
For extra special bonus points, you can do something like this:
var test = require("tap").test
test("make sure the thingie is a thing", function (t) {
t.equal(thingie, "thing", "thingie should be thing")
t.deepEqual(array, ["foo", "bar"], "array has foo and bar elements")
t.strictDeepEqual(object, {foo: 42, bar: "thingie"}, "object has foo (Number) and bar (String) property")
t.type(thingie, "string", "type of thingie is string")
t.ok(true, "this is always true")
t.notOk(false, "this is never true")
t.test("a child test", function (t) {
t.equal(this, superEasy, "right!?")
t.similar(7, 2, "ever notice 7 is kinda like 2?", {todo: true})
t.test("so skippable", {skip: true}, function (t) {
t.plan(1) // only one test in this block
t.ok(true, "but when the flag changes, it'll pass")
// no need to end, since we had a plan.
})
t.end()
})
t.ok(99, "can also skip individual assertions", {skip: true})
// end lets it know it's over.
t.end()
})
test("another one", function (t) {
t.plan(1)
t.ok(true, "It's ok to plan, and also end. Watch.")
t.end() // but it must match the plan!
})
Node-tap is actually a collection of several modules, any of which may be
mixed and matched however you please.
If you don't like this test framework, and think you can do much much
better, *I strongly encourage you to do so!* If you use this library,
however, at least to output TAP-compliant results when `process.env.TAP`
is set, then the data coming out of your framework will be much more
consumable by machines.
You can also use this to build programs that *consume* the TAP data, so
this is very useful for CI systems and such.
* tap-assert: A collection of assert functions that return TAP result
objects.
* tap-consumer: A stream interface for consuming TAP data.
* tap-producer: A class that produces a TAP stream by taking in result
objects.
* tap-results: A class for keeping track of TAP result objects as they
pass by, counting up skips, passes, fails, and so on.
* tap-runner: A program that runs through a directory running all the
tests in it. (Tests which may or may not be TAP-outputting tests. But
it's better if they are.)
* tap-test: A class for actually running tests.
* tap-harness: A class that runs tests. (Tests are also Harnesses,
which is how sub-tests run.)
* tap-global-harness: A default harness that provides the top-level
support for running TAP tests.
## Experimental Code Coverage with runforcover & bunker:
```
TAP_COV=1 tap ./test [--cover=./lib,foo.js] [--coverage-dir=./coverage]
```
This feature is experimental, and will most likely change somewhat
before being finalized. Feedback welcome.

View File

@ -1,19 +0,0 @@
#!/usr/bin/env node
// just an example, really
// Run with `node tap-http.js path/to/tests/`
var argv = process.argv.slice(2)
, path = require("path")
, Runner = require("../lib/tap-runner")
, http = require("http")
, server = http.createServer(function (req, res) {
// it'd be nice to return a non-200 if the tests fail, but we don't
// know the status until it's done, so that would mean not being able
// to pipe the output
res.writeHead(200, {'content-type': 'text/plain'})
new Runner(argv, null).pipe(res)
})
server.listen(1337)

View File

@ -1,33 +0,0 @@
#!/usr/bin/env node
// read a tap stream from stdin.
var TapConsumer = require("../lib/tap-consumer")
, TapProducer = require("../lib/tap-producer")
var tc = new TapConsumer
, tp = new TapProducer
//process.stdin.pipe(tc)
process.stdin.on("data", function (c) {
c = c + ""
// console.error(JSON.stringify(c).substr(0, 100))
tc.write(c)
})
process.stdin.on("end", function () { tc.end() })
process.stdin.resume()
//tc.pipe(tp)
tc.on("data", function (c) {
tp.write(c)
})
tc.on("end", function () { tp.end() })
tp.on("data", function (c) {
console.error(["output write", c])
process.stdout.write(c)
})
tp.on("end", function (er, total, ok) {
if (er) throw er
process.exit(total - ok)
})

View File

@ -1,147 +0,0 @@
#!/usr/bin/env node
var argv = process.argv.slice(2)
, path = require("path")
, Runner = require("../lib/tap-runner")
, nopt = require("nopt")
, knownOpts =
{ cover: [path, false]
, "cover-dir": path
, stderr: Boolean
, stdout: Boolean
, diag: Boolean
, version: Boolean
, tap: Boolean
, timeout: Number
, gc: Boolean
, debug: Boolean
, "debug-brk": Boolean
, strict: Boolean
, harmony: Boolean
}
, shorthands =
// debugging 1: show stderr
{ d: ["--stderr"]
// debugging 2: show stderr and tap
, dd: ["--stderr", "--tap"]
// debugging 3: show stderr, tap, AND always show diagnostics.
, ddd: ["--stderr", "--tap", "--diag"]
, "expose-gc": ["--gc"]
, g: ["--gc"]
, e: ["--stderr"]
, t: ["--timeout"]
, o: ["--tap"]
, c: ["--cover"]
, v: ["--version"]
, "?": ["--help"]
, h: ["--help"]
}
, defaults =
{ cover: "./lib"
, "cover-dir": "./coverage"
, stderr: process.env.TAP_STDERR !== '0'
, tap: process.env.TAP
, diag: process.env.TAP_DIAG
, timeout: +process.env.TAP_TIMEOUT || 30
, gc: false
, debug: false
, "debug-brk": false
, strict: false
, harmony: false
, version: false
, help: false }
, options = nopt(knownOpts, shorthands)
if (options.version) {
console.log(require("../package.json").version)
process.exit(0)
}
if (options.help) {
console.log(function(){/*
Usage:
tap <options> <files>
Run the files as tap tests, parse the output, and report the results
Options:
--stderr Print standard error output of tests to standard error.
--tap Print raw tap output.
--diag Print diagnostic output for passed tests, as well as failed.
(Implies --tap)
--gc Expose the garbage collector to tests.
--timeout Maximum time to wait for a subtest, in seconds. Default: 30
--debug Pass the '--debug' flag to node for debugging
--debug-brk Pass the '--debug-brk' flag to node for debugging
--strict Enforce strict mode when running tests.
--harmony Enable harmony features for tests.
--version Print the version of node tap.
--help Print this help.
Please report bugs! https://github.com/isaacs/node-tap/issues
*/}.toString().split(/\n/).slice(1, -1).join("\n"))
process.exit(0)
}
Object.keys(defaults).forEach(function (k) {
if (!options.hasOwnProperty(k)) options[k] = defaults[k]
})
// other tests that might rely on these
if (options.diag) process.env.TAP_DIAG = true
if (options.tap) process.env.TAP = true
if (options.timeout) process.env.TAP_TIMEOUT = options.timeout
var r = new Runner(options)
, TapProducer = require("../lib/tap-producer")
if (options.tap || options.diag) {
r.pipe(process.stdout)
} else {
r.on("file", function (file, results, details) {
var s = (details.ok ? "" : "not ") + "ok "+results.name
, n = details.pass + "/" + details.testsTotal
, dots = new Array(Math.max(1, 60 - s.length - n.length)).join(".")
console.log("%s %s %s", s, dots, n)
if (details.ok) {
if (details.skip) {
console.log(" skipped: %s", details.skip)
}
if (details.todo) {
console.log(" todo: %s", details.todo)
}
} else {
// console.error(details)
console.log(" Command: %s", results.command)
console.log(" " + TapProducer.encode(details.list)
.split(/\n/).join("\n "))
}
})
r.on("end", function () {
//console.log(r)
var s = "total"
, n = r.results.pass + "/" + r.results.testsTotal
, dots = new Array(60 - s.length - n.length).join(".")
, ok = r.results.ok ? "ok" : "not ok"
console.log("%s %s %s\n\n%s", s, dots, n, ok)
if (r.doCoverage) {
console.error( "\nCoverage: %s\n"
, path.resolve(r.coverageOutDir, "index.html") )
}
})
}
r.on("end", function () {
process.exit(r.results.ok ? 0 : 1)
})

View File

@ -1,15 +0,0 @@
var Bar = module.exports = function(str) {
this.bar = str;
this.str = str;
};
Bar.prototype.foo = function() {
var self = this;
return self.bar;
};
Bar.prototype.baz = function() {
var self = this;
return self.str;
};

View File

@ -1,15 +0,0 @@
var Foo = module.exports = function(str) {
this.foo = str;
this.str = str;
};
Foo.prototype.bar = function() {
var self = this;
return self.foo;
};
Foo.prototype.baz = function() {
var self = this;
return self.str;
};

View File

@ -1,20 +0,0 @@
var test = require('tap').test,
Bar = require('../lib/bar'),
bar;
test('setup', function(t) {
bar = new Bar('baz');
t.ok(bar);
t.end();
});
test('bar', function(t) {
t.equal('baz', bar.foo());
t.end();
});
test('teardown', function(t) {
t.ok(true);
t.end();
});

View File

@ -1,29 +0,0 @@
var test = require('tap').test,
Foo = require('../lib/foo'),
Bar = require('../lib/bar'),
foo, bar;
test('setup', function(t) {
foo = new Foo('baz');
t.ok(foo);
bar = new Bar('baz');
t.ok(bar);
t.end();
});
test('baz from Foo', function(t) {
t.equal('baz', foo.baz());
t.end();
});
test('baz from Bar', function(t) {
t.equal('baz', bar.baz());
t.end();
});
test('teardown', function(t) {
t.ok(true);
t.end();
});

View File

@ -1,20 +0,0 @@
var test = require('tap').test,
Foo = require('../lib/foo'),
foo;
test('setup', function(t) {
foo = new Foo('baz');
t.ok(foo);
t.end();
});
test('bar', function(t) {
t.equal('baz', foo.bar());
t.end();
});
test('teardown', function(t) {
t.ok(true);
t.end();
});

View File

@ -1 +0,0 @@
module.exports = Math

View File

@ -1,237 +0,0 @@
var tap = require("tap")
, test = tap.test
, plan = tap.plan
, math
test("load sut", function (t) {
math = require("../lib/math")
t.ok(math, "object loaded")
t.end()
})
test("validate constants", function (t) {
t.equal(math.LN10, 2.302585092994046, "ln 10")
t.equal(math.PI, 3.141592653589793, "pi")
t.equal(math.E, 2.718281828459045, "e")
t.equal(math.LOG10E, 0.4342944819032518, "log 10 e")
t.equal(math.SQRT2, 1.4142135623730951, "sqrt 2")
t.equal(math.SQRT1_2, 0.7071067811865476, "sqrt 1/2")
t.equal(math.LN2, 0.6931471805599453, "ln2")
t.end()
})
test("using this", function (t) {
// this also works.
this.equal(t, this, "call in scope of test obj")
this.end()
})
// test setTimeout, just a trivial example.
test("setTimeout", function (t) {
var start = Date.now()
setTimeout(function () {
t.ok(Date.now() >= start + 50, "timeout fired after delay")
t.end()
}, 50)
})
// another way to do the same, using a plan.
// this is more robust, but annoying when you have a long list
// of tests for something. For async stuff, it's generally better,
// since there's a higher risk of the control flowing off to lala land.
test("setTimeout planned", function (t) {
t.plan(1)
var start = Date.now()
setTimeout(function () {
t.ok(Date.now() >= start + 50, "timeout fired after delay")
}, 50)
})
// plans also are good for cases where things may fire in a non-deterministic
// order, since it won't be as obvious when everything is done.
test("setTimeout parallel", function (t) {
t.plan(2)
var start = Date.now()
setTimeout(function A () {
t.ok(Date.now() >= start + 50, "timeout A fired after delay")
}, 50)
setTimeout(function B () {
t.ok(Date.now() >= start + 50, "timeout B fired after delay")
}, 50)
})
// something slightly less hello worldy
test("async test", function (t) {
t.plan(4)
var fs = require("fs")
t.ok(fs, "fs library should load")
var rs = fs.createReadStream(__filename)
t.ok(rs, "read stream should start fine.")
rs.on("open", function (fd) {
t.type(fd, "number", "file descriptor should be a number")
t.equal(fd, rs.fd, "fd should match stream fd")
})
})
// you can bail out of the entire everything if something is just
// Not Right (db not installed, etc.)
test("tarp", function (parent) {
if (7 === 5) {
parent.bailout("math is broken")
}
// bailout bubbles up a bit like "error" events
// if unhandled, then the parent will bail, as well.
parent.test("child bailouts", function (child) {
child.on("bailout", function (s) {
parent.fail("children shouldn't bail.")
})
child.bailout("try to bail out, but instead just fail a test")
})
parent.test("child bailout 2", function (child) {
child.bailout("this one will bail out")
})
})
// tests marked "todo" can fail without counting against the overall score
// never ever ever write tests to "verify" incorrect behavior!
test("unfinished test", function (t) {
t.equal(math.cos(math.PI), -1, "cos(PI)")
t.equal(math.sin(math.PI), 0, "sin(PI)")
t.equal(math.face, "your face", "math.face should be your face # TODO")
t.end()
})
// tests can have children.
test("http server", function (t) {
// one test plus 4 children.
t.plan(5)
var http = require("http")
, PORT = 12346
t.ok(http, "http module should load")
var server
t.test("set up server", function (t) {
t.plan(2)
server = http.createServer(function (req, res) {
t.comment("Request: "+req.url)
res.writeHead(200, {})
res.end(req.method + " " + req.url)
})
t.ok(server, "createServer should create a server")
server.listen(PORT, t.cb("listen should fire callback"))
})
// set the "parallel" flag on this one.
// That signals the harness to proceed immediately to the next test,
// and run them in parallel.
// Default behavior is to wait for each test to complete before proceeding
// to the next one.
// The first not-parallel test encountered will cause it to wait for that
// test, as well as all the parallel tests before it.
// A, B', C', D', E (where ' means "parallel")
// Runs A, and then B, C, and D in parallel, and then E.
t.test("testing POST", {parallel: true}, function (t) {
t.plan(1)
http.request("POST", { method: "POST"
, host: "localhost"
, path: "/foo"
, port: PORT }).on("response", function (res) {
t.bufferStream(res, function (s) { t.equal(s, "POST /foo") })
}).end()
})
t.test("testing GET", {parallel: true}, function (t) {
t.plan(1)
http.request("POST", { method: "GET"
, host: "localhost"
, path: "/foo"
, port: PORT }).on("response", function (res) {
t.bufferStream(res, function (s) { t.equal(s, "GET /foo") })
}).end()
})
// wrap in a test so that if this throws, it'll log as a failed test.
t.test("teardown", function (t) {
server.close()
t.end()
})
})
// yo dawg!
test("meta-tests", function (t) {
t.plan(5)
// t.fails() wraps a child test and succeeds if it fails.
t.fails(t.test("this should fail", function (t) {
t.ok(false, "assert false")
t.end()
}))
// t.timesOut() wraps a child test and succeeds if it times out.
// if t.end() is called, or if a plan is completed, then it fails.
// set the timeout really low so that it will not take forever.
t.timesOut(t.test("this should timeout", { timeout: 1 }, function (t) {
t.ok(true, "assert true")
// t.end() never called.
}))
// t.incomplete() wraps a child test and succeeds if it ends before
// the plan is finished.
t.incomplete(t.test("this should be incomplete", function (t) {
t.plan(100)
t.ok(true, "assert true")
// calling end prematurely.
t.end()
}))
// t.bailsOut() wraps a child test and succeeds if it calls bailout()
t.bailsOut(t.test("this should bailout", function (t) {
t.bailout("oh noes, bailing out!")
}))
// low-level analysis of subtests
t.test("verifying test success/failure expectations", function (t) {
t.once("end", function () {
var res = t.results
, is = t.equal
// hijack!
t.clear()
is(res.ok, false, "ok")
is(res.bailedOut, false, "bailed out")
is(res.skip, 2, "skips")
is(res.skipPass, 1, "skip that passed")
is(res.skipFail, 1, "skip that failed")
is(res.todo, 2, "todos")
is(res.todoPass, 1, "todo that passed")
is(res.todoFail, 1, "todo that failed")
is(res.failTotal, 3, "failures total")
is(res.fail, 1, "relevant failure")
is(res.passTotal, 3, "passes total")
is(res.pass, 1, "relevant pass")
is(res.testsTotal, 6, "total tests")
is(res.tests, 2, "should be 2 relevant tests")
t.end()
})
// run the metatest.
// *this* is the actual SUT in this case.
t.ok(false, "failing todo #todo")
// can also set #todo or #skip explicitly
t.ok(true, "succeeding todo", {todo: true})
t.ok(false, "failing skip #skip", {skip: true})
t.ok(true, "suceeding skip #skip")
t.ok(false, "failing test")
t.ok(true, "succeeding test")
t.end()
})
})

View File

@ -1,16 +0,0 @@
var GlobalHarness = require("./tap-global-harness")
// this lets you do stuff like:
// var test = require("tap").test
// test(...)
// to run stuff in the global harness.
exports = module.exports = new GlobalHarness()
exports.createProducer = exports.Producer = require("./tap-producer")
exports.createConsumer = exports.Consumer = require("./tap-consumer")
exports.yamlish = require("yamlish")
exports.createTest = exports.Test = require("./tap-test")
exports.createHarness = exports.Harness = require("./tap-harness")
exports.createRunner = exports.Runner = require("./tap-runner")
exports.assert = require("./tap-assert")

View File

@ -1,466 +0,0 @@
// an assert module that returns tappable data for each assertion.
var difflet = require('difflet')
, deepEqual = require('deep-equal')
, bufferEqual = require('buffer-equal')
, Buffer = require('buffer').Buffer
module.exports = assert
var syns = {}
, id = 1
function assert (ok, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
//console.error("assert %j", [ok, message, extra])
//if (extra && extra.skip) return assert.skip(message, extra)
//console.error("assert", [ok, message, extra])
ok = !!ok
var res = { id : id ++, ok: ok }
var caller = getCaller(extra && extra.error)
if (extra && extra.error) {
res.type = extra.error.name
res.message = extra.error.message
res.code = extra.error.code
|| extra.error.type
res.errno = extra.error.errno
delete extra.error
}
if (caller.file) {
res.file = caller.file
res.line = +caller.line
res.column = +caller.column
}
res.stack = caller.stack
res.name = message || "(unnamed assert)"
if (extra) Object.keys(extra).forEach(function (k) {
if (!res.hasOwnProperty(k)) res[k] = extra[k]
})
// strings and objects are hard to diff by eye
if (!ok &&
res.hasOwnProperty("found") &&
res.hasOwnProperty("wanted") &&
res.found !== res.wanted) {
if (typeof res.wanted !== typeof res.found ||
typeof res.wanted === "object" && (!res.found || !res.wanted)) {
res.type = { found: typeof found
, wanted: typeof wanted }
} else if (typeof res.wanted === "string") {
res.diff = diffString(res.found, res.wanted)
} else if (typeof res.wanted === "object") {
res.diff = diffObject(res.found, res.wanted)
}
}
//console.error("assert return", res)
return res
}
assert.ok = assert
syns.ok = [ "true", "assert" ]
function notOk (ok, message, extra) {
return assert(!ok, message, extra)
}
assert.notOk = notOk
syns.notOk = [ "false", "notok" ]
function error (er, message, extra) {
if (!er) {
// just like notOk(er)
return assert(!er, message, extra)
}
message = message || er.message
extra = extra || {}
extra.error = er
return assert.fail(message, extra)
}
assert.error = error
syns.error = [ "ifError", "ifErr", "iferror" ]
function pass (message, extra) {
return assert(true, message, extra)
}
assert.pass = pass
function fail (message, extra) {
//console.error("assert.fail", [message, extra])
//if (extra && extra.skip) return assert.skip(message, extra)
return assert(false, message, extra)
}
assert.fail = fail
function skip (message, extra) {
//console.error("assert.skip", message, extra)
if (!extra) extra = {}
return { id: id ++, skip: true, name: message || "",
explanation: extra.explanation || "" }
}
assert.skip = skip
function throws (fn, wanted, message, extra) {
if (typeof wanted === "string") {
extra = message
message = wanted
wanted = null
}
if (extra && extra.skip) return assert.skip(message, extra)
var found = null
try {
fn()
} catch (e) {
found = { name: e.name, message: e.message }
}
extra = extra || {}
extra.found = found
if (wanted) {
wanted = { name: wanted.name, message: wanted.message }
extra.wanted = wanted
}
if (!message) {
message = "Expected to throw"
if (wanted) message += ": "+wanted.name + " " + wanted.message
}
return (wanted) ? assert.similar(found, wanted, message, extra)
: assert.ok(found, message, extra)
}
assert.throws = throws
function doesNotThrow (fn, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
var found = null
try {
fn()
} catch (e) {
found = {name: e.name, message: e.message}
}
message = message || "Should not throw"
return assert.equal(found, null, message, extra)
}
assert.doesNotThrow = doesNotThrow
function equal (a, b, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
extra = extra || {}
message = message || "should be equal"
extra.found = a
extra.wanted = b
return assert(a === b, message, extra)
}
assert.equal = equal
syns.equal = ["equals"
,"isEqual"
,"is"
,"strictEqual"
,"strictEquals"]
function equivalent (a, b, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
var extra = extra || {}
message = message || "should be equivalent"
extra.found = a
extra.wanted = b
if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
return assert(bufferEqual(a, b), message, extra)
} else {
return assert(deepEqual(a, b), message, extra)
}
}
assert.equivalent = equivalent
syns.equivalent = ["isEquivalent"
,"looseEqual"
,"looseEquals"
,"isDeeply"
,"same"
,"deepEqual"
,"deepEquals"]
function strictDeepEqual (a, b, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
var extra = extra || {}
message = message || "should be strictly equal"
extra.found = a
extra.wanted = b
if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
return assert(bufferEqual(a, b), message, extra)
} else {
return assert(deepEqual(a, b, {strict: true}), message, extra)
}
}
assert.strictDeepEqual = strictDeepEqual
syns.strictDeepEqual = ["isStrictEquivalent"
,"isStrictly"
,"exactSame"
,"strictDeepEqual"
,"strictDeepEquals"]
function inequal (a, b, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
extra = extra || {}
message = message || "should not be equal"
extra.found = a
extra.doNotWant = b
return assert(a !== b, message, extra)
}
assert.inequal = inequal
syns.inequal = ["notEqual"
,"notEquals"
,"notStrictEqual"
,"notStrictEquals"
,"isNotEqual"
,"isNot"
,"not"
,"doesNotEqual"
,"isInequal"]
function inequivalent (a, b, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
extra = extra || {}
message = message || "should not be equivalent"
extra.found = a
extra.doNotWant = b
if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) {
return assert(!bufferEqual(a, b), message, extra)
} else {
return assert(!deepEqual(a, b), message, extra)
}
}
assert.inequivalent = inequivalent
syns.inequivalent = ["notEquivalent"
,"notDeepEqual"
,"notDeeply"
,"notSame"
,"isNotDeepEqual"
,"isNotDeeply"
,"isNotEquivalent"
,"isInequivalent"]
function similar (a, b, message, extra, flip) {
if (extra && extra.skip) return assert.skip(message, extra)
// test that a has all the fields in b
message = message || "should be similar"
if (typeof a === "string" &&
(Object.prototype.toString.call(b) === "[object RegExp]")) {
extra = extra || {}
extra.pattern = b
extra.string = a
var ok = a.match(b)
extra.match = ok
if (flip) ok = !ok
return assert.ok(ok, message, extra)
}
var isObj = assert(a && typeof a === "object", message, extra)
if (!isObj.ok) {
// not an object
if (a == b) isObj.ok = true
if (flip) isObj.ok = !isObj.ok
return isObj
}
var eq = flip ? inequivalent : equivalent
return eq(selectFields(a, b), b, message, extra)
}
assert.similar = similar
syns.similar = ["isSimilar"
,"has"
,"hasFields"
,"like"
,"isLike"]
function dissimilar (a, b, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
message = message || "should be dissimilar"
return similar(a, b, message, extra, true)
}
assert.dissimilar = dissimilar
syns.dissimilar = ["unsimilar"
,"notSimilar"
,"unlike"
,"isUnlike"
,"notLike"
,"isNotLike"
,"doesNotHave"
,"isNotSimilar"
,"isDissimilar"]
function type (thing, t, message, extra) {
if (extra && extra.skip) return assert.skip(message, extra)
var name = t
if (typeof name === "function") name = name.name || "(anonymous ctor)"
//console.error("name=%s", name)
message = message || "type is "+name
var type = typeof thing
//console.error("type=%s", type)
if (!thing && type === "object") type = "null"
if (type === "object" && t !== "object") {
if (typeof t === "function") {
//console.error("it is a function!")
extra = extra || {}
extra.found = Object.getPrototypeOf(thing).constructor.name
extra.wanted = name
//console.error(thing instanceof t, name)
return assert.ok(thing instanceof t, message, extra)
}
//console.error("check prototype chain")
// check against classnames or objects in prototype chain, as well.
// type(new Error("asdf"), "Error")
// type(Object.create(foo), foo)
var p = thing
while (p = Object.getPrototypeOf(p)) {
if (p === t || p.constructor && p.constructor.name === t) {
type = name
break
}
}
}
//console.error(type, name, type === name)
return assert.equal(type, name, message, extra)
}
assert.type = type
syns.type = ["isa"]
// synonyms are helpful.
Object.keys(syns).forEach(function (c) {
syns[c].forEach(function (s) {
Object.defineProperty(assert, s, { value: assert[c], enumerable: false })
})
})
// helpers below
function selectFields (a, b) {
// get the values in A of the fields in B
var ret = Array.isArray(b) ? [] : {}
Object.keys(b).forEach(function (k) {
if (!a.hasOwnProperty(k)) return
var v = b[k]
, av = a[k]
if (v && av && typeof v === "object" && typeof av === "object"
&& !(v instanceof Date)
&& !(v instanceof RegExp)
&& !(v instanceof String)
&& !(v instanceof Boolean)
&& !(v instanceof Number)
&& !(Array.isArray(v))) {
ret[k] = selectFields(av, v)
} else ret[k] = av
})
return ret
}
function sortObject (obj) {
if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) {
return obj
}
return Object.keys(obj).sort().reduce(function (acc, key) {
acc[key] = sortObject(obj[key])
return acc
}, {})
}
function stringify (a) {
return JSON.stringify(sortObject(a), (function () {
var seen = []
, keys = []
return function (key, val) {
var s = seen.indexOf(val)
if (s !== -1) {
return "[Circular: "+keys[s]+"]"
}
if (val && typeof val === "object" || typeof val === "function") {
seen.push(val)
keys.push(val["!"] || val.name || key || "<root>")
if (typeof val === "function") {
return val.toString().split(/\n/)[0]
} else if (typeof val.toUTCString === "function") {
return val.toUTCString()
}
}
return val
}})())
}
function diffString (f, w) {
if (w === f) return null
var p = 0
, l = w.length
while (p < l && w.charAt(p) === f.charAt(p)) p ++
w = stringify(w).substr(1).replace(/"$/, "")
f = stringify(f).substr(1).replace(/"$/, "")
return diff(f, w, p)
}
function diffObject (f, w) {
return difflet({ indent : 2, comment : true }).compare(w, f)
}
function diff (f, w, p) {
if (w === f) return null
var i = p || 0 // it's going to be at least p. JSON can only be bigger.
, l = w.length
while (i < l && w.charAt(i) === f.charAt(i)) i ++
var pos = Math.max(0, i - 20)
w = w.substr(pos, 40)
f = f.substr(pos, 40)
var pointer = i - pos
return "FOUND: "+f+"\n"
+ "WANTED: "+w+"\n"
+ (new Array(pointer + 9).join(" "))
+ "^ (at position = "+p+")"
}
function getCaller (er) {
// get the first file/line that isn't this file.
if (!er) er = new Error
var stack = er.stack || ""
stack = stack.split(/\n/)
for (var i = 1, l = stack.length; i < l; i ++) {
var s = stack[i].match(/\(([^):]+):([0-9]+):([0-9]+)\)$/)
if (!s) continue
var file = s[1]
, line = +s[2]
, col = +s[3]
if (file.indexOf(__dirname) === 0) continue
if (file.match(/tap-test\/test.js$/)) continue
else break
}
var res = {}
if (file && file !== __filename && !file.match(/tap-test\/test.js$/)) {
res.file = file
res.line = line
res.column = col
}
res.stack = stack.slice(1).map(function (s) {
return s.replace(/^\s*at\s*/, "")
})
return res
}

View File

@ -1,63 +0,0 @@
// this is just a harness that pipes to stdout.
// It's the default one.
module.exports = BrowserHarness
var BrowserHarness = global.TAP_Browser_Harness
, inherits = require("inherits")
, Results = require("./tap-results")
, Harness = require("./tap-harness")
, Test = require("./tap-test")
inherits(BrowserHarness, Harness)
function BrowserHarness (outPipe) {
//console.error("calling BrowserHarness")
if (browserHarness) return browserHarness
if (!(this instanceof BrowserHarness)) {
return browserHarness = new BrowserHarness
}
browserHarness = global.TAP_Browser_Harness = this
Harness.call(this, Test)
if (outPipe) this.output.pipe(outPipe)
this.test = this.test.bind(this)
this.plan = this.plan.bind(this)
var output = this.output
this.on("childEnd", function (child) {
//console.error("childEnd in global harness")
//console.error(child.results)
// write out the stuff for this child.
//console.error("child.conf", child.conf)
// maybe write some other stuff about the number of tests in this
// thing, etc. I dunno.
//console.error("child results", child.results)
this.results.list.forEach(function (res) {
//delete res.error
//console.error("child resuilt", res)
output.write(res)
})
//console.error("wrote child results")
this.results.list.length = 0
})
var streamEnded = false
this.on("end", function () {
//console.error("global ending the stream")
if (!streamEnded) {
this.results.list.forEach(function (res) {
output.write(res)
})
this.results.list.length = 0
output.end()
streamEnded = true
}
})
// TODO: handle global errors
// process.on("unhandledException", function (e) {
// this.bailout("unhandled exception: " + e.message)
// })
}

View File

@ -1,246 +0,0 @@
module.exports = TapConsumer
// pipe a stream into this that's emitting tap-formatted data,
// and it'll emit "data" events with test objects or comment strings
// and an "end" event with the final results.
var yamlish = require("yamlish")
, Results = require("./tap-results")
, inherits = require("inherits")
TapConsumer.decode = TapConsumer.parse = function (str) {
var tc = new TapConsumer
, list = []
tc.on("data", function (res) {
list.push(res)
})
tc.end(str)
tc.results.list = list
return tc.results
}
var Stream = require("stream").Stream
inherits(TapConsumer, Stream)
function TapConsumer () {
if (!(this instanceof TapConsumer)) {
return new TapConsumer
}
Stream.call(this)
this.results = new Results
this.readable = this.writable = true
this.on("data", function (res) {
if (typeof res === "object") this.results.add(res)
})
this._plan = null
this._buffer = ""
this._indent = []
this._current = null
this._actualCount = 0
this._passed = []
this._failed = []
//console.error("TapConsumer ctor done")
}
TapConsumer.prototype.bailedOut = false
TapConsumer.prototype.write = function (chunk) {
if (!this.writable) this.emit("error", new Error("not writable"))
if (this.bailedOut) return true
this._buffer = this._buffer + chunk
// split it up into lines.
var lines = this._buffer.split(/\r?\n/)
// ignore the last line, since it might be incomplete.
this._buffer = lines.pop()
for (var i = 0, l = lines.length; i < l; i ++) {
//console.error([i, lines[i]])
// see if it's indented.
var line = lines[i]
, spaces = (this._indent.length && !line.trim())
|| line.match(/^\s/)
// at this level, only interested in fully undented stuff.
if (spaces) {
var c = i
while (c < l && (!lines[c].trim() || lines[c].match(/^\s/))) {
this._indent.push(lines[c++])
}
//console.error(c-i, "indented", this._indent, this._current)
i = c - 1
continue
}
// some kind of line. summary, ok, notok, comment, or garbage.
// this also finishes parsing any of the indented lines from before
this._parseLine(line)
}
return true
}
TapConsumer.prototype.end = function () {
// finish up any hanging indented sections or final buffer
if (this._buffer.match(/^\s/)) this._indent.push(this.buffer)
else this._parseLine(this._buffer)
if (!this.bailedOut &&
this._plan !== null &&
this.results.testsTotal !== this._plan) {
while (this._actualCount < this._plan) {
this.emit("data", {ok: false, name:"MISSING TEST",
id:this._actualCount ++ })
}
}
this._parseLine("")
this._buffer = ""
this.writable = false
this.emit("end", null, this._actualCount, this._passed)
}
TapConsumer.prototype._parseLine = function (line) {
if (this.bailedOut) return
//console.error("_parseLine", [line])
// if there are any indented lines, and there is a
// current object already, then they belong to it.
// if there is not a current object, then they're garbage.
if (this._current && this._indent.length) {
this._parseIndented()
}
this._indent.length = 0
if (this._current) {
if (this._current.ok) this._passed.push(this._current.id)
else this._failed.push(this._current.id)
this.emit("data", this._current)
}
this._current = null
line = line.trim()
if (!line) return
// try to see what kind of line this is.
var bo
if (bo = line.match(/^bail out!\s*(.*)$/i)) {
this.bailedOut = true
// this.emit("error", new Error(line))
this.emit("bailout", bo[1])
return
}
if (line.match(/^#/)) { // just a comment
line = line.replace(/^#+/, "").trim()
// console.error("outputting comment", [line])
if (line) this.emit("data", line)
return
}
var plan = line.match(/^([0-9]+)\.\.([0-9]+)(?:\s+#(.*))?$/)
if (plan) {
var start = +(plan[1])
, end = +(plan[2])
, comment = plan[3]
// TODO: maybe do something else with this?
// it might be something like: "1..0 #Skip because of reasons"
this._plan = end
this.emit("plan", end, comment)
// plan must come before or after all tests.
if (this._actualCount !== 0) {
this._sawPlan = true
}
return
}
if (line.match(/^(not )?ok(?:\s+([0-9]+))?/)) {
this._parseResultLine(line)
return
}
// garbage. emit as a comment.
//console.error("emitting", [line.trim()])
if (line.trim()) this.emit("data", line.trim())
}
TapConsumer.prototype._parseDirective = function (line) {
line = line.trim()
if (line.match(/^TODO\b/i)) {
return { todo:true, explanation: line.replace(/^TODO\s*/i, "") }
} else if (line.match(/^SKIP\b/i)) {
return { skip:true, explanation: line.replace(/^SKIP\s*/i, "") }
}
}
TapConsumer.prototype._parseResultLine = function (line) {
this._actualCount ++
if (this._sawPlan) {
this.emit("data", {ok: false, name:"plan in the middle of tests"
,id:this._actualCount ++})
}
var parsed = line.match(/^(not )?ok(?: ([0-9]+))?(?:(?: - )?(.*))?$/)
, ok = !parsed[1]
, id = +(parsed[2] || this._actualCount)
, rest = parsed[3] || ""
, name
, res = { id:id, ok:ok }
// split on un-escaped # characters
//console.log("# "+JSON.stringify([name, rest]))
rest = rest.replace(/([^\\])((?:\\\\)*)#/g, "$1\n$2").split("\n")
name = rest.shift()
rest = rest.filter(function (r) { return r.trim() }).join("#")
//console.log("# "+JSON.stringify([name, rest]))
// now, let's see if there's a directive in there.
var dir = this._parseDirective(rest.trim())
if (!dir) name += rest ? "#" + rest : ""
else {
res.ok = true
if (dir.skip) res.skip = true
else if (dir.todo) res.todo = true
if (dir.explanation) res.explanation = dir.explanation
}
res.name = name
//console.error(line, [ok, id, name])
this._current = res
}
TapConsumer.prototype._parseIndented = function () {
// pull yamlish block out
var ind = this._indent
, ys
, ye
, yind
, diag
//console.error(ind, this._indent)
for (var i = 0, l = ind.length; i < l; i ++) {
var line = ind[i]
if (line === undefined) continue
var lt = line.trim()
if (!ys) {
ys = line.match(/^(\s*)---(.*)$/)
if (ys) {
yind = ys[1]
diag = [ys[2]]
//console.error([line,ys, diag])
continue
} else if (lt) this.emit("data", lt)
} else if (ys && !ye) {
if (line === yind + "...") ye = true
else {
diag.push(line.substr(yind.length))
}
} else if (ys && ye && lt) this.emit("data", lt)
}
if (diag) {
//console.error('about to parse', diag)
diag = yamlish.decode(diag.join("\n"))
//console.error('parsed', diag)
Object.keys(diag).forEach(function (k) {
//console.error(this._current, k)
if (!this._current.hasOwnProperty(k)) this._current[k] = diag[k]
}, this)
}
}

View File

@ -1,78 +0,0 @@
var fs = require('fs'),
path = require('path'),
asyncMap = require("slide").asyncMap,
util = require('util');
var CovHtml = module.exports = function(cov_stats, cov_dir, cb) {
var index = [];
asyncMap(
Object.keys(cov_stats),
function(f, cb) {
var st = cov_stats[f],
missing_lines = st.missing.map(function(l) {
return l.number;
}),
out = '<!doctype html>\n<html lang="en">\n<head>\n ' +
'<meta charset="utf-8">\n <title>' +
f + ' (' + st.loc + ')</title>\n' +
'<style type="text/css">\n' +
'li {\n' +
' font-family: monospace;\n' +
' white-space: pre;\n' +
'}\n' +
'</style>\n' +
'</head>\n<body>\n' +
'<h1>' + f + ' (' + st.loc + ')' + '</h1>' +
'<h2>Run: ' + (st.missing.length ? st.loc - st.missing.length : st.loc) + ', Missing: ' +
st.missing.length + ', Percentage: ' + st.percentage + '</h2>' +
'<h2>Source:</h2>\n' +
'<ol>\n' +
st.lines.map(function(line) {
var number = line.number,
color = (missing_lines.indexOf(number) !== -1) ? '#fcc' : '#cfc';
return '<li id="L' + line.number + '" style="background-color: ' + color +
';">' + line.source.replace(/</g, "&lt;") + '</li>';
}).join('\n') +
'</ol>\n' +
'<h2>Data</h2>\n'+
'<pre>' + util.inspect(st, true, Infinity, false).replace(/</g, "&lt;") + '</pre></body>\n</html>';
fs.writeFile(
cov_dir + '/' +
f.replace(process.cwd() + '/', '').replace(/\//g, '+') + '.html',
out,
'utf8',
function(err) {
if (err) {
throw err;
}
index.push(f);
cb();
});
},
function(err) {
if (err) {
throw err;
}
var out = '<!doctype html>\n<html lang="en">\n<head>\n ' +
'<meta charset="utf-8">\n <title>Coverage Index</title>\n</head>\n' +
'<body>\n<h1>Code Coverage Information</h1>\n<ul>' +
index.map(function(fname) {
return '<li><a href="' +
fname.replace(process.cwd() + '/', '').replace(/\//g, '+') + '.html' +
'">' + fname + '</a></li>';
}).join('\n') + '</ul>\n</body>\n</html>';
fs.writeFile(cov_dir + '/index.html', out, 'utf8', function(err) {
if (err) {
throw err;
}
cb();
});
}
);
};

View File

@ -1,80 +0,0 @@
// this is just a harness that pipes to stdout.
// It's the default one.
module.exports = GlobalHarness
var globalHarness = global.TAP_Global_Harness
, inherits = require("inherits")
, Results = require("./tap-results")
, Harness = require("./tap-harness")
, Test = require("./tap-test")
inherits(GlobalHarness, Harness)
function GlobalHarness () {
//console.error("calling GlobalHarness")
if (globalHarness) return globalHarness
if (!(this instanceof GlobalHarness)) {
return globalHarness = new GlobalHarness
}
globalHarness = global.TAP_Global_Harness = this
Harness.call(this, Test)
this.output.pipe(process.stdout)
//this.output.on("data", function () {
// process.nextTick(process.stdout.flush.bind(process.stdout))
//})
this.test = this.test.bind(this)
this.plan = this.plan.bind(this)
var output = this.output
this.on("childEnd", function (child) {
//console.error("childEnd in global harness")
//console.error(child.results)
// write out the stuff for this child.
//console.error("child.conf", child.conf)
// maybe write some other stuff about the number of tests in this
// thing, etc. I dunno.
//console.error("child results", child.results)
this.results.list.forEach(function (res) {
//delete res.error
//console.error("child resuilt", res)
output.write(res)
})
//console.error("wrote child results")
this.results.list.length = 0
})
var streamEnded = false
this.on("end", function () {
//console.error("global ending the stream")
if (!streamEnded) {
this.results.list.forEach(function (res) {
output.write(res)
})
this.results.list.length = 0
output.end()
streamEnded = true
// If we had fails, then make sure that the exit code
// reflects that failure.
var exitCode
if (!this.results.ok)
exitCode = process.exitCode = 1
if (exitCode !== 0) {
process.on('exit', function (code) {
if (code === 0)
process.exit(exitCode)
})
}
}
})
//this.on("end", this.output.end.bind(this.output))
process.on("unhandledException", function (e) {
this.bailout("unhandled exception: " + e.message)
})
}

View File

@ -1,226 +0,0 @@
// a thing that runs tests.
// Every "test" is also a harness. If they do not have a harness,
// then they are attached to the defaut "global harness",
// which writes its results to stdout.
// TODO:
// - Bailout should stop running any tests.
// - "skip" in the test config obj should skip it.
module.exports = Harness
var EE = require("events").EventEmitter
require("inherits")(Harness, EE)
var Results = require("./tap-results")
, TapProducer = require("./tap-producer")
, assert = require("./tap-assert")
function Harness (Test) {
if (!(this instanceof Harness)) return new Harness(Test)
//console.error("Test in "+this.constructor.name, Test)
this._Test = Test
this._plan = null
this._children = []
this._processing = false
this._testCount = 0
this._planSum = 0
this.results = new Results()
// emit result events on the harness.
//this.results.on("result", function (res) {
// console.error("proxying result ev from res to harness")
// this.emit("result", res)
//}.bind(this))
var me = this
this.results.on("result", this.emit.bind(this, "result"))
var p = this.process.bind(this)
this.process = function () {
this._processing = true
process.nextTick(p)
}
this.output = new TapProducer()
EE.call(this)
}
// this function actually only gets called bound to
// the Harness object, and on process.nextTick. Even if
// passed as an event handler, everything *else* will
// happen before it gets called.
Harness.prototype.process = function () {
//console.error("harness process")
// "end" can emit multiple times, so only actually move on
// to the next test if the current one is actually over.
// TODO: multiple in-process tests, if all are marked "async"
if (this._current) {
if (!this._current._ended) return
// handle the current one before moving onto the next.
this.childEnd(this._current)
}
var skip = true
while (skip) {
//console.error("checking for skips")
var current = this._current = this._children.shift()
if (current) {
skip = current.conf.skip
if (skip) {
//console.error("add a failure for the skipping")
this.results.add(assert.fail(current.conf.name
,{skip:true, diag:false}))
}
} else skip = false
}
// keep processing through skipped tests, instead of running them.
if (current && this._bailedOut) {
return this.process()
}
//console.error("got current?", !!current)
if (current) {
current.on("end", this.process)
current.emit("ready")
//console.error("emitted ready")
//console.error("_plan", this._plan, this.constructor.name)
} else if (!this._plan || (this._plan && this._plan === this._testCount)) {
//console.error("Harness process: no more left. ending")
if (this._endNice) {
this._endNice()
} else {
this.end()
}
} else {
this._processing = false;
}
}
Harness.prototype.end = function () {
if (this._children.length) {
return this.process()
}
//console.error("harness end", this.constructor.name)
if (this._bailedOut) return
// can't call .end() more than once.
if (this._ended) {
//console.error("adding failure for end calling")
this.results.add(assert.fail("end called more than once"))
}
// see if the plan is completed properly, if there was one.
if (this._plan !== null) {
var total = this._testCount
if (total !== this._plan) {
this.results.add(assert.equal(total, this._plan, "test count != plan"))
}
this._plan = total
}
//console.error("setting ended true", this.constructor.name)
this._ended = true
this.emit("end")
}
Harness.prototype.plan = function (p) {
//console.error("setting plan", new Error().stack)
if (this._plan !== null) {
//console.error("about to add failure for calling plan")
return this.results.add(assert.fail("plan set multiple times"))
}
this._plan = p
if (p === 0 || this.results.testsTotal) {
this.end()
}
}
Harness.prototype.childEnd = function (child) {
//console.error("childEnd")
this._testCount ++
this._planSum += child._plan
//console.error("adding set of child.results")
this.results.add(child.conf.name || "(unnamed test)")
this.results.addSet(child.results)
this.emit("childEnd", child)
// was this planned?
if (this._plan === this._testCount) {
//console.error("plan", [this._plan, this._testCount])
return this.end()
}
}
function copyObj(o) {
var copied = {}
Object.keys(o).forEach(function (k) { copied[k] = o[k] })
return copied
}
Harness.prototype.test = function test (name, conf, cb) {
if (this._bailedOut) return
if (typeof conf === "function") cb = conf, conf = null
if (typeof name === "object") conf = name, name = null
if (typeof name === "function") cb = name, name = null
conf = (conf ? copyObj(conf) : {})
name = name || ""
//console.error("making test", [name, conf, cb])
// timeout: value in milliseconds. Defaults to 30s
// Set to Infinity to have no timeout.
if (isNaN(conf.timeout)) conf.timeout = 30000
var t = new this._Test(this, name, conf)
var self = this
if (cb) {
//console.error("attaching cb to ready event")
t.on("ready", function () {
if (!isNaN(conf.timeout) && isFinite(conf.timeout)) {
var timer = setTimeout(this.timeout.bind(this), conf.timeout)
var clear = function () {
clearTimeout(timer)
}
t.on("end", clear)
t.on("bailout", function (message) {
self.bailout(message)
clear()
})
}
})
t.on("ready", cb.bind(t, t))
// proxy the child results to this object.
//t.on("result", function (res) {
// console.error("in harness, proxying result up")
// t.results.add(res)
//})
}
return t
}
Harness.prototype.bailout = function (message) {
// console.error("Harness bailout", this.constructor.name)
message = message || ""
//console.error("adding bailout message result")
this.results.add({bailout: message})
// console.error(">>> results after bailout" , this.results)
this._bailedOut = true
this.emit("bailout", message)
this.output.end({bailout: message})
}
Harness.prototype.add = function (child) {
//console.error("adding child")
this._children.push(child)
if (!this._processing) this.process()
}
// the tearDown function is *always* guaranteed to happen.
// Even if there's a bailout.
Harness.prototype.tearDown = function (fn) {
this.on("end", fn)
}

View File

@ -1,131 +0,0 @@
module.exports = TapProducer
var Results = require("./tap-results")
, inherits = require("inherits")
, yamlish = require("yamlish")
TapProducer.encode = function (result, diag) {
var tp = new TapProducer(diag)
, out = ""
tp.on("data", function (c) { out += c })
if (Array.isArray(result)) {
result.forEach(tp.write, tp)
} else tp.write(result)
tp.end()
return out
}
var Stream = require("stream").Stream
inherits(TapProducer, Stream)
function TapProducer (diag) {
Stream.call(this)
this.diag = diag
this.count = 0
this.readable = this.writable = true
this.results = new Results
}
TapProducer.prototype.trailer = true
TapProducer.prototype.write = function (res) {
// console.error("TapProducer.write", res)
if (typeof res === "function") throw new Error("wtf?")
if (!this.writable) this.emit("error", new Error("not writable"))
if (!this._didHead) {
this.emit("data", "TAP version 13\n")
this._didHead = true
}
var diag = res.diag
if (diag === undefined) diag = this.diag
this.emit("data", encodeResult(res, this.count + 1, diag))
if (typeof res === "string") return true
if (res.bailout) {
var bo = "bail out!"
if (typeof res.bailout === "string") bo += " " + res.bailout
this.emit("data", bo)
return
}
this.results.add(res, false)
this.count ++
}
TapProducer.prototype.end = function (res) {
if (res) this.write(res)
// console.error("TapProducer end", res, this.results)
this.emit("data", "\n1.."+this.results.testsTotal+"\n")
if (this.trailer && typeof this.trailer !== "string") {
// summary trailer.
var trailer = "tests "+this.results.testsTotal + "\n"
if (this.results.pass) {
trailer += "pass " + this.results.pass + "\n"
}
if (this.results.fail) {
trailer += "fail " + this.results.fail + "\n"
}
if (this.results.skip) {
trailer += "skip "+this.results.skip + "\n"
}
if (this.results.todo) {
trailer += "todo "+this.results.todo + "\n"
}
if (this.results.bailedOut) {
trailer += "bailed out" + "\n"
}
if (this.results.testsTotal === this.results.pass) {
trailer += "\nok\n"
}
this.trailer = trailer
}
if (this.trailer) this.write(this.trailer)
this.writable = false
this.emit("end", null, this.count, this.ok)
}
function encodeResult (res, count, diag) {
// console.error(res, count, diag)
if (typeof res === "string") {
res = res.split(/\r?\n/).map(function (l) {
if (!l.trim()) return l.trim()
return "# " + l
}).join("\n")
if (res.substr(-1) !== "\n") res += "\n"
return res
}
if (res.bailout) return ""
if (!!process.env.TAP_NODIAG) diag = false
else if (!!process.env.TAP_DIAG) diag = true
else if (diag === undefined) diag = !res.ok
var output = ""
res.name = res.name && ("" + res.name).trim()
output += ( !res.ok ? "not " : "") + "ok " + count
+ ( !res.name ? ""
: " " + res.name.replace(/[\r\n]/g, " ") )
+ ( res.skip ? " # SKIP " + ( res.explanation || "" )
: res.todo ? " # TODO " + ( res.explanation || "" )
: "" )
+ "\n"
if (!diag) return output
var d = {}
, dc = 0
Object.keys(res).filter(function (k) {
return k !== "ok" && k !== "name" && k !== "id"
}).forEach(function (k) {
dc ++
d[k] = res[k]
})
//console.error(d, "about to encode")
if (dc > 0) output += " ---"+yamlish.encode(d)+"\n ...\n"
return output
}

View File

@ -1,72 +0,0 @@
// A class for counting up results in a test harness.
module.exports = Results
var inherits = require("inherits")
, EventEmitter = require("events").EventEmitter
inherits(Results, EventEmitter)
function Results (r) {
//console.error("result constructor", r)
this.ok = true
this.addSet(r)
}
Results.prototype.addSet = function (r) {
//console.error("add set of results", r)
r = r || {ok: true}
; [ "todo"
, "todoPass"
, "todoFail"
, "skip"
, "skipPass"
, "skipFail"
, "pass"
, "passTotal"
, "fail"
, "failTotal"
, "tests"
, "testsTotal" ].forEach(function (k) {
this[k] = (this[k] || 0) + (r[k] || 0)
//console.error([k, this[k]])
}, this)
this.ok = this.ok && r.ok && true
this.bailedOut = this.bailedOut || r.bailedOut || false
this.list = (this.list || []).concat(r.list || [])
this.emit("set", this.list)
//console.error("after addSet", this)
}
Results.prototype.add = function (r, addToList) {
if (typeof r === 'object') {
var pf = r.ok ? "pass" : "fail"
, PF = r.ok ? "Pass" : "Fail"
this.testsTotal ++
this[pf + "Total"] ++
if (r.skip) {
this["skip" + PF] ++
this.skip ++
} else if (r.todo) {
this["todo" + PF] ++
this.todo ++
} else {
this.tests ++
this[pf] ++
}
if (r.bailout || typeof r.bailout === "string") {
// console.error("Bailing out in result")
this.bailedOut = true
}
this.ok = !!(this.ok && (r.ok || r.skip || r.todo))
}
if (addToList === false) return
this.list = this.list || []
this.list.push(r)
this.emit("result", r)
}

View File

@ -1,502 +0,0 @@
var fs = require("fs")
, child_process = require("child_process")
, path = require("path")
, chain = require("slide").chain
, asyncMap = require("slide").asyncMap
, TapProducer = require("./tap-producer.js")
, TapConsumer = require("./tap-consumer.js")
, assert = require("./tap-assert.js")
, inherits = require("inherits")
, util = require("util")
, CovHtml = require("./tap-cov-html.js")
, glob = require("glob")
// XXX Clean up the coverage options
, doCoverage = process.env.TAP_COV
|| process.env.npm_package_config_coverage
|| process.env.npm_config_coverage
module.exports = Runner
inherits(Runner, TapProducer)
function Runner (options, cb) {
this.options = options
var diag = this.options.diag
var dir = this.options.argv.remain
TapProducer.call(this, diag)
this.doCoverage = doCoverage
// An array of full paths to files to obtain coverage
this.coverageFiles = []
// The source of these files
this.coverageFilesSource = {}
// Where to write coverage information
this.coverageOutDir = this.options["coverage-dir"]
// Temporary test files bunkerified we'll remove later
this.f2delete = []
// Raw coverage stats, as read from JSON files
this.rawCovStats = []
// Processed coverage information, per file to cover:
this.covStats = {}
if (dir) {
var filesToCover = this.options.cover
if (doCoverage) {
var mkdirp = require("mkdirp")
this.coverageOutDir = path.resolve(this.coverageOutDir)
this.getFilesToCover(filesToCover)
var self = this
return mkdirp(this.coverageOutDir, '0755', function (er) {
if (er) return self.emit("error", er)
self.run(dir, cb)
})
}
this.run(dir, cb)
}
}
Runner.prototype.run = function() {
var self = this
, args = Array.prototype.slice.call(arguments)
, cb = args.pop() || finish
function finish (er) {
if (er) {
self.emit("error", er)
}
if (!doCoverage) return self.end()
// Cleanup temporary test files with coverage:
self.f2delete.forEach(function(f) {
fs.unlinkSync(f)
})
self.getFilesToCoverSource(function(err, data) {
if (err) {
self.emit("error", err)
}
self.getPerFileCovInfo(function(err, data) {
if (err) {
self.emit("error", err)
}
self.mergeCovStats(function(err, data) {
if (err) {
self.emit("error", err)
}
CovHtml(self.covStats, self.coverageOutDir, function() {
self.end()
})
})
})
})
}
if (Array.isArray(args[0])) {
args = args[0]
}
self.runFiles(args, "", cb)
}
Runner.prototype.runDir = function (dir, cb) {
var self = this
fs.readdir(dir, function (er, files) {
if (er) {
self.write(assert.fail("failed to readdir " + dir, { error: er }))
self.end()
return
}
files = files.sort(function(a, b) {
return a > b ? 1 : -1
})
files = files.filter(function(f) {
return !f.match(/^\./)
})
files = files.map(function(file) {
return path.resolve(dir, file)
})
self.runFiles(files, path.resolve(dir), cb)
})
}
// glob the filenames so that test/*.js works on windows
Runner.prototype.runFiles = function (files, dir, cb) {
var self = this
var globRes = []
chain(files.map(function (f) {
return function (cb) {
glob(f, function (er, files) {
if (er)
return cb(er)
globRes.push.apply(globRes, files)
cb()
})
}
}), function (er) {
if (er)
return cb(er)
runFiles(self, globRes, dir, cb)
})
}
// set some default options for node debugging tests
function setOptionsForDebug(self) {
// Note: we automatically increase the default timeout here. Yes
// the user can specify --timeout to increase, but by default,
// 30 seconds is not a long time to debug your test.
self.options.timeout = 1000000;
// Note: we automatically turn on stderr so user can see the 'debugger listening on port' message.
// Without this it looks like tap has hung..
self.options.stderr = true;
}
function runFiles(self, files, dir, cb) {
chain(files.map(function(f) {
return function (cb) {
if (self._bailedOut) return
var relDir = dir || path.dirname(f)
, fileName = relDir === "." ? f : f.substr(relDir.length + 1)
self.write(fileName)
fs.lstat(f, function(er, st) {
if (er) {
self.write(assert.fail("failed to stat " + f, {error: er}))
return cb()
}
var cmd = f, args = [], env = {}
if (path.extname(f) === ".js") {
cmd = process.execPath
if (self.options.gc) {
args.push("--expose-gc")
}
if (self.options.debug) {
args.push("--debug")
setOptionsForDebug(self)
}
if (self.options["debug-brk"]) {
args.push("--debug-brk")
setOptionsForDebug(self)
}
if (self.options.strict) {
args.push("--use-strict")
}
if (self.options.harmony) {
args.push("--harmony")
}
args.push(fileName)
} else if (path.extname(f) === ".coffee") {
cmd = "coffee"
args.push(fileName)
} else {
// Check if file is executable
if ((st.mode & parseInt('0100', 8)) && process.getuid) {
if (process.getuid() != st.uid) {
return cb()
}
} else if ((st.mode & parseInt('0010', 8)) && process.getgid) {
if (process.getgid() != st.gid) {
return cb()
}
} else if ((st.mode & parseInt('0001', 8)) == 0) {
return cb()
}
cmd = path.resolve(cmd)
}
if (st.isDirectory()) {
return self.runDir(f, cb)
}
if (doCoverage && path.extname(f) === ".js") {
var foriginal = fs.readFileSync(f, "utf8")
, fcontents = self.coverHeader() + foriginal + self.coverFooter()
, tmpBaseName = path.basename(f, path.extname(f))
+ ".with-coverage." + process.pid + path.extname(f)
, tmpFname = path.resolve(path.dirname(f), tmpBaseName)
fs.writeFileSync(tmpFname, fcontents, "utf8")
args.splice(-1, 1, tmpFname)
}
for (var i in process.env) {
env[i] = process.env[i]
}
env.TAP = 1
var cp = child_process.spawn(cmd, args, { env: env, cwd: relDir })
, out = ""
, err = ""
, tc = new TapConsumer()
, childTests = [f]
var timeout = setTimeout(function () {
if (!cp._ended) {
cp._timedOut = true
cp.kill()
}
}, self.options.timeout * 1000)
tc.on("data", function(c) {
self.emit("result", c)
self.write(c)
})
tc.on("bailout", function (message) {
clearTimeout(timeout)
console.log("# " + f.substr(process.cwd().length + 1))
process.stderr.write(err)
process.stdout.write(out + "\n")
self._bailedOut = true
cp._ended = true
cp.kill()
})
cp.stdout.pipe(tc)
cp.stdout.on("data", function (c) { out += c })
cp.stderr.on("data", function (c) {
if (self.options.stderr) process.stderr.write(c)
err += c
})
cp.on("close", function (code, signal) {
if (cp._ended) return
cp._ended = true
var ok = !cp._timedOut && code === 0
clearTimeout(timeout)
//childTests.forEach(function (c) { self.write(c) })
var res = { name: path.dirname(f).replace(process.cwd() + "/", "")
+ "/" + fileName
, ok: ok
, exit: code }
if (cp._timedOut)
res.timedOut = cp._timedOut
if (signal)
res.signal = signal
if (err) {
res.stderr = err
if (tc.results.ok &&
tc.results.tests === 0 &&
!self.options.stderr) {
// perhaps a compilation error or something else failed.
// no need if stderr is set, since it will have been
// output already anyway.
console.error(err)
}
}
// tc.results.ok = tc.results.ok && ok
tc.results.add(res)
res.command = '"'+[cmd].concat(args).join(" ")+'"'
self.emit("result", res)
self.emit("file", f, res, tc.results)
self.write(res)
self.write("\n")
if (doCoverage) {
self.f2delete.push(tmpFname)
}
cb()
})
})
}
}), cb)
return self
}
// Get an array of full paths to files we are interested into obtain
// code coverage.
Runner.prototype.getFilesToCover = function(filesToCover) {
var self = this
filesToCover = filesToCover.split(",").map(function(f) {
return path.resolve(f)
}).filter(function(f) {
var existsSync = fs.existsSync || path.existsSync;
return existsSync(f)
})
function recursive(f) {
if (path.extname(f) === "") {
// Is a directory:
fs.readdirSync(f).forEach(function(p) {
recursive(f + "/" + p)
})
} else {
self.coverageFiles.push(f)
}
}
filesToCover.forEach(function(f) {
recursive(f)
})
}
// Prepend to every test file to run. Note tap.test at the very top due it
// "plays" with include paths.
Runner.prototype.coverHeader = function() {
// semi here since we're injecting it before the first line,
// and don't want to mess up line numbers in the test files.
return "var ___TAP_COVERAGE = require("
+ JSON.stringify(require.resolve("runforcover"))
+ ").cover(/.*/g);"
}
// Append at the end of every test file to run. Actually, the stuff which gets
// the coverage information.
// Maybe it would be better to move into a separate file template so editing
// could be easier.
Runner.prototype.coverFooter = function() {
var self = this
// This needs to be a string with proper interpolations:
return [ ""
, "var ___TAP = require(" + JSON.stringify(require.resolve("./main.js")) + ")"
, "if (typeof ___TAP._plan === 'number') ___TAP._plan ++"
, "___TAP.test(" + JSON.stringify("___coverage") + ", function(t) {"
, " var covFiles = " + JSON.stringify(self.coverageFiles)
, " , covDir = " + JSON.stringify(self.coverageOutDir)
, " , path = require('path')"
, " , fs = require('fs')"
, " , testFnBase = path.basename(__filename, '.js') + '.json'"
, " , testFn = path.resolve(covDir, testFnBase)"
, ""
, " function asyncForEach(arr, fn, callback) {"
, " if (!arr.length) {"
, " return callback()"
, " }"
, " var completed = 0"
, " arr.forEach(function(i) {"
, " fn(i, function (err) {"
, " if (err) {"
, " callback(err)"
, " callback = function () {}"
, " } else {"
, " completed += 1"
, " if (completed === arr.length) {"
, " callback()"
, " }"
, " }"
, " })"
, " })"
, " }"
, ""
, " ___TAP_COVERAGE(function(coverageData) {"
, " var outObj = {}"
, " asyncForEach(covFiles, function(f, cb) {"
, " if (coverageData[f]) {"
, " var stats = coverageData[f].stats()"
, " , stObj = stats"
, " stObj.lines = stats.lines.map(function (l) {"
, " return { number: l.lineno, source: l.source() }"
, " })"
, " outObj[f] = stObj"
, " }"
, " cb()"
, " }, function(err) {"
, " ___TAP_COVERAGE.release()"
, " fs.writeFileSync(testFn, JSON.stringify(outObj))"
, " t.end()"
, " })"
, " })"
, "})" ].join("\n")
}
Runner.prototype.getFilesToCoverSource = function(cb) {
var self = this
asyncMap(self.coverageFiles, function(f, cb) {
fs.readFile(f, "utf8", function(err, data) {
var lc = 0
if (err) {
cb(err)
}
self.coverageFilesSource[f] = data.split("\n").map(function(l) {
lc += 1
return { number: lc, source: l }
})
cb()
})
}, cb)
}
Runner.prototype.getPerFileCovInfo = function(cb) {
var self = this
, covPath = path.resolve(self.coverageOutDir)
fs.readdir(covPath, function(err, files) {
if (err) {
self.emit("error", err)
}
var covFiles = files.filter(function(f) {
return path.extname(f) === ".json"
})
asyncMap(covFiles, function(f, cb) {
fs.readFile(path.resolve(covPath, f), "utf8", function(err, data) {
if (err) {
cb(err)
}
self.rawCovStats.push(JSON.parse(data))
cb()
})
}, function(f, cb) {
fs.unlink(path.resolve(covPath, f), cb)
}, cb)
})
}
Runner.prototype.mergeCovStats = function(cb) {
var self = this
self.rawCovStats.forEach(function(st) {
Object.keys(st).forEach(function(i) {
// If this is the first time we reach this file, just add the info:
if (!self.covStats[i]) {
self.covStats[i] = {
missing: st[i].lines
}
} else {
// If we already added info for this file before, we need to remove
// from self.covStats any line not duplicated again (since it has
// run on such case)
self.covStats[i].missing = self.covStats[i].missing.filter(
function(l) {
return (st[i].lines.indexOf(l))
})
}
})
})
// This is due to a bug into
// chrisdickinson/node-bunker/blob/feature/add-coverage-interface
// which is using array indexes for line numbers instead of the right number
Object.keys(self.covStats).forEach(function(f) {
self.covStats[f].missing = self.covStats[f].missing.map(function(line) {
return { number: line.number, source: line.source }
})
})
Object.keys(self.coverageFilesSource).forEach(function(f) {
if (!self.covStats[f]) {
self.covStats[f] = { missing: self.coverageFilesSource[f]
, percentage: 0
}
}
self.covStats[f].lines = self.coverageFilesSource[f]
self.covStats[f].loc = self.coverageFilesSource[f].length
if (!self.covStats[f].percentage) {
self.covStats[f].percentage =
1 - (self.covStats[f].missing.length / self.covStats[f].loc)
}
})
cb()
}

View File

@ -1,110 +0,0 @@
// This is a very simple test framework that leverages the tap framework
// to run tests and output tap-parseable results.
module.exports = Test
var assert = require("./tap-assert")
, inherits = require("inherits")
, Results = require("./tap-results")
, Harness = require("./tap-harness")
// tests are also test harnesses
inherits(Test, Harness)
function Test (harness, name, conf) {
//console.error("test ctor")
if (!(this instanceof Test)) return new Test(harness, name, conf)
Harness.call(this, Test)
conf.name = name || conf.name || "(anonymous)"
this.conf = conf
this.harness = harness
this.harness.add(this)
}
// it's taking too long!
Test.prototype.timeout = function () {
// detect false alarms
if (this._ended) return
this.fail("Timeout!")
this.end()
}
Test.prototype.clear = function () {
this._started = false
this._ended = false
this._plan = null
this._bailedOut = false
this._testCount = 0
this.results = new Results()
}
// this gets called if a test throws ever
Test.prototype.threw = function (ex) {
//console.error("threw!", ex.stack)
this.fail(ex.name + ": " + ex.message, { error: ex, thrown: true })
// may emit further failing tests if the plan is not completed
//console.error("end, because it threw")
if (!this._ended) this.end()
}
Test.prototype.comment = function (m) {
if (typeof m !== "string") {
return this.fail("Test.comment argument must be a string")
}
this.result("\n" + m.trim())
}
Test.prototype.result = function (res) {
this.results.add(res)
this._testCount ++
this.emit("result", res)
if (this._plan === this._testCount) {
process.nextTick(this._endNice.bind(this))
}
}
Test.prototype._endNice = function () {
if (!this._ended) this.end()
}
// parasitic
// Who says you can't do multiple inheritance in js?
Object.getOwnPropertyNames(assert).forEach(function (k) {
if (k === "prototype" || k === "name") return
var d = Object.getOwnPropertyDescriptor(assert, k)
, v = d.value
if (!v) return
d.value = assertParasite(v)
Object.defineProperty(Test.prototype, k, d)
})
function assertParasite (fn) { return function _testAssert () {
//console.error("_testAssert", fn.name, arguments)
if (this._bailedOut) return
var res = fn.apply(assert, arguments)
this.result(res)
return res
}}
// a few tweaks on the EE emit function, because
// we want to catch all thrown errors and bubble up "bailout"
Test.prototype.emit = (function (em) { return function (t) {
// bailouts bubble until handled
if (t === "bailout" &&
this.listeners(t).length === 0 &&
this.harness) {
return this.harness.bailout(arguments[1])
}
if (t === "error") return em.apply(this, arguments)
try {
em.apply(this, arguments)
} catch (ex) {
// any exceptions in a test are a failure
//console.error("caught!", ex.stack)
this.threw(ex)
}
}})(Harness.prototype.emit)

View File

@ -1,4 +0,0 @@
language: node_js
node_js:
- 0.8
- "0.10"

View File

@ -1,62 +0,0 @@
buffer-equal
============
Return whether two buffers are equal.
[![build status](https://secure.travis-ci.org/substack/node-buffer-equal.png)](http://travis-ci.org/substack/node-buffer-equal)
example
=======
``` js
var bufferEqual = require('buffer-equal');
console.dir(bufferEqual(
new Buffer([253,254,255]),
new Buffer([253,254,255])
));
console.dir(bufferEqual(
new Buffer('abc'),
new Buffer('abcd')
));
console.dir(bufferEqual(
new Buffer('abc'),
'abc'
));
```
output:
```
true
false
undefined
```
methods
=======
``` js
var bufferEqual = require('buffer-equal')
```
bufferEqual(a, b)
-----------------
Return whether the two buffers `a` and `b` are equal.
If `a` or `b` is not a buffer, return `undefined`.
install
=======
With [npm](http://npmjs.org) do:
```
npm install buffer-equal
```
license
=======
MIT

View File

@ -1,14 +0,0 @@
var bufferEqual = require('../');
console.dir(bufferEqual(
new Buffer([253,254,255]),
new Buffer([253,254,255])
));
console.dir(bufferEqual(
new Buffer('abc'),
new Buffer('abcd')
));
console.dir(bufferEqual(
new Buffer('abc'),
'abc'
));

View File

@ -1,14 +0,0 @@
var Buffer = require('buffer').Buffer; // for use with browserify
module.exports = function (a, b) {
if (!Buffer.isBuffer(a)) return undefined;
if (!Buffer.isBuffer(b)) return undefined;
if (typeof a.equals === 'function') return a.equals(b);
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
};

View File

@ -1,56 +0,0 @@
{
"name": "buffer-equal",
"description": "return whether two buffers are equal",
"version": "0.0.1",
"repository": {
"type": "git",
"url": "git://github.com/substack/node-buffer-equal.git"
},
"main": "index.js",
"keywords": [
"buffer",
"equal"
],
"directories": {
"example": "example",
"test": "test"
},
"scripts": {
"test": "tap test/*.js"
},
"devDependencies": {
"tap": "0.2.4"
},
"engines": {
"node": ">=0.4.0"
},
"license": "MIT",
"author": {
"name": "James Halliday",
"email": "mail@substack.net",
"url": "http://substack.net"
},
"bugs": {
"url": "https://github.com/substack/node-buffer-equal/issues"
},
"homepage": "https://github.com/substack/node-buffer-equal",
"_id": "buffer-equal@0.0.1",
"dist": {
"shasum": "91bc74b11ea405bc916bc6aa908faafa5b4aac4b",
"tarball": "http://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz"
},
"_from": "buffer-equal@~0.0.0",
"_npmVersion": "1.4.3",
"_npmUser": {
"name": "substack",
"email": "mail@substack.net"
},
"maintainers": [
{
"name": "substack",
"email": "mail@substack.net"
}
],
"_shasum": "91bc74b11ea405bc916bc6aa908faafa5b4aac4b",
"_resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz"
}

View File

@ -1,35 +0,0 @@
var bufferEqual = require('../');
var test = require('tap').test;
test('equal', function (t) {
var eq = bufferEqual(
new Buffer([253,254,255]),
new Buffer([253,254,255])
);
t.strictEqual(eq, true);
t.end();
});
test('not equal', function (t) {
var eq = bufferEqual(
new Buffer('abc'),
new Buffer('abcd')
);
t.strictEqual(eq, false);
t.end();
});
test('not equal not buffer', function (t) {
var eq = bufferEqual(
new Buffer('abc'),
'abc'
);
t.strictEqual(eq, undefined);
t.end();
});
test('equal not buffer', function (t) {
var eq = bufferEqual('abc', 'abc');
t.strictEqual(eq, undefined);
t.end();
});

View File

@ -1,4 +0,0 @@
language: node_js
node_js:
- 0.4
- 0.6

View File

@ -1,18 +0,0 @@
This software is released under the MIT license:
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.

View File

@ -1,11 +0,0 @@
var equal = require('../');
console.dir([
equal(
{ a : [ 2, 3 ], b : [ 4 ] },
{ a : [ 2, 3 ], b : [ 4 ] }
),
equal(
{ x : 5, y : [6] },
{ x : 5, y : 6 }
)
]);

Some files were not shown because too many files have changed in this diff Show More