--- Begin Message ---
- To: Debian Bug Tracking System <submit@bugs.debian.org>
- Subject: unblock: node-formidable/1.2.1-1
- From: Xavier <yadd@debian.org>
- Date: Fri, 15 Mar 2019 08:19:24 +0100
- Message-id: <c964d467-ca8d-d6a8-e0e5-b0eee5f68df9@debian.org>
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package node-formidable
Hello,
node-formidable hasn't been updated for years. Testing version isn't
compatible with our nodejs but this was not seen since there was no
real tests (see https://bugs.debian.org/924589).
I upgraded it and added full tests (build and autopkgtest).
node-formidable reverse dependencies:
- node-superagent:
+- node-multiparty (no reverse dependencies)
node-formidable bug does not affect these packages since the failing
functions are not used in it, that's why I decrease bug severity to
important. I tested the 2 reverse dependencies with both old and new
node-formidable with success (sbuild and autopkgtest).
debdiff is big since I embedded some node modules (only for tests, they
are not installed). Upstream changes are not so big. I updated also
debian/* files and added examples (and tests of course).
I think it's not risky to update node-formidable. However I leave you
appreciate if it is opportune.
Cheers,
Xavier
unblock node-formidable/1.2.1-1
-- System Information:
Debian Release: buster/sid
APT prefers testing
APT policy: (900, 'testing'), (500, 'unstable')
Architecture: amd64 (x86_64)
Kernel: Linux 4.19.0-2-amd64 (SMP w/8 CPU cores)
Kernel taint flags: TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8),
LANGUAGE= (charmap=UTF-8)
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..45032a1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/test/tmp/*
+*.upload
+*.un~
+/node_modules/*
diff --git a/.npmignore b/.npmignore
index 4fbabb3..ed16858 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,4 +1,7 @@
-/test/tmp/
+/test
+/tool
+/example
+/benchmark
*.upload
*.un~
*.http
diff --git a/.travis.yml b/.travis.yml
index cb931cb..694a62f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: node_js
node_js:
- - 0.8
- - 0.9
- - "0.10"
+ - 4
+ - 6
+ - 7
diff --git a/Readme.md b/Readme.md
index 1aecf08..ee1abfe 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1,13 +1,15 @@
# Formidable
-[![Build Status](https://secure.travis-ci.org/felixge/node-formidable.png?branch=master)](http://travis-ci.org/felixge/node-formidable)
+[![Build Status](https://travis-ci.org/felixge/node-formidable.svg?branch=master)](https://travis-ci.org/felixge/node-formidable)
## Purpose
-A node.js module for parsing form data, especially file uploads.
+A Node.js module for parsing form data, especially file uploads.
## Current status
+**Maintainers Wanted:** Please see https://github.com/felixge/node-formidable/issues/412
+
This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading
and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from
a large variety of clients and is considered production-ready.
@@ -22,17 +24,12 @@ a large variety of clients and is considered production-ready.
## Installation
-Via [npm](http://github.com/isaacs/npm):
-```
-npm install formidable@latest
-```
-Manually:
-```
-git clone git://github.com/felixge/node-formidable.git formidable
-vim my.js
-# var formidable = require('./formidable');
+```sh
+npm i -S formidable
```
+This is a low-level package, and if you're using a high-level framework it may already be included. However, [Express v4](http://expressjs.com) does not include any multipart handling, nor does [body-parser](https://github.com/expressjs/body-parser).
+
Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.
## Example
@@ -82,11 +79,10 @@ form.encoding = 'utf-8';
Sets encoding for incoming form fields.
```javascript
-form.uploadDir = process.env.TMP || process.env.TMPDIR || process.env.TEMP || '/tmp' || process.cwd();
+form.uploadDir = "/my/dir";
```
-The directory for placing file uploads in. You can move them later on using
-`fs.rename()`. The default directory is picked at module load time depending on
-the first existing directory from those listed above.
+Sets the directory for placing file uploads in. You can move them later on using
+`fs.rename()`. The default is `os.tmpdir()`.
```javascript
form.keepExtensions = false;
@@ -99,23 +95,35 @@ form.type
Either 'multipart' or 'urlencoded' depending on the incoming request.
```javascript
-form.maxFieldsSize = 2 * 1024 * 1024;
+form.maxFieldsSize = 20 * 1024 * 1024;
+```
+Limits the amount of memory all fields together (except files) can allocate in bytes.
+If this value is exceeded, an `'error'` event is emitted. The default
+size is 20MB.
+
+```javascript
+form.maxFileSize = 200 * 1024 * 1024;
```
-Limits the amount of memory a field (not file) can allocate in bytes.
+Limits the size of uploaded file.
If this value is exceeded, an `'error'` event is emitted. The default
-size is 2MB.
+size is 200MB.
```javascript
-form.maxFields = 0;
+form.maxFields = 1000;
```
Limits the number of fields that the querystring parser will decode. Defaults
-to 0 (unlimited).
+to 1000 (0 for unlimited).
```javascript
form.hash = false;
```
If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.
+```javascript
+form.multiples = false;
+```
+If this option is enabled, when you call `form.parse`, the `files` argument will contain arrays of files for inputs which submit multiple files using the HTML5 `multiple` attribute.
+
```javascript
form.bytesReceived
```
@@ -129,7 +137,7 @@ The expected number of bytes in this form.
```javascript
form.parse(request, [cb]);
```
-Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback:
+Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields and files are collected and passed to the callback:
```javascript
@@ -198,15 +206,20 @@ If hash calculation was set, you can read the hex digest out of this var.
#### 'progress'
+
+Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
+
```javascript
form.on('progress', function(bytesReceived, bytesExpected) {
});
```
-Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
#### 'field'
+
+Emitted whenever a field / value pair has been received.
+
```javascript
form.on('field', function(name, value) {
});
@@ -214,7 +227,10 @@ form.on('field', function(name, value) {
#### 'fileBegin'
-Emitted whenever a field / value pair has been received.
+Emitted whenever a new file is detected in the upload stream. Use this event if
+you want to stream the file to somewhere else while buffering the upload on
+the file system.
+
```javascript
form.on('fileBegin', function(name, file) {
});
@@ -222,11 +238,8 @@ form.on('fileBegin', function(name, file) {
#### 'file'
-Emitted whenever a new file is detected in the upload stream. Use this even if
-you want to stream the file to somewhere else while buffering the upload on
-the file system.
-
Emitted whenever a field / file pair has been received. `file` is an instance of `File`.
+
```javascript
form.on('file', function(name, file) {
});
@@ -235,6 +248,7 @@ form.on('file', function(name, file) {
#### 'error'
Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.
+
```javascript
form.on('error', function(err) {
});
@@ -243,7 +257,7 @@ form.on('error', function(err) {
#### 'aborted'
-Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. In the future there will be a separate 'timeout' event (needs a change in the node core).
+Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. After this event is emitted, an `error` event will follow. In the future there will be a separate 'timeout' event (needs a change in the node core).
```javascript
form.on('aborted', function() {
});
@@ -260,11 +274,30 @@ Emitted when the entire request has been received, and all contained files have
## Changelog
+### v1.1.1 (2017-01-15)
+
+ * Fix DeprecationWarning about os.tmpDir() (Christian)
+ * Update `buffer.write` order of arguments for Node 7 (Kornel Lesiński)
+ * JSON Parser emits error events to the IncomingForm (alessio.montagnani)
+ * Improved Content-Disposition parsing (Sebastien)
+ * Access WriteStream of fs during runtime instead of include time (Jonas Amundsen)
+ * Use built-in toString to convert buffer to hex (Charmander)
+ * Add hash to json if present (Nick Stamas)
+ * Add license to package.json (Simen Bekkhus)
+
+### v1.0.14 (2013-05-03)
+
+* Add failing hash tests. (Ben Trask)
+* Enable hash calculation again (Eugene Girshov)
+* Test for immediate data events (Tim Smart)
+* Re-arrange IncomingForm#parse (Tim Smart)
+
### v1.0.13
* Only update hash if update method exists (Sven Lito)
* According to travis v0.10 needs to go quoted (Sven Lito)
* Bumping build node versions (Sven Lito)
+* Additional fix for empty requests (Eugene Girshov)
* Change the default to 1000, to match the new Node behaviour. (OrangeDog)
* Add ability to control maxKeys in the querystring parser. (OrangeDog)
* Adjust test case to work with node 0.9.x (Eugene Girshov)
@@ -284,120 +317,12 @@ Emitted when the entire request has been received, and all contained files have
* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley)
* Documentation improvements (Sven Lito, Andre Azevedo)
* Add support for application/octet-stream (Ion Lupascu, Chris Scribner)
-* Use os.tmpDir() to get tmp directory (Andrew Kelley)
+* Use os.tmpdir() to get tmp directory (Andrew Kelley)
* Improve package.json (Andrew Kelley, Sven Lito)
* Fix benchmark script (Andrew Kelley)
* Fix scope issue in incoming_forms (Sven Lito)
* Fix file handle leak on error (OrangeDog)
-### v1.0.11
-
-* Calculate checksums for incoming files (sreuter)
-* Add definition parameters to "IncomingForm" as an argument (Math-)
-
-### v1.0.10
-
-* Make parts to be proper Streams (Matt Robenolt)
-
-### v1.0.9
-
-* Emit progress when content length header parsed (Tim Koschützki)
-* Fix Readme syntax due to GitHub changes (goob)
-* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara)
-
-### v1.0.8
-
-* Strip potentially unsafe characters when using `keepExtensions: true`.
-* Switch to utest / urun for testing
-* Add travis build
-
-### v1.0.7
-
-* Remove file from package that was causing problems when installing on windows. (#102)
-* Fix typos in Readme (Jason Davies).
-
-### v1.0.6
-
-* Do not default to the default to the field name for file uploads where
- filename="".
-
-### v1.0.5
-
-* Support filename="" in multipart parts
-* Explain unexpected end() errors in parser better
-
-**Note:** Starting with this version, formidable emits 'file' events for empty
-file input fields. Previously those were incorrectly emitted as regular file
-input fields with value = "".
-
-### v1.0.4
-
-* Detect a good default tmp directory regardless of platform. (#88)
-
-### v1.0.3
-
-* Fix problems with utf8 characters (#84) / semicolons in filenames (#58)
-* Small performance improvements
-* New test suite and fixture system
-
-### v1.0.2
-
-* Exclude node\_modules folder from git
-* Implement new `'aborted'` event
-* Fix files in example folder to work with recent node versions
-* Make gently a devDependency
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2)
-
-### v1.0.1
-
-* Fix package.json to refer to proper main directory. (#68, Dean Landolt)
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1)
-
-### v1.0.0
-
-* Add support for multipart boundaries that are quoted strings. (Jeff Craig)
-
-This marks the beginning of development on version 2.0 which will include
-several architectural improvements.
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0)
-
-### v0.9.11
-
-* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki)
-* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class
-
-**Important:** The old property names of the File class will be removed in a
-future release.
-
-[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11)
-
-### Older releases
-
-These releases were done before starting to maintain the above Changelog:
-
-* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10)
-* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9)
-* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8)
-* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7)
-* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6)
-* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5)
-* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4)
-* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3)
-* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2)
-* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
-* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0)
-
## License
Formidable is licensed under the MIT license.
diff --git a/benchmark/bench-multipart-parser.js b/benchmark/bench-multipart-parser.js
index 49abc43..1978e58 100644
--- a/benchmark/bench-multipart-parser.js
+++ b/benchmark/bench-multipart-parser.js
@@ -44,7 +44,7 @@ parser.onEnd = function() {
var start = +new Date(),
nparsed = parser.write(buffer),
- duration = +new Date - start,
+ duration = +new Date() - start,
mbPerSec = (mb / (duration / 1000)).toFixed(2);
console.log(mbPerSec+' mb/sec');
@@ -59,8 +59,8 @@ function createMultipartBuffer(boundary, size) {
, tail = '\r\n--'+boundary+'--\r\n'
, buffer = new Buffer(size);
- buffer.write(head, 'ascii', 0);
- buffer.write(tail, 'ascii', buffer.length - tail.length);
+ buffer.write(head, 0, 'ascii');
+ buffer.write(tail, buffer.length - tail.length, 'ascii');
return buffer;
}
diff --git a/debian/changelog b/debian/changelog
index d929834..d805bea 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+node-formidable (1.2.1-1) unstable; urgency=medium
+
+ * Team upload
+ * Bump debhelper compatibility level to 11
+ * Declare compliance with policy 4.3.0
+ * Change section to javascript
+ * Change priority to optional
+ * Update debian/watch
+ * New upstream version 1.2.1 (Closes: #924589)
+ * Add upstream/metadata
+ * Enable tests using pkg-js-tools
+ * Fix VCS fields
+ * Update debian/copyright
+ * Update debian/copyright
+ * Fix install
+ * Install examples
+
+ -- Xavier Guimard <yadd@debian.org> Thu, 14 Mar 2019 21:17:08 +0100
+
node-formidable (1.0.13-1) unstable; urgency=low
* Initial release (Closes: #703836)
diff --git a/debian/clean b/debian/clean
new file mode 100644
index 0000000..b979df5
--- /dev/null
+++ b/debian/clean
@@ -0,0 +1 @@
+test/tmp/*
diff --git a/debian/compat b/debian/compat
index 45a4fb7..b4de394 100644
--- a/debian/compat
+++ b/debian/compat
@@ -1 +1 @@
-8
+11
diff --git a/debian/control b/debian/control
index 115429b..1bab968 100644
--- a/debian/control
+++ b/debian/control
@@ -1,21 +1,23 @@
Source: node-formidable
-Section: web
-Priority: extra
Maintainer: Debian Javascript Maintainers <pkg-javascript-devel@lists.alioth.debian.org>
Uploaders: Jérémy Lal <kapouer@melix.org>
-Build-Depends:
- debhelper (>= 8.0.0)
- , dh-buildinfo
-Standards-Version: 3.9.3
+Section: javascript
+Testsuite: autopkgtest-pkg-nodejs
+Priority: optional
+Build-Depends: debhelper (>= 11~),
+ nodejs,
+ node-hashish,
+ node-request,
+ pkg-js-tools
+Standards-Version: 4.3.0
+Vcs-Browser: https://salsa.debian.org/js-team/node-formidable
+Vcs-Git: https://salsa.debian.org/js-team/node-formidable.git
Homepage: https://github.com/felixge/node-formidable
-Vcs-Git: git://git.debian.org/collab-maint/node-formidable.git
-Vcs-Browser: http://git.debian.org/?p=collab-maint/node-formidable.git
Package: node-formidable
Architecture: all
-Depends:
- ${misc:Depends}
- , nodejs
+Depends: ${misc:Depends},
+ nodejs
Description: Multipart form data parser module for Node.js
node-formidable is a well-tested parser for multipart/form-data sent by
http clients. It emphasizes support for file uploads.
diff --git a/debian/copyright b/debian/copyright
index a68a70b..2dd5262 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,10 +1,35 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: formidable
Files: *
-Copyright: 2011 Felix Geisendörfer <felix@debuggable.com>
+Copyright: 2011-2013, Felix Geisendörfer <felix@debuggable.com>
License: Expat
+Files: debian/*
+Copyright: 2013, Jérémy Lal <kapouer@melix.org>
+ 2019, Xavier Guimard <yadd@debian.org>
+License: Expat
+
+Files: debian/tests/node_modules/chainsaw/*
+Copyright: 2010, James Halliday <mail@substack.net>
+License: Expat
+
+Files: debian/tests/node_modules/findit/*
+Copyright: 2013-2014, James Halliday <mail@substack.net>
+License: Expat
+Comment: The upstream distribution does not contain an explicit statement of
+ copyright ownership. Pursuant to the Berne Convention for the Protection of
+ Literary and Artistic Works, it is assumed that all content is copyright by
+ its respective authors unless otherwise stated.
+
+Files: debian/tests/node_modules/seq/*
+Copyright: 2011, James Halliday <mail@substack.net>
+License: Expat
+Comment: The upstream distribution does not contain an explicit statement of
+ copyright ownership. Pursuant to the Berne Convention for the Protection of
+ Literary and Artistic Works, it is assumed that all content is copyright by
+ its respective authors unless otherwise stated.
+
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
diff --git a/debian/examples b/debian/examples
new file mode 100644
index 0000000..0bbe99e
--- /dev/null
+++ b/debian/examples
@@ -0,0 +1 @@
+example/*
diff --git a/debian/install b/debian/install
index bce9365..4af254f 100644
--- a/debian/install
+++ b/debian/install
@@ -1 +1,2 @@
-lib/* usr/lib/nodejs/formidable/
+lib usr/lib/nodejs/formidable/
+package.json usr/lib/nodejs/formidable/
diff --git a/debian/rules b/debian/rules
index 218df65..20809a4 100755
--- a/debian/rules
+++ b/debian/rules
@@ -5,4 +5,4 @@
#export DH_VERBOSE=1
%:
- dh $@
+ dh $@ --with nodejs
diff --git a/debian/tests/node_modules/chainsaw/README.markdown b/debian/tests/node_modules/chainsaw/README.markdown
new file mode 100644
index 0000000..9bb1259
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/README.markdown
@@ -0,0 +1,140 @@
+Chainsaw
+========
+
+Build chainable fluent interfaces the easy way in node.js.
+
+With this meta-module you can write modules with chainable interfaces.
+Chainsaw takes care of all of the boring details and makes nested flow control
+super simple too.
+
+Just call `Chainsaw` with a constructor function like in the examples below.
+In your methods, just do `saw.next()` to move along to the next event and
+`saw.nest()` to create a nested chain.
+
+Examples
+========
+
+add_do.js
+---------
+
+This silly example adds values with a chainsaw.
+
+ var Chainsaw = require('chainsaw');
+
+ function AddDo (sum) {
+ return Chainsaw(function (saw) {
+ this.add = function (n) {
+ sum += n;
+ saw.next();
+ };
+
+ this.do = function (cb) {
+ saw.nest(cb, sum);
+ };
+ });
+ }
+
+ AddDo(0)
+ .add(5)
+ .add(10)
+ .do(function (sum) {
+ if (sum > 12) this.add(-10);
+ })
+ .do(function (sum) {
+ console.log('Sum: ' + sum);
+ })
+ ;
+
+Output:
+ Sum: 5
+
+prompt.js
+---------
+
+This example provides a wrapper on top of stdin with the help of
+[node-lazy](https://github.com/pkrumins/node-lazy) for line-processing.
+
+ var Chainsaw = require('chainsaw');
+ var Lazy = require('lazy');
+
+ module.exports = Prompt;
+ function Prompt (stream) {
+ var waiting = [];
+ var lines = [];
+ var lazy = Lazy(stream).lines.map(String)
+ .forEach(function (line) {
+ if (waiting.length) {
+ var w = waiting.shift();
+ w(line);
+ }
+ else lines.push(line);
+ })
+ ;
+
+ var vars = {};
+ return Chainsaw(function (saw) {
+ this.getline = function (f) {
+ var g = function (line) {
+ saw.nest(f, line, vars);
+ };
+
+ if (lines.length) g(lines.shift());
+ else waiting.push(g);
+ };
+
+ this.do = function (cb) {
+ saw.nest(cb, vars);
+ };
+ });
+ }
+
+And now for the new Prompt() module in action:
+
+ var util = require('util');
+ var stdin = process.openStdin();
+
+ Prompt(stdin)
+ .do(function () {
+ util.print('x = ');
+ })
+ .getline(function (line, vars) {
+ vars.x = parseInt(line, 10);
+ })
+ .do(function () {
+ util.print('y = ');
+ })
+ .getline(function (line, vars) {
+ vars.y = parseInt(line, 10);
+ })
+ .do(function (vars) {
+ if (vars.x + vars.y < 10) {
+ util.print('z = ');
+ this.getline(function (line) {
+ vars.z = parseInt(line, 10);
+ })
+ }
+ else {
+ vars.z = 0;
+ }
+ })
+ .do(function (vars) {
+ console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
+ process.exit();
+ })
+ ;
+
+Installation
+============
+
+With [npm](http://github.com/isaacs/npm), just do:
+ npm install chainsaw
+
+or clone this project on github:
+
+ git clone http://github.com/substack/node-chainsaw.git
+
+To run the tests with [expresso](http://github.com/visionmedia/expresso),
+just do:
+
+ expresso
+
diff --git a/debian/tests/node_modules/chainsaw/examples/add_do.js b/debian/tests/node_modules/chainsaw/examples/add_do.js
new file mode 100644
index 0000000..378705d
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/examples/add_do.js
@@ -0,0 +1,25 @@
+var Chainsaw = require('chainsaw');
+
+function AddDo (sum) {
+ return Chainsaw(function (saw) {
+ this.add = function (n) {
+ sum += n;
+ saw.next();
+ };
+
+ this.do = function (cb) {
+ saw.nest(cb, sum);
+ };
+ });
+}
+
+AddDo(0)
+ .add(5)
+ .add(10)
+ .do(function (sum) {
+ if (sum > 12) this.add(-10);
+ })
+ .do(function (sum) {
+ console.log('Sum: ' + sum);
+ })
+;
diff --git a/debian/tests/node_modules/chainsaw/examples/prompt.js b/debian/tests/node_modules/chainsaw/examples/prompt.js
new file mode 100644
index 0000000..0a06d71
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/examples/prompt.js
@@ -0,0 +1,67 @@
+var Chainsaw = require('chainsaw');
+var Lazy = require('lazy');
+
+module.exports = Prompt;
+function Prompt (stream) {
+ var waiting = [];
+ var lines = [];
+ var lazy = Lazy(stream).lines.map(String)
+ .forEach(function (line) {
+ if (waiting.length) {
+ var w = waiting.shift();
+ w(line);
+ }
+ else lines.push(line);
+ })
+ ;
+
+ var vars = {};
+ return Chainsaw(function (saw) {
+ this.getline = function (f) {
+ var g = function (line) {
+ saw.nest(f, line, vars);
+ };
+
+ if (lines.length) g(lines.shift());
+ else waiting.push(g);
+ };
+
+ this.do = function (cb) {
+ saw.nest(cb, vars);
+ };
+ });
+}
+
+var util = require('util');
+if (__filename === process.argv[1]) {
+ var stdin = process.openStdin();
+ Prompt(stdin)
+ .do(function () {
+ util.print('x = ');
+ })
+ .getline(function (line, vars) {
+ vars.x = parseInt(line, 10);
+ })
+ .do(function () {
+ util.print('y = ');
+ })
+ .getline(function (line, vars) {
+ vars.y = parseInt(line, 10);
+ })
+ .do(function (vars) {
+ if (vars.x + vars.y < 10) {
+ util.print('z = ');
+ this.getline(function (line) {
+ vars.z = parseInt(line, 10);
+ })
+ }
+ else {
+ vars.z = 0;
+ }
+ })
+ .do(function (vars) {
+ console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
+ process.exit();
+ })
+ ;
+}
diff --git a/debian/tests/node_modules/chainsaw/index.js b/debian/tests/node_modules/chainsaw/index.js
new file mode 100755
index 0000000..597cc48
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/index.js
@@ -0,0 +1,108 @@
+var Traverse = require('traverse');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = Chainsaw;
+function Chainsaw (builder) {
+ var saw = Chainsaw.saw(builder, {});
+ var r = builder.call(saw.handlers, saw);
+ if (r !== undefined) saw.handlers = r;
+ return saw.chain();
+};
+
+Chainsaw.saw = function (builder, handlers) {
+ var saw = new EventEmitter;
+ saw.handlers = handlers;
+ saw.actions = [];
+ saw.step = 0;
+
+ saw.chain = function () {
+ var ch = Traverse(saw.handlers).map(function (node) {
+ if (this.isRoot) return node;
+ var ps = this.path;
+
+ if (typeof node === 'function') {
+ this.update(function () {
+ saw.actions.push({
+ path : ps,
+ args : [].slice.call(arguments)
+ });
+ return ch;
+ });
+ }
+ });
+
+ process.nextTick(function () {
+ saw.emit('begin');
+ saw.next();
+ });
+
+ return ch;
+ };
+
+ saw.next = function () {
+ var action = saw.actions[saw.step];
+ saw.step ++;
+
+ if (!action) {
+ saw.emit('end');
+ }
+ else if (!action.trap) {
+ var node = saw.handlers;
+ action.path.forEach(function (key) { node = node[key] });
+ node.apply(saw.handlers, action.args);
+ }
+ };
+
+ saw.nest = function (cb) {
+ var args = [].slice.call(arguments, 1);
+ var autonext = true;
+
+ if (typeof cb === 'boolean') {
+ var autonext = cb;
+ cb = args.shift();
+ }
+
+ var s = Chainsaw.saw(builder, {});
+ var r = builder.call(s.handlers, s);
+
+ if (r !== undefined) s.handlers = r;
+ cb.apply(s.chain(), args);
+ if (autonext !== false) s.on('end', saw.next);
+ };
+
+ saw.trap = function (name, cb) {
+ var ps = Array.isArray(name) ? name : [name];
+ saw.actions.push({
+ path : ps,
+ step : saw.step,
+ cb : cb,
+ trap : true
+ });
+ };
+
+ saw.down = function (name) {
+ var ps = (Array.isArray(name) ? name : [name]).join('/');
+ var i = saw.actions.slice(saw.step).map(function (x) {
+ if (x.trap && x.step <= saw.step) return false;
+ return x.path.join('/') == ps;
+ }).indexOf(true);
+
+ if (i >= 0) saw.step += i;
+ else saw.step = saw.actions.length;
+
+ var act = saw.actions[saw.step - 1];
+ if (act && act.trap) {
+ // It's a trap!
+ saw.step = act.step;
+ act.cb();
+ }
+ else saw.next();
+ };
+
+ saw.jump = function (step) {
+ saw.step = step;
+ saw.next();
+ };
+
+ return saw;
+};
diff --git a/debian/tests/node_modules/chainsaw/package.json b/debian/tests/node_modules/chainsaw/package.json
new file mode 100644
index 0000000..66b1b08
--- /dev/null
+++ b/debian/tests/node_modules/chainsaw/package.json
@@ -0,0 +1,61 @@
+{
+ "_from": "chainsaw@>=0.0.7 <0.1",
+ "_id": "chainsaw@0.0.9",
+ "_inBundle": false,
+ "_integrity": "sha1-EaBRAtHEx4W20EFdM21aOhYSkT4=",
+ "_location": "/chainsaw",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "chainsaw@>=0.0.7 <0.1",
+ "name": "chainsaw",
+ "escapedName": "chainsaw",
+ "rawSpec": ">=0.0.7 <0.1",
+ "saveSpec": null,
+ "fetchSpec": ">=0.0.7 <0.1"
+ },
+ "_requiredBy": [
+ "/seq"
+ ],
+ "_resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.0.9.tgz",
+ "_shasum": "11a05102d1c4c785b6d0415d336d5a3a1612913e",
+ "_spec": "chainsaw@>=0.0.7 <0.1",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable/node_modules/seq",
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "bugs": {
+ "url": "https://github.com/substack/node-chainsaw/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "traverse": ">=0.3.0 <0.4"
+ },
+ "deprecated": false,
+ "description": "Build chainable fluent interfaces the easy way... with a freakin' chainsaw!",
+ "engine": {
+ "node": ">=0.4.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "https://github.com/substack/node-chainsaw#readme",
+ "keywords": [
+ "chain",
+ "fluent",
+ "interface",
+ "monad",
+ "monadic"
+ ],
+ "license": "MIT/X11",
+ "main": "./index.js",
+ "name": "chainsaw",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/substack/node-chainsaw.git"
+ },
+ "version": "0.0.9"
+}
diff --git a/debian/tests/node_modules/findit/README.markdown b/debian/tests/node_modules/findit/README.markdown
new file mode 100644
index 0000000..d622819
--- /dev/null
+++ b/debian/tests/node_modules/findit/README.markdown
@@ -0,0 +1,101 @@
+findit
+======
+
+Recursively walk directory trees. Think `/usr/bin/find`.
+
+example time!
+=============
+
+callback style
+--------------
+
+````javascript
+require('findit').find(__dirname, function (file) {
+ console.log(file);
+})
+````
+
+emitter style
+-------------
+
+````javascript
+var finder = require('findit').find(__dirname);
+
+finder.on('directory', function (dir, stat) {
+ console.log(dir + '/');
+});
+
+finder.on('file', function (file, stat) {
+ console.log(file);
+});
+
+finder.on('link', function (link, stat) {
+ console.log(link);
+});
+````
+
+synchronous
+-----------
+
+````javascript
+var files = require('findit').sync(__dirname);
+ console.dir(files);
+````
+
+methods
+=======
+
+find(basedir, options, cb)
+-----------------
+
+Do an asynchronous recursive walk starting at `basedir`.
+
+Optionally supply an options object. Setting the property 'follow_symlinks'
+will follow symlinks.
+
+Optionally supply a callback that will get the same arguments as the path event
+documented below in "events".
+
+If `basedir` is actually a non-directory regular file, findit emits a single
+"file" event for it then emits "end".
+
+Findit uses `fs.lstat()` so symlinks are not traversed automatically. To have it
+follow symlinks, supply the options argument with 'follow_symlinks' set to true.
+Findit won't traverse an inode that it has seen before so directories can have
+symlink cycles and findit won't blow up.
+
+Returns an EventEmitter. See "events".
+
+sync(basedir, options, cb)
+-----------------
+
+Return an array of files and directories from a synchronous recursive walk
+starting at `basedir`.
+
+Optionally supply an options object. Setting the property 'follow_symlinks'
+will follow symlinks.
+
+An optional callback `cb` will get called with `cb(file, stat)` if specified.
+
+events
+======
+
+file: [ file, stat ]
+--------------------
+
+Emitted for just files which are not directories.
+
+directory : [ directory, stat ]
+-------------------------------
+
+Emitted for directories.
+
+path : [ file, stat ]
+---------------------
+
+Emitted for both files and directories.
+
+end
+---
+
+Emitted when the recursive walk is done.
diff --git a/debian/tests/node_modules/findit/examples/callback.js b/debian/tests/node_modules/findit/examples/callback.js
new file mode 100644
index 0000000..829630e
--- /dev/null
+++ b/debian/tests/node_modules/findit/examples/callback.js
@@ -0,0 +1,3 @@
+require('findit').find(__dirname, function (file) {
+ console.log(file);
+})
diff --git a/debian/tests/node_modules/findit/examples/emitter.js b/debian/tests/node_modules/findit/examples/emitter.js
new file mode 100644
index 0000000..f97adf3
--- /dev/null
+++ b/debian/tests/node_modules/findit/examples/emitter.js
@@ -0,0 +1,9 @@
+var finder = require('findit').find(__dirname);
+
+finder.on('directory', function (dir) {
+ console.log(dir + '/');
+});
+
+finder.on('file', function (file) {
+ console.log(file);
+});
diff --git a/debian/tests/node_modules/findit/examples/sync.js b/debian/tests/node_modules/findit/examples/sync.js
new file mode 100644
index 0000000..b09e0b2
--- /dev/null
+++ b/debian/tests/node_modules/findit/examples/sync.js
@@ -0,0 +1,2 @@
+var files = require('findit').findSync(__dirname);
+console.dir(files);
diff --git a/debian/tests/node_modules/findit/index.js b/debian/tests/node_modules/findit/index.js
new file mode 100644
index 0000000..c1d9eb9
--- /dev/null
+++ b/debian/tests/node_modules/findit/index.js
@@ -0,0 +1,142 @@
+var fs = require('fs');
+var path = require('path');
+var EventEmitter = require('events').EventEmitter;
+var Seq = require('seq');
+
+function createInodeChecker() {
+ var inodes = {};
+ return function inodeSeen(inode) {
+ if (inodes[inode]) {
+ return true;
+ } else {
+ inodes[inode] = true;
+ return false;
+ }
+ }
+}
+
+exports = module.exports = find;
+exports.find = find;
+function find (base, options, cb) {
+ cb = arguments[arguments.length - 1];
+ if (typeof(cb) !== 'function') {
+ cb = undefined;
+ }
+ var em = new EventEmitter;
+ var inodeSeen = createInodeChecker();
+
+ function finder (dir, f) {
+ Seq()
+ .seq(fs.readdir, dir, Seq)
+ .flatten()
+ .seqEach(function (file) {
+ var p = dir + '/' + file;
+ fs.lstat(p, this.into(p));
+ })
+ .seq(function () {
+ this(null, Object.keys(this.vars));
+ })
+ .flatten()
+ .seqEach(function (file) {
+ var stat = this.vars[file];
+ if (cb) cb(file, stat);
+
+ if (inodeSeen(stat.ino)) {
+ // already seen this inode, probably a recursive symlink
+ this(null);
+ }
+ else {
+ em.emit('path', file, stat);
+
+ if (stat.isSymbolicLink()) {
+ em.emit('link', file, stat);
+ if (options && options.follow_symlinks) {
+ path.exists(file, function(exists) {
+ if (exists) {
+ fs.readlink(file, function(err, resolvedPath) {
+ if (err) {
+ em.emit('error', err);
+ } else {
+ finder(path.resolve(path.dir(file), resolvedPath));
+ }
+ });
+ }
+ });
+ } else {
+ this(null);
+ }
+ }
+ else if (stat.isDirectory()) {
+ em.emit('directory', file, stat);
+ finder(file, this);
+ }
+ else {
+ em.emit('file', file, stat);
+ this(null);
+ }
+ }
+ })
+ .seq(f.bind({}, null))
+ .catch(em.emit.bind(em, 'error'))
+ ;
+ }
+
+ fs.lstat(base, function (err, s) {
+ if (err) {
+ em.emit('error', err);
+ }
+ if (s.isDirectory()) {
+ finder(base, em.emit.bind(em, 'end'));
+ }
+ else if (s.isSymbolicLink()) {
+ if (cb) cb(base, s);
+ em.emit('link', base, s);
+ em.emit('end');
+ }
+ else {
+ if (cb) cb(base, s);
+ em.emit('file', base, s);
+ em.emit('end');
+ }
+ });
+
+ return em;
+};
+
+exports.findSync = function findSync(dir, options, callback) {
+ cb = arguments[arguments.length - 1];
+ if (typeof(cb) !== 'function') {
+ cb = undefined;
+ }
+ var inodeSeen = createInodeChecker();
+ var files = [];
+ var fileQueue = [];
+ var processFile = function processFile(file) {
+ var stat = fs.lstatSync(file);
+ if (inodeSeen(stat.ino)) {
+ return;
+ }
+ files.push(file);
+ cb && cb(file, stat)
+ if (stat.isDirectory()) {
+ fs.readdirSync(file).forEach(function(f) { fileQueue.push(path.join(file, f)); });
+ } else if (stat.isSymbolicLink()) {
+ if (options && options.follow_symlinks && path.existsSync(file)) {
+ fileQueue.push(fs.realpathSync(file));
+ }
+ }
+ };
+ /* we don't include the starting directory unless it is a file */
+ var stat = fs.lstatSync(dir);
+ if (stat.isDirectory()) {
+ fs.readdirSync(dir).forEach(function(f) { fileQueue.push(path.join(dir, f)); });
+ } else {
+ fileQueue.push(dir);
+ }
+ while (fileQueue.length > 0) {
+ processFile(fileQueue.shift());
+ }
+ return files;
+};
+
+exports.find.sync = exports.findSync;
diff --git a/debian/tests/node_modules/findit/package.json b/debian/tests/node_modules/findit/package.json
new file mode 100644
index 0000000..0b4cac9
--- /dev/null
+++ b/debian/tests/node_modules/findit/package.json
@@ -0,0 +1,68 @@
+{
+ "_from": "findit@^0.1.2",
+ "_id": "findit@0.1.2",
+ "_inBundle": false,
+ "_integrity": "sha1-rH/mAM1qMqNWcoNrdM9vHd4uEfg=",
+ "_location": "/findit",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "findit@^0.1.2",
+ "name": "findit",
+ "escapedName": "findit",
+ "rawSpec": "^0.1.2",
+ "saveSpec": null,
+ "fetchSpec": "^0.1.2"
+ },
+ "_requiredBy": [
+ "#DEV:/"
+ ],
+ "_resolved": "https://registry.npmjs.org/findit/-/findit-0.1.2.tgz",
+ "_shasum": "ac7fe600cd6a32a35672836b74cf6f1dde2e11f8",
+ "_spec": "findit@^0.1.2",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable",
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "bugs": {
+ "url": "https://github.com/substack/node-findit/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "seq": ">=0.1.7"
+ },
+ "deprecated": false,
+ "description": "Walk a directory tree.",
+ "devDependencies": {
+ "expresso": "0.7.x",
+ "hashish": ">=0.0.2 <0.1"
+ },
+ "engine": [
+ "node >=0.2.0"
+ ],
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "https://github.com/substack/node-findit#readme",
+ "keywords": [
+ "find",
+ "walk",
+ "directory",
+ "recursive",
+ "tree"
+ ],
+ "license": "MIT/X11",
+ "main": "./index.js",
+ "name": "findit",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/substack/node-findit.git"
+ },
+ "scripts": {
+ "test": "expresso"
+ },
+ "version": "0.1.2"
+}
diff --git a/debian/tests/node_modules/gently/Makefile b/debian/tests/node_modules/gently/Makefile
new file mode 100644
index 0000000..01f7140
--- /dev/null
+++ b/debian/tests/node_modules/gently/Makefile
@@ -0,0 +1,4 @@
+test:
+ @find test/simple/test-*.js | xargs -n 1 -t node
+
+.PHONY: test
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/Readme.md b/debian/tests/node_modules/gently/Readme.md
new file mode 100644
index 0000000..f8f0c66
--- /dev/null
+++ b/debian/tests/node_modules/gently/Readme.md
@@ -0,0 +1,167 @@
+# Gently
+
+## Purpose
+
+A node.js module that helps with stubbing and behavior verification. It allows you to test the most remote and nested corners of your code while keeping being fully unobtrusive.
+
+## Features
+
+* Overwrite and stub individual object functions
+* Verify that all expected calls have been made in the expected order
+* Restore stubbed functions to their original behavior
+* Detect object / class names from obj.constructor.name and obj.toString()
+* Hijack any required module function or class constructor
+
+## Installation
+
+Via [npm](http://github.com/isaacs/npm):
+
+ npm install gently@latest
+
+## Example
+
+Make sure your dog is working properly:
+
+ function Dog() {}
+
+ Dog.prototype.seeCat = function() {
+ this.bark('whuf, whuf');
+ this.run();
+ }
+
+ Dog.prototype.bark = function(bark) {
+ require('sys').puts(bark);
+ }
+
+ var gently = new (require('gently'))
+ , assert = require('assert')
+ , dog = new Dog();
+
+ gently.expect(dog, 'bark', function(bark) {
+ assert.equal(bark, 'whuf, whuf');
+ });
+ gently.expect(dog, 'run');
+
+ dog.seeCat();
+
+You can also easily test event emitters with this, for example a simple sequence of 2 events emitted by `fs.WriteStream`:
+
+ var gently = new (require('gently'))
+ , stream = new (require('fs').WriteStream)('my_file.txt');
+
+ gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'open');
+ });
+
+ gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'drain');
+ });
+
+For a full read world example, check out this test case: [test-incoming-form.js](http://github.com/felixge/node-formidable/blob/master/test/simple/test-incoming-form.js) (in [node-formdiable](http://github.com/felixge/node-formidable)).
+
+## API
+
+### Gently
+
+#### new Gently()
+
+Creates a new gently instance. It listens to the process `'exit'` event to make sure all expectations have been verified.
+
+#### gently.expect(obj, method, [[count], stubFn])
+
+Creates an expectation for an objects method to be called. You can optionally specify the call `count` you are expecting, as well as `stubFn` function that will run instead of the original function.
+
+Returns a reference to the function that is getting overwritten.
+
+#### gently.expect([count], stubFn)
+
+Returns a function that is supposed to be executed `count` times, delegating any calls to the provided `stubFn` function. Naming your stubFn closure will help to properly diagnose errors that are being thrown:
+
+ childProcess.exec('ls', gently.expect(function lsCallback(code) {
+ assert.equal(0, code);
+ }));
+
+#### gently.restore(obj, method)
+
+Restores an object method that has been previously overwritten using `gently.expect()`.
+
+#### gently.hijack(realRequire)
+
+Returns a new require functions that catches a reference to all required modules into `gently.hijacked`.
+
+To use this function, include a line like this in your `'my-module.js'`.
+
+ if (global.GENTLY) require = GENTLY.hijack(require);
+
+ var sys = require('sys');
+ exports.hello = function() {
+ sys.log('world');
+ };
+
+Now you can write a test for the module above:
+
+ var gently = global.GENTLY = new (require('gently'))
+ , myModule = require('./my-module');
+
+ gently.expect(gently.hijacked.sys, 'log', function(str) {
+ assert.equal(str, 'world');
+ });
+
+ myModule.hello();
+
+#### gently.stub(location, [exportsName])
+
+Returns a stub class that will be used instead of the real class from the module at `location` with the given `exportsName`.
+
+This allows to test an OOP version of the previous example, where `'my-module.js'`.
+
+ if (global.GENTLY) require = GENTLY.hijack(require);
+
+ var World = require('./world');
+
+ exports.hello = function() {
+ var world = new World();
+ world.hello();
+ }
+
+And `world.js` looks like this:
+
+ var sys = require('sys');
+
+ function World() {
+
+ }
+ module.exports = World;
+
+ World.prototype.hello = function() {
+ sys.log('world');
+ };
+
+Testing `'my-module.js'` can now easily be accomplished:
+
+ var gently = global.GENTLY = new (require('gently'))
+ , WorldStub = gently.stub('./world')
+ , myModule = require('./my-module')
+ , WORLD;
+
+ gently.expect(WorldStub, 'new', function() {
+ WORLD = this;
+ });
+
+ gently.expect(WORLD, 'hello');
+
+ myModule.hello();
+
+#### gently.hijacked
+
+An object that holds the references to all hijacked modules.
+
+#### gently.verify([msg])
+
+Verifies that all expectations of this gently instance have been satisfied. If not called manually, this method is called when the process `'exit'` event is fired.
+
+If `msg` is given, it will appear in any error that might be thrown.
+
+## License
+
+Gently is licensed under the MIT license.
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/example/dog.js b/debian/tests/node_modules/gently/example/dog.js
new file mode 100644
index 0000000..022fae0
--- /dev/null
+++ b/debian/tests/node_modules/gently/example/dog.js
@@ -0,0 +1,22 @@
+require('../test/common');
+function Dog() {}
+
+Dog.prototype.seeCat = function() {
+ this.bark('whuf, whuf');
+ this.run();
+}
+
+Dog.prototype.bark = function(bark) {
+ require('sys').puts(bark);
+}
+
+var gently = new (require('gently'))
+ , assert = require('assert')
+ , dog = new Dog();
+
+gently.expect(dog, 'bark', function(bark) {
+ assert.equal(bark, 'whuf, whuf');
+});
+gently.expect(dog, 'run');
+
+dog.seeCat();
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/example/event_emitter.js b/debian/tests/node_modules/gently/example/event_emitter.js
new file mode 100644
index 0000000..7def134
--- /dev/null
+++ b/debian/tests/node_modules/gently/example/event_emitter.js
@@ -0,0 +1,11 @@
+require('../test/common');
+var gently = new (require('gently'))
+ , stream = new (require('fs').WriteStream)('my_file.txt');
+
+gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'open');
+});
+
+gently.expect(stream, 'emit', function(event) {
+ assert.equal(event, 'drain');
+});
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/index.js b/debian/tests/node_modules/gently/index.js
new file mode 100644
index 0000000..69122bd
--- /dev/null
+++ b/debian/tests/node_modules/gently/index.js
@@ -0,0 +1 @@
+module.exports = require('./lib/gently');
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/lib/gently/.gently.js.swp b/debian/tests/node_modules/gently/lib/gently/.gently.js.swp
new file mode 100644
index 0000000..f2ce523
Binary files /dev/null and b/debian/tests/node_modules/gently/lib/gently/.gently.js.swp differ
diff --git a/debian/tests/node_modules/gently/lib/gently/gently.js b/debian/tests/node_modules/gently/lib/gently/gently.js
new file mode 100644
index 0000000..7ff7e51
--- /dev/null
+++ b/debian/tests/node_modules/gently/lib/gently/gently.js
@@ -0,0 +1,151 @@
+var path = require('path');
+
+function Gently() {
+ this.expectations = [];
+ this.hijacked = {};
+
+ var self = this;
+ process.addListener('exit', function() {
+ self.verify('process exit');
+ });
+};
+module.exports = Gently;
+
+Gently.prototype.stub = function(location, exportsName) {
+ function Stub() {
+ Stub['new'].apply(this, arguments);
+ };
+
+ Stub['new'] = function () {};
+
+ var stubName = 'require('+JSON.stringify(location)+')';
+ if (exportsName) {
+ stubName += '.'+exportsName;
+ }
+
+ Stub.prototype.toString = Stub.toString = function() {
+ return stubName;
+ };
+
+ var exports = this.hijacked[location] || {};
+ if (exportsName) {
+ exports[exportsName] = Stub;
+ } else {
+ exports = Stub;
+ }
+
+ this.hijacked[location] = exports;
+ return Stub;
+};
+
+Gently.prototype.hijack = function(realRequire) {
+ var self = this;
+ return function(location) {
+ return self.hijacked[location] = (self.hijacked[location])
+ ? self.hijacked[location]
+ : realRequire(location);
+ };
+};
+
+Gently.prototype.expect = function(obj, method, count, stubFn) {
+ if (typeof obj != 'function' && typeof obj != 'object') {
+ throw new Error
+ ( 'Bad 1st argument for gently.expect(), '
+ + 'object or function expected, got: '+(typeof obj)
+ );
+ } else if (typeof obj == 'function' && (typeof method != 'string')) {
+ // expect(stubFn) interface
+ stubFn = obj;
+ obj = null;
+ method = null;
+ count = 1;
+ } else if (typeof method == 'function') {
+ // expect(count, stubFn) interface
+ count = obj;
+ stubFn = method;
+ obj = null;
+ method = null;
+ } else if (typeof count == 'function') {
+ // expect(obj, method, stubFn) interface
+ stubFn = count;
+ count = 1;
+ } else if (count === undefined) {
+ // expect(obj, method) interface
+ count = 1;
+ }
+
+ var name = this._name(obj, method, stubFn);
+ while (count-- > 0) {
+ this.expectations.push({obj: obj, method: method, stubFn: stubFn, name: name});
+ }
+
+ var self = this;
+ function delegate() {
+ return self._stubFn(this, obj, method, name, Array.prototype.slice.call(arguments));
+ }
+
+ if (!obj) {
+ return delegate;
+ }
+
+ var original = (obj[method])
+ ? obj[method]._original || obj[method]
+ : undefined;
+
+ obj[method] = delegate;
+ return obj[method]._original = original;
+};
+
+Gently.prototype.restore = function(obj, method) {
+ if (!obj[method] || !obj[method]._original) {
+ throw new Error(this._name(obj, method)+' is not gently stubbed');
+ }
+ obj[method] = obj[method]._original;
+};
+
+Gently.prototype.verify = function(msg) {
+ if (!this.expectations.length) {
+ return;
+ }
+
+ var expectation = this.expectations[0];
+ throw new Error
+ ( 'Expected call to '+expectation.name+' did not happen'
+ + ( (msg)
+ ? ' ('+msg+')'
+ : ''
+ )
+ );
+};
+
+Gently.prototype._stubFn = function(self, obj, method, name, args) {
+ var expectation = this.expectations.shift();
+ if (!expectation) {
+ throw new Error('Unexpected call to '+name+', no call was expected');
+ }
+
+ if (expectation.obj !== obj || expectation.method !== method) {
+ this.expectations.unshift(expectation);
+ throw new Error('Unexpected call to '+name+', expected call to '+ expectation.name);
+ }
+
+ if (expectation.stubFn) {
+ return expectation.stubFn.apply(self, args);
+ }
+};
+
+Gently.prototype._name = function(obj, method, stubFn) {
+ if (obj) {
+ var objectName = obj.toString();
+ if (objectName == '[object Object]' && obj.constructor.name) {
+ objectName = '['+obj.constructor.name+']';
+ }
+ return (objectName)+'.'+method+'()';
+ }
+
+ if (stubFn.name) {
+ return stubFn.name+'()';
+ }
+
+ return '>> '+stubFn.toString()+' <<';
+};
diff --git a/debian/tests/node_modules/gently/lib/gently/index.js b/debian/tests/node_modules/gently/lib/gently/index.js
new file mode 100644
index 0000000..64c1977
--- /dev/null
+++ b/debian/tests/node_modules/gently/lib/gently/index.js
@@ -0,0 +1 @@
+module.exports = require('./gently');
\ No newline at end of file
diff --git a/debian/tests/node_modules/gently/package.json b/debian/tests/node_modules/gently/package.json
new file mode 100644
index 0000000..22feffe
--- /dev/null
+++ b/debian/tests/node_modules/gently/package.json
@@ -0,0 +1,37 @@
+{
+ "_from": "gently@^0.8.0",
+ "_id": "gently@0.8.0",
+ "_inBundle": false,
+ "_integrity": "sha1-vDhduZ7BmU3WpENo4KvrSCsZKyw=",
+ "_location": "/gently",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "gently@^0.8.0",
+ "name": "gently",
+ "escapedName": "gently",
+ "rawSpec": "^0.8.0",
+ "saveSpec": null,
+ "fetchSpec": "^0.8.0"
+ },
+ "_requiredBy": [
+ "#DEV:/"
+ ],
+ "_resolved": "https://registry.npmjs.org/gently/-/gently-0.8.0.tgz",
+ "_shasum": "bc385db99ec1994dd6a44368e0abeb482b192b2c",
+ "_spec": "gently@^0.8.0",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable",
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "## Purpose",
+ "directories": {
+ "lib": "./lib/gently"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "main": "./lib/gently/index",
+ "name": "gently",
+ "version": "0.8.0"
+}
diff --git a/debian/tests/node_modules/seq/README.markdown b/debian/tests/node_modules/seq/README.markdown
new file mode 100644
index 0000000..3689261
--- /dev/null
+++ b/debian/tests/node_modules/seq/README.markdown
@@ -0,0 +1,442 @@
+Seq
+===
+
+Seq is an asynchronous flow control library with a chainable interface for
+sequential and parallel actions. Even the error handling is chainable.
+
+Each action in the chain operates on a stack of values.
+There is also a variables hash for storing values by name.
+
+[TOC]
+
+
+
+Examples
+========
+
+stat_all.js
+-----------
+
+````javascript
+var fs = require('fs');
+var Hash = require('hashish');
+var Seq = require('seq');
+
+Seq()
+ .seq(function () {
+ fs.readdir(__dirname, this);
+ })
+ .flatten()
+ .parEach(function (file) {
+ fs.stat(__dirname + '/' + file, this.into(file));
+ })
+ .seq(function () {
+ var sizes = Hash.map(this.vars, function (s) { return s.size })
+ console.dir(sizes);
+ })
+;
+````
+
+Output:
+
+ { 'stat_all.js': 404, 'parseq.js': 464 }
+
+parseq.js
+---------
+
+````javascript
+var fs = require('fs');
+var exec = require('child_process').exec;
+
+var Seq = require('seq');
+Seq()
+ .seq(function () {
+ exec('whoami', this)
+ })
+ .par(function (who) {
+ exec('groups ' + who, this);
+ })
+ .par(function (who) {
+ fs.readFile(__filename, 'ascii', this);
+ })
+ .seq(function (groups, src) {
+ console.log('Groups: ' + groups.trim());
+ console.log('This file has ' + src.length + ' bytes');
+ })
+;
+````
+
+Output:
+
+ Groups: substack : substack dialout cdrom floppy audio src video plugdev games netdev fuse www
+ This file has 464 bytes
+
+
+
+
+API
+===
+
+Each method executes callbacks with a context (its `this`) described in the next
+section. Every method returns `this`.
+
+Whenever `this()` is called with a non-falsy first argument, the error value
+propagates down to the first `catch` it sees, skipping over all actions in
+between. There is an implicit `catch` at the end of all chains that prints the
+error stack if available and otherwise just prints the error.
+
+
+
+Seq(xs=[])
+----------
+
+The constructor function creates a new `Seq` chain with the methods described
+below. The optional array argument becomes the new context stack.
+
+Array argument is new in 0.3. `Seq()` now behaves like `Seq.ap()`.
+
+
+.seq(cb)
+--------
+.seq(key, cb, *args)
+--------------------
+
+This eponymous function executes actions sequentially.
+Once all running parallel actions are finished executing,
+the supplied callback is `apply()`'d with the context stack.
+
+To execute the next action in the chain, call `this()`. The first
+argument must be the error value. The rest of the values will become the stack
+for the next action in the chain and are also available at `this.args`.
+
+If `key` is specified, the second argument sent to `this` goes to
+`this.vars[key]` in addition to the stack and `this.args`.
+`this.vars` persists across all requests unless it is overwritten.
+
+All arguments after `cb` will be bound to `cb`, which is useful because
+`.bind()` makes you set `this`. If you pass in `Seq` in the arguments list,
+it'll get transformed into `this` so that you can do:
+
+````javascript
+Seq()
+ .seq(fs.readdir, __dirname, Seq)
+ .seq(function (files) { console.dir(files) })
+;
+````
+
+which prints an array of files in `__dirname`.
+
+
+.par(cb)
+--------
+.par(key, cb, *args)
+--------------------
+
+Use `par` to execute actions in parallel.
+Chain multiple parallel actions together and collect all the responses on the
+stack with a sequential operation like `seq`.
+
+Each `par` sets one element in the stack with the second argument to `this()` in
+the order in which it appears, so multiple `par`s can be chained together.
+
+Like with `seq`, the first argument to `this()` should be the error value and
+the second will get pushed to the stack. Further arguments are available in
+`this.args`.
+
+If `key` is specified, the result from the second argument send to `this()` goes
+to `this.vars[key]`.
+`this.vars` persists across all requests unless it is overwritten.
+
+All arguments after `cb` will be bound to `cb`, which is useful because
+`.bind()` makes you set `this`. Like `.seq()`, you can pass along `Seq` in these
+bound arguments and it will get tranformed into `this`.
+
+
+.catch(cb)
+----------
+
+Catch errors. Whenever a function calls `this` with a non-falsy first argument,
+the message propagates down the chain to the first `catch` it sees.
+The callback `cb` fires with the error object as its first argument and the key
+that the action that caused the error was populating, which may be undefined.
+
+`catch` is a sequential action and further actions may appear after a `catch` in
+a chain. If the execution reaches a `catch` in a chain and no error has occured,
+the `catch` is skipped over.
+
+For convenience, there is a default error handler at the end of all chains.
+This default error handler looks like this:
+
+````javascript
+.catch(function (err) {
+ console.error(err.stack ? err.stack : err)
+})
+````
+
+
+.forEach(cb)
+------------
+
+Execute each action in the stack under the context of the chain object.
+`forEach` does not wait for any of the actions to finish and does not itself
+alter the stack, but the callback may alter the stack itself by modifying
+`this.stack`.
+
+The callback is executed `cb(x,i)` where `x` is the element and `i` is the
+index.
+
+`forEach` is a sequential operation like `seq` and won't run until all pending
+parallel requests yield results.
+
+
+.seqEach(cb)
+------------
+
+Like `forEach`, call `cb` for each element on the stack, but unlike `forEach`,
+`seqEach` waits for the callback to yield with `this` before moving on to the
+next element in the stack.
+
+The callback is executed `cb(x,i)` where `x` is the element and `i` is the
+index.
+
+If `this()` is supplied non-falsy error, the error propagates downward but any
+other arguments are ignored. `seqEach` does not modify the stack itself.
+
+
+.parEach(cb)
+------------
+.parEach(limit, cb)
+-------------------
+
+Like `forEach`, calls cb for each element in the stack and doesn't wait for the
+callback to yield a result with `this()` before moving on to the next iteration.
+Unlike `forEach`, `parEach` waits for all actions to call `this()` before moving
+along to the next action in the chain.
+
+The callback is executed `cb(x,i)` where `x` is the element and `i` is the
+index.
+
+`parEach` does not modify the stack itself and errors supplied to `this()`
+propagate.
+
+Optionally, if limit is supplied to `parEach`, at most `limit` callbacks will be
+active at a time.
+
+
+.seqMap(cb)
+-----------
+
+Like `seqEach`, but collect the values supplied to `this` and set the stack to
+these values.
+
+
+.parMap(cb)
+-----------
+.parMap(limit, cb)
+------------------
+
+Like `parEach`, but collect the values supplied to `this` and set the stack to
+these values.
+
+
+.seqFilter(cb)
+-----------
+
+Executes the callback `cb(x, idx)` against each element on the stack, waiting for the
+callback to yield with `this` before moving on to the next element. If the callback
+returns an error or a falsey value, the element will not be included in the resulting
+stack.
+
+Any errors from the callback are consumed and **do not** propagate.
+
+Calls to `this.into(i)` will place the value, if accepted by the callback, at the index in
+the results as if it were ordered at i-th index on the stack before filtering (with ties
+broken by the values). This implies `this.into` will never override another stack value
+even if their indices collide. Finally, the value will only actually appear at `i` if the
+callback accepts or moves enough values before `i`.
+
+
+.parFilter(cb)
+-----------
+.parFilter(limit, cb)
+------------------
+
+Executes the callback `cb(x, idx)` against each element on the stack, but **does not**
+wait for it to yield before moving on to the next element. If the callback returns an
+error or a falsey value, the element will not be included in the resulting stack.
+
+Any errors from the callback are consumed and **do not** propagate.
+
+Calls to `this.into(i)` will place the value, if accepted by the callback, at the index in
+the results as if it were ordered at i-th index on the stack before filtering (with ties
+broken by the values). This implies `this.into` will never override another stack value
+even if their indices collide. Finally, the value will only actually appear at `i` if the
+callback accepts or moves enough values before `i`.
+
+Optionally, if limit is supplied to `parEach`, at most `limit` callbacks will be
+active at a time.
+
+
+.do(cb)
+-------
+Create a new nested context. `cb`'s first argument is the previous context, and `this`
+is the nested `Seq` object.
+
+
+.flatten(fully=true)
+--------------------
+
+Recursively flatten all the arrays in the stack. Set `fully=false` to flatten
+only one level.
+
+
+.unflatten()
+------------
+
+Turn the contents of the stack into a single array item. You can think of it
+as the inverse of `flatten(false)`.
+
+
+.extend([x,y...])
+-----------------
+
+Like `push`, but takes an array. This is like python's `[].extend()`.
+
+
+.set(xs)
+--------
+
+Set the stack to a new array. This assigns the reference, it does not copy.
+
+
+.empty()
+--------
+
+Set the stack to [].
+
+
+.push(x,y...), .pop(), .shift(), .unshift(x), .splice(...), reverse()
+---------------------------------------------------------------------
+.map(...), .filter(...), .reduce(...)
+-------------------------------------
+
+Executes an array operation on the stack.
+
+The methods `map`, `filter`, and `reduce` are also proxies to their Array counterparts:
+they have identical signatures to the Array methods, operate synchronously on the context
+stack, and do not pass a Context object (unlike `seqMap` and `parMap`).
+
+The result of the transformation is assigned to the context stack; in the case of `reduce`,
+if you do not return an array, the value will be wrapped in one.
+
+````javascript
+Seq([1, 2, 3])
+ .reduce(function(sum, x){ return sum + x; }, 0)
+ .seq(function(sum){
+ console.log('sum: %s', sum);
+ // sum: 6
+ console.log('stack is Array?', Array.isArray(this.stack));
+ // stack is Array: true
+ console.log('stack:', this.stack);
+ // stack: [6]
+ })
+;
+````
+
+
+
+
+Explicit Parameters
+-------------------
+
+For environments like coffee-script or nested logic where threading `this` is
+bothersome, you can use:
+
+* seq_
+* par_
+* forEach_
+* seqEach_
+* parEach_
+* seqMap_
+* parMap_
+
+which work exactly like their un-underscored counterparts except for the first
+parameter to the supplied callback is set to the context, `this`.
+
+
+
+Context Object
+==============
+
+Each callback gets executed with its `this` set to a function in order to yield
+results, error values, and control. The function also has these useful fields:
+
+this.stack
+----------
+
+The execution stack.
+
+this.stack_
+-----------
+
+The previous stack value, mostly used internally for hackish purposes.
+
+this.vars
+---------
+
+A hash of key/values populated with `par(key, ...)`, `seq(key, ...)` and
+`this.into(key)`.
+
+this.into(key)
+--------------
+
+Instead of sending values to the stack, sets a key and returns `this`.
+Use `this.into(key)` interchangeably with `this` for yielding keyed results.
+`into` overrides the optional key set by `par(key, ...)` and `seq(key, ...)`.
+
+this.ok
+-------
+
+Set the `err` to null. Equivalent to `this.bind(this, null)`.
+
+this.args
+---------
+
+`this.args` is like `this.stack`, but it contains all the arguments to `this()`
+past the error value, not just the first. `this.args` is an array with the same
+indices as `this.stack` but also stores keyed values for the last sequential
+operation. Each element in `this.array` is set to `[].slice.call(arguments, 1)`
+from inside `this()`.
+
+this.error
+----------
+
+This is used for error propagation. You probably shouldn't mess with it.
+
+
+
+Installation
+============
+
+With [npm](http://github.com/isaacs/npm), just do:
+
+ npm install seq
+
+or clone this project on github:
+
+ git clone http://github.com/substack/node-seq.git
+
+To run the tests with [expresso](http://github.com/visionmedia/expresso),
+just do:
+
+ expresso
+
+
+
+Dependencies
+------------
+
+This module uses [chainsaw](http://github.com/substack/node-chainsaw)
+When you `npm install seq` this dependency will automatically be installed.
+
+
diff --git a/debian/tests/node_modules/seq/examples/join.js b/debian/tests/node_modules/seq/examples/join.js
new file mode 100644
index 0000000..cc05c4f
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/join.js
@@ -0,0 +1,18 @@
+var Seq = require('seq');
+Seq()
+ .par(function () {
+ var that = this;
+ setTimeout(function () { that(null, 'a') }, 300);
+ })
+ .par(function () {
+ var that = this;
+ setTimeout(function () { that(null, 'b') }, 200);
+ })
+ .par(function () {
+ var that = this;
+ setTimeout(function () { that(null, 'c') }, 100);
+ })
+ .seq(function (a, b, c) {
+ console.dir([ a, b, c ])
+ })
+;
diff --git a/debian/tests/node_modules/seq/examples/parseq.coffee b/debian/tests/node_modules/seq/examples/parseq.coffee
new file mode 100644
index 0000000..d4ca0ab
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/parseq.coffee
@@ -0,0 +1,12 @@
+fs = require 'fs'
+exec = require('child_process').exec
+Seq = require 'seq'
+
+Seq()
+ .seq_((next) -> exec 'whoami', next)
+ .par_((next, who) -> exec('groups ' + who, next))
+ .par_((next, who) -> fs.readFile(__filename, 'utf8', next))
+ .seq_((next, groups, src) ->
+ console.log('Groups: ' + groups.trim())
+ console.log('This file has ' + src.length + ' bytes')
+ )
diff --git a/debian/tests/node_modules/seq/examples/parseq.js b/debian/tests/node_modules/seq/examples/parseq.js
new file mode 100644
index 0000000..2cdcf21
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/parseq.js
@@ -0,0 +1,19 @@
+var fs = require('fs');
+var exec = require('child_process').exec;
+
+var Seq = require('seq');
+Seq()
+ .seq(function () {
+ exec('whoami', this)
+ })
+ .par(function (who) {
+ exec('groups ' + who, this);
+ })
+ .par(function (who) {
+ fs.readFile(__filename, 'utf8', this);
+ })
+ .seq(function (groups, src) {
+ console.log('Groups: ' + groups.trim());
+ console.log('This file has ' + src.length + ' bytes');
+ })
+;
diff --git a/debian/tests/node_modules/seq/examples/stat_all.coffee b/debian/tests/node_modules/seq/examples/stat_all.coffee
new file mode 100644
index 0000000..83ec0b2
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/stat_all.coffee
@@ -0,0 +1,16 @@
+fs = require 'fs'
+Hash = require 'hashish'
+Seq = require 'seq'
+
+Seq()
+ .seq_((next) ->
+ fs.readdir(__dirname, next)
+ )
+ .flatten()
+ .parEach_((next, file) ->
+ fs.stat(__dirname + '/' + file, next.into(file))
+ )
+ .seq_((next) ->
+ sizes = Hash.map(next.vars, (s) -> s.size)
+ console.dir sizes
+ )
diff --git a/debian/tests/node_modules/seq/examples/stat_all.js b/debian/tests/node_modules/seq/examples/stat_all.js
new file mode 100644
index 0000000..b9962eb
--- /dev/null
+++ b/debian/tests/node_modules/seq/examples/stat_all.js
@@ -0,0 +1,17 @@
+var fs = require('fs');
+var Hash = require('hashish');
+var Seq = require('seq');
+
+Seq()
+ .seq(function () {
+ fs.readdir(__dirname, this);
+ })
+ .flatten()
+ .parEach(function (file) {
+ fs.stat(__dirname + '/' + file, this.into(file));
+ })
+ .seq(function () {
+ var sizes = Hash.map(this.vars, function (s) { return s.size })
+ console.dir(sizes);
+ })
+;
diff --git a/debian/tests/node_modules/seq/index.js b/debian/tests/node_modules/seq/index.js
new file mode 100755
index 0000000..4e0888b
--- /dev/null
+++ b/debian/tests/node_modules/seq/index.js
@@ -0,0 +1,520 @@
+var EventEmitter = require('events').EventEmitter;
+var Hash = require('hashish');
+var Chainsaw = require('chainsaw');
+
+module.exports = Seq;
+function Seq (xs) {
+ if (xs && !Array.isArray(xs) || arguments.length > 1) {
+ throw new Error('Optional argument to Seq() is exactly one Array');
+ }
+
+ var ch = Chainsaw(function (saw) {
+ builder.call(this, saw, xs || []);
+ });
+
+ process.nextTick(function () {
+ ch['catch'](function (err) {
+ console.error(err.stack ? err.stack : err)
+ });
+ });
+ return ch;
+}
+
+Seq.ap = Seq; // for compatability with versions <0.3
+
+function builder (saw, xs) {
+ var context = {
+ vars : {},
+ args : {},
+ stack : xs,
+ error : null
+ };
+ context.stack_ = context.stack;
+
+ function action (step, key, f, g) {
+ var cb = function (err) {
+ var args = [].slice.call(arguments, 1);
+ if (err) {
+ context.error = { message : err, key : key };
+ saw.jump(lastPar);
+ saw.down('catch');
+ g();
+ }
+ else {
+ if (typeof key == 'number') {
+ context.stack_[key] = args[0];
+ context.args[key] = args;
+ }
+ else {
+ context.stack_.push.apply(context.stack_, args);
+ if (key !== undefined) {
+ context.vars[key] = args[0];
+ context.args[key] = args;
+ }
+ }
+ if (g) g(args, key);
+ }
+ };
+ Hash(context).forEach(function (v,k) { cb[k] = v });
+
+ cb.into = function (k) {
+ key = k;
+ return cb;
+ };
+
+ cb.next = function (err, xs) {
+ context.stack_.push.apply(context.stack_, xs);
+ cb.apply(cb, [err].concat(context.stack));
+ };
+
+ cb.pass = function (err) {
+ cb.apply(cb, [err].concat(context.stack));
+ };
+
+ cb.ok = cb.bind(cb, null);
+
+ f.apply(cb, context.stack);
+ }
+
+ var running = 0;
+ var errors = 0;
+
+ this.seq = function (key, cb) {
+ var bound = [].slice.call(arguments, 2);
+
+ if (typeof key === 'function') {
+ if (arguments.length > 1) bound.unshift(cb);
+ cb = key;
+ key = undefined;
+ }
+
+ if (context.error) saw.next()
+ else if (running === 0) {
+ action(saw.step, key,
+ function () {
+ context.stack_ = [];
+ var args = [].slice.call(arguments);
+ args.unshift.apply(args, bound.map(function (arg) {
+ return arg === Seq ? this : arg
+ }, this));
+
+ cb.apply(this, args);
+ }, function () {
+ context.stack = context.stack_;
+ saw.next()
+ }
+ );
+ }
+ };
+
+ var lastPar = null;
+ this.par = function (key, cb) {
+ lastPar = saw.step;
+
+ if (running == 0) {
+ // empty the active stack for the first par() in a chain
+ context.stack_ = [];
+ }
+
+ var bound = [].slice.call(arguments, 2);
+ if (typeof key === 'function') {
+ if (arguments.length > 1) bound.unshift(cb);
+ cb = key;
+ key = context.stack_.length;
+ context.stack_.push(null);
+ }
+ var cb_ = function () {
+ var args = [].slice.call(arguments);
+ args.unshift.apply(args, bound.map(function (arg) {
+ return arg === Seq ? this : arg
+ }, this));
+
+ cb.apply(this, args);
+ };
+
+ running ++;
+
+ var step = saw.step;
+ process.nextTick(function () {
+ action(step, key, cb_, function (args) {
+ if (!args) errors ++;
+
+ running --;
+ if (running == 0) {
+ context.stack = context.stack_.slice();
+ saw.step = lastPar;
+ if (errors > 0) saw.down('catch');
+ errors = 0;
+ saw.next();
+ }
+ });
+ });
+ saw.next();
+ };
+
+ [ 'seq', 'par' ].forEach(function (name) {
+ this[name + '_'] = function (key) {
+ var args = [].slice.call(arguments);
+
+ var cb = typeof key === 'function'
+ ? args[0] : args[1];
+
+ var fn = function () {
+ var argv = [].slice.call(arguments);
+ argv.unshift(this);
+ cb.apply(this, argv);
+ };
+
+ if (typeof key === 'function') {
+ args[0] = fn;
+ }
+ else {
+ args[1] = fn;
+ }
+
+ this[name].apply(this, args);
+ };
+ }, this);
+
+ this['catch'] = function (cb) {
+ if (context.error) {
+ cb.call(context, context.error.message, context.error.key);
+ context.error = null;
+ }
+ saw.next();
+ };
+
+ this.forEach = function (cb) {
+ this.seq(function () {
+ context.stack_ = context.stack.slice();
+ var end = context.stack.length;
+
+ if (end === 0) this(null)
+ else context.stack.forEach(function (x, i) {
+ action(saw.step, i, function () {
+ cb.call(this, x, i);
+ if (i == end - 1) saw.next();
+ });
+ });
+ });
+ };
+
+ this.seqEach = function (cb) {
+ this.seq(function () {
+ context.stack_ = context.stack.slice();
+ var xs = context.stack.slice();
+ if (xs.length === 0) this(null);
+ else (function next (i) {
+ action(
+ saw.step, i,
+ function () { cb.call(this, xs[i], i) },
+ function (args) {
+ if (!args || i === xs.length - 1) saw.next();
+ else next(i + 1);
+ }
+ );
+ }).bind(this)(0);
+ });
+ };
+
+ this.parEach = function (limit, cb) {
+ var xs = context.stack.slice();
+ if (cb === undefined) { cb = limit; limit = xs.length }
+ context.stack_ = [];
+
+ var active = 0;
+ var finished = 0;
+ var queue = [];
+
+ if (xs.length === 0) saw.next()
+ else xs.forEach(function call (x, i) {
+ if (active >= limit) {
+ queue.push(call.bind(this, x, i));
+ }
+ else {
+ active ++;
+ action(saw.step, i,
+ function () {
+ cb.call(this, x, i);
+ },
+ function () {
+ active --;
+ finished ++;
+ if (queue.length > 0) queue.shift()();
+ else if (finished === xs.length) {
+ saw.next();
+ }
+ }
+ );
+ }
+ });
+ };
+
+ this.parMap = function (limit, cb) {
+ var res = [];
+ var len = context.stack.length;
+ if (cb === undefined) { cb = limit; limit = len }
+ var res = [];
+
+ Seq()
+ .extend(context.stack)
+ .parEach(limit, function (x, i) {
+ var self = this;
+
+ var next = function () {
+ res[i] = arguments[1];
+ self.apply(self, arguments);
+ };
+
+ next.stack = self.stack;
+ next.stack_ = self.stack_;
+ next.vars = self.vars;
+ next.args = self.args;
+ next.error = self.error;
+
+ next.into = function (key) {
+ return function () {
+ res[key] = arguments[1];
+ self.apply(self, arguments);
+ };
+ };
+
+ next.ok = function () {
+ var args = [].slice.call(arguments);
+ args.unshift(null);
+ return next.apply(next, args);
+ };
+
+ cb.apply(next, arguments);
+ })
+ .seq(function () {
+ context.stack = res;
+ saw.next();
+ })
+ ;
+ };
+
+ this.seqMap = function (cb) {
+ var res = [];
+ var lastIdx = context.stack.length - 1;
+
+ this.seqEach(function (x, i) {
+ var self = this;
+
+ var next = function () {
+ res[i] = arguments[1];
+ if (i === lastIdx)
+ context.stack = res;
+ self.apply(self, arguments);
+ };
+
+ next.stack = self.stack;
+ next.stack_ = self.stack_;
+ next.vars = self.vars;
+ next.args = self.args;
+ next.error = self.error;
+
+ next.into = function (key) {
+ return function () {
+ res[key] = arguments[1];
+ if (i === lastIdx)
+ context.stack = res;
+ self.apply(self, arguments);
+ };
+ };
+
+ next.ok = function () {
+ var args = [].slice.call(arguments);
+ args.unshift(null);
+ return next.apply(next, args);
+ };
+
+ cb.apply(next, arguments);
+ });
+ };
+
+ /**
+ * Consumes any errors that occur in `cb`. Calls to `this.into(i)` will place
+ * that value, if accepted by the filter, at the index in the results as
+ * if it were the i-th index before filtering. (This means it will never
+ * override another value, and will only actually appear at i if the filter
+ * accepts all values before i.)
+ */
+ this.parFilter = function (limit, cb) {
+ var res = [];
+ var len = context.stack.length;
+ if (cb === undefined) { cb = limit; limit = len }
+ var res = [];
+
+ Seq()
+ .extend(context.stack)
+ .parEach(limit, function (x, i) {
+ var self = this;
+
+ var next = function (err, ok) {
+ if (!err && ok)
+ res.push([i, x]);
+ arguments[0] = null; // discard errors
+ self.apply(self, arguments);
+ };
+
+ next.stack = self.stack;
+ next.stack_ = self.stack_;
+ next.vars = self.vars;
+ next.args = self.args;
+ next.error = self.error;
+
+ next.into = function (key) {
+ return function (err, ok) {
+ if (!err && ok)
+ res.push([key, x]);
+ arguments[0] = null; // discard errors
+ self.apply(self, arguments);
+ };
+ };
+
+ next.ok = function () {
+ var args = [].slice.call(arguments);
+ args.unshift(null);
+ return next.apply(next, args);
+ };
+
+ cb.apply(next, arguments);
+ })
+ .seq(function () {
+ context.stack = res.sort().map(function(pair){ return pair[1]; });
+ saw.next();
+ })
+ ;
+ };
+
+ /**
+ * Consumes any errors that occur in `cb`. Calls to `this.into(i)` will place
+ * that value, if accepted by the filter, at the index in the results as
+ * if it were the i-th index before filtering. (This means it will never
+ * override another value, and will only actually appear at i if the filter
+ * accepts all values before i.)
+ */
+ this.seqFilter = function (cb) {
+ var res = [];
+ var lastIdx = context.stack.length - 1;
+
+ this.seqEach(function (x, i) {
+ var self = this;
+
+ var next = function (err, ok) {
+ if (!err && ok)
+ res.push([i, x]);
+ if (i === lastIdx)
+ context.stack = res.sort().map(function(pair){ return pair[1]; });
+ arguments[0] = null; // discard errors
+ self.apply(self, arguments);
+ };
+
+ next.stack = self.stack;
+ next.stack_ = self.stack_;
+ next.vars = self.vars;
+ next.args = self.args;
+ next.error = self.error;
+
+ next.into = function (key) {
+ return function (err, ok) {
+ if (!err && ok)
+ res.push([key, x]);
+ if (i === lastIdx)
+ context.stack = res.sort().map(function(pair){ return pair[1]; });
+ arguments[0] = null; // discard errors
+ self.apply(self, arguments);
+ };
+ };
+
+ next.ok = function () {
+ var args = [].slice.call(arguments);
+ args.unshift(null);
+ return next.apply(next, args);
+ };
+
+ cb.apply(next, arguments);
+ });
+ };
+
+ [ 'forEach', 'seqEach', 'parEach', 'seqMap', 'parMap', 'seqFilter', 'parFilter' ]
+ .forEach(function (name) {
+ this[name + '_'] = function (cb) {
+ this[name].call(this, function () {
+ var args = [].slice.call(arguments);
+ args.unshift(this);
+ cb.apply(this, args);
+ });
+ };
+ }, this)
+ ;
+
+ ['push','pop','shift','unshift','splice','reverse']
+ .forEach(function (name) {
+ this[name] = function () {
+ context.stack[name].apply(
+ context.stack,
+ [].slice.call(arguments)
+ );
+ saw.next();
+ return this;
+ };
+ }, this)
+ ;
+
+ [ 'map', 'filter', 'reduce' ]
+ .forEach(function (name) {
+ this[name] = function () {
+ var res = context.stack[name].apply(
+ context.stack,
+ [].slice.call(arguments)
+ );
+ // stack must be an array, or bad things happen
+ context.stack = (Array.isArray(res) ? res : [res]);
+ saw.next();
+ return this;
+ };
+ }, this)
+ ;
+
+ this.extend = function (xs) {
+ if (!Array.isArray(xs)) {
+ throw new Error('argument to .extend() is not an Array');
+ }
+ context.stack.push.apply(context.stack, xs);
+ saw.next();
+ };
+
+ this.flatten = function (pancake) {
+ var xs = [];
+ // should we fully flatten this array? (default: true)
+ if (pancake === undefined) { pancake = true; }
+ context.stack.forEach(function f (x) {
+ if (Array.isArray(x) && pancake) x.forEach(f);
+ else if (Array.isArray(x)) xs = xs.concat(x);
+ else xs.push(x);
+ });
+ context.stack = xs;
+ saw.next();
+ };
+
+ this.unflatten = function () {
+ context.stack = [context.stack];
+ saw.next();
+ };
+
+ this.empty = function () {
+ context.stack = [];
+ saw.next();
+ };
+
+ this.set = function (stack) {
+ context.stack = stack;
+ saw.next();
+ };
+
+ this['do'] = function (cb) {
+ saw.nest(cb, context);
+ };
+}
diff --git a/debian/tests/node_modules/seq/package.json b/debian/tests/node_modules/seq/package.json
new file mode 100644
index 0000000..39784d1
--- /dev/null
+++ b/debian/tests/node_modules/seq/package.json
@@ -0,0 +1,74 @@
+{
+ "_from": "seq@>=0.1.7",
+ "_id": "seq@0.3.5",
+ "_inBundle": false,
+ "_integrity": "sha1-rgKvOkJHk9jMvyEtaRdODFTf/jg=",
+ "_location": "/seq",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "seq@>=0.1.7",
+ "name": "seq",
+ "escapedName": "seq",
+ "rawSpec": ">=0.1.7",
+ "saveSpec": null,
+ "fetchSpec": ">=0.1.7"
+ },
+ "_requiredBy": [
+ "/findit"
+ ],
+ "_resolved": "https://registry.npmjs.org/seq/-/seq-0.3.5.tgz",
+ "_shasum": "ae02af3a424793d8ccbf212d69174e0c54dffe38",
+ "_spec": "seq@>=0.1.7",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable/node_modules/findit",
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "bugs": {
+ "url": "https://github.com/substack/node-seq/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "chainsaw": ">=0.0.7 <0.1",
+ "hashish": ">=0.0.2 <0.1"
+ },
+ "deprecated": false,
+ "description": "Chainable asynchronous flow control with sequential and parallel primitives and pipeline-style error handling",
+ "devDependencies": {
+ "expresso": ">=0.7.x"
+ },
+ "engine": {
+ "node": ">=0.4.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "https://github.com/substack/node-seq#readme",
+ "keywords": [
+ "flow-control",
+ "flow",
+ "control",
+ "async",
+ "asynchronous",
+ "chain",
+ "pipeline",
+ "sequence",
+ "sequential",
+ "parallel",
+ "error"
+ ],
+ "license": "MIT/X11",
+ "main": "./index.js",
+ "name": "seq",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/substack/node-seq.git"
+ },
+ "script": {
+ "test": "expresso"
+ },
+ "version": "0.3.5"
+}
diff --git a/debian/tests/node_modules/urun/.travis.yml b/debian/tests/node_modules/urun/.travis.yml
new file mode 100644
index 0000000..f1d0f13
--- /dev/null
+++ b/debian/tests/node_modules/urun/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.6
diff --git a/debian/tests/node_modules/urun/Makefile b/debian/tests/node_modules/urun/Makefile
new file mode 100644
index 0000000..6a355bb
--- /dev/null
+++ b/debian/tests/node_modules/urun/Makefile
@@ -0,0 +1,6 @@
+SHELL := /bin/bash
+
+test:
+ @find test -name test-*.js -type f | xargs -tn1 node
+
+.PHONY: test
diff --git a/debian/tests/node_modules/urun/Readme.md b/debian/tests/node_modules/urun/Readme.md
new file mode 100644
index 0000000..0d9ea23
--- /dev/null
+++ b/debian/tests/node_modules/urun/Readme.md
@@ -0,0 +1,45 @@
+# urun
+
+[![Build Status](https://secure.travis-ci.org/felixge/node-urun.png)](http://travis-ci.org/felixge/node-urun)
+
+The minimal test runner.
+
+## Why yet another test runner?
+
+I wanted something simple, that just runs test files, shows progress, and
+behaves like a good UNIX citizen. Now it exists.
+
+## Install
+
+```
+npm install urun
+```
+
+## Usage
+
+In order to execute all test-*.js files inside a given directory, simply do:
+
+```js
+require('urun')(__dirname);
+```
+
+You now get a nice progress indication, as well as detailed output for each
+test that fails.
+
+The only other feature is specifying a regex for the files to run (default is
+`/test-.+\.js$/`), for example:
+
+```js
+require('urun')(__dirname, { include: /.+Test\.js$/ });
+```
+
+## Reporter
+
+```js
+require('urun')(__dirname, { reporter: 'BashReporter' }); // default
+require('urun')(__dirname, { reporter: 'BashTapReporter' }); // tap compliant output
+```
+
+## License
+
+This module is licensed under the MIT license.
diff --git a/debian/tests/node_modules/urun/index.js b/debian/tests/node_modules/urun/index.js
new file mode 100644
index 0000000..05ad807
--- /dev/null
+++ b/debian/tests/node_modules/urun/index.js
@@ -0,0 +1,23 @@
+var FileFilter = require('./lib/FileFilter');
+var FileFinder = require('./lib/FileFinder');
+var Runner = require('./lib/Runner');
+
+module.exports = function(dir, options) {
+ var options = options || {};
+ var include = options.include || /test-.+\.js$/;
+ var Reporter = require('./lib/reporter/'
+ + (process.env.REPORTER || options.reporter || 'BashReporter'));
+
+ var finder = new FileFinder(dir);
+ var filter = new FileFilter({include: include});
+
+ finder.execute(function(err, files) {
+ if (err) throw err;
+
+ files = filter.filter(files);
+
+ var runner = new Runner({files: files});
+ var reporter = new Reporter({runner: runner});
+ runner.execute();
+ });
+};
diff --git a/debian/tests/node_modules/urun/lib/FileExecutor.js b/debian/tests/node_modules/urun/lib/FileExecutor.js
new file mode 100644
index 0000000..0d33451
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/FileExecutor.js
@@ -0,0 +1,46 @@
+var spawn = require('child_process').spawn;
+
+module.exports = FileExecutor;
+function FileExecutor(options) {
+ this._file = options.file;
+ this._bin = process.execPath;
+ this._cwd = options.cwd || process.cwd();
+ this._output = '';
+}
+
+FileExecutor.prototype.execute = function(cb) {
+ var self = this;
+ var child = spawn(this._bin, [this._file]);
+
+ this._capture(child.stdout);
+ this._capture(child.stderr);
+
+ child.on('exit', function(code, signal) {
+ cb(self._errorFor(code, signal), self._output);
+ });
+};
+
+FileExecutor.prototype._capture = function(stream) {
+ var self = this;
+
+ stream.setEncoding('utf8');
+ stream.on('data', function(chunk) {
+ self._output += chunk;
+ });
+};
+
+FileExecutor.prototype._errorFor = function(code, signal) {
+ if (!code && !signal) return null;
+
+ var prefix = 'node ' + this.relativePath() + ' died with ';
+
+ if (code) return new Error(prefix + 'code: ' + code);
+ if (signal) return new Error(prefix + 'signal: ' + signal);
+};
+
+FileExecutor.prototype.relativePath = function() {
+ var path = this._file;
+ return (path.indexOf(this._cwd) === 0)
+ ? path = path.substr(this._cwd.length + 1)
+ : path;
+};
diff --git a/debian/tests/node_modules/urun/lib/FileFilter.js b/debian/tests/node_modules/urun/lib/FileFilter.js
new file mode 100644
index 0000000..0ab530a
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/FileFilter.js
@@ -0,0 +1,16 @@
+module.exports = FileFilter;
+function FileFilter(options) {
+ options = options || {};
+
+ this._include = options.include;
+}
+
+FileFilter.prototype.filter = function(files) {
+ var self = this;
+
+ return files.filter(function(file) {
+ if (!self._include) return true;
+
+ return self._include.test(file);
+ });
+};
diff --git a/debian/tests/node_modules/urun/lib/FileFinder.js b/debian/tests/node_modules/urun/lib/FileFinder.js
new file mode 100644
index 0000000..a1f6c60
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/FileFinder.js
@@ -0,0 +1,66 @@
+var path = require('path');
+var fs = require('fs');
+var noOp = function() {};
+
+module.exports = FileFinder;
+function FileFinder(dir) {
+ this._dir = dir;
+}
+
+FileFinder.prototype.execute = function(cb) {
+ var files = [];
+ this._readdir(this._dir, files, function(err) {
+ cb(err, files);
+ });
+};
+
+FileFinder.prototype._readdir = function(dir, results, cb) {
+ var self = this;
+ fs.readdir(dir, function(err, files) {
+ if (err) {
+ cb(err);
+ cb = noOp;
+ return;
+ }
+
+ self._inspect(dir, files, results, cb);
+ });
+};
+
+FileFinder.prototype._inspect = function(dir, files, results, cb) {
+ var remaining = files.length;
+ var self = this;
+
+ if (!remaining) return cb(null);
+
+ files.forEach(function(file) {
+ var filePath = path.join(dir, file);
+
+ fs.stat(filePath, function(err, stat) {
+ if (err) {
+ cb(err);
+ cb = noOp;
+ return;
+ }
+
+ remaining--;
+ if (stat.isDirectory()) {
+ remaining++;
+ self._readdir(filePath, results, function(err) {
+ if (err) {
+ cb(err);
+ cb = noOp;
+ return;
+ }
+
+ remaining--;
+ if (!remaining) cb(null);
+ });
+ } else {
+ results.push(filePath);
+ }
+
+ if (!remaining) cb(null);
+ });
+ });
+};
diff --git a/debian/tests/node_modules/urun/lib/Runner.js b/debian/tests/node_modules/urun/lib/Runner.js
new file mode 100644
index 0000000..8a30375
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/Runner.js
@@ -0,0 +1,33 @@
+var FileExecutor = require('./FileExecutor');
+var EventEmitter = require('events').EventEmitter;
+var util = require('util');
+
+module.exports = Runner;
+util.inherits(Runner, EventEmitter);
+function Runner(options) {
+ this._files = [].concat(options.files);
+ this._cwd = options.cwd || process.cwd();
+}
+
+Runner.prototype.execute = function() {
+ this.emit('start', [].concat(this._files));
+ this._nextFile();
+};
+
+Runner.prototype._nextFile = function() {
+ var file = this._files.shift();
+ if (!file) {
+ this.emit('end');
+ return;
+ }
+
+ var self = this;
+ var executor = new FileExecutor({file: file, cwd: this._cwd});
+ var relativePath = executor.relativePath();
+
+ this.emit('fileStart', relativePath);
+ executor.execute(function(err, output) {
+ self.emit('fileEnd', relativePath, err, output);
+ self._nextFile();
+ });
+};
diff --git a/debian/tests/node_modules/urun/lib/reporter/BashReporter.js b/debian/tests/node_modules/urun/lib/reporter/BashReporter.js
new file mode 100644
index 0000000..22ca0f1
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/reporter/BashReporter.js
@@ -0,0 +1,101 @@
+var str = require('../str');
+
+module.exports = BashReporter;
+function BashReporter(options) {
+ this._runner = options.runner;
+ this._currentFile = null;
+ this._lastLine = null;
+ this._start = null;
+ this._fail = 0;
+ this._pass = 0;
+ this._total = 0;
+ this._interval = null;
+
+ this._runner.on('start', this._handleStart.bind(this));
+ this._runner.on('fileStart', this._handleFileStart.bind(this));
+ this._runner.on('fileEnd', this._handleFileEnd.bind(this));
+ this._runner.on('end', this._handleEnd.bind(this));
+}
+
+BashReporter.prototype._handleStart = function(files) {
+ this._start = Date.now();
+ this._total = files.length;
+ this._interval = setInterval(this.updateProgress.bind(this), 1000);
+};
+
+BashReporter.prototype._handleFileStart = function(file) {
+ this._currentFile = file;
+ this.updateProgress();
+};
+
+BashReporter.prototype._handleFileEnd = function(file, err, output) {
+ if (err) {
+ this._fail++;
+
+ if (output.substr(0, 1) !== '\n') output = '\n' + output;
+ output = output.replace(/^/mg, ' ');
+
+ process.stdout.write('\n' + output + '\n');
+ } else {
+ this._pass++;
+ }
+
+ this.updateProgress();
+};
+
+BashReporter.prototype._handleEnd = function() {
+ process.stdout.write('\n');
+ clearInterval(this._interval);
+
+ var exitCode = (this._fail > 0)
+ ? 1
+ : 0;
+
+ process.exit(exitCode);
+};
+
+BashReporter.prototype.updateProgress = function() {
+ var template = '\r[%s %s %s/%s %s node %s]';
+
+ var line = str.sprintf(
+ template,
+ this.elapsedTime(),
+ this._fail,
+ this._pass,
+ this._total,
+ this.progress(),
+ this._currentFile
+ );
+
+ this.clearLine();
+ process.stdout.write(line);
+ this._lastLine = line;
+};
+
+BashReporter.prototype.clearLine = function() {
+ if (!this._lastLine) return;
+
+ var spaces = str.repeat(' ', this._lastLine.length);
+ process.stdout.write('\r' + spaces + '\r');
+};
+
+BashReporter.prototype.elapsedTime = function(showMs) {
+ var duration = new Date - this._start;
+
+ var seconds = Math.floor((duration) / 1000);
+ var minutes = Math.floor(seconds / 60);
+ var hours = Math.floor(minutes / 60);
+
+ seconds -= (minutes * 60) - (hours * 60 * 60);
+ minutes -= hours * 60;
+
+ if (minutes < 10) minutes = '0' + minutes;
+ if (seconds < 10) seconds = '0' + seconds;
+
+ return hours + ':' + minutes + ':' + seconds;
+};
+
+BashReporter.prototype.progress = function() {
+ var index = this._fail + this._pass;
+ return ((index) * 100 / this._total).toFixed(1) + '%';
+};
diff --git a/debian/tests/node_modules/urun/lib/reporter/BashTapReporter.js b/debian/tests/node_modules/urun/lib/reporter/BashTapReporter.js
new file mode 100644
index 0000000..2694cda
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/reporter/BashTapReporter.js
@@ -0,0 +1,38 @@
+module.exports = BashTapReporter;
+
+function BashTapReporter(options) {
+ this._runner = options.runner;
+ this._fail = false;
+ this._count = 1;
+
+ this._runner.on('start', this._handleStart.bind(this));
+ this._runner.on('fileEnd', this._handleFileEnd.bind(this));
+ this._runner.on('end', this._handleEnd.bind(this));
+}
+
+BashTapReporter.prototype._handleStart = function(files) {
+ console.log('%d..%d', 1, files.length);
+};
+
+BashTapReporter.prototype._handleFileEnd = function(file, err, output) {
+ if (err) {
+ console.log('not ok %d %s', this._count, this._tapTitle(file));
+ console.log(output.replace(/^/gm, ' '));
+ this._fail = true;
+ } else {
+ console.log('ok %d %s', this._count, this._tapTitle(file));
+ }
+ this._count++;
+};
+
+BashTapReporter.prototype._handleEnd = function() {
+ var exitCode = (this._fail)
+ ? 1
+ : 0;
+
+ process.exit(exitCode);
+};
+
+BashTapReporter.prototype._tapTitle = function(title) {
+ return title.replace(/#/g, '');
+}
diff --git a/debian/tests/node_modules/urun/lib/str.js b/debian/tests/node_modules/urun/lib/str.js
new file mode 100644
index 0000000..c6baf73
--- /dev/null
+++ b/debian/tests/node_modules/urun/lib/str.js
@@ -0,0 +1,30 @@
+var str = module.exports;
+var util = require('util');
+
+// custom / simplified flavor of sprintf
+str.sprintf = function() {
+ var args = Array.prototype.slice.call(arguments);
+ var str = args.shift();
+
+ return str.replace(/%[so]/g, function(m, i, s) {
+ var arg = args.shift();
+ if (m == '%o') {
+ return util.inspect(arg);
+ }
+
+ if (!arg && arg !== 0) {
+ return '';
+ }
+
+ return arg.toString();
+ });
+};
+
+str.repeat = function(string, times) {
+ var repeated = '';
+ for (var i = 0; i < times; i++) {
+ repeated += string;
+ }
+
+ return repeated;
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/Makefile b/debian/tests/node_modules/urun/node_modules/utest/Makefile
new file mode 100644
index 0000000..6a355bb
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/Makefile
@@ -0,0 +1,6 @@
+SHELL := /bin/bash
+
+test:
+ @find test -name test-*.js -type f | xargs -tn1 node
+
+.PHONY: test
diff --git a/debian/tests/node_modules/urun/node_modules/utest/Readme.md b/debian/tests/node_modules/urun/node_modules/utest/Readme.md
new file mode 100644
index 0000000..674a92c
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/Readme.md
@@ -0,0 +1,76 @@
+# utest
+
+The minimal unit testing library.
+
+## Why yet another test library?
+
+I wanted something simple, that just does unit tests (no async) and nothing
+else. And each test is supposed to be a standalone UNIX program. Now it exists.
+
+## Install
+
+```
+npm install utest
+```
+
+## Usage
+
+Running a test with utest is very simple:
+
+```js
+var test = require('utest');
+var assert = require('assert');
+
+test('Number#toFixed', {
+ 'returns a string': function() {
+ assert.equal(typeof (5).toFixed(), 'string');
+ },
+
+ 'takes number of decimal places': function() {
+ assert.equal((5).toFixed(1), '5.0');
+ },
+
+ 'does not round': function() {
+ assert.equal((5.55).toFixed(1), '5.5');
+ },
+});
+```
+
+The only additional feature is running a before/after method:
+
+```js
+var test = require('utest');
+var assert = require('assert');
+
+test('Date', {
+ before: function() {
+ this.date = new Date;
+ },
+
+ after: function() {
+ this.date = null;
+ },
+
+ 'lets you manipulate the year': function() {
+ this.date.setYear(2012);
+ assert.equal(this.date.getFullYear(), 2012);
+ },
+
+ 'can be coerced into a number': function() {
+ assert.equal(typeof +this.date, 'number');
+ },
+});
+```
+
+## Future Features
+
+I want to keep this library as minimal as possible, but I do consider the
+addition of the following features:
+
+* TAP output (if TAP=1 in the environment, switch to TapReporter class)
+* Leak detection (automatically add a final test that fails if there are global
+ leaks).
+
+## License
+
+This module is licensed under the MIT license.
diff --git a/debian/tests/node_modules/urun/node_modules/utest/index.js b/debian/tests/node_modules/urun/node_modules/utest/index.js
new file mode 100644
index 0000000..ec222e1
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/index.js
@@ -0,0 +1,16 @@
+module.exports = utest;
+utest.Collection = require('./lib/Collection');
+utest.TestCase = require('./lib/TestCase');
+utest.BashReporter = require('./lib/reporter/BashReporter');
+
+var collection;
+var reporter;
+function utest(name, tests) {
+ if (!collection) {
+ collection = new utest.Collection();
+ reporter = new utest.BashReporter({collection: collection});
+ }
+
+ var testCase = new utest.TestCase({name: name, tests: tests});
+ collection.add(testCase);
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/lib/Collection.js b/debian/tests/node_modules/urun/node_modules/utest/lib/Collection.js
new file mode 100644
index 0000000..db9be5c
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/lib/Collection.js
@@ -0,0 +1,33 @@
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = Collection;
+util.inherits(Collection, EventEmitter);
+function Collection(options) {
+ this._pass = 0;
+ this._fail = 0;
+}
+
+Collection.prototype.add = function(testCase) {
+ this._start = this._start || Date.now();
+
+ var self = this;
+ testCase
+ .on('pass', function(name) {
+ self._pass++;
+ self.emit('pass', testCase, name);
+ })
+ .on('fail', function(name, err) {
+ self._fail++;
+ self.emit('fail', testCase, name, err);
+ })
+ .run();
+};
+
+Collection.prototype.stats = function() {
+ return {
+ pass : this._pass,
+ fail : this._fail,
+ duration : Date.now() - this._start,
+ };
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/lib/TestCase.js b/debian/tests/node_modules/urun/node_modules/utest/lib/TestCase.js
new file mode 100644
index 0000000..9e2a017
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/lib/TestCase.js
@@ -0,0 +1,36 @@
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = TestCase;
+util.inherits(TestCase, EventEmitter);
+function TestCase(properties) {
+ this.name = properties.name;
+ this._tests = properties.tests;
+}
+
+TestCase.prototype.run = function() {
+ var noop = function() {};
+ var before = this._tests.before || noop;
+ var after = this._tests.after || noop;
+
+ for (var test in this._tests) {
+ if (test === 'before' || test === 'after') continue;
+
+ var fn = this._tests[test];
+ var context = {};
+
+ try {
+ before.call(context);
+ fn.call(context);
+ after.call(context);
+ } catch (_err) {
+ var err = _err;
+ }
+
+ if (!err) {
+ this.emit('pass', test);
+ } else {
+ this.emit('fail', test, err);
+ }
+ }
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/lib/reporter/BashReporter.js b/debian/tests/node_modules/urun/node_modules/utest/lib/reporter/BashReporter.js
new file mode 100644
index 0000000..69308fc
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/lib/reporter/BashReporter.js
@@ -0,0 +1,26 @@
+module.exports = BashReporter;
+function BashReporter(options) {
+ this._process = options.process || process;
+ this._collection = options.collection;
+
+ this._collection.on('fail', this._handleFail.bind(this));
+ this._process.on('exit', this._handleExit.bind(this));
+}
+
+BashReporter.prototype._handleFail = function(testCase, test, error) {
+ this._process.stdout.write('Failed: ' + testCase.name + ' ' + test + '\n\n');
+ var stack = error.stack.replace(/^/gm, ' ');
+ this._process.stdout.write(stack + '\n\n');
+};
+
+BashReporter.prototype._handleExit = function() {
+ var stats = this._collection.stats();
+ this._process.stdout.write(
+ stats.fail + ' fail | ' +
+ stats.pass + ' pass | ' +
+ stats.duration + ' ms ' +
+ '\n'
+ );
+
+ if (stats.fail) this._process.reallyExit(1);
+};
diff --git a/debian/tests/node_modules/urun/node_modules/utest/package.json b/debian/tests/node_modules/urun/node_modules/utest/package.json
new file mode 100644
index 0000000..47b5572
--- /dev/null
+++ b/debian/tests/node_modules/urun/node_modules/utest/package.json
@@ -0,0 +1,48 @@
+{
+ "_from": "utest@0.0.2",
+ "_id": "utest@0.0.2",
+ "_inBundle": false,
+ "_integrity": "sha1-OGLil1MJ6l3glAREpsbuAXlyahY=",
+ "_location": "/urun/utest",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "version",
+ "registry": true,
+ "raw": "utest@0.0.2",
+ "name": "utest",
+ "escapedName": "utest",
+ "rawSpec": "0.0.2",
+ "saveSpec": null,
+ "fetchSpec": "0.0.2"
+ },
+ "_requiredBy": [
+ "/urun"
+ ],
+ "_resolved": "https://registry.npmjs.org/utest/-/utest-0.0.2.tgz",
+ "_shasum": "3862e2975309ea5de0940444a6c6ee0179726a16",
+ "_spec": "utest@0.0.2",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable/node_modules/urun",
+ "author": {
+ "name": "Felix Geisendörfer",
+ "email": "felix@debuggable.com",
+ "url": "http://debuggable.com/"
+ },
+ "bundleDependencies": false,
+ "dependencies": {},
+ "deprecated": false,
+ "description": "The minimal unit testing library.",
+ "devDependencies": {},
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "https://github.com/felixge/node-utest",
+ "main": "./index",
+ "name": "utest",
+ "repository": {
+ "url": ""
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "version": "0.0.2"
+}
diff --git a/debian/tests/node_modules/urun/package.json b/debian/tests/node_modules/urun/package.json
new file mode 100644
index 0000000..c4b7633
--- /dev/null
+++ b/debian/tests/node_modules/urun/package.json
@@ -0,0 +1,54 @@
+{
+ "_from": "urun@^0.0.6",
+ "_id": "urun@0.0.6",
+ "_inBundle": false,
+ "_integrity": "sha1-4PqFaYA2fYa/FG4YC8OJAyCrHS8=",
+ "_location": "/urun",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "urun@^0.0.6",
+ "name": "urun",
+ "escapedName": "urun",
+ "rawSpec": "^0.0.6",
+ "saveSpec": null,
+ "fetchSpec": "^0.0.6"
+ },
+ "_requiredBy": [
+ "#DEV:/"
+ ],
+ "_resolved": "https://registry.npmjs.org/urun/-/urun-0.0.6.tgz",
+ "_shasum": "e0fa856980367d86bf146e180bc3890320ab1d2f",
+ "_spec": "urun@^0.0.6",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable",
+ "author": {
+ "name": "Felix Geisendörfer",
+ "email": "felix@debuggable.com",
+ "url": "http://debuggable.com/"
+ },
+ "bundleDependencies": false,
+ "dependencies": {
+ "utest": "0.0.2"
+ },
+ "deprecated": false,
+ "description": "The minimal test runner.",
+ "devDependencies": {
+ "sinon": "1.2.0",
+ "utest": "0.0.1"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "https://github.com/felixge/node-urun",
+ "main": "./index",
+ "name": "urun",
+ "optionalDependencies": {},
+ "repository": {
+ "url": ""
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "version": "0.0.6"
+}
diff --git a/debian/tests/node_modules/utest/.travis.yml b/debian/tests/node_modules/utest/.travis.yml
new file mode 100644
index 0000000..f1d0f13
--- /dev/null
+++ b/debian/tests/node_modules/utest/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.6
diff --git a/debian/tests/node_modules/utest/Makefile b/debian/tests/node_modules/utest/Makefile
new file mode 100644
index 0000000..6a355bb
--- /dev/null
+++ b/debian/tests/node_modules/utest/Makefile
@@ -0,0 +1,6 @@
+SHELL := /bin/bash
+
+test:
+ @find test -name test-*.js -type f | xargs -tn1 node
+
+.PHONY: test
diff --git a/debian/tests/node_modules/utest/Readme.md b/debian/tests/node_modules/utest/Readme.md
new file mode 100644
index 0000000..0d789fe
--- /dev/null
+++ b/debian/tests/node_modules/utest/Readme.md
@@ -0,0 +1,106 @@
+# utest
+
+[![Build Status](https://secure.travis-ci.org/felixge/node-utest.png)](http://travis-ci.org/felixge/node-utest)
+
+The minimal unit testing library.
+
+## Why yet another test library?
+
+I wanted something simple, that just does unit tests (no async) and where each
+test is a standalone UNIX program. Now it exists.
+
+## How do I run async tests?
+
+Currently there is only one sane way: Do not use a framework. Instead use one
+file per test.
+
+If that becomes an issue, you should write more unit tests. (It is not a unit
+test if it does I/O).
+
+## Install
+
+```
+npm install utest
+```
+
+## Usage
+
+Running a test with utest is very simple:
+
+```js
+var test = require('utest');
+var assert = require('assert');
+
+test('Number#toFixed', {
+ 'returns a string': function() {
+ assert.equal(typeof (5).toFixed(), 'string');
+ },
+
+ 'takes number of decimal places': function() {
+ assert.equal((5).toFixed(1), '5.0');
+ },
+
+ 'does not round': function() {
+ assert.equal((5.55).toFixed(1), '5.5');
+ },
+});
+```
+
+It is also possible to define a before/after method:
+
+```js
+var test = require('utest');
+var assert = require('assert');
+
+test('Date', {
+ before: function() {
+ this.date = new Date;
+ },
+
+ after: function() {
+ this.date = null;
+ },
+
+ 'lets you manipulate the year': function() {
+ this.date.setYear(2012);
+ assert.equal(this.date.getFullYear(), 2012);
+ },
+
+ 'can be coerced into a number': function() {
+ assert.equal(typeof +this.date, 'number');
+ },
+});
+```
+
+Last but not least, you can run individual tests by prefixing them with an
+exclamation mark. This is useful when putting debug statements into the subject
+under test:
+
+```js
+var test = require('utest');
+var assert = require('assert');
+
+test('MyTest', {
+ '!will be executed': function() {
+ // ...
+ },
+
+ 'will not be exectuted': function() {
+ // ...
+ },
+});
+```
+
+## Future Features
+
+I want to keep this library as minimal as possible, but I do consider the
+addition of the following features:
+
+* Nested test cases
+* TAP output (if TAP=1 in the environment, switch to TapReporter class)
+* Leak detection (automatically add a final test that fails if there are global
+ leaks).
+
+## License
+
+This module is licensed under the MIT license.
diff --git a/debian/tests/node_modules/utest/browser.js b/debian/tests/node_modules/utest/browser.js
new file mode 100644
index 0000000..32fd588
--- /dev/null
+++ b/debian/tests/node_modules/utest/browser.js
@@ -0,0 +1,20 @@
+if (!Function.prototype.bind) {
+ Function.prototype.bind = function (scope) {
+ var fn = this;
+ return function () {
+ return fn.apply(scope, arguments);
+ };
+ };
+}
+
+// Not shimed by Browserify:
+process.exit = function () {};
+
+var test = require('./index');
+test.Reporter = test.ConsoleReporter;
+
+module.exports = function (name, tests) {
+ process.nextTick(function () {
+ test(name, tests);
+ });
+};
diff --git a/debian/tests/node_modules/utest/index.js b/debian/tests/node_modules/utest/index.js
new file mode 100644
index 0000000..ac75255
--- /dev/null
+++ b/debian/tests/node_modules/utest/index.js
@@ -0,0 +1,23 @@
+module.exports = utest;
+utest.Collection = require('./lib/Collection');
+utest.TestCase = require('./lib/TestCase');
+utest.BashReporter = require('./lib/reporter/BashReporter');
+utest.ConsoleReporter = require('./lib/reporter/ConsoleReporter');
+utest.Reporter = utest.BashReporter;
+
+var collection;
+var reporter;
+function utest(name, tests) {
+ if (!collection) {
+ collection = new utest.Collection();
+ reporter = new utest.Reporter({collection: collection});
+
+ process.nextTick(collection.run.bind(collection));
+ collection.on('complete', function(stats) {
+ process.exit(stats.fail ? 1 : 0);
+ });
+ }
+
+ var testCase = new utest.TestCase({name: name, tests: tests});
+ collection.add(testCase);
+};
diff --git a/debian/tests/node_modules/utest/lib/Collection.js b/debian/tests/node_modules/utest/lib/Collection.js
new file mode 100644
index 0000000..385bc89
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/Collection.js
@@ -0,0 +1,54 @@
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+module.exports = Collection;
+util.inherits(Collection, EventEmitter);
+function Collection(options) {
+ this._pass = 0;
+ this._fail = 0;
+ this._skip = 0;
+ this._testCases = [];
+ this._onlyRunSelectedTests = false;
+}
+
+Collection.prototype.add = function(testCase) {
+ this._testCases.push(testCase);
+ if (testCase.hasSelectedTests()) this._onlyRunSelectedTests = true;
+};
+
+Collection.prototype.run = function() {
+ this._start = this._start || Date.now();
+ for (var i = 0; i < this._testCases.length; i++) {
+ var testCase = this._testCases[i];
+ this._runTestCase(testCase);
+ }
+ this.emit('complete', this.stats());
+};
+
+Collection.prototype._runTestCase = function(testCase) {
+ this.emit('run', testCase);
+ var self = this;
+ testCase
+ .on('pass', function(name) {
+ self._pass++;
+ self.emit('pass', testCase, name);
+ })
+ .on('fail', function(name, err) {
+ self._fail++;
+ self.emit('fail', testCase, name, err);
+ })
+ .on('skip', function(name, err) {
+ self._skip++;
+ self.emit('skip', testCase, name);
+ })
+ .run(this._onlyRunSelectedTests);
+};
+
+Collection.prototype.stats = function() {
+ return {
+ pass : this._pass,
+ fail : this._fail,
+ skip : this._skip,
+ duration : Date.now() - this._start,
+ };
+};
diff --git a/debian/tests/node_modules/utest/lib/TestCase.js b/debian/tests/node_modules/utest/lib/TestCase.js
new file mode 100644
index 0000000..1cbe1aa
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/TestCase.js
@@ -0,0 +1,61 @@
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var doNothing = function() {};
+
+module.exports = TestCase;
+util.inherits(TestCase, EventEmitter);
+function TestCase(properties) {
+ this.name = properties.name;
+ this._tests = properties.tests;
+}
+
+TestCase.prototype.run = function(onlyRunSelectedTests) {
+ var before = this._tests.before || doNothing;
+ var after = this._tests.after || doNothing;
+
+ for (var test in this._tests) {
+ if (test === 'before' || test === 'after') continue;
+
+ if (onlyRunSelectedTests && !this._isSelected(test)) {
+ this.emit('skip', test);
+ continue;
+ }
+
+ var fn = this._tests[test];
+ var context = {};
+ var err = null;
+
+ try {
+ before.call(context);
+ fn.call(context);
+ } catch (_err) {
+ err = _err;
+ } finally {
+ try {
+ after.call(context);
+ } catch (_err) {
+ if (!err) {
+ err = _err;
+ }
+ }
+ }
+
+ if (!err) {
+ this.emit('pass', test);
+ } else {
+ this.emit('fail', test, err);
+ }
+ }
+};
+
+TestCase.prototype.hasSelectedTests = function() {
+ for (var test in this._tests) {
+ if (this._isSelected(test)) return true;
+ }
+
+ return false;
+};
+
+TestCase.prototype._isSelected = function(test) {
+ return test.substr(0, 1) === '!';
+};
diff --git a/debian/tests/node_modules/utest/lib/reporter/BashReporter.js b/debian/tests/node_modules/utest/lib/reporter/BashReporter.js
new file mode 100644
index 0000000..b1a1237
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/reporter/BashReporter.js
@@ -0,0 +1,34 @@
+var Util = require('util');
+
+module.exports = BashReporter;
+function BashReporter(options) {
+ this._process = options.process || process;
+ this._collection = options.collection;
+
+ this._collection.on('fail', this._handleFail.bind(this));
+ this._collection.on('complete', this._handleComplete.bind(this));
+}
+
+BashReporter.prototype._handleFail = function(testCase, test, error) {
+ this._process.stdout.write('Failed: ' + testCase.name + ' ' + test + '\n\n');
+ var stack = (error.stack)
+ ? error.stack
+ : 'Exception without stack: ' + Util.inspect(error);
+
+ stack = stack.replace(/^/gm, ' ');
+ this._process.stdout.write(stack + '\n\n');
+};
+
+BashReporter.prototype._handleComplete = function(stats) {
+ var output =
+ stats.fail + ' fail | ' +
+ stats.pass + ' pass | ' +
+ stats.duration + ' ms ' +
+ '\n';
+
+ if (stats.skip) {
+ output = stats.skip + ' SKIPPED | ' + output;
+ }
+
+ this._process.stdout.write(output);
+};
diff --git a/debian/tests/node_modules/utest/lib/reporter/ConsoleReporter.js b/debian/tests/node_modules/utest/lib/reporter/ConsoleReporter.js
new file mode 100644
index 0000000..a67e54c
--- /dev/null
+++ b/debian/tests/node_modules/utest/lib/reporter/ConsoleReporter.js
@@ -0,0 +1,34 @@
+var Util = require('util');
+
+module.exports = ConsoleReporter;
+function ConsoleReporter(options) {
+ this._collection = options.collection;
+
+ this._collection.on('run', this._handleRun.bind(this));
+ this._collection.on('fail', this._handleFail.bind(this));
+ this._collection.on('complete', this._handleComplete.bind(this));
+}
+
+ConsoleReporter.prototype._handleRun = function(testCase) {
+ console.log('Running: ' + testCase.name);
+};
+
+ConsoleReporter.prototype._handleFail = function(testCase, test, error) {
+ var msg = 'Failed: ' + testCase.name + ' ' + test;
+ var stack = (error.stack)
+ ? error.stack
+ : 'Exception without stack: ' + Util.inspect(error);
+
+ stack = stack.replace(/^/gm, ' ');
+ console.error(msg + '\n\n' + stack + '\n');
+};
+
+ConsoleReporter.prototype._handleComplete = function(stats) {
+ if (stats.skip) {
+ console.warn(stats.skip + ' SKIPPED');
+ }
+ console.info(stats.fail + ' fail | ' +
+ stats.pass + ' pass | ' +
+ stats.duration + ' ms');
+
+};
diff --git a/debian/tests/node_modules/utest/package.json b/debian/tests/node_modules/utest/package.json
new file mode 100644
index 0000000..e7fd6ab
--- /dev/null
+++ b/debian/tests/node_modules/utest/package.json
@@ -0,0 +1,50 @@
+{
+ "_from": "utest@^0.0.8",
+ "_id": "utest@0.0.8",
+ "_inBundle": false,
+ "_integrity": "sha1-/AlFH+aXuQCNDEMv4NtDnWzzeRQ=",
+ "_location": "/utest",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "utest@^0.0.8",
+ "name": "utest",
+ "escapedName": "utest",
+ "rawSpec": "^0.0.8",
+ "saveSpec": null,
+ "fetchSpec": "^0.0.8"
+ },
+ "_requiredBy": [
+ "#DEV:/"
+ ],
+ "_resolved": "https://registry.npmjs.org/utest/-/utest-0.0.8.tgz",
+ "_shasum": "fc09451fe697b9008d0c432fe0db439d6cf37914",
+ "_spec": "utest@^0.0.8",
+ "_where": "/home/xavier/dev/debian/packages/node-formidable",
+ "author": {
+ "name": "Felix Geisendörfer",
+ "email": "felix@debuggable.com",
+ "url": "http://debuggable.com/"
+ },
+ "browser": "./browser.js",
+ "bundleDependencies": false,
+ "dependencies": {},
+ "deprecated": false,
+ "description": "The minimal unit testing library.",
+ "devDependencies": {},
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "https://github.com/felixge/node-utest",
+ "main": "./index",
+ "name": "utest",
+ "optionalDependencies": {},
+ "repository": {
+ "url": ""
+ },
+ "scripts": {
+ "test": "make test"
+ },
+ "version": "0.0.8"
+}
diff --git a/debian/tests/node_modules/utest/syntax.json b/debian/tests/node_modules/utest/syntax.json
new file mode 100644
index 0000000..b98ee1b
--- /dev/null
+++ b/debian/tests/node_modules/utest/syntax.json
@@ -0,0 +1,5 @@
+{
+ "addSemicolons": true,
+ "trimWhitespace": true,
+ "quotes": "'"
+}
diff --git a/debian/tests/pkg-js/files b/debian/tests/pkg-js/files
new file mode 100644
index 0000000..af03f72
--- /dev/null
+++ b/debian/tests/pkg-js/files
@@ -0,0 +1,2 @@
+debian/tests/node_modules
+test
diff --git a/debian/tests/pkg-js/test b/debian/tests/pkg-js/test
new file mode 100644
index 0000000..b104878
--- /dev/null
+++ b/debian/tests/pkg-js/test
@@ -0,0 +1 @@
+NODE_PATH=debian/tests/node_modules node test/run.js
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..28cff30
--- /dev/null
+++ b/debian/upstream/metadata
@@ -0,0 +1,7 @@
+---
+Archive: GitHub
+Bug-Database: https://github.com/felixge/node-formidable/issues
+Contact: https://github.com/felixge/node-formidable/issues
+Name: node-formidable
+Repository: https://github.com/felixge/node-formidable.git
+Repository-Browse: https://github.com/felixge/node-formidable
diff --git a/debian/watch b/debian/watch
index c125df3..fe59010 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,3 +1,5 @@
-version=3
-https://alioth.debian.org/~dapal/npmjs.php?id=formidable \
- http://registry.npmjs.org/formidable/-/formidable-(\d+.*)\.tgz
+version=4
+opts=\
+dversionmangle=auto,\
+filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/node-formidable-$1.tar.gz/ \
+ https://github.com/felixge/node-formidable/releases .*/archive/v?([\d\.]+).tar.gz
diff --git a/example/json.js b/example/json.js
index eb8a724..0ef5a42 100644
--- a/example/json.js
+++ b/example/json.js
@@ -8,8 +8,8 @@ var common = require('../test/common'),
server = http.createServer(function(req, res) {
if (req.method !== 'POST') {
- res.writeHead(200, {'content-type': 'text/plain'})
- res.end('Please POST a JSON payload to http://localhost:'+port+'/')
+ res.writeHead(200, {'content-type': 'text/plain'});
+ res.end('Please POST a JSON payload to http://localhost:'+port+'/');
return;
}
@@ -50,18 +50,18 @@ var request = http.request({
console.log('Status:', response.statusCode);
response.pipe(process.stdout);
response.on('end', function() {
- console.log('\n')
+ console.log('\n');
process.exit();
});
// response.on('data', function(chunk) {
// data += chunk.toString('utf8');
// });
// response.on('end', function() {
- // console.log('Response Data:')
+ // console.log('Response Data:');
// console.log(data);
// process.exit();
// });
-})
+});
request.write('{"numbers":[1,2,3,4,5],"nested":{"key":"value"}}');
request.end();
diff --git a/example/post.js b/example/post.js
index f6c15a6..8458fbd 100644
--- a/example/post.js
+++ b/example/post.js
@@ -1,7 +1,8 @@
-require('../test/common');
+var common = require('../test/common');
var http = require('http'),
util = require('util'),
- formidable = require('formidable'),
+ formidable = common.formidable,
+ port = common.port,
server;
server = http.createServer(function(req, res) {
@@ -38,6 +39,6 @@ server = http.createServer(function(req, res) {
res.end('404');
}
});
-server.listen(TEST_PORT);
+server.listen(port);
-console.log('listening on http://localhost:'+TEST_PORT+'/');
+console.log('listening on http://localhost:'+port+'/');
diff --git a/example/upload.js b/example/upload.js
index 050cdd9..0b498d6 100644
--- a/example/upload.js
+++ b/example/upload.js
@@ -1,7 +1,9 @@
-require('../test/common');
+var common = require('../test/common');
var http = require('http'),
util = require('util'),
- formidable = require('formidable'),
+ os = require('os'),
+ formidable = common.formidable,
+ port = common.port,
server;
server = http.createServer(function(req, res) {
@@ -19,7 +21,7 @@ server = http.createServer(function(req, res) {
files = [],
fields = [];
- form.uploadDir = TEST_TMP;
+ form.uploadDir = os.tmpdir();
form
.on('field', function(field, value) {
@@ -43,6 +45,6 @@ server = http.createServer(function(req, res) {
res.end('404');
}
});
-server.listen(TEST_PORT);
+server.listen(port);
-console.log('listening on http://localhost:'+TEST_PORT+'/');
+console.log('listening on http://localhost:'+port+'/');
diff --git a/lib/file.js b/lib/file.js
index 1e7184d..50d34c0 100644
--- a/lib/file.js
+++ b/lib/file.js
@@ -1,7 +1,7 @@
if (global.GENTLY) require = GENTLY.hijack(require);
var util = require('util'),
- WriteStream = require('fs').WriteStream,
+ fs = require('fs'),
EventEmitter = require('events').EventEmitter,
crypto = require('crypto');
@@ -23,17 +23,19 @@ function File(properties) {
if(typeof this.hash === 'string') {
this.hash = crypto.createHash(properties.hash);
+ } else {
+ this.hash = null;
}
}
module.exports = File;
util.inherits(File, EventEmitter);
File.prototype.open = function() {
- this._writeStream = new WriteStream(this.path);
+ this._writeStream = new fs.WriteStream(this.path);
};
File.prototype.toJSON = function() {
- return {
+ var json = {
size: this.size,
path: this.path,
name: this.name,
@@ -43,16 +45,23 @@ File.prototype.toJSON = function() {
filename: this.filename,
mime: this.mime
};
+ if (this.hash && this.hash != "") {
+ json.hash = this.hash;
+ }
+ return json;
};
File.prototype.write = function(buffer, cb) {
var self = this;
+ if (self.hash) {
+ self.hash.update(buffer);
+ }
+
+ if (this._writeStream.closed) {
+ return cb();
+ }
+
this._writeStream.write(buffer, function() {
- if (self.hash) {
- if (self.hash.hasOwnProperty('update')) {
- self.hash.update(buffer);
- }
- }
self.lastModifiedDate = new Date();
self.size += buffer.length;
self.emit('progress', self.size);
@@ -62,10 +71,10 @@ File.prototype.write = function(buffer, cb) {
File.prototype.end = function(cb) {
var self = this;
+ if (self.hash) {
+ self.hash = self.hash.digest('hex');
+ }
this._writeStream.end(function() {
- if(self.hash) {
- self.hash = self.hash.digest('hex');
- }
self.emit('end');
cb();
});
diff --git a/lib/incoming_form.js b/lib/incoming_form.js
index 291236d..dbd920b 100644
--- a/lib/incoming_form.js
+++ b/lib/incoming_form.js
@@ -1,5 +1,6 @@
if (global.GENTLY) require = GENTLY.hijack(require);
+var crypto = require('crypto');
var fs = require('fs');
var util = require('util'),
path = require('path'),
@@ -23,13 +24,15 @@ function IncomingForm(opts) {
this.ended = false;
this.maxFields = opts.maxFields || 1000;
- this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024;
+ this.maxFieldsSize = opts.maxFieldsSize || 20 * 1024 * 1024;
+ this.maxFileSize = opts.maxFileSize || 200 * 1024 * 1024;
this.keepExtensions = opts.keepExtensions || false;
- this.uploadDir = opts.uploadDir || os.tmpDir();
+ this.uploadDir = opts.uploadDir || (os.tmpdir && os.tmpdir()) || os.tmpDir();
this.encoding = opts.encoding || 'utf-8';
this.headers = null;
this.type = null;
- this.hash = false;
+ this.hash = opts.hash || false;
+ this.multiples = opts.multiples || false;
this.bytesReceived = null;
this.bytesExpected = null;
@@ -37,10 +40,11 @@ function IncomingForm(opts) {
this._parser = null;
this._flushing = 0;
this._fieldsSize = 0;
+ this._fileSize = 0;
this.openedFiles = [];
return this;
-};
+}
util.inherits(IncomingForm, EventEmitter);
exports.IncomingForm = IncomingForm;
@@ -74,6 +78,40 @@ IncomingForm.prototype.parse = function(req, cb) {
return true;
};
+ // Setup callback first, so we don't miss anything from data events emitted
+ // immediately.
+ if (cb) {
+ var fields = {}, files = {};
+ this
+ .on('field', function(name, value) {
+ fields[name] = value;
+ })
+ .on('file', function(name, file) {
+ if (this.multiples) {
+ if (files[name]) {
+ if (!Array.isArray(files[name])) {
+ files[name] = [files[name]];
+ }
+ files[name].push(file);
+ } else {
+ files[name] = file;
+ }
+ } else {
+ files[name] = file;
+ }
+ })
+ .on('error', function(err) {
+ cb(err, fields, files);
+ })
+ .on('end', function() {
+ cb(null, fields, files);
+ });
+ }
+
+ // Parse headers and setup the parser, ready to start listening for data.
+ this.writeHeaders(req.headers);
+
+ // Start listening for data.
var self = this;
req
.on('error', function(err) {
@@ -97,25 +135,6 @@ IncomingForm.prototype.parse = function(req, cb) {
}
});
- if (cb) {
- var fields = {}, files = {};
- this
- .on('field', function(name, value) {
- fields[name] = value;
- })
- .on('file', function(name, file) {
- files[name] = file;
- })
- .on('error', function(err) {
- cb(err, fields, files);
- })
- .on('end', function() {
- cb(null, fields, files);
- });
- }
-
- this.writeHeaders(req.headers);
-
return this;
};
@@ -126,8 +145,11 @@ IncomingForm.prototype.writeHeaders = function(headers) {
};
IncomingForm.prototype.write = function(buffer) {
+ if (this.error) {
+ return;
+ }
if (!this._parser) {
- this._error(new Error('unintialized parser'));
+ this._error(new Error('uninitialized parser'));
return;
}
@@ -160,6 +182,7 @@ IncomingForm.prototype.onPart = function(part) {
IncomingForm.prototype.handlePart = function(part) {
var self = this;
+ // This MUST check exactly for undefined. You can not change it to !part.filename.
if (part.filename === undefined) {
var value = ''
, decoder = new StringDecoder(this.encoding);
@@ -194,6 +217,14 @@ IncomingForm.prototype.handlePart = function(part) {
this.openedFiles.push(file);
part.on('data', function(buffer) {
+ self._fileSize += buffer.length;
+ if (self._fileSize > self.maxFileSize) {
+ self._error(new Error('maxFileSize exceeded, received '+self._fileSize+' bytes of file data'));
+ return;
+ }
+ if (buffer.length == 0) {
+ return;
+ }
self.pause();
file.write(buffer, function() {
self.resume();
@@ -241,8 +272,8 @@ IncomingForm.prototype._parseContentType = function() {
}
if (this.headers['content-type'].match(/multipart/i)) {
- var m;
- if (m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i)) {
+ var m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i);
+ if (m) {
this._initMultipart(m[1] || m[2]);
} else {
this._error(new Error('bad content-type header, no multipart boundary'));
@@ -264,21 +295,25 @@ IncomingForm.prototype._error = function(err) {
}
this.error = err;
- this.pause();
this.emit('error', err);
if (Array.isArray(this.openedFiles)) {
this.openedFiles.forEach(function(file) {
file._writeStream.destroy();
- setTimeout(fs.unlink, 0, file.path);
+ setTimeout(fs.unlink, 0, file.path, function(error) { });
});
}
};
IncomingForm.prototype._parseContentLength = function() {
+ this.bytesReceived = 0;
if (this.headers['content-length']) {
- this.bytesReceived = 0;
this.bytesExpected = parseInt(this.headers['content-length'], 10);
+ } else if (this.headers['transfer-encoding'] === undefined) {
+ this.bytesExpected = 0;
+ }
+
+ if (this.bytesExpected !== null) {
this.emit('progress', this.bytesReceived, this.bytesExpected);
}
};
@@ -325,10 +360,11 @@ IncomingForm.prototype._initMultipart = function(boundary) {
headerField = headerField.toLowerCase();
part.headers[headerField] = headerValue;
- var m;
+ // matches either a quoted-string or a token (RFC 2616 section 19.5.1)
+ var m = headerValue.match(/\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i);
if (headerField == 'content-disposition') {
- if (m = headerValue.match(/\bname="([^"]+)"/i)) {
- part.name = m[1];
+ if (m) {
+ part.name = m[2] || m[3] || '';
}
part.filename = self._fileName(headerValue);
@@ -366,13 +402,13 @@ IncomingForm.prototype._initMultipart = function(boundary) {
can be divided by 4, it will result in a number of buytes that
can be divided vy 3.
*/
- var offset = parseInt(part.transferBuffer.length / 4) * 4;
- part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64'))
+ var offset = parseInt(part.transferBuffer.length / 4, 10) * 4;
+ part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64'));
part.transferBuffer = part.transferBuffer.substring(offset);
};
parser.onPartEnd = function() {
- part.emit('data', new Buffer(part.transferBuffer, 'base64'))
+ part.emit('data', new Buffer(part.transferBuffer, 'base64'));
part.emit('end');
};
break;
@@ -394,10 +430,12 @@ IncomingForm.prototype._initMultipart = function(boundary) {
};
IncomingForm.prototype._fileName = function(headerValue) {
- var m = headerValue.match(/\bfilename="(.*?)"($|; )/i);
+ // matches either a quoted-string or a token (RFC 2616 section 19.5.1)
+ var m = headerValue.match(/\bfilename=("(.*?)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))($|;\s)/i);
if (!m) return;
- var filename = m[1].substr(m[1].lastIndexOf('\\') + 1);
+ var match = m[2] || m[3] || '';
+ var filename = match.substr(match.lastIndexOf('\\') + 1);
filename = filename.replace(/%22/g, '"');
filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
return String.fromCharCode(code);
@@ -434,10 +472,9 @@ IncomingForm.prototype._initOctetStream = function() {
type: mime
});
- file.open();
-
this.emit('fileBegin', filename, file);
-
+ file.open();
+ this.openedFiles.push(file);
this._flushing++;
var self = this;
@@ -466,8 +503,10 @@ IncomingForm.prototype._initOctetStream = function() {
self.ended = true;
var done = function(){
- self.emit('file', 'file', file);
- self._maybeEnd();
+ file.end(function() {
+ self.emit('file', 'file', file);
+ self._maybeEnd();
+ });
};
if(outstandingWrites === 0){
@@ -481,16 +520,12 @@ IncomingForm.prototype._initOctetStream = function() {
IncomingForm.prototype._initJSONencoded = function() {
this.type = 'json';
- var parser = new JSONParser()
+ var parser = new JSONParser(this)
, self = this;
- if (this.bytesExpected) {
- parser.initWithLength(this.bytesExpected);
- }
-
parser.onField = function(key, val) {
self.emit('field', key, val);
- }
+ };
parser.onEnd = function() {
self.ended = true;
@@ -501,14 +536,12 @@ IncomingForm.prototype._initJSONencoded = function() {
};
IncomingForm.prototype._uploadPath = function(filename) {
- var name = '';
- for (var i = 0; i < 32; i++) {
- name += Math.floor(Math.random() * 16).toString(16);
- }
+ var buf = crypto.randomBytes(16);
+ var name = 'upload_' + buf.toString('hex');
if (this.keepExtensions) {
var ext = path.extname(filename);
- ext = ext.replace(/(\.[a-z0-9]+).*/, '$1');
+ ext = ext.replace(/(\.[a-z0-9]+).*/i, '$1');
name += ext;
}
@@ -523,4 +556,3 @@ IncomingForm.prototype._maybeEnd = function() {
this.emit('end');
};
-
diff --git a/lib/json_parser.js b/lib/json_parser.js
index 6ce966b..28a23ba 100644
--- a/lib/json_parser.js
+++ b/lib/json_parser.js
@@ -1,35 +1,30 @@
if (global.GENTLY) require = GENTLY.hijack(require);
-var Buffer = require('buffer').Buffer
+var Buffer = require('buffer').Buffer;
-function JSONParser() {
- this.data = new Buffer('');
+function JSONParser(parent) {
+ this.parent = parent;
+ this.chunks = [];
this.bytesWritten = 0;
-};
-exports.JSONParser = JSONParser;
-
-JSONParser.prototype.initWithLength = function(length) {
- this.data = new Buffer(length);
}
+exports.JSONParser = JSONParser;
JSONParser.prototype.write = function(buffer) {
- if (this.data.length >= this.bytesWritten + buffer.length) {
- buffer.copy(this.data, this.bytesWritten);
- } else {
- this.data = Buffer.concat([this.data, buffer]);
- }
this.bytesWritten += buffer.length;
+ this.chunks.push(buffer);
return buffer.length;
-}
+};
JSONParser.prototype.end = function() {
try {
- var fields = JSON.parse(this.data.toString('utf8'))
+ var fields = JSON.parse(Buffer.concat(this.chunks));
for (var field in fields) {
this.onField(field, fields[field]);
}
- } catch (e) {}
+ } catch (e) {
+ this.parent.emit('error', e);
+ }
this.data = null;
this.onEnd();
-}
\ No newline at end of file
+};
diff --git a/lib/multipart_parser.js b/lib/multipart_parser.js
index 98a6856..36de2b0 100644
--- a/lib/multipart_parser.js
+++ b/lib/multipart_parser.js
@@ -46,7 +46,7 @@ function MultipartParser() {
this.index = null;
this.flags = 0;
-};
+}
exports.MultipartParser = MultipartParser;
MultipartParser.stateToString = function(stateNumber) {
@@ -58,8 +58,8 @@ MultipartParser.stateToString = function(stateNumber) {
MultipartParser.prototype.initWithBoundary = function(str) {
this.boundary = new Buffer(str.length+4);
- this.boundary.write('\r\n--', 'ascii', 0);
- this.boundary.write(str, 'ascii', 4);
+ this.boundary.write('\r\n--', 0);
+ this.boundary.write(str, 4);
this.lookbehind = new Buffer(this.boundary.length+8);
this.state = S.START;
@@ -127,18 +127,25 @@ MultipartParser.prototype.write = function(buffer) {
state = S.START_BOUNDARY;
case S.START_BOUNDARY:
if (index == boundary.length - 2) {
- if (c != CR) {
+ if (c == HYPHEN) {
+ flags |= F.LAST_BOUNDARY;
+ } else if (c != CR) {
return i;
}
index++;
break;
} else if (index - 1 == boundary.length - 2) {
- if (c != LF) {
+ if (flags & F.LAST_BOUNDARY && c == HYPHEN){
+ callback('end');
+ state = S.END;
+ flags = 0;
+ } else if (!(flags & F.LAST_BOUNDARY) && c == LF) {
+ index = 0;
+ callback('partBegin');
+ state = S.HEADER_FIELD_START;
+ } else {
return i;
}
- index = 0;
- callback('partBegin');
- state = S.HEADER_FIELD_START;
break;
}
@@ -214,7 +221,7 @@ MultipartParser.prototype.write = function(buffer) {
case S.PART_DATA:
prevIndex = index;
- if (index == 0) {
+ if (index === 0) {
// boyer-moore derrived algorithm to safely skip non-boundary data
i += boundaryEnd;
while (i < bufferLength && !(buffer[i] in boundaryChars)) {
@@ -226,7 +233,7 @@ MultipartParser.prototype.write = function(buffer) {
if (index < boundary.length) {
if (boundary[index] == c) {
- if (index == 0) {
+ if (index === 0) {
dataCallback('partData', true);
}
index++;
@@ -260,6 +267,7 @@ MultipartParser.prototype.write = function(buffer) {
callback('partEnd');
callback('end');
state = S.END;
+ flags = 0;
} else {
index = 0;
}
@@ -310,7 +318,7 @@ MultipartParser.prototype.end = function() {
self[callbackSymbol]();
}
};
- if ((this.state == S.HEADER_FIELD_START && this.index == 0) ||
+ if ((this.state == S.HEADER_FIELD_START && this.index === 0) ||
(this.state == S.PART_DATA && this.index == this.boundary.length)) {
callback(this, 'partEnd');
callback(this, 'end');
diff --git a/lib/querystring_parser.js b/lib/querystring_parser.js
index 320ce5a..fcaffe0 100644
--- a/lib/querystring_parser.js
+++ b/lib/querystring_parser.js
@@ -7,7 +7,7 @@ var querystring = require('querystring');
function QuerystringParser(maxKeys) {
this.maxKeys = maxKeys;
this.buffer = '';
-};
+}
exports.QuerystringParser = QuerystringParser;
QuerystringParser.prototype.write = function(buffer) {
diff --git a/package.json b/package.json
index 4b42a1d..bf07c37 100644
--- a/package.json
+++ b/package.json
@@ -2,14 +2,15 @@
"name": "formidable",
"description": "A node.js module for parsing form data, especially file uploads.",
"homepage": "https://github.com/felixge/node-formidable",
- "version": "1.0.13",
+ "license": "MIT",
+ "version": "1.2.1",
"devDependencies": {
- "gently": "0.8.0",
- "findit": "0.1.1",
- "hashish": "0.0.4",
- "urun": "~0.0.6",
- "utest": "0.0.3",
- "request": "~2.11.4"
+ "gently": "^0.8.0",
+ "findit": "^0.1.2",
+ "hashish": "^0.0.4",
+ "urun": "^0.0.6",
+ "utest": "^0.0.8",
+ "request": "^2.11.4"
},
"directories": {
"lib": "./lib"
@@ -19,9 +20,6 @@
"test": "node test/run.js",
"clean": "rm test/tmp/*"
},
- "engines": {
- "node": "<0.9.0"
- },
"repository": {
"type": "git",
"url": "git://github.com/felixge/node-formidable.git"
diff --git a/test/fixture/http/encoding/beta-sticker-1.png.http b/test/fixture/http/encoding/beta-sticker-1.png.http
new file mode 100644
index 0000000..833b83c
--- /dev/null
+++ b/test/fixture/http/encoding/beta-sticker-1.png.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 2483
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="sticker"; filename="beta-sticker-1.png"
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+
+iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABh5JREFUeNrMmHtIHEcYwGfv5SNwaovxEanEiJKqlYCCTRo1f0SvDeof1legEcE/YttQaNOiaQjYFFtpKaJILZU8SCRUWqlJGpoWepGLTXqUEnzFxCrnK9DEelbvvPOe/WacuY7r7HmGFjrwsbNzt7u//V7zfYvQ/2xI/9K1/NyvMP9PgCTuGmmL6/0ckD9UOGmbIExUsqMkAPHJjv5QwKRtgKioqDlh5+w/7IFeCuLlxCeA2zQ0IcCwh2qoaLH09fUdTElJ2e/1elU+n0/y+9fvPz4+fvfYsWN3YOoBcXPiocLghD4mBYHhQTCErqWlZU9FRcXJqKiowyqVSk/uSEH4o8fjWVlYWDB2d3e3d3R0WGB5jYqLg/NyGgsKxMNgkDB4451NTU3vxcXF1SlBKB0tFsuVxsbGjlu3bj2GJQeIk8K5RVBqBTMxrYRfuHAh9/jx4+ejo6MPS9I6f6hHPOC6rOLi4vyVlZXf7t27Z5c5/iZfkgMxxyUwFy9ezC0tLe3V6XRJ/MOCAYjWwsLCni0oKCh98uSJaWhoyMZFn0/uT2qBqYi/1NbWxjc0NJwPFUYExc/B53R5eXk5ZrN5YH5+3slFn5+D2uBDzG90IJETExOtzGdC9RelNf78wYMH3xQWFn4Ep0sgyyCr1NmJP6kEIa5tbW3dEx8fXxeKRoJpT76OR3p6enllZWUKTCOwNalFAglWDkTCvLq6+uR2YYKZSw4GQVKNfZQCafjkqhKYTBsTE3NY/uYi2Q4MP5KTkw9QGB3VEMv6G/YioqFLly5lazQavfytxobnUW+PWTGisIyNPEL3QYLB4PPIyMi4EydO7JUBbTIZ0RDYOFPkE8t/OdHczCK6Y/qdzP8BfUTW8Tj/uQndvT1F5vOzVvTLz1PwX4cQbt++fekURsNpSNLIw16v1z/HLsRRgecsSnovm8nxs5bvUe+NN1Bz47fkfBaAXj2aA2BWEsM/3hhFX1/5Fe3NTEAfvn8NXTO+tSH68IiNjU2Qw/AmCzg2XCQp+YyhJAu9c+pl9GJ+KmhiEt38bhjpoyJQRtYudA60k3dwD6o4mouKjmSiolcy0ArRqnXz3rT+knwFEShhNKLNlmmFP7Kf8XxuehHpj0QQmLdPGch/ioYyCSAe57pMaHnJgcprctDdwUkRjKi8CUTWhipvbm7uvlJo3zFNoHJDOznPeGEXqn+9EBUf+AQZXvqU+BEG/KCpHz2flYh+ALO9++ZX5L/Mj3gfevjw4ZRoP+PzD/b4HadPn844c+aMkb0F1DqIz9byzBvquXytvr6+7vr16+Ow9CfN2njjdfFAWpo9o2FnNmm12kQMw24gcvSnhbHb7Y+huHsNlhapLNHSxK3idlq287qhhrkKlSByOBzIZrPhGyCn04ncbjfRGAMV5ZlQxvDw8E+yYi1Q3qpleYjUQlNTU5aysrJqgNBhIAwGVSDCkFj48BVFULA1eCl7XV3dx1CKYK3YqKnY7u9Ti2royclJ76FDh1YhxefgsoFpCIOtra0RuGBQwYbRaLzc1dVlpjA2ZiqmKbWsDAmEYU9Pz8Tg4OCNoqKixNTU1BQostDq6iqBcrlcRBiYfEff1KBR+OnpabPBYOikWlnhtOOWm0zUffpnZ2ednZ2dJtCYMTs7+xkA2x0eHk6gsMYwFPYr/EC1Wo2LMEWzWa1WC1QRZ8FUVgpj42ohD3umWqHjRFxf5RkZGVkCNQ9CcTWQn5+flpSUtBOiMKAt7Fek/FSAmpmZMVdVVZ0dGxv7g4PhteMVlbBIofv0sh4Lbmhtb2+/Cbv1eFpaWmJCQsJODMO0hGGgUghAAay9v7//i5KSki9lmmG+4+Jg/MHaIH6f0dCkqaNFFc5VkViam5v319TUNEDdvRubEGsNYHGqsAwMDFxta2u7DdpdpA+3c+LgWiHfVkCiFnpDw0iLqwgqO6BVKoPo00K6WIDsOzE6OrpE395FzeLgxMn5jVe0dYTa26s5jfFg4VR0nAuwNtrFda1rgmToD6VzVWq3eTPyYAxOwwH5gvT2PiWY7X4fUgJTywp1fivyyL6E+Lb6XvQ0X9AkBeeXZED+p/k+9LcAAwAXm3hBLzoZPAAAAABJRU5ErkJggg==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/binaryfile.tar.gz.http b/test/fixture/http/encoding/binaryfile.tar.gz.http
new file mode 100644
index 0000000..4f4fadb
--- /dev/null
+++ b/test/fixture/http/encoding/binaryfile.tar.gz.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 676
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="file"; filename="binaryfile.tar.gz"
+Content-Type: application/x-gzip
+Content-Transfer-Encoding: base64
+
+H4sIAGiNIU8AA+3R0W6CMBQGYK59iobLZantRDG73osUOGqnFNJWM2N897UghG1ZdmWWLf93U/jP4bRAq8q92hJ/dY1J7kQEqyyLq8yXYrp2ltkqkTKXYiEykYc++ZTLVcLEvQ40dXReWcYSV1pdnL/v+6n+R11mjKVG1ZQ+s3TT2FpXqjhQ+hjzE1mnGxNLkgu+7tOKWjIVmVKTC6XL9ZaeXj4VQhwKWzL+cI4zwgQuuhkh3mhTad/Hkssh3im3027X54JnQ360R/M19OT8kC7SEN7Ooi2VvrEfznHQRWzl83gxttZKmzGehzPRW/+W8X+3fvL8sFet9sS6m3EIma02071MU3Uf9KHrmV1/+y8DAAAAAAAAAAAAAAAAAAAAAMB/9A6txIuJACgAAA==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/blank.gif.http b/test/fixture/http/encoding/blank.gif.http
new file mode 100644
index 0000000..7426f5b
--- /dev/null
+++ b/test/fixture/http/encoding/blank.gif.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 323
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="file"; filename="blank.gif"
+Content-Type: image/gif
+Content-Transfer-Encoding: base64
+
+R0lGODlhAQABAJH/AP///wAAAMDAwAAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/menu_seperator.png.http b/test/fixture/http/encoding/menu_seperator.png.http
new file mode 100644
index 0000000..d08fd37
--- /dev/null
+++ b/test/fixture/http/encoding/menu_seperator.png.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Length: 1509
+
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
+Content-Disposition: form-data; name="image"; filename="menu_separator.png"
+Content-Type: image/png
+Content-Transfer-Encoding: base64
+
+iVBORw0KGgoAAAANSUhEUgAAAAIAAAAYCAIAAABfmbuOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDcxODNBNzJERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDcxODNBNzNERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNzE4M0E3MERENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNzE4M0E3MURENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pmvhbb8AAAAXSURBVHjaYnHk9PON8WJiAIPBSwEEGAAPrgG+VozFWgAAAABJRU5ErkJggg==
+--\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/--
diff --git a/test/fixture/http/encoding/plain.txt.http b/test/fixture/http/encoding/plain.txt.http
new file mode 100644
index 0000000..5e85ad6
--- /dev/null
+++ b/test/fixture/http/encoding/plain.txt.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 221
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="file"; filename="plain.txt"
+Content-Type: text/plain
+Content-Transfer-Encoding: 7bit
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/misc/empty-multipart.http b/test/fixture/http/misc/empty-multipart.http
new file mode 100644
index 0000000..81c6125
--- /dev/null
+++ b/test/fixture/http/misc/empty-multipart.http
@@ -0,0 +1,5 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 0
+
diff --git a/test/fixture/http/misc/empty-multipart2.http b/test/fixture/http/misc/empty-multipart2.http
new file mode 100644
index 0000000..eda6528
--- /dev/null
+++ b/test/fixture/http/misc/empty-multipart2.http
@@ -0,0 +1,6 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 31
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/misc/empty-urlencoded.http b/test/fixture/http/misc/empty-urlencoded.http
new file mode 100644
index 0000000..bb197d3
--- /dev/null
+++ b/test/fixture/http/misc/empty-urlencoded.http
@@ -0,0 +1,5 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Length: 0
+Content-Type: application/x-www-form-urlencoded
+
diff --git a/test/fixture/http/misc/empty.http b/test/fixture/http/misc/empty.http
new file mode 100644
index 0000000..4c4cee5
--- /dev/null
+++ b/test/fixture/http/misc/empty.http
@@ -0,0 +1,4 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Length: 0
+
diff --git a/test/fixture/http/misc/minimal.http b/test/fixture/http/misc/minimal.http
new file mode 100644
index 0000000..594cdd3
--- /dev/null
+++ b/test/fixture/http/misc/minimal.http
@@ -0,0 +1,3 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+
diff --git a/test/fixture/http/no-filename/filename-name.http b/test/fixture/http/no-filename/filename-name.http
new file mode 100644
index 0000000..43672a3
--- /dev/null
+++ b/test/fixture/http/no-filename/filename-name.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Length: 1000
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; filename="plain.txt"; name="upload"
+Content-Type: text/plain
+
+I am a plain text file
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG--
+
diff --git a/test/fixture/http/no-filename/generic.http b/test/fixture/http/no-filename/generic.http
new file mode 100644
index 0000000..e0dee27
--- /dev/null
+++ b/test/fixture/http/no-filename/generic.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Length: 1000
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; name="upload"; filename=""
+Content-Type: text/plain
+
+I am a plain text file
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG--
+
diff --git a/test/fixture/http/preamble/crlf.http b/test/fixture/http/preamble/crlf.http
new file mode 100644
index 0000000..1d5f709
--- /dev/null
+++ b/test/fixture/http/preamble/crlf.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 184
+
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/preamble/preamble.http b/test/fixture/http/preamble/preamble.http
new file mode 100644
index 0000000..d14d433
--- /dev/null
+++ b/test/fixture/http/preamble/preamble.http
@@ -0,0 +1,13 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 226
+
+This is a preamble which should be ignored
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ--
diff --git a/test/fixture/http/special-chars-in-filename/osx-chrome-13.http b/test/fixture/http/special-chars-in-filename/osx-chrome-13.http
new file mode 100644
index 0000000..4ef3917
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/osx-chrome-13.http
@@ -0,0 +1,26 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Connection: keep-alive
+Referer: http://localhost:8080/
+Content-Length: 383
+Cache-Control: max-age=0
+Origin: http://localhost:8080
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Encoding: gzip,deflate,sdch
+Accept-Language: en-US,en;q=0.8
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
+Cookie: jqCookieJar_tablesorter=%7B%22showListTable%22%3A%5B%5B5%2C1%5D%2C%5B1%2C0%5D%5D%7D
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG
+Content-Disposition: form-data; name="upload"; filename=": \ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+I am a text file with a funky name!
+
+------WebKitFormBoundarytyE4wkKlZ5CQJVTG--
diff --git a/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http b/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http
new file mode 100644
index 0000000..bf49f85
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http
@@ -0,0 +1,24 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Language: en-us,en;q=0.5
+Accept-Encoding: gzip,deflate
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
+Keep-Alive: 115
+Connection: keep-alive
+Referer: http://localhost:8080/
+Content-Type: multipart/form-data; boundary=---------------------------9849436581144108930470211272
+Content-Length: 438
+
+-----------------------------9849436581144108930470211272
+Content-Disposition: form-data; name="title"
+
+Weird filename
+-----------------------------9849436581144108930470211272
+Content-Disposition: form-data; name="upload"; filename=": \ ? % * | " < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+I am a text file with a funky name!
+
+-----------------------------9849436581144108930470211272--
diff --git a/test/fixture/http/special-chars-in-filename/osx-safari-5.http b/test/fixture/http/special-chars-in-filename/osx-safari-5.http
new file mode 100644
index 0000000..ff158a4
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/osx-safari-5.http
@@ -0,0 +1,23 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Origin: http://localhost:8080
+Content-Length: 383
+User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryQJZ1gvhvdgfisJPJ
+Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
+Referer: http://localhost:8080/
+Accept-Language: en-us
+Accept-Encoding: gzip, deflate
+Connection: keep-alive
+
+------WebKitFormBoundaryQJZ1gvhvdgfisJPJ
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundaryQJZ1gvhvdgfisJPJ
+Content-Disposition: form-data; name="upload"; filename=": \ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+I am a text file with a funky name!
+
+------WebKitFormBoundaryQJZ1gvhvdgfisJPJ--
diff --git a/test/fixture/http/special-chars-in-filename/xp-chrome-12.http b/test/fixture/http/special-chars-in-filename/xp-chrome-12.http
new file mode 100644
index 0000000..f0fc533
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-chrome-12.http
@@ -0,0 +1,24 @@
+POST /upload HTTP/1.1
+Host: 192.168.56.1:8080
+Connection: keep-alive
+Referer: http://192.168.56.1:8080/
+Content-Length: 344
+Cache-Control: max-age=0
+Origin: http://192.168.56.1:8080
+User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryEvqBNplR3ByrwQPa
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+Accept-Encoding: gzip,deflate,sdch
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
+
+------WebKitFormBoundaryEvqBNplR3ByrwQPa
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundaryEvqBNplR3ByrwQPa
+Content-Disposition: form-data; name="upload"; filename=" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+
+------WebKitFormBoundaryEvqBNplR3ByrwQPa--
diff --git a/test/fixture/http/special-chars-in-filename/xp-ie-7.http b/test/fixture/http/special-chars-in-filename/xp-ie-7.http
new file mode 100644
index 0000000..2e2c61c
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-ie-7.http
@@ -0,0 +1,22 @@
+POST /upload HTTP/1.1
+Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*
+Referer: http://192.168.56.1:8080/
+Accept-Language: de
+User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
+Content-Type: multipart/form-data; boundary=---------------------------7db1fe232017c
+Accept-Encoding: gzip, deflate
+Host: 192.168.56.1:8080
+Content-Length: 368
+Connection: Keep-Alive
+Cache-Control: no-cache
+
+-----------------------------7db1fe232017c
+Content-Disposition: form-data; name="title"
+
+Weird filename
+-----------------------------7db1fe232017c
+Content-Disposition: form-data; name="upload"; filename=" ? % * | " < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: application/octet-stream
+
+
+-----------------------------7db1fe232017c--
diff --git a/test/fixture/http/special-chars-in-filename/xp-ie-8.http b/test/fixture/http/special-chars-in-filename/xp-ie-8.http
new file mode 100644
index 0000000..e2b94fa
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-ie-8.http
@@ -0,0 +1,22 @@
+POST /upload HTTP/1.1
+Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*
+Referer: http://192.168.56.1:8080/
+Accept-Language: de
+User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
+Content-Type: multipart/form-data; boundary=---------------------------7db3a8372017c
+Accept-Encoding: gzip, deflate
+Host: 192.168.56.1:8080
+Content-Length: 368
+Connection: Keep-Alive
+Cache-Control: no-cache
+
+-----------------------------7db3a8372017c
+Content-Disposition: form-data; name="title"
+
+Weird filename
+-----------------------------7db3a8372017c
+Content-Disposition: form-data; name="upload"; filename=" ? % * | " < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: application/octet-stream
+
+
+-----------------------------7db3a8372017c--
diff --git a/test/fixture/http/special-chars-in-filename/xp-safari-5.http b/test/fixture/http/special-chars-in-filename/xp-safari-5.http
new file mode 100644
index 0000000..6379ac0
--- /dev/null
+++ b/test/fixture/http/special-chars-in-filename/xp-safari-5.http
@@ -0,0 +1,22 @@
+POST /upload HTTP/1.1
+Host: 192.168.56.1:8080
+Referer: http://192.168.56.1:8080/
+Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
+Accept-Language: en-US
+Origin: http://192.168.56.1:8080
+User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4
+Accept-Encoding: gzip, deflate
+Content-Type: multipart/form-data; boundary=----WebKitFormBoundarykmaWSUbu697WN9TM
+Content-Length: 344
+Connection: keep-alive
+
+------WebKitFormBoundarykmaWSUbu697WN9TM
+Content-Disposition: form-data; name="title"
+
+Weird filename
+------WebKitFormBoundarykmaWSUbu697WN9TM
+Content-Disposition: form-data; name="upload"; filename=" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt"
+Content-Type: text/plain
+
+
+------WebKitFormBoundarykmaWSUbu697WN9TM--
diff --git a/test/fixture/http/workarounds/missing-hyphens1.http b/test/fixture/http/workarounds/missing-hyphens1.http
new file mode 100644
index 0000000..2826890
--- /dev/null
+++ b/test/fixture/http/workarounds/missing-hyphens1.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 178
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ
diff --git a/test/fixture/http/workarounds/missing-hyphens2.http b/test/fixture/http/workarounds/missing-hyphens2.http
new file mode 100644
index 0000000..8e18194
--- /dev/null
+++ b/test/fixture/http/workarounds/missing-hyphens2.http
@@ -0,0 +1,12 @@
+POST /upload HTTP/1.1
+Host: localhost:8080
+Content-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ
+Content-Length: 180
+
+------TLV0SrKD4z1TRxRhAPUvZ
+Content-Disposition: form-data; name="upload"; filename="plain.txt"
+Content-Type: text/plain
+
+I am a plain text file
+
+------TLV0SrKD4z1TRxRhAPUvZ
diff --git a/test/fixture/js/encoding.js b/test/fixture/js/encoding.js
index 83dfb15..fc22026 100644
--- a/test/fixture/js/encoding.js
+++ b/test/fixture/js/encoding.js
@@ -1,19 +1,24 @@
module.exports['menu_seperator.png.http'] = [
- {type: 'file', name: 'image', filename: 'menu_separator.png', fixture: 'menu_separator.png'}
+ {type: 'file', name: 'image', filename: 'menu_separator.png', fixture: 'menu_separator.png',
+ sha1: 'c845ca3ea794be298f2a1b79769b71939eaf4e54'}
];
module.exports['beta-sticker-1.png.http'] = [
- {type: 'file', name: 'sticker', filename: 'beta-sticker-1.png', fixture: 'beta-sticker-1.png'}
+ {type: 'file', name: 'sticker', filename: 'beta-sticker-1.png', fixture: 'beta-sticker-1.png',
+ sha1: '6abbcffd12b4ada5a6a084fe9e4584f846331bc4'}
];
module.exports['blank.gif.http'] = [
- {type: 'file', name: 'file', filename: 'blank.gif', fixture: 'blank.gif'}
+ {type: 'file', name: 'file', filename: 'blank.gif', fixture: 'blank.gif',
+ sha1: 'a1fdee122b95748d81cee426d717c05b5174fe96'}
];
module.exports['binaryfile.tar.gz.http'] = [
- {type: 'file', name: 'file', filename: 'binaryfile.tar.gz', fixture: 'binaryfile.tar.gz'}
+ {type: 'file', name: 'file', filename: 'binaryfile.tar.gz', fixture: 'binaryfile.tar.gz',
+ sha1: 'cfabe13b348e5e69287d677860880c52a69d2155'}
];
module.exports['plain.txt.http'] = [
- {type: 'file', name: 'file', filename: 'plain.txt', fixture: 'plain.txt'}
+ {type: 'file', name: 'file', filename: 'plain.txt', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'}
];
diff --git a/test/fixture/js/misc.js b/test/fixture/js/misc.js
index 3e27472..1ae9fb9 100644
--- a/test/fixture/js/misc.js
+++ b/test/fixture/js/misc.js
@@ -2,4 +2,6 @@ module.exports = {
'empty.http': [],
'empty-urlencoded.http': [],
'empty-multipart.http': [],
+ 'empty-multipart2.http': [],
+ 'minimal.http': [],
};
diff --git a/test/fixture/js/no-filename.js b/test/fixture/js/no-filename.js
index c36e792..f03b4f0 100644
--- a/test/fixture/js/no-filename.js
+++ b/test/fixture/js/no-filename.js
@@ -1,7 +1,9 @@
module.exports['generic.http'] = [
- {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt'},
+ {type: 'file', name: 'upload', filename: '', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
];
module.exports['filename-name.http'] = [
- {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+ {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
];
diff --git a/test/fixture/js/preamble.js b/test/fixture/js/preamble.js
index da569b2..d2e4cfd 100644
--- a/test/fixture/js/preamble.js
+++ b/test/fixture/js/preamble.js
@@ -1,7 +1,9 @@
module.exports['crlf.http'] = [
- {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+ {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
];
module.exports['preamble.http'] = [
- {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+ {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
];
diff --git a/test/fixture/js/special-chars-in-filename.js b/test/fixture/js/special-chars-in-filename.js
index eb76fdc..f5eccda 100644
--- a/test/fixture/js/special-chars-in-filename.js
+++ b/test/fixture/js/special-chars-in-filename.js
@@ -5,7 +5,7 @@ function expect(filename) {
{type: 'field', name: 'title', value: 'Weird filename'},
{type: 'file', name: 'upload', filename: filename, fixture: properFilename},
];
-};
+}
var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
diff --git a/test/fixture/js/workarounds.js b/test/fixture/js/workarounds.js
index d336505..e59c5b2 100644
--- a/test/fixture/js/workarounds.js
+++ b/test/fixture/js/workarounds.js
@@ -1,6 +1,8 @@
module.exports['missing-hyphens1.http'] = [
- {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+ {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
];
module.exports['missing-hyphens2.http'] = [
- {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt'},
+ {type: 'file', name: 'upload', filename: 'plain.txt', fixture: 'plain.txt',
+ sha1: 'b31d07bac24ac32734de88b3687dddb10e976872'},
];
diff --git a/test/fixture/multi_video.upload b/test/fixture/multi_video.upload
new file mode 100644
index 0000000..9c82ba3
Binary files /dev/null and b/test/fixture/multi_video.upload differ
diff --git a/test/fixture/multipart.js b/test/fixture/multipart.js
index a476169..aa354e7 100644
--- a/test/fixture/multipart.js
+++ b/test/fixture/multipart.js
@@ -1,4 +1,4 @@
-exports['rfc1867'] =
+exports.rfc1867 =
{ boundary: 'AaB03x',
raw:
'--AaB03x\r\n'+
@@ -54,7 +54,7 @@ exports['noTrailing\r\n'] =
]
};
-exports['emptyHeader'] =
+exports.emptyHeader =
{ boundary: 'AaB03x',
raw:
'--AaB03x\r\n'+
diff --git a/test/integration/test-fixtures.js b/test/integration/test-fixtures.js
index eb32fd8..6c03194 100644
--- a/test/integration/test-fixtures.js
+++ b/test/integration/test-fixtures.js
@@ -36,7 +36,7 @@ function testNext(fixtures) {
if (!fixture) return server.close();
var name = fixture.name;
- var fixture = fixture.fixture;
+ fixture = fixture.fixture;
uploadFixture(name, function(err, parts) {
if (err) throw err;
@@ -47,19 +47,21 @@ function testNext(fixtures) {
assert.equal(parsedPart.name, expectedPart.name);
if (parsedPart.type === 'file') {
- var filename = parsedPart.value.name;
- assert.equal(filename, expectedPart.filename);
+ var file = parsedPart.value;
+ assert.equal(file.name, expectedPart.filename);
+ if(expectedPart.sha1) assert.equal(file.hash, expectedPart.sha1);
}
});
testNext(fixtures);
});
-};
+}
function uploadFixture(name, cb) {
server.once('request', function(req, res) {
var form = new formidable.IncomingForm();
form.uploadDir = common.dir.tmp;
+ form.hash = "sha1";
form.parse(req);
function callback() {
diff --git a/test/legacy/integration/test-multipart-parser.js b/test/legacy/integration/test-multipart-parser.js
index 75232aa..45047fe 100644
--- a/test/legacy/integration/test-multipart-parser.js
+++ b/test/legacy/integration/test-multipart-parser.js
@@ -33,7 +33,7 @@ Object.keys(fixtures).forEach(function(name) {
parser.onHeaderValue = function(b, start, end) {
headerValue += b.toString('ascii', start, end);
- }
+ };
parser.onHeaderEnd = function() {
part.headers[headerField] = headerValue;
@@ -44,13 +44,13 @@ Object.keys(fixtures).forEach(function(name) {
parser.onPartData = function(b, start, end) {
var str = b.toString('ascii', start, end);
part.data += b.slice(start, end);
- }
+ };
parser.onEnd = function() {
endCalled = true;
- }
+ };
- buffer.write(fixture.raw, 'binary', 0);
+ buffer.write(fixture.raw, 0, undefined, 'binary');
while (offset < buffer.length) {
if (offset + CHUNK_LENGTH < buffer.length) {
diff --git a/test/legacy/simple/test-incoming-form.js b/test/legacy/simple/test-incoming-form.js
index d79a8e2..ddb1325 100644
--- a/test/legacy/simple/test-incoming-form.js
+++ b/test/legacy/simple/test-incoming-form.js
@@ -38,7 +38,7 @@ test(function constructor() {
assert.strictEqual(form.encoding, 'utf-8');
assert.strictEqual(form.bytesReceived, null);
assert.strictEqual(form.bytesExpected, null);
- assert.strictEqual(form.maxFieldsSize, 2 * 1024 * 1024);
+ assert.strictEqual(form.maxFieldsSize, 20 * 1024 * 1024);
assert.strictEqual(form._parser, null);
assert.strictEqual(form._flushing, 0);
assert.strictEqual(form._fieldsSize, 0);
@@ -62,17 +62,17 @@ test(function parse() {
var REQ = {headers: {}}
, emit = {};
- var events = ['error', 'aborted', 'data', 'end'];
- gently.expect(REQ, 'on', events.length, function(event, fn) {
- assert.equal(event, events.shift());
- emit[event] = fn;
- return this;
- });
-
gently.expect(form, 'writeHeaders', function(headers) {
assert.strictEqual(headers, REQ.headers);
});
+ var EVENTS = ['error', 'aborted', 'data', 'end'];
+ gently.expect(REQ, 'on', EVENTS.length, function(event, fn) {
+ assert.equal(event, EVENTS.shift());
+ emit[event] = fn;
+ return this;
+ });
+
form.parse(REQ);
(function testPause() {
@@ -196,10 +196,6 @@ test(function parse() {
REQ = {headers: {}},
parseCalled = 0;
- gently.expect(REQ, 'on', 4, function() {
- return this;
- });
-
gently.expect(form, 'on', 4, function(event, fn) {
if (event == 'field') {
fn('field1', 'foo');
@@ -219,15 +215,17 @@ test(function parse() {
return this;
});
+ gently.expect(form, 'writeHeaders');
+
+ gently.expect(REQ, 'on', 4, function() {
+ return this;
+ });
+
var parseCbOk = function (err, fields, files) {
assert.deepEqual(fields, {field1: 'bar', field2: 'nice'});
assert.deepEqual(files, {file1: '2', file2: '3'});
};
- gently.expect(form, 'writeHeaders');
form.parse(REQ, parseCbOk);
- gently.expect(REQ, 'on', 4, function() {
- return this;
- });
var ERR = new Error('test');
gently.expect(form, 'on', 3, function(event, fn) {
@@ -239,6 +237,9 @@ test(function parse() {
fn(ERR);
gently.expect(form, 'on');
gently.expect(form, 'writeHeaders');
+ gently.expect(REQ, 'on', 4, function() {
+ return this;
+ });
}
return this;
});
@@ -248,6 +249,25 @@ test(function parse() {
assert.deepEqual(fields, {foo: 'bar'});
});
})();
+
+ (function testWriteOrder() {
+ gently.expect(EventEmitterStub, 'call');
+ var form = new IncomingForm();
+ var REQ = new events.EventEmitter();
+ var BUF = {};
+ var DATACB = null;
+
+ REQ.on('newListener', function(event, fn) {
+ if ('data' === event) fn(BUF);
+ });
+
+ gently.expect(form, 'writeHeaders');
+ gently.expect(form, 'write', function(buf) {
+ assert.strictEqual(buf, BUF);
+ });
+
+ form.parse(REQ);
+ })();
});
test(function pause() {
@@ -311,7 +331,7 @@ test(function write() {
delete form._parser;
gently.expect(form, '_error', function(err) {
- assert.ok(err.message.match(/unintialized parser/i));
+ assert.ok(err.message.match(/uninitialized parser/i));
});
form.write(BUFFER);
})();
@@ -378,9 +398,12 @@ test(function parseContentLength() {
var HEADERS = {};
form.headers = {};
+ gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
+ assert.equal(event, 'progress');
+ assert.equal(bytesReceived, 0);
+ assert.equal(bytesExpected, 0);
+ });
form._parseContentLength();
- assert.strictEqual(form.bytesReceived, null);
- assert.strictEqual(form.bytesExpected, null);
form.headers['content-length'] = '8';
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
@@ -545,7 +568,6 @@ test(function _initUrlencoded() {
test(function _error() {
var ERR = new Error('bla');
- gently.expect(form, 'pause');
gently.expect(form, 'emit', function(event, err) {
assert.equal(event, 'error');
assert.strictEqual(err, ERR);
diff --git a/test/legacy/simple/test-multipart-parser.js b/test/legacy/simple/test-multipart-parser.js
index bf2cd5e..c732d32 100644
--- a/test/legacy/simple/test-multipart-parser.js
+++ b/test/legacy/simple/test-multipart-parser.js
@@ -34,7 +34,7 @@ test(function parserError() {
buffer = new Buffer(5);
parser.initWithBoundary(boundary);
- buffer.write('--ad', 'ascii', 0);
+ buffer.write('--ad', 0);
assert.equal(parser.write(buffer), 5);
});
diff --git a/test/legacy/system/test-multi-video-upload.js b/test/legacy/system/test-multi-video-upload.js
index a52db6a..b35ffd6 100644
--- a/test/legacy/system/test-multi-video-upload.js
+++ b/test/legacy/system/test-multi-video-upload.js
@@ -41,12 +41,12 @@ server.on('request', function(req, res) {
assert.ok(uploads['shortest_video.flv']);
assert.ok(uploads['shortest_video.flv'].ended);
assert.ok(uploads['shortest_video.flv'].progress.length > 3);
- assert.equal(uploads['shortest_video.flv'].file.hash, 'da39a3ee5e6b4b0d3255bfef95601890afd80709');
+ assert.equal(uploads['shortest_video.flv'].file.hash, 'd6a17616c7143d1b1438ceeef6836d1a09186b3a');
assert.equal(uploads['shortest_video.flv'].progress.slice(-1), uploads['shortest_video.flv'].file.size);
assert.ok(uploads['shortest_video.mp4']);
assert.ok(uploads['shortest_video.mp4'].ended);
assert.ok(uploads['shortest_video.mp4'].progress.length > 3);
- assert.equal(uploads['shortest_video.mp4'].file.hash, 'da39a3ee5e6b4b0d3255bfef95601890afd80709');
+ assert.equal(uploads['shortest_video.mp4'].file.hash, '937dfd4db263f4887ceae19341dcc8d63bcd557f');
server.close();
res.writeHead(200);
diff --git a/test/run.js b/test/run.js
index 02d6d5c..887fab3 100755
--- a/test/run.js
+++ b/test/run.js
@@ -1 +1 @@
-require('urun')(__dirname)
+require('urun')(__dirname);
diff --git a/test/standalone/test-issue-46.js b/test/standalone/test-issue-46.js
index 1939328..519bf35 100644
--- a/test/standalone/test-issue-46.js
+++ b/test/standalone/test-issue-46.js
@@ -38,7 +38,7 @@ var server = http.createServer(function(req, res) {
var parts = [
{'Content-Disposition': 'form-data; name="foo"', 'body': 'bar'}
- ]
+ ];
var req = request({method: 'POST', url: url, multipart: parts}, function(e, res, body) {
var obj = JSON.parse(body);
diff --git a/test/standalone/test-keep-alive-error.js b/test/standalone/test-keep-alive-error.js
new file mode 100644
index 0000000..e0513cc
--- /dev/null
+++ b/test/standalone/test-keep-alive-error.js
@@ -0,0 +1,53 @@
+var assert = require('assert');
+var http = require('http');
+var net = require('net');
+var formidable = require('../../lib/index');
+
+var ok = 0;
+var errors = 0;
+
+var server = http.createServer(function (req, res) {
+ var form = new formidable.IncomingForm();
+ form.on('error', function (e) {
+ errors += 1;
+ res.writeHead(500);
+ res.end();
+ });
+ form.on('end', function () {
+ ok += 1;
+ res.writeHead(200);
+ res.end();
+ });
+ form.parse(req);
+}).listen(0, 'localhost', function () {
+ var client = net.createConnection(server.address().port);
+
+ // first send malformed post upload
+ client.write('POST /upload-test HTTP/1.1\r\n' +
+ 'Host: localhost\r\n' +
+ 'Connection: keep-alive\r\n' +
+ 'Content-Type: multipart/form-data; boundary=----aaa\r\n' +
+ 'Content-Length: 10011\r\n\r\n' +
+ '------aaa\n\r'); // expected \r\n
+
+ setTimeout(function () {
+ var buf = new Buffer(10000);
+ buf.fill('a');
+ client.write(buf);
+
+ // correct post upload
+ client.write('POST /upload-test HTTP/1.1\r\n' +
+ 'Host: localhost\r\n' +
+ 'Connection: keep-alive\r\n' +
+ 'Content-Type: multipart/form-data; boundary=----aaa\r\n' +
+ 'Content-Length: 13\r\n\r\n' +
+ '------aaa--\r\n');
+
+ setTimeout(function () {
+ assert(ok == 1);
+ assert(errors == 1);
+ client.end();
+ server.close();
+ }, 100);
+ }, 100);
+});
diff --git a/test/tmp/.empty b/test/tmp/.empty
new file mode 100644
index 0000000..e69de29
diff --git a/test/unit/test-file.js b/test/unit/test-file.js
index fc8f36e..1a5f044 100644
--- a/test/unit/test-file.js
+++ b/test/unit/test-file.js
@@ -4,7 +4,7 @@ var assert = common.assert;
var File = common.require('file');
var file;
-var now = new Date;
+var now = new Date();
test('IncomingForm', {
before: function() {
file = new File({
@@ -15,7 +15,7 @@ test('IncomingForm', {
lastModifiedDate: now,
filename: 'cat.png',
mime: 'image/png'
- })
+ });
},
'#toJSON()': function() {
@@ -30,4 +30,4 @@ test('IncomingForm', {
assert.equal(now, obj.mtime);
assert.equal(len, 8);
}
-});
\ No newline at end of file
+});
diff --git a/test/unit/test-incoming-form.js b/test/unit/test-incoming-form.js
index fe2ac1c..e1b516d 100644
--- a/test/unit/test-incoming-form.js
+++ b/test/unit/test-incoming-form.js
@@ -47,14 +47,17 @@ test('IncomingForm', {
var ext = path.extname(form._uploadPath('fine.jpg?foo=bar'));
assert.equal(ext, '.jpg');
- var ext = path.extname(form._uploadPath('fine?foo=bar'));
+ ext = path.extname(form._uploadPath('fine?foo=bar'));
assert.equal(ext, '');
- var ext = path.extname(form._uploadPath('super.cr2+dsad'));
+ ext = path.extname(form._uploadPath('super.cr2+dsad'));
assert.equal(ext, '.cr2');
- var ext = path.extname(form._uploadPath('super.bar'));
+ ext = path.extname(form._uploadPath('super.bar'));
assert.equal(ext, '.bar');
+
+ ext = path.extname(form._uploadPath('file.aAa'));
+ assert.equal(ext, '.aAa');
},
});
--- End Message ---