|
|
var common = require('../common'); var MultipartParserStub = GENTLY.stub('./multipart_parser', 'MultipartParser'), QuerystringParserStub = GENTLY.stub('./querystring_parser', 'QuerystringParser'), EventEmitterStub = GENTLY.stub('events', 'EventEmitter'), StreamStub = GENTLY.stub('stream', 'Stream'), FileStub = GENTLY.stub('./file');
var formidable = require(common.lib + '/index'), IncomingForm = formidable.IncomingForm, events = require('events'), fs = require('fs'), path = require('path'), Buffer = require('buffer').Buffer, fixtures = require(TEST_FIXTURES + '/multipart'), form, gently;
function test(test) { gently = new Gently(); gently.expect(EventEmitterStub, 'call'); form = new IncomingForm(); test(); gently.verify(test.name); }
test(function constructor() { assert.strictEqual(form.error, null); assert.strictEqual(form.ended, false); assert.strictEqual(form.type, null); assert.strictEqual(form.headers, null); assert.strictEqual(form.keepExtensions, false); // Can't assume dir === '/tmp' for portability
// assert.strictEqual(form.uploadDir, '/tmp');
// Make sure it is a directory instead
assert.doesNotThrow(function () { assert(fs.statSync(form.uploadDir).isDirectory()); }); 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._parser, null); assert.strictEqual(form._flushing, 0); assert.strictEqual(form._fieldsSize, 0); assert.ok(form instanceof EventEmitterStub); assert.equal(form.constructor.name, 'IncomingForm');
(function testSimpleConstructor() { gently.expect(EventEmitterStub, 'call'); var form = IncomingForm(); assert.ok(form instanceof IncomingForm); })();
(function testSimpleConstructorShortcut() { gently.expect(EventEmitterStub, 'call'); var form = formidable(); assert.ok(form instanceof IncomingForm); })(); });
test(function parse() { var REQ = {headers: {}} , emit = {};
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() { gently.expect(REQ, 'pause'); assert.strictEqual(form.pause(), true); })();
(function testPauseCriticalException() { form.ended = false;
var ERR = new Error('dasdsa'); gently.expect(REQ, 'pause', function() { throw ERR; });
gently.expect(form, '_error', function(err) { assert.strictEqual(err, ERR); });
assert.strictEqual(form.pause(), false); })();
(function testPauseHarmlessException() { form.ended = true;
var ERR = new Error('dasdsa'); gently.expect(REQ, 'pause', function() { throw ERR; });
assert.strictEqual(form.pause(), false); })();
(function testResume() { gently.expect(REQ, 'resume'); assert.strictEqual(form.resume(), true); })();
(function testResumeCriticalException() { form.ended = false;
var ERR = new Error('dasdsa'); gently.expect(REQ, 'resume', function() { throw ERR; });
gently.expect(form, '_error', function(err) { assert.strictEqual(err, ERR); });
assert.strictEqual(form.resume(), false); })();
(function testResumeHarmlessException() { form.ended = true;
var ERR = new Error('dasdsa'); gently.expect(REQ, 'resume', function() { throw ERR; });
assert.strictEqual(form.resume(), false); })();
(function testEmitError() { var ERR = new Error('something bad happened'); gently.expect(form, '_error',function(err) { assert.strictEqual(err, ERR); }); emit.error(ERR); })();
(function testEmitAborted() { gently.expect(form, 'emit',function(event) { assert.equal(event, 'aborted'); }); gently.expect(form, '_error');
emit.aborted(); })();
(function testEmitData() { var BUFFER = [1, 2, 3]; gently.expect(form, 'write', function(buffer) { assert.strictEqual(buffer, BUFFER); }); emit.data(BUFFER); })();
(function testEmitEnd() { form._parser = {};
(function testWithError() { var ERR = new Error('haha'); gently.expect(form._parser, 'end', function() { return ERR; });
gently.expect(form, '_error', function(err) { assert.strictEqual(err, ERR); });
emit.end(); })();
(function testWithoutError() { gently.expect(form._parser, 'end'); emit.end(); })();
(function testAfterError() { form.error = true; emit.end(); })(); })();
(function testWithCallback() { gently.expect(EventEmitterStub, 'call'); var form = new IncomingForm(), REQ = {headers: {}}, parseCalled = 0;
gently.expect(form, 'on', 4, function(event, fn) { if (event == 'field') { fn('field1', 'foo'); fn('field1', 'bar'); fn('field2', 'nice'); }
if (event == 'file') { fn('file1', '1'); fn('file1', '2'); fn('file2', '3'); }
if (event == 'end') { fn(); } 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'}); }; form.parse(REQ, parseCbOk);
var ERR = new Error('test'); gently.expect(form, 'on', 3, function(event, fn) { if (event == 'field') { fn('foo', 'bar'); }
if (event == 'error') { fn(ERR); gently.expect(form, 'on'); gently.expect(form, 'writeHeaders'); gently.expect(REQ, 'on', 4, function() { return this; }); } return this; });
form.parse(REQ, function parseCbErr(err, fields, files) { assert.strictEqual(err, ERR); 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() { assert.strictEqual(form.pause(), false); });
test(function resume() { assert.strictEqual(form.resume(), false); });
test(function writeHeaders() { var HEADERS = {}; gently.expect(form, '_parseContentLength'); gently.expect(form, '_parseContentType');
form.writeHeaders(HEADERS); assert.strictEqual(form.headers, HEADERS); });
test(function write() { var parser = {}, BUFFER = [1, 2, 3];
form._parser = parser; form.bytesExpected = 523423;
(function testBasic() { gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { assert.equal(event, 'progress'); assert.equal(bytesReceived, BUFFER.length); assert.equal(bytesExpected, form.bytesExpected); });
gently.expect(parser, 'write', function(buffer) { assert.strictEqual(buffer, BUFFER); return buffer.length; });
assert.equal(form.write(BUFFER), BUFFER.length); assert.equal(form.bytesReceived, BUFFER.length); })();
(function testParserError() { gently.expect(form, 'emit');
gently.expect(parser, 'write', function(buffer) { assert.strictEqual(buffer, BUFFER); return buffer.length - 1; });
gently.expect(form, '_error', function(err) { assert.ok(err.message.match(/parser error/i)); });
assert.equal(form.write(BUFFER), BUFFER.length - 1); assert.equal(form.bytesReceived, BUFFER.length + BUFFER.length); })();
(function testUninitialized() { delete form._parser;
gently.expect(form, '_error', function(err) { assert.ok(err.message.match(/unintialized parser/i)); }); form.write(BUFFER); })(); });
test(function parseContentType() { var HEADERS = {};
form.headers = {'content-type': 'application/x-www-form-urlencoded'}; gently.expect(form, '_initUrlencoded'); form._parseContentType();
// accept anything that has 'urlencoded' in it
form.headers = {'content-type': 'broken-client/urlencoded-stupid'}; gently.expect(form, '_initUrlencoded'); form._parseContentType();
var BOUNDARY = '---------------------------57814261102167618332366269'; form.headers = {'content-type': 'multipart/form-data; boundary='+BOUNDARY};
gently.expect(form, '_initMultipart', function(boundary) { assert.equal(boundary, BOUNDARY); }); form._parseContentType();
(function testQuotedBoundary() { form.headers = {'content-type': 'multipart/form-data; boundary="' + BOUNDARY + '"'};
gently.expect(form, '_initMultipart', function(boundary) { assert.equal(boundary, BOUNDARY); }); form._parseContentType(); })();
(function testNoBoundary() { form.headers = {'content-type': 'multipart/form-data'};
gently.expect(form, '_error', function(err) { assert.ok(err.message.match(/no multipart boundary/i)); }); form._parseContentType(); })();
(function testNoContentType() { form.headers = {};
gently.expect(form, '_error', function(err) { assert.ok(err.message.match(/no content-type/i)); }); form._parseContentType(); })();
(function testUnknownContentType() { form.headers = {'content-type': 'invalid'};
gently.expect(form, '_error', function(err) { assert.ok(err.message.match(/unknown content-type/i)); }); form._parseContentType(); })(); });
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();
form.headers['content-length'] = '8'; gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { assert.equal(event, 'progress'); assert.equal(bytesReceived, 0); assert.equal(bytesExpected, 8); }); form._parseContentLength(); assert.strictEqual(form.bytesReceived, 0); assert.strictEqual(form.bytesExpected, 8);
// JS can be evil, lets make sure we are not
form.headers['content-length'] = '08'; gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) { assert.equal(event, 'progress'); assert.equal(bytesReceived, 0); assert.equal(bytesExpected, 8); }); form._parseContentLength(); assert.strictEqual(form.bytesExpected, 8); });
test(function _initMultipart() { var BOUNDARY = '123', PARSER;
gently.expect(MultipartParserStub, 'new', function() { PARSER = this; });
gently.expect(MultipartParserStub.prototype, 'initWithBoundary', function(boundary) { assert.equal(boundary, BOUNDARY); });
form._initMultipart(BOUNDARY); assert.equal(form.type, 'multipart'); assert.strictEqual(form._parser, PARSER);
(function testRegularField() { var PART; gently.expect(StreamStub, 'new', function() { PART = this; });
gently.expect(form, 'onPart', function(part) { assert.strictEqual(part, PART); assert.deepEqual ( part.headers , { 'content-disposition': 'form-data; name="field1"' , 'foo': 'bar' } ); assert.equal(part.name, 'field1');
var strings = ['hello', ' world']; gently.expect(part, 'emit', 2, function(event, b) { assert.equal(event, 'data'); assert.equal(b.toString(), strings.shift()); });
gently.expect(part, 'emit', function(event, b) { assert.equal(event, 'end'); }); });
PARSER.onPartBegin(); PARSER.onHeaderField(new Buffer('content-disposition'), 0, 10); PARSER.onHeaderField(new Buffer('content-disposition'), 10, 19); PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 0, 14); PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 14, 24); PARSER.onHeaderEnd(); PARSER.onHeaderField(new Buffer('foo'), 0, 3); PARSER.onHeaderValue(new Buffer('bar'), 0, 3); PARSER.onHeaderEnd(); PARSER.onHeadersEnd(); PARSER.onPartData(new Buffer('hello world'), 0, 5); PARSER.onPartData(new Buffer('hello world'), 5, 11); PARSER.onPartEnd(); })();
(function testFileField() { var PART; gently.expect(StreamStub, 'new', function() { PART = this; });
gently.expect(form, 'onPart', function(part) { assert.deepEqual ( part.headers , { 'content-disposition': 'form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"' , 'content-type': 'text/plain' } ); assert.equal(part.name, 'field2'); assert.equal(part.filename, 'Sun"et.jpg'); assert.equal(part.mime, 'text/plain');
gently.expect(part, 'emit', function(event, b) { assert.equal(event, 'data'); assert.equal(b.toString(), '... contents of file1.txt ...'); });
gently.expect(part, 'emit', function(event, b) { assert.equal(event, 'end'); }); });
PARSER.onPartBegin(); PARSER.onHeaderField(new Buffer('content-disposition'), 0, 19); PARSER.onHeaderValue(new Buffer('form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"'), 0, 85); PARSER.onHeaderEnd(); PARSER.onHeaderField(new Buffer('Content-Type'), 0, 12); PARSER.onHeaderValue(new Buffer('text/plain'), 0, 10); PARSER.onHeaderEnd(); PARSER.onHeadersEnd(); PARSER.onPartData(new Buffer('... contents of file1.txt ...'), 0, 29); PARSER.onPartEnd(); })();
(function testEnd() { gently.expect(form, '_maybeEnd'); PARSER.onEnd(); assert.ok(form.ended); })(); });
test(function _fileName() { // TODO
return; });
test(function _initUrlencoded() { var PARSER;
gently.expect(QuerystringParserStub, 'new', function() { PARSER = this; });
form._initUrlencoded(); assert.equal(form.type, 'urlencoded'); assert.strictEqual(form._parser, PARSER);
(function testOnField() { var KEY = 'KEY', VAL = 'VAL'; gently.expect(form, 'emit', function(field, key, val) { assert.equal(field, 'field'); assert.equal(key, KEY); assert.equal(val, VAL); });
PARSER.onField(KEY, VAL); })();
(function testOnEnd() { gently.expect(form, '_maybeEnd');
PARSER.onEnd(); assert.equal(form.ended, true); })(); });
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); });
form._error(ERR); assert.strictEqual(form.error, ERR);
// make sure _error only does its thing once
form._error(ERR); });
test(function onPart() { var PART = {}; gently.expect(form, 'handlePart', function(part) { assert.strictEqual(part, PART); });
form.onPart(PART); });
test(function handlePart() { (function testUtf8Field() { var PART = new events.EventEmitter(); PART.name = 'my_field';
gently.expect(form, 'emit', function(event, field, value) { assert.equal(event, 'field'); assert.equal(field, 'my_field'); assert.equal(value, 'hello world: €'); });
form.handlePart(PART); PART.emit('data', new Buffer('hello')); PART.emit('data', new Buffer(' world: ')); PART.emit('data', new Buffer([0xE2])); PART.emit('data', new Buffer([0x82, 0xAC])); PART.emit('end'); })();
(function testBinaryField() { var PART = new events.EventEmitter(); PART.name = 'my_field2';
gently.expect(form, 'emit', function(event, field, value) { assert.equal(event, 'field'); assert.equal(field, 'my_field2'); assert.equal(value, 'hello world: '+new Buffer([0xE2, 0x82, 0xAC]).toString('binary')); });
form.encoding = 'binary'; form.handlePart(PART); PART.emit('data', new Buffer('hello')); PART.emit('data', new Buffer(' world: ')); PART.emit('data', new Buffer([0xE2])); PART.emit('data', new Buffer([0x82, 0xAC])); PART.emit('end'); })();
(function testFieldSize() { form.maxFieldsSize = 8; var PART = new events.EventEmitter(); PART.name = 'my_field';
gently.expect(form, '_error', function(err) { assert.equal(err.message, 'maxFieldsSize exceeded, received 9 bytes of field data'); });
form.handlePart(PART); form._fieldsSize = 1; PART.emit('data', new Buffer(7)); PART.emit('data', new Buffer(1)); })();
(function testFilePart() { var PART = new events.EventEmitter(), FILE = new events.EventEmitter(), PATH = '/foo/bar';
PART.name = 'my_file'; PART.filename = 'sweet.txt'; PART.mime = 'sweet.txt';
gently.expect(form, '_uploadPath', function(filename) { assert.equal(filename, PART.filename); return PATH; });
gently.expect(FileStub, 'new', function(properties) { assert.equal(properties.path, PATH); assert.equal(properties.name, PART.filename); assert.equal(properties.type, PART.mime); FILE = this;
gently.expect(form, 'emit', function (event, field, file) { assert.equal(event, 'fileBegin'); assert.strictEqual(field, PART.name); assert.strictEqual(file, FILE); });
gently.expect(FILE, 'open'); });
form.handlePart(PART); assert.equal(form._flushing, 1);
var BUFFER; gently.expect(form, 'pause'); gently.expect(FILE, 'write', function(buffer, cb) { assert.strictEqual(buffer, BUFFER); gently.expect(form, 'resume'); // @todo handle cb(new Err)
cb(); });
PART.emit('data', BUFFER = new Buffer('test'));
gently.expect(FILE, 'end', function(cb) { gently.expect(form, 'emit', function(event, field, file) { assert.equal(event, 'file'); assert.strictEqual(file, FILE); });
gently.expect(form, '_maybeEnd');
cb(); assert.equal(form._flushing, 0); });
PART.emit('end'); })(); });
test(function _uploadPath() { (function testUniqueId() { var UUID_A, UUID_B; gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) { assert.equal(uploadDir, form.uploadDir); UUID_A = uuid; }); form._uploadPath();
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) { UUID_B = uuid; }); form._uploadPath();
assert.notEqual(UUID_A, UUID_B); })();
(function testFileExtension() { form.keepExtensions = true; var FILENAME = 'foo.jpg', EXT = '.bar';
gently.expect(GENTLY.hijacked.path, 'extname', function(filename) { assert.equal(filename, FILENAME); gently.restore(path, 'extname');
return EXT; });
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, name) { assert.equal(path.extname(name), EXT); }); form._uploadPath(FILENAME); })(); });
test(function _maybeEnd() { gently.expect(form, 'emit', 0); form._maybeEnd();
form.ended = true; form._flushing = 1; form._maybeEnd();
gently.expect(form, 'emit', function(event) { assert.equal(event, 'end'); });
form.ended = true; form._flushing = 0; form._maybeEnd(); });
|