Comparing version 0.0.2 to 0.0.7
212
firebird.js
@@ -1,9 +0,215 @@ | ||
var binding = require("./build/default/binding"); | ||
var binding = require("./build/Release/binding"); | ||
var stream = require("stream"); | ||
var util = require("util"); | ||
var events = require('events'); | ||
var SchunkSize = 4*1024; | ||
var Connection = binding.Connection; | ||
var Connection = binding.Connection; | ||
var FBEventEmitter = binding.FBEventEmitter; | ||
var FBResult = binding.FBResult; | ||
var FBStatement = binding.FBStatement; | ||
var FBblob = binding.FBblob; | ||
// inherit FBEventEmitter (and all descendants ) from events.EventEmitter | ||
FBEventEmitter.prototype.__proto__ = events.EventEmitter.prototype; | ||
function MakeSafe(obj,meth){ | ||
var superm = obj.prototype[meth]; | ||
obj.prototype[meth] = function safe(){ | ||
if(this.inAsyncCall){ | ||
var self = this; | ||
var args = arguments; | ||
this.once("fbStopAsync",function(){ | ||
safe.apply(self,args); | ||
//superm.apply(self,args); | ||
}); | ||
} | ||
else { | ||
superm.apply(this,arguments); | ||
} | ||
} | ||
} | ||
MakeSafe(Connection,"query"); | ||
MakeSafe(Connection,"commit"); | ||
MakeSafe(Connection,"rollback"); | ||
MakeSafe(FBResult,"fetch"); | ||
MakeSafe(FBStatement,"exec"); | ||
MakeSafe(FBblob,"_read"); | ||
MakeSafe(FBblob,"_write"); | ||
var superConnect = Connection.prototype.connect; | ||
Connection.prototype.connect = function(db,user,pass,role,cb){ | ||
var obj = this; | ||
superConnect.call(this,db,user,pass,role,function (err){ | ||
if(err) obj.emit('error',err); | ||
else obj.emit('connected'); | ||
if(cb) cb(err); | ||
}); | ||
}; | ||
var superQuery = Connection.prototype.query; | ||
Connection.prototype.query = function(sql,cb){ | ||
var obj = this; | ||
superQuery.call(this,sql,function(err,res){ | ||
if(err) obj.emit('error',err); | ||
else obj.emit('result',res); | ||
if(cb) cb(err,res); | ||
}); | ||
}; | ||
binding.FBblob.prototype._readAll = function(initialSize, chunkSize, callback){ | ||
if(initialSize instanceof Function) | ||
{ | ||
callback = initialSize; | ||
chunkSize = null; | ||
initialSize = null; | ||
} | ||
else | ||
if(chunkSize instanceof Function) | ||
{ | ||
callback = chunkSize; | ||
chunkSize = null; | ||
} | ||
if(!chunkSize) chunkSize = 1024; | ||
if(!initialSize) initialSize = 0; | ||
var chunk = new Buffer(chunkSize); | ||
var res = new Buffer(initialSize); | ||
var cPos = 0; | ||
this._openSync(); | ||
var self = this; | ||
this._read(chunk,function receiver(err,b,len){ | ||
if(err) | ||
{ | ||
self.emit('error',err); | ||
} | ||
else | ||
if(len>0) | ||
{ | ||
self.emit('data', chunk, len); | ||
if(res.length<=(cPos+len)) | ||
{ | ||
var nr = new Buffer(cPos+len); | ||
res.copy(nr); | ||
res = nr; | ||
} | ||
chunk.copy(res,cPos,0,len); | ||
cPos = cPos + len; | ||
self._read(chunk,receiver); | ||
} | ||
else | ||
{ | ||
self._closeSync(); | ||
self.emit('end',res,cPos); | ||
if(callback) callback(null, res, cPos); | ||
} | ||
}); | ||
} | ||
exports.createConnection = function () { | ||
var c = new Connection; | ||
var c = new Connection(); | ||
return c; | ||
}; | ||
exports.createConnectionPool = function(settings){ | ||
}; | ||
// Allows further extention | ||
exports.binding = binding; | ||
var buf = null; | ||
function allocBuf(){ | ||
buf = new Buffer(SchunkSize); | ||
} | ||
function ReadStream(strm) { | ||
if(buf == null) allocBuf(); | ||
strm._blob._read(buf,function s_rcv(err, b, len){ | ||
if(err) | ||
{ | ||
strm.emit('error',err); | ||
} | ||
else | ||
if(len>0) | ||
{ | ||
strm.emit('data', b, len); | ||
if(!strm._paused) strm._blob._read(buf,s_rcv); | ||
} | ||
else | ||
{ | ||
strm.emit('end'); | ||
} | ||
}); | ||
}; | ||
function Stream(blob){ | ||
if(!(blob instanceof binding.FBblob )) { | ||
throw new Error('Expecting blob'); | ||
//blob = new binding.FBblob(); | ||
} | ||
stream.Stream.call(this); | ||
this._blob = blob; | ||
this.readable = false; | ||
this.writeable = false; | ||
if(blob.isReadable) | ||
{ | ||
this._blob._openSync(); | ||
this.readable = true; | ||
this._paused = true; | ||
} | ||
else | ||
this.writable = true; | ||
}; | ||
util.inherits(Stream, stream.Stream); | ||
exports.Stream = Stream; | ||
Stream.prototype.pause = function(){ | ||
this._paused = true; | ||
}; | ||
Stream.prototype.resume = function(){ | ||
this._paused = false; | ||
ReadStream(this); | ||
}; | ||
Stream.prototype.destroy = function(){ | ||
this._blob._closeSync(); | ||
this.emit('close'); | ||
}; | ||
Stream.prototype.write = function(data, encoding, fd) { | ||
if (typeof data != 'string') { | ||
}; | ||
var self = this; | ||
//this._blob._writeSync(data); | ||
this._blob._write(data,function(err){ | ||
if(err) self.emit('error',err); | ||
//self.emit('drain'); | ||
}); | ||
} | ||
Stream.prototype.end = function(data, encoding, fd) { | ||
var self = this; | ||
if(data) this._blob._write(data,function(err){ | ||
console.log('in blob write callback'); | ||
if(err) self.emit('error',err); | ||
self.destroy(); | ||
}) | ||
else self.destroy(); | ||
} | ||
{ "name" : "firebird" | ||
, "version" : "0.0.2" | ||
, "version" : "v0.0.7" | ||
, "description" : "Firebird binding to node, uses libfbclient." | ||
@@ -4,0 +4,0 @@ , "author": "Denys Khanzhiyev" |
179
README.md
C++ NodeJS module to work with Firebird SQL Server. Uses libfbclient. | ||
Inspired by node-mysql-libmysql, node-postgress and other modules used as sample source. | ||
Inspired by ibpp, firebird samples, node-mysql-libmysql, node-postgress and other node modules used as sample source. | ||
@@ -7,10 +7,16 @@ # Features | ||
* Synchronous and Asynchronous methods for connection, query and fetch data; | ||
* Support of Firebird Events (__post_event statement); | ||
* Covered with tests in nodeunit. | ||
* Support of Firebird Events (post_event statement); | ||
* Covered with tests in nodeunit; | ||
* blob field support; | ||
* blob stream compatible to node stream class; | ||
* prepared statements; | ||
As for now in plans are: | ||
* adding blob field support; | ||
* connection pool support; | ||
* prepared statements pool; | ||
* transaction parameters support; | ||
* continous refactoring; | ||
* more tests. | ||
* more tests; | ||
* services api. | ||
@@ -20,3 +26,3 @@ # Getting Started | ||
You will need: | ||
NodeJS (tested with v0.3.2-pre) | ||
NodeJS (tested with v0.6.0) | ||
Firebird (tested with v2.5) | ||
@@ -28,11 +34,12 @@ | ||
wget http://downloads.sourceforge.net/project/firebird/firebird-linux-i386/2.5-Release/FirebirdCS-2.5.0.26074-0.i686.rpm | ||
rpm -ivh FirebirdCS-2.5.0.26074-0.i686.rpm | ||
wget http://downloads.sourceforge.net/project/firebird/firebird-linux-i386/2.5-Release/FirebirdCS-2.5.0.26074-0.i686.rpm | ||
rpm -ivh FirebirdCS-2.5.0.26074-0.i686.rpm | ||
Update your path: | ||
export PATH=$PATH:/opt/firebird/bin | ||
export PATH=$PATH:/opt/firebird/bin | ||
Create some Database: | ||
isql -user sysdba -password masterkey | ||
CREATE DATABSE 'test.fdb'; | ||
CREATE DATABASE 'test.fdb'; | ||
CONNECT 'test.fdb'; | ||
@@ -46,7 +53,16 @@ CREATE TABLE TEST (id integer, name varchar(50)); | ||
node-waf configure build | ||
node-waf configure install | ||
or use npm: | ||
npm install firebird | ||
To run tests update ./tests/config.js with your test database connection parameters and | ||
git submodule update --init | ||
node-waf test | ||
Play with it from node: | ||
var fb = require("./firebird"), | ||
var fb = require("./firebird"); | ||
sys = require("sys"); | ||
@@ -56,7 +72,16 @@ var con = fb.createConnection(); | ||
con.querySync("insert into test (id,name) values (5, 'new one')"); | ||
var res = conn.querySync("select * from test"); | ||
var res = con.querySync("select * from test"); | ||
con.commitSync(); | ||
var rows = res.fetchSync("all",true); | ||
console.log(sys.inspect(rows)); | ||
Check also samples directory. | ||
# Links | ||
- [node.js and firebird installing on Amazon EC2 instance](http://mapopa.blogspot.com/2011/01/nodejs-and-firebird-installing-on.html) on Mariuz's Blog | ||
- [Catch Firebird events with Node.js](http://www.king-foo.be/2011/07/catch-firebird-events-with-node-js) on www.king-foo.be | ||
- [NodeJS home](http://nodejs.org) | ||
- [Collection of NodeJS modules](https://github.com/joyent/node/wiki/modules) | ||
# Reference | ||
@@ -133,5 +158,6 @@ | ||
Note: | ||
Notes: | ||
There is only one transaction associated with connection. | ||
Transacation is automatically started before any query. Use of mutliple transactions with same connection may be added in future. | ||
Transacation is automatically started before any query if connection does not have active transaction (check `inTransaction` property). | ||
Use of mutliple transactions with same connection may be added in future. | ||
You also should note that DDL statements (altering database structure) are commited automatically. | ||
@@ -157,2 +183,8 @@ | ||
* * * | ||
function prepareSync(sql); | ||
* `sql` - string, an SQL query to prepare. | ||
Synchronously prepares SQL statement and returns FBStatement object. | ||
* * * | ||
inTransaction; | ||
@@ -163,6 +195,32 @@ | ||
* * * | ||
function newBlobSync(); | ||
Creates new FBblob object and opens it for write. After finishing write operation and closing blob | ||
one may insert it in database passing as parameter to exec, execSync methods of FBStatement object. | ||
* * * | ||
## FBResult object | ||
Represents results of SQL query if any. | ||
Represents results of SQL query if any. You should use this object to fetch rows from database. | ||
Each row may be represented as array of field values or as object with named fields. | ||
### Data types | ||
Here is Interbase to Node data type accordance: | ||
Firebird Node | ||
DATE -> Date | ||
TIME -> Date | ||
TIMESTAMP -> Date | ||
CHAR -> String | ||
VARCHAR -> String | ||
SMALLINT -> Integer | ||
INTEGER -> Integer | ||
NUMERIC -> Integer, Number (depends on scale) | ||
DECIMAL -> Integer, Number (depends on scale) | ||
FLOAT -> Number | ||
DOUBLE -> Number | ||
BLOB -> FBblob | ||
### FBResult object members | ||
@@ -193,6 +251,91 @@ | ||
* * * | ||
## FBStatement object | ||
Represents prepared SQL query (returned by `Connection.prepare()` and `Connection.prepareSync()`). | ||
FBStatement is derived form FBResult class. So it can fetch rows just like FBresult object after call to execSync, exec methods. | ||
### FBStatement object members | ||
* * * | ||
function execSync(param1, param2, ..., paramN); | ||
* `param1, param2, ..., paramN` - parameters of prepared statement in the same order as in SQL and with appropriate types. | ||
Synchronously executes prepared statement with given parameters. You may fetch rows with methods inherited from FBResult. | ||
* * * | ||
function exec(param1, param2, ..., paramN); | ||
* `param1, param2, ..., paramN` - parameters of prepared statement in the same order as in SQL and with appropriate types. | ||
Asynchronously executes prepared statement with given parameters. FBStatement emits 'result' or 'error' event. | ||
You may fetch rows with methods inherited from FBResult after 'result' event emitted. | ||
* * * | ||
## FBblob object | ||
Represents BLOB data type. | ||
### FBblob object members | ||
* * * | ||
function _openSync(); | ||
Synchronously opens blob for reading. | ||
* * * | ||
function _closeSync(); | ||
Synchronously closes previously opened blob. | ||
* * * | ||
function _readSync(buffer); | ||
* `buffer` - Node buffer to fill with data. | ||
Synchronously reads BLOB segment (chunk) into buffer. Tries to fill whole buffer with data. | ||
Returns actual number of bytes read. | ||
* * * | ||
function _read(buffer, callback); | ||
* `buffer` - Node buffer to fill with data. | ||
* `callback` - function(err,buffer,len), err - Error object in case of error, or null;buffer - buffer filled with data; len - actual data length. | ||
Asynchronously reads BLOB segment (chunk) into buffer. Tries to fill whole buffer with data. | ||
* * * | ||
function _readAll([[initialSize], [[chunkSize], [callback]]]); | ||
* `initialSize` - optional, initial result buffer to allocate, default = 0; | ||
* `chunkSize` - optional, size of chunk used to read data, default = 1024; | ||
* `callback` - optional, function (err, buffer, len), err - Error object in case of error, or null;buffer - buffer filled with data; len - actual data length. | ||
Asynchronously reads all data from BLOB field. Object emits events while reading data `error`, `drain', `end`. | ||
* * * | ||
function _writeSync(buffer,[len]); | ||
* `buffer` - Node buffer to write from to blob; | ||
* `len` - optional length parameter, if specified only len bytes from buffer will be writen. | ||
Synchronously writes BLOB segment (chunk) from buffer. | ||
Returns number of bytes actually writen. | ||
* * * | ||
function _write(buffer,[len],[callback]); | ||
* `buffer` - Node buffer to write from to blob; | ||
* `len` - optional length parameter, if specified only len bytes from buffer will be writen. | ||
* `callback` - function(err), err - Error object in case of error, or null; | ||
Asynchronously writes BLOB segment (chunk) from buffer and calls callback function if any. | ||
* * * | ||
## Stream object | ||
Represents BLOB stream. Create BLOB stream using `var strm = new fb.Stream(FBblob);`. | ||
You may pipe strm to/from NodeJS Stream objects (fs or socket). | ||
You may also look at [NodeJS Streams reference](http://nodejs.org/docs/v0.4.4/api/streams.html). | ||
@@ -9,3 +9,3 @@ /* | ||
// Database connection settings | ||
db: "/opt/firebird/databases/test.fdb", | ||
db: "test.fdb", | ||
user: "sysdba", | ||
@@ -12,0 +12,0 @@ password: "masterkey", |
@@ -11,3 +11,3 @@ /* | ||
var | ||
fb_binding = require("../../build/default/binding"); | ||
fb_binding = require("../../firebird.js"); | ||
@@ -17,3 +17,3 @@ | ||
test.expect(4); | ||
var conn = new fb_binding.Connection; | ||
var conn = fb_binding.createConnection(); | ||
conn.connect(cfg.db, cfg.user, cfg.password, cfg.role, function(){ | ||
@@ -28,2 +28,3 @@ test.ok(conn.connected,"Connected to database"); | ||
}); | ||
}); | ||
@@ -33,8 +34,12 @@ }; | ||
exports.AsyncQueryWithError = function (test) { | ||
test.expect(4); | ||
var conn = new fb_binding.Connection; | ||
test.expect(5); | ||
var conn = fb_binding.createConnection(); | ||
conn.connect(cfg.db, cfg.user, cfg.password, cfg.role, function(){ | ||
test.ok(conn.connected,"Connected to database"); | ||
conn.on('error',function(err){ | ||
test.ok(err,"There is error"); | ||
return true; | ||
}); | ||
conn.query("select * from non_existent_table", function(err,res){ | ||
test.ok(err,"There is error"); | ||
test.ok(err,"There is error"); | ||
test.ok(!res,"No result"); | ||
@@ -50,3 +55,3 @@ conn.disconnect(); | ||
test.expect(6); | ||
var conn = new fb_binding.Connection; | ||
var conn = fb_binding.createConnection(); | ||
conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -65,6 +70,28 @@ test.ok(conn.connected,"Connected to database"); | ||
}); | ||
} | ||
exports.InAsyncCallConnection = function(test){ | ||
test.expect(7); | ||
var conn = fb_binding.createConnection(); | ||
conn.on("fbStartAsync",function(){ | ||
test.ok(true,"StartAsync Called"); | ||
}); | ||
conn.on("fbStopAsync",function(){ | ||
test.ok(true,"StopAsync Called"); | ||
}); | ||
test.ok(!conn.inAsyncCall,"not inAsyncCall initially"); | ||
conn.connect(cfg.db, cfg.user, cfg.password, cfg.role, function(res){ | ||
conn.query("select * from rdb$relations", function(err,res){ | ||
conn.disconnect(); | ||
conn.once("fbStopAsync",function(){ | ||
test.done(); | ||
}); | ||
}); | ||
test.ok(conn.inAsyncCall,"inAsyncCall query"); | ||
}); | ||
test.ok(conn.inAsyncCall,"inAsyncCall connect"); | ||
} | ||
@@ -11,6 +11,7 @@ /* | ||
var | ||
fb_binding = require("../../build/default/binding"); | ||
fb_binding = require("../../build/Release/binding"); | ||
safe_con = require("../../firebird.js"); | ||
exports.ConnectionBinding = function (test) { | ||
test.expect(15); | ||
test.expect(19); | ||
test.ok("Connection" in fb_binding, "Connection"); | ||
@@ -32,7 +33,33 @@ var conn = new fb_binding.Connection; | ||
test.ok("rollbackSync" in conn, "rollbackSync"); | ||
test.ok("prepareSync" in conn, "prepareSync"); | ||
test.ok("inAsyncCall" in conn, "inAsyncCall"); | ||
test.ok("startTransactionSync" in conn, "startTransactionSync"); | ||
test.ok("newBlobSync" in conn, "newBlobSync"); | ||
test.done(); | ||
}; | ||
exports.SafeConnectionBinding = function (test) { | ||
test.expect(16); | ||
test.ok("createConnection" in safe_con, "createConnection"); | ||
var conn = safe_con.createConnection(); | ||
test.ok(conn, "Connection created"); | ||
test.ok("connectSync" in conn, "connectSync"); | ||
test.ok("connect" in conn, "connect"); | ||
test.ok("connected" in conn, "connected"); | ||
test.ok("disconnect" in conn, "disconnect"); | ||
test.ok("querySync" in conn, "querySync"); | ||
test.ok("query" in conn, "query"); | ||
test.ok("addFBevent" in conn,"addFBevent"); | ||
test.ok("deleteFBevent" in conn,"deleteFBevent"); | ||
test.ok("commit" in conn, "commit"); | ||
test.ok("commitSync" in conn, "commitSync"); | ||
test.ok("inTransaction" in conn, "inTransaction"); | ||
test.ok("rollback" in conn, "rollback"); | ||
test.ok("rollbackSync" in conn, "rollbackSync"); | ||
test.ok("inAsyncCall" in conn, "inAsyncCall"); | ||
test.done(); | ||
}; | ||
exports.FBResultBinding = function(test){ | ||
test.expect(3); | ||
test.expect(4); | ||
var conn = new fb_binding.Connection; | ||
@@ -44,2 +71,3 @@ conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
test.ok("fetch" in res, "fetch"); | ||
test.ok("inAsyncCall" in res, "inAsyncCall"); | ||
conn.disconnect(); | ||
@@ -49,2 +77,22 @@ test.done(); | ||
exports.FBblobBinding = function(test){ | ||
test.expect(6); | ||
var blob = fb_binding.FBblob.prototype; | ||
test.ok("_readSync" in blob, 'readSync'); | ||
test.ok("_read" in blob, 'read'); | ||
test.ok("_openSync" in blob, '_openSync'); | ||
test.ok("_closeSync" in blob, '_closeSync'); | ||
test.ok("_writeSync" in blob, '_writeSync'); | ||
test.ok("_write" in blob, '_write'); | ||
test.done(); | ||
} | ||
exports.FBstatementBinding = function(test){ | ||
test.expect(2); | ||
var stmt = fb_binding.FBStatement.prototype; | ||
test.ok("execSync" in stmt, 'execSync'); | ||
test.ok("exec" in stmt, 'exec'); | ||
// test.ok("inAsyncCall" in stmt, "inAsyncCall"); | ||
test.done(); | ||
} | ||
@@ -11,3 +11,6 @@ /* | ||
var | ||
fb_binding = require("../../build/default/binding"); | ||
fb_binding = require("../../firebird.js"); | ||
var zexports = {}; | ||
@@ -17,3 +20,3 @@ | ||
{ | ||
var conn = new fb_binding.Connection; | ||
var conn = fb_binding.createConnection(); | ||
conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -31,3 +34,3 @@ conn.querySync("\ | ||
function Connect(){ | ||
var conn = new fb_binding.Connection; | ||
var conn = fb_binding.createConnection(); | ||
conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -45,4 +48,29 @@ return conn; | ||
function WaitForFinish(finished,clean,timeout){ | ||
var timedout = false; | ||
var tid = setTimeout(function(){ | ||
timedout = true; | ||
},timeout); | ||
process.nextTick(function loop(){ | ||
if(finished.call()||timedout){ | ||
clearTimeout(tid); | ||
clean.call(); | ||
} | ||
else process.nextTick(loop); | ||
}); | ||
/* | ||
setTimeout(function loop(){ | ||
if(finished.call()||timedout){ | ||
clearTimeout(tid); | ||
clean.call(); | ||
} | ||
else setTimeout(loop,0); | ||
},0); | ||
*/ | ||
} | ||
function CleanUp(){ | ||
var con = new fb_binding.Connection; | ||
var con = fb_binding.createConnection(); | ||
con.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -70,3 +98,3 @@ con.querySync("drop procedure DoEvent;"); | ||
// console.log('after add another'); | ||
// Wait 2 sec for event | ||
// Wait 1 sec for event | ||
setTimeout(function(){ | ||
@@ -76,3 +104,3 @@ conn.disconnect(); | ||
test.done(); | ||
}, 2000); | ||
}, 1000); | ||
@@ -88,2 +116,3 @@ } | ||
var eName = "Event1"; | ||
var finished = false; | ||
conn.addFBevent(eName); | ||
@@ -93,12 +122,14 @@ conn.on("fbevent",function(event,count){ | ||
test.ok(count==1,"One event"); | ||
finished = true; | ||
}); | ||
GenEvent(eName); | ||
// Wait 2 sec for event | ||
setTimeout(function(){ | ||
WaitForFinish(function(){ return finished; }, | ||
function(){ | ||
conn.disconnect(); | ||
CleanUp(); | ||
test.done(); | ||
}, 2000); | ||
}, 5000); | ||
} | ||
@@ -113,19 +144,22 @@ | ||
var eName = "Event1"; | ||
conn.addFBevent(eName); | ||
GenEvent(eName); | ||
conn.addFBevent("strange"); | ||
var finished = false; | ||
conn.on("fbevent",function(event,count){ | ||
test.ok(event==eName, "We got that event"); | ||
test.ok(count==1,"One event"); | ||
finished = true; | ||
}); | ||
conn.addFBevent(eName); | ||
GenEvent(eName); | ||
conn.addFBevent("strange"); | ||
// Wait 2 sec for event | ||
setTimeout(function(){ | ||
WaitForFinish(function(){ return finished; }, | ||
function(){ | ||
conn.disconnect(); | ||
CleanUp(); | ||
test.done(); | ||
}, 2000); | ||
}, 5000); | ||
} | ||
@@ -141,2 +175,3 @@ | ||
var evcount = 0; | ||
var expected_count = 100; //400;? | ||
conn.on("fbevent", function(event,count){ | ||
@@ -149,3 +184,3 @@ //console.log("->"+event+" "+count); | ||
var en; | ||
for(var i = 0; i<40; i++){ | ||
for(var i = 0; i<expected_count; i++){ | ||
en = 'Event'+i; | ||
@@ -156,3 +191,3 @@ events.push(en); | ||
events = events.reverse(); | ||
for(var i = 0; i<40; i++){ | ||
for(var i = 0; i<expected_count; i++){ | ||
setTimeout((function(idx){ | ||
@@ -164,9 +199,35 @@ return function(){ | ||
} | ||
WaitForFinish(function(){ return (evcount == expected_count); }, | ||
function(){ | ||
test.ok(evcount == expected_count, "We have "+ expected_count + " events"); | ||
conn.disconnect(); | ||
CleanUp(); | ||
test.done(); | ||
}, expected_count*250); | ||
} | ||
exports.AddAndDelete = function(test){ | ||
test.expect(2); | ||
Init(); | ||
var conn = Connect(); | ||
test.ok(conn.connected,"Connected to database"); | ||
var called = false; | ||
conn.on("fbevent", function(event,count){ | ||
//console.log("->"+event+" "+count); | ||
called = true; | ||
}); | ||
var eN = 'eventName'; | ||
conn.addFBevent(eN); | ||
conn.deleteFBevent(eN); | ||
GenEvent(eN); | ||
setTimeout(function(){ | ||
test.ok(evcount == 40, "We have 40 events"); | ||
conn.disconnect(); | ||
CleanUp(); | ||
test.done(); | ||
},5000); | ||
} | ||
test.ok(!called,"Event not called"); | ||
conn.disconnect(); | ||
CleanUp(); | ||
test.done(); | ||
}, 1000); | ||
} |
@@ -11,3 +11,3 @@ /* | ||
var | ||
fb_binding = require("../../build/default/binding"); | ||
fb_binding = require("../../firebird.js"); | ||
@@ -19,3 +19,3 @@ var | ||
setUp: function(callback){ | ||
this.conn = new fb_binding.Connection; | ||
this.conn = fb_binding.createConnection(); | ||
this.conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -22,0 +22,0 @@ this.res = this.conn.querySync("select * from rdb$relations"); |
@@ -11,3 +11,4 @@ /* | ||
var | ||
fb_binding = require("../../build/default/binding"); | ||
fb_binding = require("../../firebird.js"); | ||
@@ -17,3 +18,3 @@ | ||
test.expect(3); | ||
var conn = new fb_binding.Connection; | ||
var conn = fb_binding.createConnection(); | ||
conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -29,3 +30,3 @@ test.ok(conn.connected,"Connected to database"); | ||
function Connect(){ | ||
var conn = new fb_binding.Connection; | ||
var conn = fb_binding.createConnection(); | ||
conn.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -37,3 +38,3 @@ conn.querySync("create table TEST_TRANS (ID INTEGER, NAME VARCHAR(20))"); | ||
conn.disconnect(); | ||
var con = new fb_binding.Connection; | ||
var con = fb_binding.createConnection(); | ||
con.connectSync(cfg.db, cfg.user, cfg.password, cfg.role); | ||
@@ -40,0 +41,0 @@ con.querySync("drop table TEST_TRANS;"); |
@@ -33,2 +33,10 @@ Nodeunit contributors (sorted alphabeticaly) | ||
* **[Λlisue](https://github.com/lambdalisue)** | ||
* Add machineout reporter | ||
* **[Matthias Lübken](https://github.com/luebken)** | ||
* Utility functions for tracking incomplete tests on exit | ||
* **[Oleg Efimov](https://github.com/Sannis)** | ||
@@ -56,3 +64,7 @@ | ||
* **[Maciej Małecki](https://github.com/mmalecki)** | ||
* Removal of `testCase` | ||
**[Full contributors list](https://github.com/caolan/nodeunit/contributors).** | ||
@@ -82,10 +82,10 @@ /*global setTimeout: false, console: false */ | ||
//// nextTick implementation with browser-compatible fallback //// | ||
async.nextTick = function (fn) { | ||
if (typeof process === 'undefined' || !(process.nextTick)) { | ||
if (typeof process === 'undefined' || !(process.nextTick)) { | ||
async.nextTick = function (fn) { | ||
setTimeout(fn, 0); | ||
} | ||
else { | ||
process.nextTick(fn); | ||
} | ||
}; | ||
}; | ||
} | ||
else { | ||
async.nextTick = process.nextTick; | ||
} | ||
@@ -603,2 +603,23 @@ async.forEach = function (arr, iterator, callback) { | ||
async.memoize = function (fn, hasher) { | ||
var memo = {}; | ||
hasher = hasher || function (x) { | ||
return x; | ||
}; | ||
return function () { | ||
var args = Array.prototype.slice.call(arguments); | ||
var callback = args.pop(); | ||
var key = hasher.apply(null, args); | ||
if (key in memo) { | ||
callback.apply(null, memo[key]); | ||
} | ||
else { | ||
fn.apply(null, args.concat([function () { | ||
memo[key] = arguments; | ||
callback.apply(null, arguments); | ||
}])); | ||
} | ||
}; | ||
}; | ||
}()); |
@@ -162,5 +162,3 @@ /* | ||
if (!this.JSON) { | ||
this.JSON = {}; | ||
} | ||
var JSON = {}; | ||
@@ -167,0 +165,0 @@ (function () { |
@@ -174,5 +174,3 @@ /*! | ||
if (!this.JSON) { | ||
this.JSON = {}; | ||
} | ||
var JSON = {}; | ||
@@ -497,3 +495,3 @@ (function () { | ||
}()); | ||
var assert = {}; | ||
var assert = this.assert = {}; | ||
var types = {}; | ||
@@ -503,3 +501,4 @@ var core = {}; | ||
var reporter = {}; | ||
(function(){ | ||
/*global setTimeout: false, console: false */ | ||
(function () { | ||
@@ -509,9 +508,13 @@ var async = {}; | ||
// global on the server, window in the browser | ||
var root = this; | ||
var previous_async = root.async; | ||
var root = this, | ||
previous_async = root.async; | ||
if(typeof module !== 'undefined' && module.exports) module.exports = async; | ||
else root.async = async; | ||
if (typeof module !== 'undefined' && module.exports) { | ||
module.exports = async; | ||
} | ||
else { | ||
root.async = async; | ||
} | ||
async.noConflict = function(){ | ||
async.noConflict = function () { | ||
root.async = previous_async; | ||
@@ -523,5 +526,7 @@ return async; | ||
var _forEach = function(arr, iterator){ | ||
if(arr.forEach) return arr.forEach(iterator); | ||
for(var i=0; i<arr.length; i++){ | ||
var _forEach = function (arr, iterator) { | ||
if (arr.forEach) { | ||
return arr.forEach(iterator); | ||
} | ||
for (var i = 0; i < arr.length; i += 1) { | ||
iterator(arr[i], i, arr); | ||
@@ -531,14 +536,18 @@ } | ||
var _map = function(arr, iterator){ | ||
if(arr.map) return arr.map(iterator); | ||
var _map = function (arr, iterator) { | ||
if (arr.map) { | ||
return arr.map(iterator); | ||
} | ||
var results = []; | ||
_forEach(arr, function(x, i, a){ | ||
_forEach(arr, function (x, i, a) { | ||
results.push(iterator(x, i, a)); | ||
}) | ||
}); | ||
return results; | ||
}; | ||
var _reduce = function(arr, iterator, memo){ | ||
if(arr.reduce) return arr.reduce(iterator, memo); | ||
_forEach(arr, function(x, i, a){ | ||
var _reduce = function (arr, iterator, memo) { | ||
if (arr.reduce) { | ||
return arr.reduce(iterator, memo); | ||
} | ||
_forEach(arr, function (x, i, a) { | ||
memo = iterator(memo, x, i, a); | ||
@@ -549,7 +558,11 @@ }); | ||
var _keys = function(obj){ | ||
if(Object.keys) return Object.keys(obj); | ||
var _keys = function (obj) { | ||
if (Object.keys) { | ||
return Object.keys(obj); | ||
} | ||
var keys = []; | ||
for(var k in obj){ | ||
if(obj.hasOwnProperty(k)) keys.push(k); | ||
for (var k in obj) { | ||
if (obj.hasOwnProperty(k)) { | ||
keys.push(k); | ||
} | ||
} | ||
@@ -559,7 +572,11 @@ return keys; | ||
var _indexOf = function(arr, item){ | ||
if(arr.indexOf) return arr.indexOf(item); | ||
for(var i=0; i<arr.length; i++){ | ||
if(arr[i] === item) return i; | ||
var _indexOf = function (arr, item) { | ||
if (arr.indexOf) { | ||
return arr.indexOf(item); | ||
} | ||
for (var i = 0; i < arr.length; i += 1) { | ||
if (arr[i] === item) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
@@ -571,21 +588,27 @@ }; | ||
//// nextTick implementation with browser-compatible fallback //// | ||
async.nextTick = function(fn){ | ||
if(typeof process == 'undefined' || !(process.nextTick)){ | ||
if (typeof process === 'undefined' || !(process.nextTick)) { | ||
async.nextTick = function (fn) { | ||
setTimeout(fn, 0); | ||
}; | ||
} | ||
else { | ||
async.nextTick = process.nextTick; | ||
} | ||
async.forEach = function (arr, iterator, callback) { | ||
if (!arr.length) { | ||
return callback(); | ||
} | ||
else process.nextTick(fn); | ||
}; | ||
async.forEach = function(arr, iterator, callback){ | ||
if(!arr.length) return callback(); | ||
var completed = 0; | ||
_forEach(arr, function(x){ | ||
iterator(x, function(err){ | ||
if(err){ | ||
_forEach(arr, function (x) { | ||
iterator(x, function (err) { | ||
if (err) { | ||
callback(err); | ||
callback = function(){}; | ||
callback = function () {}; | ||
} | ||
else { | ||
completed++; | ||
if(completed == arr.length) callback(); | ||
completed += 1; | ||
if (completed === arr.length) { | ||
callback(); | ||
} | ||
} | ||
@@ -596,15 +619,21 @@ }); | ||
async.forEachSeries = function(arr, iterator, callback){ | ||
if(!arr.length) return callback(); | ||
async.forEachSeries = function (arr, iterator, callback) { | ||
if (!arr.length) { | ||
return callback(); | ||
} | ||
var completed = 0; | ||
var iterate = function(){ | ||
iterator(arr[completed], function(err){ | ||
if(err){ | ||
var iterate = function () { | ||
iterator(arr[completed], function (err) { | ||
if (err) { | ||
callback(err); | ||
callback = function(){}; | ||
callback = function () {}; | ||
} | ||
else { | ||
completed++; | ||
if(completed == arr.length) callback(); | ||
else iterate(); | ||
completed += 1; | ||
if (completed === arr.length) { | ||
callback(); | ||
} | ||
else { | ||
iterate(); | ||
} | ||
} | ||
@@ -617,4 +646,4 @@ }); | ||
var doParallel = function(fn){ | ||
return function(){ | ||
var doParallel = function (fn) { | ||
return function () { | ||
var args = Array.prototype.slice.call(arguments); | ||
@@ -624,4 +653,4 @@ return fn.apply(null, [async.forEach].concat(args)); | ||
}; | ||
var doSeries = function(fn){ | ||
return function(){ | ||
var doSeries = function (fn) { | ||
return function () { | ||
var args = Array.prototype.slice.call(arguments); | ||
@@ -633,13 +662,13 @@ return fn.apply(null, [async.forEachSeries].concat(args)); | ||
var _asyncMap = function(eachfn, arr, iterator, callback){ | ||
var _asyncMap = function (eachfn, arr, iterator, callback) { | ||
var results = []; | ||
arr = _map(arr, function(x, i){ | ||
arr = _map(arr, function (x, i) { | ||
return {index: i, value: x}; | ||
}); | ||
eachfn(arr, function(x, callback){ | ||
iterator(x.value, function(err, v){ | ||
eachfn(arr, function (x, callback) { | ||
iterator(x.value, function (err, v) { | ||
results[x.index] = v; | ||
callback(err); | ||
}); | ||
}, function(err){ | ||
}, function (err) { | ||
callback(err, results); | ||
@@ -654,9 +683,9 @@ }); | ||
// work in many situations. | ||
async.reduce = function(arr, memo, iterator, callback){ | ||
async.forEachSeries(arr, function(x, callback){ | ||
iterator(memo, x, function(err, v){ | ||
async.reduce = function (arr, memo, iterator, callback) { | ||
async.forEachSeries(arr, function (x, callback) { | ||
iterator(memo, x, function (err, v) { | ||
memo = v; | ||
callback(err); | ||
}); | ||
}, function(err){ | ||
}, function (err) { | ||
callback(err, memo); | ||
@@ -670,4 +699,6 @@ }); | ||
async.reduceRight = function(arr, memo, iterator, callback){ | ||
var reversed = _map(arr, function(x){return x;}).reverse(); | ||
async.reduceRight = function (arr, memo, iterator, callback) { | ||
var reversed = _map(arr, function (x) { | ||
return x; | ||
}).reverse(); | ||
async.reduce(reversed, memo, iterator, callback); | ||
@@ -678,16 +709,18 @@ }; | ||
var _filter = function(eachfn, arr, iterator, callback){ | ||
var _filter = function (eachfn, arr, iterator, callback) { | ||
var results = []; | ||
arr = _map(arr, function(x, i){ | ||
arr = _map(arr, function (x, i) { | ||
return {index: i, value: x}; | ||
}); | ||
eachfn(arr, function(x, callback){ | ||
iterator(x.value, function(v){ | ||
if(v) results.push(x); | ||
eachfn(arr, function (x, callback) { | ||
iterator(x.value, function (v) { | ||
if (v) { | ||
results.push(x); | ||
} | ||
callback(); | ||
}); | ||
}, function(err){ | ||
callback(_map(results.sort(function(a,b){ | ||
}, function (err) { | ||
callback(_map(results.sort(function (a, b) { | ||
return a.index - b.index; | ||
}), function(x){ | ||
}), function (x) { | ||
return x.value; | ||
@@ -703,16 +736,18 @@ })); | ||
var _reject = function(eachfn, arr, iterator, callback){ | ||
var _reject = function (eachfn, arr, iterator, callback) { | ||
var results = []; | ||
arr = _map(arr, function(x, i){ | ||
arr = _map(arr, function (x, i) { | ||
return {index: i, value: x}; | ||
}); | ||
eachfn(arr, function(x, callback){ | ||
iterator(x.value, function(v){ | ||
if(!v) results.push(x); | ||
eachfn(arr, function (x, callback) { | ||
iterator(x.value, function (v) { | ||
if (!v) { | ||
results.push(x); | ||
} | ||
callback(); | ||
}); | ||
}, function(err){ | ||
callback(_map(results.sort(function(a,b){ | ||
}, function (err) { | ||
callback(_map(results.sort(function (a, b) { | ||
return a.index - b.index; | ||
}), function(x){ | ||
}), function (x) { | ||
return x.value; | ||
@@ -725,9 +760,13 @@ })); | ||
var _detect = function(eachfn, arr, iterator, main_callback){ | ||
eachfn(arr, function(x, callback){ | ||
iterator(x, function(result){ | ||
if(result) main_callback(x); | ||
else callback(); | ||
var _detect = function (eachfn, arr, iterator, main_callback) { | ||
eachfn(arr, function (x, callback) { | ||
iterator(x, function (result) { | ||
if (result) { | ||
main_callback(x); | ||
} | ||
else { | ||
callback(); | ||
} | ||
}); | ||
}, function(err){ | ||
}, function (err) { | ||
main_callback(); | ||
@@ -739,12 +778,12 @@ }); | ||
async.some = function(arr, iterator, main_callback){ | ||
async.forEach(arr, function(x, callback){ | ||
iterator(x, function(v){ | ||
if(v){ | ||
async.some = function (arr, iterator, main_callback) { | ||
async.forEach(arr, function (x, callback) { | ||
iterator(x, function (v) { | ||
if (v) { | ||
main_callback(true); | ||
main_callback = function(){}; | ||
main_callback = function () {}; | ||
} | ||
callback(); | ||
}); | ||
}, function(err){ | ||
}, function (err) { | ||
main_callback(false); | ||
@@ -756,12 +795,12 @@ }); | ||
async.every = function(arr, iterator, main_callback){ | ||
async.forEach(arr, function(x, callback){ | ||
iterator(x, function(v){ | ||
if(!v){ | ||
async.every = function (arr, iterator, main_callback) { | ||
async.forEach(arr, function (x, callback) { | ||
iterator(x, function (v) { | ||
if (!v) { | ||
main_callback(false); | ||
main_callback = function(){}; | ||
main_callback = function () {}; | ||
} | ||
callback(); | ||
}); | ||
}, function(err){ | ||
}, function (err) { | ||
main_callback(true); | ||
@@ -773,21 +812,34 @@ }); | ||
async.sortBy = function(arr, iterator, callback){ | ||
async.map(arr, function(x, callback){ | ||
iterator(x, function(err, criteria){ | ||
if(err) callback(err); | ||
else callback(null, {value: x, criteria: criteria}); | ||
async.sortBy = function (arr, iterator, callback) { | ||
async.map(arr, function (x, callback) { | ||
iterator(x, function (err, criteria) { | ||
if (err) { | ||
callback(err); | ||
} | ||
else { | ||
callback(null, {value: x, criteria: criteria}); | ||
} | ||
}); | ||
}, function(err, results){ | ||
if(err) return callback(err); | ||
else callback(null, _map(results.sort(function(left, right){ | ||
var a = left.criteria, b = right.criteria; | ||
return a < b ? -1 : a > b ? 1 : 0; | ||
}), function(x){return x.value;})); | ||
}) | ||
}, function (err, results) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
else { | ||
var fn = function (left, right) { | ||
var a = left.criteria, b = right.criteria; | ||
return a < b ? -1 : a > b ? 1 : 0; | ||
}; | ||
callback(null, _map(results.sort(fn), function (x) { | ||
return x.value; | ||
})); | ||
} | ||
}); | ||
}; | ||
async.auto = function(tasks, callback){ | ||
callback = callback || function(){}; | ||
async.auto = function (tasks, callback) { | ||
callback = callback || function () {}; | ||
var keys = _keys(tasks); | ||
if(!keys.length) return callback(null); | ||
if (!keys.length) { | ||
return callback(null); | ||
} | ||
@@ -797,8 +849,8 @@ var completed = []; | ||
var listeners = []; | ||
var addListener = function(fn){ | ||
var addListener = function (fn) { | ||
listeners.unshift(fn); | ||
}; | ||
var removeListener = function(fn){ | ||
for(var i=0; i<listeners.length; i++){ | ||
if(listeners[i] === fn){ | ||
var removeListener = function (fn) { | ||
for (var i = 0; i < listeners.length; i += 1) { | ||
if (listeners[i] === fn) { | ||
listeners.splice(i, 1); | ||
@@ -809,8 +861,10 @@ return; | ||
}; | ||
var taskComplete = function(){ | ||
_forEach(listeners, function(fn){fn();}); | ||
var taskComplete = function () { | ||
_forEach(listeners, function (fn) { | ||
fn(); | ||
}); | ||
}; | ||
addListener(function(){ | ||
if(completed.length == keys.length){ | ||
addListener(function () { | ||
if (completed.length === keys.length) { | ||
callback(null); | ||
@@ -820,9 +874,9 @@ } | ||
_forEach(keys, function(k){ | ||
var task = (tasks[k] instanceof Function)? [tasks[k]]: tasks[k]; | ||
var taskCallback = function(err){ | ||
if(err){ | ||
_forEach(keys, function (k) { | ||
var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; | ||
var taskCallback = function (err) { | ||
if (err) { | ||
callback(err); | ||
// stop subsequent errors hitting callback multiple times | ||
callback = function(){}; | ||
callback = function () {}; | ||
} | ||
@@ -834,14 +888,16 @@ else { | ||
}; | ||
var requires = task.slice(0, Math.abs(task.length-1)) || []; | ||
var ready = function(){ | ||
return _reduce(requires, function(a,x){ | ||
return (a && _indexOf(completed, x) != -1); | ||
var requires = task.slice(0, Math.abs(task.length - 1)) || []; | ||
var ready = function () { | ||
return _reduce(requires, function (a, x) { | ||
return (a && _indexOf(completed, x) !== -1); | ||
}, true); | ||
}; | ||
if(ready()) task[task.length-1](taskCallback); | ||
if (ready()) { | ||
task[task.length - 1](taskCallback); | ||
} | ||
else { | ||
var listener = function(){ | ||
if(ready()){ | ||
var listener = function () { | ||
if (ready()) { | ||
removeListener(listener); | ||
task[task.length-1](taskCallback); | ||
task[task.length - 1](taskCallback); | ||
} | ||
@@ -854,10 +910,12 @@ }; | ||
async.waterfall = function(tasks, callback){ | ||
if(!tasks.length) return callback(); | ||
callback = callback || function(){}; | ||
var wrapIterator = function(iterator){ | ||
return function(err){ | ||
if(err){ | ||
async.waterfall = function (tasks, callback) { | ||
if (!tasks.length) { | ||
return callback(); | ||
} | ||
callback = callback || function () {}; | ||
var wrapIterator = function (iterator) { | ||
return function (err) { | ||
if (err) { | ||
callback(err); | ||
callback = function(){}; | ||
callback = function () {}; | ||
} | ||
@@ -867,5 +925,11 @@ else { | ||
var next = iterator.next(); | ||
if(next) args.push(wrapIterator(next)); | ||
else args.push(callback); | ||
async.nextTick(function(){iterator.apply(null, args);}); | ||
if (next) { | ||
args.push(wrapIterator(next)); | ||
} | ||
else { | ||
args.push(callback); | ||
} | ||
async.nextTick(function () { | ||
iterator.apply(null, args); | ||
}); | ||
} | ||
@@ -877,36 +941,76 @@ }; | ||
async.parallel = function(tasks, callback){ | ||
callback = callback || function(){}; | ||
async.map(tasks, function(fn, callback){ | ||
if(fn){ | ||
fn(function(err){ | ||
var args = Array.prototype.slice.call(arguments,1); | ||
if(args.length <= 1) args = args[0]; | ||
callback.call(null, err, args || null); | ||
async.parallel = function (tasks, callback) { | ||
callback = callback || function () {}; | ||
if (tasks.constructor === Array) { | ||
async.map(tasks, function (fn, callback) { | ||
if (fn) { | ||
fn(function (err) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
if (args.length <= 1) { | ||
args = args[0]; | ||
} | ||
callback.call(null, err, args || null); | ||
}); | ||
} | ||
}, callback); | ||
} | ||
else { | ||
var results = {}; | ||
async.forEach(_keys(tasks), function (k, callback) { | ||
tasks[k](function (err) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
if (args.length <= 1) { | ||
args = args[0]; | ||
} | ||
results[k] = args; | ||
callback(err); | ||
}); | ||
} | ||
}, callback); | ||
}, function (err) { | ||
callback(err, results); | ||
}); | ||
} | ||
}; | ||
async.series = function(tasks, callback){ | ||
callback = callback || function(){}; | ||
async.mapSeries(tasks, function(fn, callback){ | ||
if(fn){ | ||
fn(function(err){ | ||
var args = Array.prototype.slice.call(arguments,1); | ||
if(args.length <= 1) args = args[0]; | ||
callback.call(null, err, args || null); | ||
async.series = function (tasks, callback) { | ||
callback = callback || function () {}; | ||
if (tasks.constructor === Array) { | ||
async.mapSeries(tasks, function (fn, callback) { | ||
if (fn) { | ||
fn(function (err) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
if (args.length <= 1) { | ||
args = args[0]; | ||
} | ||
callback.call(null, err, args || null); | ||
}); | ||
} | ||
}, callback); | ||
} | ||
else { | ||
var results = {}; | ||
async.forEachSeries(_keys(tasks), function (k, callback) { | ||
tasks[k](function (err) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
if (args.length <= 1) { | ||
args = args[0]; | ||
} | ||
results[k] = args; | ||
callback(err); | ||
}); | ||
} | ||
}, callback); | ||
}, function (err) { | ||
callback(err, results); | ||
}); | ||
} | ||
}; | ||
async.iterator = function(tasks){ | ||
var makeCallback = function(index){ | ||
var fn = function(){ | ||
if(tasks.length) tasks[index].apply(null, arguments); | ||
async.iterator = function (tasks) { | ||
var makeCallback = function (index) { | ||
var fn = function () { | ||
if (tasks.length) { | ||
tasks[index].apply(null, arguments); | ||
} | ||
return fn.next(); | ||
}; | ||
fn.next = function(){ | ||
return (index < tasks.length-1)? makeCallback(index+1): null; | ||
fn.next = function () { | ||
return (index < tasks.length - 1) ? makeCallback(index + 1): null; | ||
}; | ||
@@ -918,5 +1022,5 @@ return fn; | ||
async.apply = function(fn){ | ||
async.apply = function (fn) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
return function(){ | ||
return function () { | ||
return fn.apply( | ||
@@ -928,10 +1032,10 @@ null, args.concat(Array.prototype.slice.call(arguments)) | ||
var _concat = function(eachfn, arr, fn, callback){ | ||
var _concat = function (eachfn, arr, fn, callback) { | ||
var r = []; | ||
eachfn(arr, function(x, cb){ | ||
fn(x, function(err, y){ | ||
eachfn(arr, function (x, cb) { | ||
fn(x, function (err, y) { | ||
r = r.concat(y || []); | ||
cb(err); | ||
}); | ||
}, function(err){ | ||
}, function (err) { | ||
callback(err, r); | ||
@@ -943,13 +1047,74 @@ }); | ||
var _console_fn = function(name){ | ||
return function(fn){ | ||
async.whilst = function (test, iterator, callback) { | ||
if (test()) { | ||
iterator(function (err) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
async.whilst(test, iterator, callback); | ||
}); | ||
} | ||
else { | ||
callback(); | ||
} | ||
}; | ||
async.until = function (test, iterator, callback) { | ||
if (!test()) { | ||
iterator(function (err) { | ||
if (err) { | ||
return callback(err); | ||
} | ||
async.until(test, iterator, callback); | ||
}); | ||
} | ||
else { | ||
callback(); | ||
} | ||
}; | ||
async.queue = function (worker, concurrency) { | ||
var workers = 0; | ||
var tasks = []; | ||
var q = { | ||
concurrency: concurrency, | ||
push: function (data, callback) { | ||
tasks.push({data: data, callback: callback}); | ||
async.nextTick(q.process); | ||
}, | ||
process: function () { | ||
if (workers < q.concurrency && tasks.length) { | ||
var task = tasks.splice(0, 1)[0]; | ||
workers += 1; | ||
worker(task.data, function () { | ||
workers -= 1; | ||
if (task.callback) { | ||
task.callback.apply(task, arguments); | ||
} | ||
q.process(); | ||
}); | ||
} | ||
}, | ||
length: function () { | ||
return tasks.length; | ||
} | ||
}; | ||
return q; | ||
}; | ||
var _console_fn = function (name) { | ||
return function (fn) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
fn.apply(null, args.concat([function(err){ | ||
fn.apply(null, args.concat([function (err) { | ||
var args = Array.prototype.slice.call(arguments, 1); | ||
if(typeof console != 'undefined'){ | ||
if(err){ | ||
if(console.error) console.error(err); | ||
if (typeof console !== 'undefined') { | ||
if (err) { | ||
if (console.error) { | ||
console.error(err); | ||
} | ||
} | ||
else if(console[name]){ | ||
_forEach(args, function(x){console[name](x);}); | ||
else if (console[name]) { | ||
_forEach(args, function (x) { | ||
console[name](x); | ||
}); | ||
} | ||
@@ -966,3 +1131,24 @@ } | ||
})(); | ||
async.memoize = function (fn, hasher) { | ||
var memo = {}; | ||
hasher = hasher || function (x) { | ||
return x; | ||
}; | ||
return function () { | ||
var args = Array.prototype.slice.call(arguments); | ||
var callback = args.pop(); | ||
var key = hasher.apply(null, args); | ||
if (key in memo) { | ||
callback.apply(null, memo[key]); | ||
} | ||
else { | ||
fn.apply(null, args.concat([function () { | ||
memo[key] = arguments; | ||
callback.apply(null, arguments); | ||
}])); | ||
} | ||
}; | ||
}; | ||
}()); | ||
(function(exports){ | ||
@@ -982,2 +1168,5 @@ /** | ||
if(Object.keys) return Object.keys(obj); | ||
if (typeof obj != 'object' && typeof obj != 'function') { | ||
throw new TypeError('-'); | ||
} | ||
var keys = []; | ||
@@ -1132,12 +1321,2 @@ for(var k in obj){ | ||
return true; | ||
} else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { | ||
if (actual.length != expected.length) return false; | ||
for (var i = 0; i < actual.length; i++) { | ||
if (actual[i] !== expected[i]) return false; | ||
} | ||
return true; | ||
// 7.2. If the expected value is a Date object, the actual value is | ||
@@ -1305,2 +1484,3 @@ // equivalent if it is also a Date object that refers to the same time. | ||
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! | ||
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. | ||
* Only code on that line will be removed, its mostly to avoid requiring code | ||
@@ -1314,2 +1494,4 @@ * that is node specific | ||
//var assert = require('./assert'), //@REMOVE_LINE_FOR_BROWSER | ||
// async = require('../deps/async'); //@REMOVE_LINE_FOR_BROWSER | ||
@@ -1352,7 +1534,12 @@ | ||
var failures = 0; | ||
for (var i=0; i<this.length; i++) { | ||
if (this[i].failed()) failures++; | ||
for (var i = 0; i < this.length; i += 1) { | ||
if (this[i].failed()) { | ||
failures += 1; | ||
} | ||
} | ||
return failures; | ||
}; | ||
that.passes = function () { | ||
return that.length - that.failures(); | ||
}; | ||
that.duration = duration || 0; | ||
@@ -1373,3 +1560,3 @@ return that; | ||
return function () { | ||
var message = arguments[arity-1]; | ||
var message = arguments[arity - 1]; | ||
var a = exports.assertion({method: new_method, message: message}); | ||
@@ -1405,5 +1592,7 @@ try { | ||
a_list.push(a); | ||
async.nextTick(function () { | ||
options.log(a); | ||
}); | ||
if (options.log) { | ||
async.nextTick(function () { | ||
options.log(a); | ||
}); | ||
} | ||
}); | ||
@@ -1420,5 +1609,7 @@ | ||
a_list.push(a1); | ||
async.nextTick(function () { | ||
options.log(a1); | ||
}); | ||
if (options.log) { | ||
async.nextTick(function () { | ||
options.log(a1); | ||
}); | ||
} | ||
} | ||
@@ -1428,5 +1619,7 @@ if (err) { | ||
a_list.push(a2); | ||
async.nextTick(function () { | ||
options.log(a2); | ||
}); | ||
if (options.log) { | ||
async.nextTick(function () { | ||
options.log(a2); | ||
}); | ||
} | ||
} | ||
@@ -1475,3 +1668,3 @@ var end = new Date().getTime(); | ||
optionalCallback('testDone'); | ||
optionalCallback('log'); | ||
//optionalCallback('log'); | ||
@@ -1490,2 +1683,3 @@ // 'done' callback is not optional. | ||
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! | ||
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. | ||
* Only code on that line will be removed, its mostly to avoid requiring code | ||
@@ -1499,2 +1693,4 @@ * that is node specific | ||
//var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER | ||
// types = require('./types'); //@REMOVE_LINE_FOR_BROWSER | ||
@@ -1506,7 +1702,11 @@ | ||
var _keys = function(obj){ | ||
if(Object.keys) return Object.keys(obj); | ||
var _keys = function (obj) { | ||
if (Object.keys) { | ||
return Object.keys(obj); | ||
} | ||
var keys = []; | ||
for(var k in obj){ | ||
if(obj.hasOwnProperty(k)) keys.push(k); | ||
for (var k in obj) { | ||
if (obj.hasOwnProperty(k)) { | ||
keys.push(k); | ||
} | ||
} | ||
@@ -1517,2 +1717,12 @@ return keys; | ||
var _copy = function (obj) { | ||
var nobj = {}; | ||
var keys = _keys(obj); | ||
for (var i = 0; i < keys.length; i += 1) { | ||
nobj[keys[i]] = obj[keys[i]]; | ||
} | ||
return nobj; | ||
}; | ||
/** | ||
@@ -1574,3 +1784,17 @@ * Runs a test function (fn) from a loaded module. After the test function | ||
if (typeof prop === 'function') { | ||
exports.runTest(_name, suite[k], opt, cb); | ||
var in_name = false; | ||
for (var i = 0; i < _name.length; i += 1) { | ||
if (_name[i] === opt.testspec) { | ||
in_name = true; | ||
} | ||
} | ||
if (!opt.testspec || in_name) { | ||
if (opt.moduleStart) { | ||
opt.moduleStart(); | ||
} | ||
exports.runTest(_name, suite[k], opt, cb); | ||
} | ||
else { | ||
return cb(); | ||
} | ||
} | ||
@@ -1594,8 +1818,17 @@ else { | ||
exports.runModule = function (name, mod, opt, callback) { | ||
var options = types.options(opt); | ||
var options = _copy(types.options(opt)); | ||
options.moduleStart(name); | ||
var _run = false; | ||
var _moduleStart = options.moduleStart; | ||
function run_once() { | ||
if (!_run) { | ||
_run = true; | ||
_moduleStart(name); | ||
} | ||
} | ||
options.moduleStart = run_once; | ||
var start = new Date().getTime(); | ||
exports.runSuite(null, mod, opt, function (err, a_list) { | ||
exports.runSuite(null, mod, options, function (err, a_list) { | ||
var end = new Date().getTime(); | ||
@@ -1635,2 +1868,75 @@ var assertion_list = types.assertionList(a_list, end - start); | ||
/** | ||
* Wraps a test function with setUp and tearDown functions. | ||
* Used by testCase. | ||
* | ||
* @param {Function} setUp | ||
* @param {Function} tearDown | ||
* @param {Function} fn | ||
* @api private | ||
*/ | ||
var wrapTest = function (setUp, tearDown, fn) { | ||
return function (test) { | ||
var context = {}; | ||
if (tearDown) { | ||
var done = test.done; | ||
test.done = function (err) { | ||
try { | ||
tearDown.call(context, function (err2) { | ||
if (err && err2) { | ||
test._assertion_list.push( | ||
types.assertion({error: err}) | ||
); | ||
return done(err2); | ||
} | ||
done(err || err2); | ||
}); | ||
} | ||
catch (e) { | ||
done(e); | ||
} | ||
}; | ||
} | ||
if (setUp) { | ||
setUp.call(context, function (err) { | ||
if (err) { | ||
return test.done(err); | ||
} | ||
fn.call(context, test); | ||
}); | ||
} | ||
else { | ||
fn.call(context, test); | ||
} | ||
}; | ||
}; | ||
/** | ||
* Wraps a group of tests with setUp and tearDown functions. | ||
* Used by testCase. | ||
* | ||
* @param {Function} setUp | ||
* @param {Function} tearDown | ||
* @param {Object} group | ||
* @api private | ||
*/ | ||
var wrapGroup = function (setUp, tearDown, group) { | ||
var tests = {}; | ||
var keys = _keys(group); | ||
for (var i = 0; i < keys.length; i += 1) { | ||
var k = keys[i]; | ||
if (typeof group[k] === 'function') { | ||
tests[k] = wrapTest(setUp, tearDown, group[k]); | ||
} | ||
else if (typeof group[k] === 'object') { | ||
tests[k] = wrapGroup(setUp, tearDown, group[k]); | ||
} | ||
} | ||
return tests; | ||
}; | ||
/** | ||
* Utility for wrapping a suite of test functions with setUp and tearDown | ||
@@ -1645,4 +1951,2 @@ * functions. | ||
exports.testCase = function (suite) { | ||
var tests = {}; | ||
var setUp = suite.setUp; | ||
@@ -1652,43 +1956,3 @@ var tearDown = suite.tearDown; | ||
delete suite.tearDown; | ||
var keys = _keys(suite); | ||
// TODO: replace reduce here with browser-safe alternative | ||
return keys.reduce(function (tests, k) { | ||
tests[k] = function (test) { | ||
var context = {}; | ||
if (tearDown) { | ||
var done = test.done; | ||
test.done = function (err) { | ||
try { | ||
tearDown.call(context, function (err2) { | ||
if (err && err2) { | ||
test._assertion_list.push( | ||
types.assertion({error: err}) | ||
); | ||
return done(err2); | ||
} | ||
done(err || err2); | ||
}); | ||
} | ||
catch (e) { | ||
done(e); | ||
} | ||
}; | ||
} | ||
if (setUp) { | ||
setUp.call(context, function (err) { | ||
if (err) { | ||
return test.done(err); | ||
} | ||
suite[k].call(context, test); | ||
}); | ||
} | ||
else { | ||
suite[k].call(context, test); | ||
} | ||
}; | ||
return tests; | ||
}, {}); | ||
return wrapGroup(setUp, tearDown, suite); | ||
}; | ||
@@ -1703,2 +1967,3 @@ })(core); | ||
* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! | ||
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. | ||
* Only code on that line will be removed, its mostly to avoid requiring code | ||
@@ -1722,26 +1987,2 @@ * that is node specific | ||
exports.addStyles = function () { | ||
document.body.innerHTML += '<style type="text/css">' + | ||
'body { font: 12px Helvetica Neue }' + | ||
'h2 { margin:0 ; padding:0 }' + | ||
'pre {' + | ||
'font: 11px Andale Mono;' + | ||
'margin-left: 1em;' + | ||
'padding-left: 1em;' + | ||
'margin-top: 0;' + | ||
'font-size:smaller;' + | ||
'}' + | ||
'.assertion_message { margin-left: 1em; }' + | ||
' ol {' + | ||
'list-style: none;' + | ||
'margin-left: 1em;' + | ||
'padding-left: 1em;' + | ||
'text-indent: -1em;' + | ||
'}' + | ||
' ol li.pass:before { content: "\\2714 \\0020"; }' + | ||
' ol li.fail:before { content: "\\2716 \\0020"; }' + | ||
'</style>'; | ||
}; | ||
/** | ||
@@ -1756,48 +1997,84 @@ * Run all tests within each module, reporting the results | ||
var start = new Date().getTime(); | ||
exports.addStyles(); | ||
var html = ''; | ||
function setText(el, txt) { | ||
if ('innerText' in el) { | ||
el.innerText = txt; | ||
} | ||
else if ('textContent' in el){ | ||
el.textContent = txt; | ||
} | ||
} | ||
function getOrCreate(tag, id) { | ||
var el = document.getElementById(id); | ||
if (!el) { | ||
el = document.createElement(tag); | ||
el.id = id; | ||
document.body.appendChild(el); | ||
} | ||
return el; | ||
}; | ||
var header = getOrCreate('h1', 'nodeunit-header'); | ||
var banner = getOrCreate('h2', 'nodeunit-banner'); | ||
var userAgent = getOrCreate('h2', 'nodeunit-userAgent'); | ||
var tests = getOrCreate('ol', 'nodeunit-tests'); | ||
var result = getOrCreate('p', 'nodeunit-testresult'); | ||
setText(userAgent, navigator.userAgent); | ||
nodeunit.runModules(modules, { | ||
moduleStart: function (name) { | ||
html += '<h2>' + name + '</h2>'; | ||
html += '<ol>'; | ||
/*var mheading = document.createElement('h2'); | ||
mheading.innerText = name; | ||
results.appendChild(mheading); | ||
module = document.createElement('ol'); | ||
results.appendChild(module);*/ | ||
}, | ||
testDone: function (name, assertions) { | ||
if (!assertions.failures()) { | ||
html += '<li class="pass">' + name + '</li>'; | ||
var test = document.createElement('li'); | ||
var strong = document.createElement('strong'); | ||
strong.innerHTML = name + ' <b style="color: black;">(' + | ||
'<b class="fail">' + assertions.failures() + '</b>, ' + | ||
'<b class="pass">' + assertions.passes() + '</b>, ' + | ||
assertions.length + | ||
')</b>'; | ||
test.className = assertions.failures() ? 'fail': 'pass'; | ||
test.appendChild(strong); | ||
var aList = document.createElement('ol'); | ||
aList.style.display = 'none'; | ||
test.onclick = function () { | ||
var d = aList.style.display; | ||
aList.style.display = (d == 'none') ? 'block': 'none'; | ||
}; | ||
for (var i=0; i<assertions.length; i++) { | ||
var li = document.createElement('li'); | ||
var a = assertions[i]; | ||
if (a.failed()) { | ||
li.innerHTML = (a.message || a.method || 'no message') + | ||
'<pre>' + (a.error.stack || a.error) + '</pre>'; | ||
li.className = 'fail'; | ||
} | ||
else { | ||
li.innerHTML = a.message || a.method || 'no message'; | ||
li.className = 'pass'; | ||
} | ||
aList.appendChild(li); | ||
} | ||
else { | ||
html += '<li class="fail">' + name; | ||
for (var i=0; i<assertions.length; i++) { | ||
var a = assertions[i]; | ||
if (a.failed()) { | ||
if (a.error instanceof assert.AssertionError && a.message) { | ||
html += '<div class="assertion_message">' + | ||
'Assertion Message: ' + a.message + | ||
'</div>'; | ||
} | ||
html += '<pre>'; | ||
html += a.error.stack || a.error; | ||
html += '</pre>'; | ||
} | ||
}; | ||
html += '</li>'; | ||
} | ||
test.appendChild(aList); | ||
tests.appendChild(test); | ||
}, | ||
moduleDone: function () { | ||
html += '</ol>'; | ||
}, | ||
done: function (assertions) { | ||
var end = new Date().getTime(); | ||
var duration = end - start; | ||
if (assertions.failures()) { | ||
html += '<h3>FAILURES: ' + assertions.failures() + | ||
'/' + assertions.length + ' assertions failed (' + | ||
assertions.duration + 'ms)</h3>'; | ||
} | ||
else { | ||
html += '<h3>OK: ' + assertions.length + | ||
' assertions (' + assertions.duration + 'ms)</h3>'; | ||
} | ||
document.body.innerHTML += html; | ||
var failures = assertions.failures(); | ||
banner.className = failures ? 'fail': 'pass'; | ||
result.innerHTML = 'Tests completed in ' + duration + | ||
' milliseconds.<br/><span class="passed">' + | ||
assertions.passes() + '</span> assertions of ' + | ||
'<span class="all">' + assertions.length + '<span> passed, ' + | ||
assertions.failures() + ' failed.'; | ||
} | ||
@@ -1804,0 +2081,0 @@ }); |
@@ -14,2 +14,5 @@ /** | ||
if(Object.keys) return Object.keys(obj); | ||
if (typeof obj != 'object' && typeof obj != 'function') { | ||
throw new TypeError('-'); | ||
} | ||
var keys = []; | ||
@@ -169,2 +172,10 @@ for(var k in obj){ | ||
// 7.2.1 If the expcted value is a RegExp object, the actual value is | ||
// equivalent if it is also a RegExp object that refers to the same source and options | ||
} else if (actual instanceof RegExp && expected instanceof RegExp) { | ||
return actual.source === expected.source && | ||
actual.global === expected.global && | ||
actual.ignoreCase === expected.ignoreCase && | ||
actual.multiline === expected.multiline; | ||
// 7.3. Other pairs that do not both pass typeof value == "object", | ||
@@ -171,0 +182,0 @@ // equivalence is determined by ==. |
@@ -8,3 +8,3 @@ /*! | ||
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. | ||
* Only code on that line will be removed, its mostly to avoid requiring code | ||
* Only code on that line will be removed, it's mostly to avoid requiring code | ||
* that is node specific | ||
@@ -17,4 +17,5 @@ */ | ||
var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER | ||
types = require('./types'); //@REMOVE_LINE_FOR_BROWSER | ||
var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER | ||
nodeunit = require('./nodeunit'), //@REMOVE_LINE_FOR_BROWSER | ||
types = require('./types'); //@REMOVE_LINE_FOR_BROWSER | ||
@@ -26,7 +27,11 @@ | ||
var _keys = function(obj){ | ||
if(Object.keys) return Object.keys(obj); | ||
var _keys = function (obj) { | ||
if (Object.keys) { | ||
return Object.keys(obj); | ||
} | ||
var keys = []; | ||
for(var k in obj){ | ||
if(obj.hasOwnProperty(k)) keys.push(k); | ||
for (var k in obj) { | ||
if (obj.hasOwnProperty(k)) { | ||
keys.push(k); | ||
} | ||
} | ||
@@ -37,2 +42,12 @@ return keys; | ||
var _copy = function (obj) { | ||
var nobj = {}; | ||
var keys = _keys(obj); | ||
for (var i = 0; i < keys.length; i += 1) { | ||
nobj[keys[i]] = obj[keys[i]]; | ||
} | ||
return nobj; | ||
}; | ||
/** | ||
@@ -81,2 +96,3 @@ * Runs a test function (fn) from a loaded module. After the test function | ||
exports.runSuite = function (name, suite, opt, callback) { | ||
suite = wrapGroup(suite); | ||
var keys = _keys(suite); | ||
@@ -88,3 +104,2 @@ | ||
_name = name ? [].concat(name, k) : [k]; | ||
_name.toString = function () { | ||
@@ -96,3 +111,17 @@ // fallback for old one | ||
if (typeof prop === 'function') { | ||
exports.runTest(_name, suite[k], opt, cb); | ||
var in_name = false; | ||
for (var i = 0; i < _name.length; i += 1) { | ||
if (_name[i] === opt.testspec) { | ||
in_name = true; | ||
} | ||
} | ||
if (!opt.testspec || in_name) { | ||
if (opt.moduleStart) { | ||
opt.moduleStart(); | ||
} | ||
exports.runTest(_name, suite[k], opt, cb); | ||
} | ||
else { | ||
return cb(); | ||
} | ||
} | ||
@@ -116,11 +145,26 @@ else { | ||
exports.runModule = function (name, mod, opt, callback) { | ||
var options = types.options(opt); | ||
var options = _copy(types.options(opt)); | ||
options.moduleStart(name); | ||
var _run = false; | ||
var _moduleStart = options.moduleStart; | ||
mod = wrapGroup(mod); | ||
function run_once() { | ||
if (!_run) { | ||
_run = true; | ||
_moduleStart(name); | ||
} | ||
} | ||
options.moduleStart = run_once; | ||
var start = new Date().getTime(); | ||
exports.runSuite(null, mod, opt, function (err, a_list) { | ||
exports.runSuite(null, mod, options, function (err, a_list) { | ||
var end = new Date().getTime(); | ||
var assertion_list = types.assertionList(a_list, end - start); | ||
options.moduleDone(name, assertion_list); | ||
if (nodeunit.complete) { | ||
nodeunit.complete(name, assertion_list); | ||
} | ||
callback(null, a_list); | ||
@@ -199,3 +243,30 @@ }); | ||
} | ||
}; | ||
}; | ||
/** | ||
* Returns a serial callback from two functions. | ||
* | ||
* @param {Function} funcFirst | ||
* @param {Function} funcSecond | ||
* @api private | ||
*/ | ||
var getSerialCallback = function (fns) { | ||
if (!fns.length) { | ||
return null; | ||
} | ||
return function (callback) { | ||
var that = this; | ||
var bound_fns = []; | ||
for (var i = 0, len = fns.length; i < len; i++) { | ||
(function (j) { | ||
bound_fns.push(function () { | ||
return fns[j].apply(that, arguments); | ||
}); | ||
})(i); | ||
} | ||
return async.series(bound_fns, callback); | ||
}; | ||
}; | ||
@@ -208,39 +279,48 @@ | ||
* | ||
* @param {Function} setUp | ||
* @param {Function} tearDown | ||
* @param {Object} group | ||
* @param {Array} setUps - parent setUp functions | ||
* @param {Array} tearDowns - parent tearDown functions | ||
* @api private | ||
*/ | ||
var wrapGroup = function (setUp, tearDown, group) { | ||
var wrapGroup = function (group, setUps, tearDowns) { | ||
var tests = {}; | ||
var setUps = setUps ? setUps.slice(): []; | ||
var tearDowns = tearDowns ? tearDowns.slice(): []; | ||
if (group.setUp) { | ||
setUps.push(group.setUp); | ||
delete group.setUp; | ||
} | ||
if (group.tearDown) { | ||
tearDowns.unshift(group.tearDown); | ||
delete group.tearDown; | ||
} | ||
var keys = _keys(group); | ||
for (var i=0; i<keys.length; i++) { | ||
for (var i = 0; i < keys.length; i += 1) { | ||
var k = keys[i]; | ||
if (typeof group[k] === 'function') { | ||
tests[k] = wrapTest(setUp, tearDown, group[k]); | ||
tests[k] = wrapTest( | ||
getSerialCallback(setUps), | ||
getSerialCallback(tearDowns), | ||
group[k] | ||
); | ||
} | ||
else if (typeof group[k] === 'object') { | ||
tests[k] = wrapGroup(setUp, tearDown, group[k]); | ||
tests[k] = wrapGroup(group[k], setUps, tearDowns); | ||
} | ||
} | ||
return tests; | ||
} | ||
}; | ||
/** | ||
* Utility for wrapping a suite of test functions with setUp and tearDown | ||
* functions. | ||
* | ||
* @param {Object} suite | ||
* @return {Object} | ||
* @api public | ||
* Backwards compatibility for test suites using old testCase API | ||
*/ | ||
exports.testCase = function (suite) { | ||
var setUp = suite.setUp; | ||
var tearDown = suite.tearDown; | ||
delete suite.setUp; | ||
delete suite.tearDown; | ||
return wrapGroup(setUp, tearDown, suite); | ||
return suite; | ||
}; |
@@ -16,3 +16,5 @@ /*! | ||
reporters = require('./reporters'), | ||
path = require('path'); | ||
assert = require('./assert'), | ||
path = require('path') | ||
events = require('events'); | ||
@@ -27,2 +29,3 @@ | ||
exports.reporters = reporters; | ||
exports.assert = assert; | ||
@@ -78,2 +81,3 @@ // backwards compatibility | ||
var end = new Date().getTime(); | ||
exports.done() | ||
options.done(types.assertionList(all_assertions, end - start)); | ||
@@ -84,1 +88,21 @@ }); | ||
}; | ||
/* Export all prototypes from events.EventEmitter */ | ||
var label; | ||
for (label in events.EventEmitter.prototype) { | ||
exports[label] = events.EventEmitter.prototype[label]; | ||
} | ||
/* Emit event 'complete' on completion of a test suite. */ | ||
exports.complete = function(name, assertions) | ||
{ | ||
exports.emit('complete', name, assertions); | ||
}; | ||
/* Emit event 'complete' on completion of all tests. */ | ||
exports.done = function() | ||
{ | ||
exports.emit('done'); | ||
}; | ||
module.exports = exports; |
@@ -34,3 +34,5 @@ /*! | ||
exports.run = function (modules, options) { | ||
var start = new Date().getTime(); | ||
var start = new Date().getTime(), div; | ||
options = options || {}; | ||
div = options.div || document.body; | ||
@@ -51,3 +53,3 @@ function setText(el, txt) { | ||
el.id = id; | ||
document.body.appendChild(el); | ||
div.appendChild(el); | ||
} | ||
@@ -54,0 +56,0 @@ return el; |
@@ -14,4 +14,4 @@ /*! | ||
fs = require('fs'), | ||
sys = require('sys'), | ||
path = require('path'); | ||
track = require('../track'), | ||
path = require('path'), | ||
AssertionError = require('../assert').AssertionError; | ||
@@ -33,3 +33,3 @@ | ||
exports.run = function (files, options) { | ||
exports.run = function (files, options, callback) { | ||
@@ -58,16 +58,31 @@ if (!options) { | ||
var start = new Date().getTime(); | ||
var paths = files.map(function (p) { | ||
return path.join(process.cwd(), p); | ||
var tracker = track.createTracker(function (tracker) { | ||
if (tracker.unfinished()) { | ||
console.log(''); | ||
console.log(error(bold( | ||
'FAILURES: Undone tests (or their setups/teardowns): ' | ||
))); | ||
var names = tracker.names(); | ||
for (var i = 0; i < names.length; i += 1) { | ||
console.log('- ' + names[i]); | ||
} | ||
console.log(''); | ||
console.log('To fix this, make sure all tests call test.done()'); | ||
process.reallyExit(tracker.unfinished()); | ||
} | ||
}); | ||
nodeunit.runFiles(paths, { | ||
var opts = { | ||
testspec: options.testspec, | ||
moduleStart: function (name) { | ||
sys.puts('\n' + bold(name)); | ||
console.log('\n' + bold(name)); | ||
}, | ||
testDone: function (name, assertions) { | ||
tracker.remove(name); | ||
if (!assertions.failures()) { | ||
sys.puts('✔ ' + name); | ||
console.log('✔ ' + name); | ||
} | ||
else { | ||
sys.puts(error('✖ ' + name) + '\n'); | ||
console.log(error('✖ ' + name) + '\n'); | ||
assertions.forEach(function (a) { | ||
@@ -77,3 +92,3 @@ if (a.failed()) { | ||
if (a.error instanceof AssertionError && a.message) { | ||
sys.puts( | ||
console.log( | ||
'Assertion Message: ' + | ||
@@ -83,3 +98,3 @@ assertion_message(a.message) | ||
} | ||
sys.puts(a.error.stack + '\n'); | ||
console.log(a.error.stack + '\n'); | ||
} | ||
@@ -89,7 +104,7 @@ }); | ||
}, | ||
done: function (assertions) { | ||
var end = new Date().getTime(); | ||
done: function (assertions, end) { | ||
var end = end || new Date().getTime(); | ||
var duration = end - start; | ||
if (assertions.failures()) { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(error('FAILURES: ')) + assertions.failures() + | ||
@@ -101,17 +116,22 @@ '/' + assertions.length + ' assertions failed (' + | ||
else { | ||
sys.puts( | ||
'\n' + bold(ok('OK: ')) + assertions.length + | ||
' assertions (' + assertions.duration + 'ms)' | ||
console.log( | ||
'\n' + bold(ok('OK: ')) + assertions.length + | ||
' assertions (' + assertions.duration + 'ms)' | ||
); | ||
} | ||
// alexgorbatchev 2010-11-10 :: should be able to flush stdout | ||
// here, but doesn't seem to work, instead delay the exit to give | ||
// enough to time flush. | ||
// process.stdout.flush() | ||
// process.stdout.end() | ||
setTimeout(function () { | ||
process.reallyExit(assertions.failures()); | ||
}, 10); | ||
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); | ||
}, | ||
testStart: function(name) { | ||
tracker.put(name); | ||
} | ||
}); | ||
}; | ||
if (files && files.length) { | ||
var paths = files.map(function (p) { | ||
return path.join(process.cwd(), p); | ||
}); | ||
nodeunit.runFiles(paths, opts); | ||
} else { | ||
nodeunit.runModules(files,opts); | ||
} | ||
}; |
@@ -14,3 +14,2 @@ /*! | ||
fs = require('fs'), | ||
sys = require('sys'), | ||
path = require('path'), | ||
@@ -32,3 +31,3 @@ AssertionError = require('assert').AssertionError; | ||
exports.run = function (files, options) { | ||
exports.run = function (files, options, callback) { | ||
@@ -40,11 +39,11 @@ var start = new Date().getTime(); | ||
sys.puts('<html>'); | ||
sys.puts('<head>'); | ||
sys.puts('<title></title>'); | ||
sys.puts('<style type="text/css">'); | ||
sys.puts('body { font: 12px Helvetica Neue }'); | ||
sys.puts('h2 { margin:0 ; padding:0 }'); | ||
sys.puts('pre { font: 11px Andale Mono; margin-left: 1em; padding-left: 1em; margin-top:0; font-size:smaller;}'); | ||
sys.puts('.assertion_message { margin-left: 1em; }'); | ||
sys.puts(' ol {' + | ||
console.log('<html>'); | ||
console.log('<head>'); | ||
console.log('<title></title>'); | ||
console.log('<style type="text/css">'); | ||
console.log('body { font: 12px Helvetica Neue }'); | ||
console.log('h2 { margin:0 ; padding:0 }'); | ||
console.log('pre { font: 11px Andale Mono; margin-left: 1em; padding-left: 1em; margin-top:0; font-size:smaller;}'); | ||
console.log('.assertion_message { margin-left: 1em; }'); | ||
console.log(' ol {' + | ||
' list-style: none;' + | ||
@@ -55,18 +54,19 @@ ' margin-left: 1em;' + | ||
'}'); | ||
sys.puts(' ol li.pass:before { content: "\\2714 \\0020"; }'); | ||
sys.puts(' ol li.fail:before { content: "\\2716 \\0020"; }'); | ||
sys.puts('</style>'); | ||
sys.puts('</head>'); | ||
sys.puts('<body>'); | ||
console.log(' ol li.pass:before { content: "\\2714 \\0020"; }'); | ||
console.log(' ol li.fail:before { content: "\\2716 \\0020"; }'); | ||
console.log('</style>'); | ||
console.log('</head>'); | ||
console.log('<body>'); | ||
nodeunit.runFiles(paths, { | ||
testspec: options.testspec, | ||
moduleStart: function (name) { | ||
sys.puts('<h2>' + name + '</h2>'); | ||
sys.puts('<ol>'); | ||
console.log('<h2>' + name + '</h2>'); | ||
console.log('<ol>'); | ||
}, | ||
testDone: function (name, assertions) { | ||
if (!assertions.failures()) { | ||
sys.puts('<li class="pass">' + name + '</li>'); | ||
console.log('<li class="pass">' + name + '</li>'); | ||
} | ||
else { | ||
sys.puts('<li class="fail">' + name); | ||
console.log('<li class="fail">' + name); | ||
assertions.forEach(function (a) { | ||
@@ -76,16 +76,16 @@ if (a.failed()) { | ||
if (a.error instanceof AssertionError && a.message) { | ||
sys.puts('<div class="assertion_message">' + | ||
console.log('<div class="assertion_message">' + | ||
'Assertion Message: ' + a.message + | ||
'</div>'); | ||
} | ||
sys.puts('<pre>'); | ||
sys.puts(a.error.stack); | ||
sys.puts('</pre>'); | ||
console.log('<pre>'); | ||
console.log(a.error.stack); | ||
console.log('</pre>'); | ||
} | ||
}); | ||
sys.puts('</li>'); | ||
console.log('</li>'); | ||
} | ||
}, | ||
moduleDone: function () { | ||
sys.puts('</ol>'); | ||
console.log('</ol>'); | ||
}, | ||
@@ -96,3 +96,3 @@ done: function (assertions) { | ||
if (assertions.failures()) { | ||
sys.puts( | ||
console.log( | ||
'<h3>FAILURES: ' + assertions.failures() + | ||
@@ -104,3 +104,3 @@ '/' + assertions.length + ' assertions failed (' + | ||
else { | ||
sys.puts( | ||
console.log( | ||
'<h3>OK: ' + assertions.length + | ||
@@ -110,11 +110,8 @@ ' assertions (' + assertions.duration + 'ms)</h3>' | ||
} | ||
sys.puts('</body>'); | ||
// should be able to flush stdout here, but doesn't seem to work, | ||
// instead delay the exit to give enough to time flush. | ||
setTimeout(function () { | ||
process.reallyExit(assertions.failures()); | ||
}, 10); | ||
console.log('</body>'); | ||
console.log('</html>'); | ||
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); | ||
} | ||
}); | ||
}; |
@@ -6,5 +6,10 @@ module.exports = { | ||
'minimal': require('./minimal'), | ||
'html': require('./html') | ||
'html': require('./html'), | ||
'eclipse': require('./eclipse'), | ||
'machineout': require('./machineout'), | ||
'tap': require('./tap'), | ||
'nested': require('./nested'), | ||
'verbose' : require('./verbose') | ||
// browser test reporter is not listed because it cannot be used | ||
// with the command line tool, only inside a browser. | ||
}; |
@@ -14,3 +14,2 @@ /*! | ||
fs = require('fs'), | ||
sys = require('sys'), | ||
path = require('path'), | ||
@@ -106,2 +105,3 @@ async = require('../../deps/async'), | ||
nodeunit.runFiles(paths, { | ||
testspec: opts.testspec, | ||
moduleStart: function (name) { | ||
@@ -119,3 +119,3 @@ curModule = { | ||
var testcase = {name: name}; | ||
for (var i=0; i<assertions.length; assertions++) { | ||
for (var i=0; i<assertions.length; i++) { | ||
var a = assertions[i]; | ||
@@ -160,3 +160,3 @@ if (a.failed()) { | ||
); | ||
sys.puts('Writing ' + filename); | ||
console.log('Writing ' + filename); | ||
fs.writeFile(filename, rendered, cb); | ||
@@ -167,3 +167,3 @@ }, | ||
else if (assertions.failures()) { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(error('FAILURES: ')) + | ||
@@ -176,3 +176,3 @@ assertions.failures() + '/' + | ||
else { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(ok('OK: ')) + assertions.length + | ||
@@ -184,7 +184,7 @@ ' assertions (' + assertions.duration + 'ms)' | ||
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); | ||
}); | ||
}); | ||
} | ||
}); | ||
} |
@@ -14,3 +14,2 @@ /*! | ||
fs = require('fs'), | ||
sys = require('sys'), | ||
path = require('path'), | ||
@@ -32,3 +31,3 @@ AssertionError = require('assert').AssertionError; | ||
exports.run = function (files, options) { | ||
exports.run = function (files, options, callback) { | ||
@@ -57,12 +56,10 @@ if (!options) { | ||
var start = new Date().getTime(); | ||
var paths = files.map(function (p) { | ||
return path.join(process.cwd(), p); | ||
}); | ||
nodeunit.runFiles(paths, { | ||
var opts = { | ||
testspec: options.testspec, | ||
moduleStart: function (name) { | ||
sys.print(bold(name) + ': '); | ||
process.stdout.write(bold(name) + ': '); | ||
}, | ||
moduleDone: function (name, assertions) { | ||
sys.puts(''); | ||
console.log(''); | ||
if (assertions.failures()) { | ||
@@ -73,3 +70,3 @@ assertions.forEach(function (a) { | ||
if (a.error instanceof AssertionError && a.message) { | ||
sys.puts( | ||
console.log( | ||
'Assertion in test ' + bold(a.testname) + ': ' + | ||
@@ -79,3 +76,3 @@ magenta(a.message) | ||
} | ||
sys.puts(a.error.stack + '\n'); | ||
console.log(a.error.stack + '\n'); | ||
} | ||
@@ -90,6 +87,6 @@ }); | ||
if (!assertions.failures()) { | ||
sys.print('.'); | ||
process.stdout.write('.'); | ||
} | ||
else { | ||
sys.print(red('F')); | ||
process.stdout.write(red('F')); | ||
assertions.forEach(function (assertion) { | ||
@@ -104,3 +101,3 @@ assertion.testname = name; | ||
if (assertions.failures()) { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(red('FAILURES: ')) + assertions.failures() + | ||
@@ -112,3 +109,3 @@ '/' + assertions.length + ' assertions failed (' + | ||
else { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(green('OK: ')) + assertions.length + | ||
@@ -118,9 +115,15 @@ ' assertions (' + assertions.duration + 'ms)' | ||
} | ||
// should be able to flush stdout here, but doesn't seem to work, | ||
// instead delay the exit to give enough to time flush. | ||
setTimeout(function () { | ||
process.reallyExit(assertions.failures()); | ||
}, 10); | ||
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); | ||
} | ||
}); | ||
}; | ||
if (files && files.length) { | ||
var paths = files.map(function (p) { | ||
return path.join(process.cwd(), p); | ||
}); | ||
nodeunit.runFiles(paths, opts); | ||
} else { | ||
nodeunit.runModules(files,opts); | ||
} | ||
}; |
@@ -14,3 +14,2 @@ /*! | ||
fs = require('fs'), | ||
sys = require('sys'), | ||
path = require('path'), | ||
@@ -32,3 +31,3 @@ AssertionError = require('assert').AssertionError; | ||
exports.run = function (files, options) { | ||
exports.run = function (files, options, callback) { | ||
@@ -62,8 +61,9 @@ if (!options) { | ||
nodeunit.runFiles(paths, { | ||
testspec: options.testspec, | ||
moduleStart: function (name) { | ||
sys.puts('\n' + bold(name)); | ||
console.log('\n' + bold(name)); | ||
}, | ||
testDone: function (name, assertions) { | ||
if (assertions.failures()) { | ||
sys.puts(error('✖ ' + name) + '\n'); | ||
console.log(error('✖ ' + name) + '\n'); | ||
assertions.forEach(function (a) { | ||
@@ -73,7 +73,7 @@ if (a.failed()) { | ||
if (a.error instanceof AssertionError && a.message) { | ||
sys.puts( | ||
console.log( | ||
'Assertion Message: ' + assertion_message(a.message) | ||
); | ||
} | ||
sys.puts(a.error.stack + '\n'); | ||
console.log(a.error.stack + '\n'); | ||
} | ||
@@ -85,6 +85,6 @@ }); | ||
if (!assertions.failures()) { | ||
sys.puts('✔ all tests passed'); | ||
console.log('✔ all tests passed'); | ||
} | ||
else { | ||
sys.puts(error('✖ some tests failed')); | ||
console.log(error('✖ some tests failed')); | ||
} | ||
@@ -96,3 +96,3 @@ }, | ||
if (assertions.failures()) { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(error('FAILURES: ')) + assertions.failures() + | ||
@@ -104,3 +104,3 @@ '/' + assertions.length + ' assertions failed (' + | ||
else { | ||
sys.puts( | ||
console.log( | ||
'\n' + bold(ok('OK: ')) + assertions.length + | ||
@@ -110,9 +110,6 @@ ' assertions (' + assertions.duration + 'ms)' | ||
} | ||
// should be able to flush stdout here, but doesn't seem to work, | ||
// instead delay the exit to give enough to time flush. | ||
setTimeout(function () { | ||
process.reallyExit(assertions.failures()); | ||
}, 10); | ||
if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); | ||
} | ||
}); | ||
}; |
@@ -8,3 +8,3 @@ /*! | ||
* You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build. | ||
* Only code on that line will be removed, its mostly to avoid requiring code | ||
* Only code on that line will be removed, it's mostly to avoid requiring code | ||
* that is node specific | ||
@@ -56,4 +56,6 @@ */ | ||
var failures = 0; | ||
for (var i=0; i<this.length; i++) { | ||
if (this[i].failed()) failures++; | ||
for (var i = 0; i < this.length; i += 1) { | ||
if (this[i].failed()) { | ||
failures += 1; | ||
} | ||
} | ||
@@ -71,3 +73,3 @@ return failures; | ||
* Create a wrapper function for assert module methods. Executes a callback | ||
* after the it's complete with an assertion object representing the result. | ||
* after it's complete with an assertion object representing the result. | ||
* | ||
@@ -81,3 +83,3 @@ * @param {Function} callback | ||
return function () { | ||
var message = arguments[arity-1]; | ||
var message = arguments[arity - 1]; | ||
var a = exports.assertion({method: new_method, message: message}); | ||
@@ -84,0 +86,0 @@ try { |
@@ -13,3 +13,3 @@ /*! | ||
fs = require('fs'), | ||
sys = require('sys'), | ||
util = require('util'), | ||
Script = process.binding('evals').Script, | ||
@@ -194,4 +194,4 @@ http = require('http'); | ||
// alexgorbatchev 2010-10-22 :: Added a bit of depth to inspection | ||
var actual = sys.inspect(e.actual, false, 10).replace(/\n$/, ''); | ||
var expected = sys.inspect(e.expected, false, 10).replace(/\n$/, ''); | ||
var actual = util.inspect(e.actual, false, 10).replace(/\n$/, ''); | ||
var expected = util.inspect(e.expected, false, 10).replace(/\n$/, ''); | ||
var multiline = ( | ||
@@ -198,0 +198,0 @@ actual.indexOf('\n') !== -1 || |
@@ -9,3 +9,6 @@ { "name": "nodeunit" | ||
, "contributors" : | ||
[ { "name": "Alex Gorbatchev" | ||
[ { "name": "Romain Beauxis" | ||
, "web": "https://github.com/toots" | ||
} | ||
, { "name": "Alex Gorbatchev" | ||
, "web": "https://github.com/alexgorbatchev" | ||
@@ -40,4 +43,7 @@ } | ||
} | ||
, { "name": "Elijah Insua <tmpvar@gmail.com>", | ||
"web": "http://tmpvar.com" | ||
} | ||
] | ||
, "version": "0.5.0" | ||
, "version": "0.6.2" | ||
, "repository" : | ||
@@ -47,3 +53,5 @@ { "type" : "git" | ||
} | ||
, "bugs" : { "web" : "http://github.com/caolan/nodeunit/issues" } | ||
, "devDependencies": | ||
{ "uglify-js": ">=1.1.0" } | ||
, "bugs" : { "url" : "http://github.com/caolan/nodeunit/issues" } | ||
, "licenses" : | ||
@@ -56,2 +64,6 @@ [ { "type" : "MIT" | ||
, "bin" : { "nodeunit" : "./bin/nodeunit" } | ||
, "dependencies" : | ||
{ "tap-assert": ">=0.0.9" | ||
, "tap-producer": ">=0.0.1" | ||
} | ||
} |
@@ -21,2 +21,4 @@ Nodeunit | ||
* [coffeemate](https://github.com/coffeemate) | ||
* [lambdalisue](https://github.com/lambdalisue) | ||
* [luebken](https://github.com/luebken) | ||
* [orlandov](https://github.com/orlandov) | ||
@@ -26,2 +28,3 @@ * [Sannis](https://github.com/Sannis) | ||
* [thegreatape](https://github.com/thegreatape) | ||
* [mmalecki](https://github.com/mmalecki) | ||
* and thanks to [cjohansen](https://github.com/cjohansen) for input and advice | ||
@@ -34,3 +37,5 @@ on implementing setUp and tearDown functions. See | ||
More contributor information can be found in the CONTRIBUTORS.md file. | ||
More contributor information can be found in the | ||
[CONTRIBUTORS.md](https://github.com/caolan/nodeunit/blob/master/CONTRIBUTORS.md) | ||
file. | ||
@@ -75,3 +80,3 @@ Usage | ||
Nodeunit uses the functions available in the node.js | ||
[assert module](http://nodejs.org/api.html#assert-280): | ||
[assert module](http://nodejs.org/docs/v0.4.2/api/assert.html): | ||
@@ -183,10 +188,7 @@ * __ok(value, [message])__ - Tests if value is a true value. | ||
Using these groups its possible to add setUp and tearDown functions to your | ||
tests. Nodeunit has a utility function called testCase which allows you to | ||
define a setUp function, which is run before each test, and a tearDown | ||
function, which is run after each test calls test.done(): | ||
Using these groups, Nodeunit allows you to define a `setUp` function, which is | ||
run before each test, and a `tearDown` function, which is run after each test | ||
calls `test.done()`: | ||
var testCase = require('nodeunit').testCase; | ||
module.exports = testCase({ | ||
module.exports = { | ||
setUp: function (callback) { | ||
@@ -204,3 +206,3 @@ this.foo = 'bar'; | ||
} | ||
}); | ||
}; | ||
@@ -300,8 +302,6 @@ In this way, its possible to have multiple groups of tests in a module, each | ||
you'll want to create a script that runs the tests for your project with the | ||
correct require paths set up. Here's an example test script, with a deps | ||
directory containing the projects dependencies: | ||
correct require paths set up. Here's an example test script, that assumes you | ||
have nodeunit in a suitably located node_modules directory. | ||
#!/usr/bin/env node | ||
require.paths.unshift(__dirname + '/deps'); | ||
var reporter = require('nodeunit').reporters.default; | ||
@@ -315,6 +315,6 @@ reporter.run(['test']); | ||
git submodule add git://github.com/caolan/nodeunit.git deps/nodeunit | ||
git submodule add git://github.com/caolan/nodeunit.git node_modules/nodeunit | ||
This will add nodeunit to the deps folder of your project. Now, when cloning | ||
the repository, nodeunit can be downloaded by doing the following: | ||
This will add nodeunit to the node_modules folder of your project. Now, when | ||
cloning the repository, nodeunit can be downloaded by doing the following: | ||
@@ -328,5 +328,2 @@ git submodule init | ||
#!/usr/bin/env node | ||
require.paths.unshift(__dirname + '/deps'); | ||
try { | ||
@@ -336,9 +333,8 @@ var reporter = require('nodeunit').reporters.default; | ||
catch(e) { | ||
var sys = require('sys'); | ||
sys.puts("Cannot find nodeunit module."); | ||
sys.puts("You can download submodules for this project by doing:"); | ||
sys.puts(""); | ||
sys.puts(" git submodule init"); | ||
sys.puts(" git submodule update"); | ||
sys.puts(""); | ||
console.log("Cannot find nodeunit module."); | ||
console.log("You can download submodules for this project by doing:"); | ||
console.log(""); | ||
console.log(" git submodule init"); | ||
console.log(" git submodule update"); | ||
console.log(""); | ||
process.exit(); | ||
@@ -362,2 +358,4 @@ } | ||
continuous integration tools such as [Hudson](http://hudson-ci.org/). | ||
* __machineout__ - Simple reporter for machine analysis. There is [nodeunit.vim](https://github.com/lambdalisue/nodeunit.vim) | ||
which is useful for TDD on VIM | ||
@@ -428,3 +426,3 @@ | ||
To run the nodeunit tests do: | ||
make test | ||
@@ -436,2 +434,18 @@ | ||
__machineout__ reporter | ||
---------------------------------------------- | ||
The default reporter is really readable for human but for machinally analysis. | ||
When you want to analyze the output of nodeunit, use __machineout__ reporter and you will get | ||
<img src="https://github.com/caolan/nodeunit/raw/master/img/example_machineout.png" /> | ||
nodeunit with vim | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
There is [nodeunit.vim](https://github.com/lambdalisue/nodeunit.vim) so you can use nodeunit with VIM. | ||
That compiler use __machineout__ reporter and it is useful to use with [vim-makegreen](https://github.com/reinh/vim-makegreen) | ||
Contributing | ||
@@ -443,2 +457,1 @@ ------------ | ||
we're following a consistent coding style. | ||
var assert = require('assert'), | ||
sys = require('sys'), | ||
fs = require('fs'), | ||
@@ -11,8 +10,7 @@ path = require('path'), | ||
process.chdir(__dirname); | ||
require.paths.push(__dirname); | ||
var env = { | ||
mock_module1: require('./fixtures/mock_module1'), | ||
mock_module2: require('./fixtures/mock_module2'), | ||
mock_module3: require('./fixtures/dir/mock_module3'), | ||
mock_module4: require('./fixtures/dir/mock_module4') | ||
mock_module1: require(__dirname + '/fixtures/mock_module1'), | ||
mock_module2: require(__dirname + '/fixtures/mock_module2'), | ||
mock_module3: require(__dirname + '/fixtures/dir/mock_module3'), | ||
mock_module4: require(__dirname + '/fixtures/dir/mock_module4') | ||
}; | ||
@@ -79,3 +77,5 @@ fn.call(env, test); | ||
nodeunit.runFiles( | ||
['fixtures/mock_module1.js', 'fixtures/mock_module2.js', 'fixtures/dir'], | ||
[__dirname + '/fixtures/mock_module1.js', | ||
__dirname + '/fixtures/mock_module2.js', | ||
__dirname + '/fixtures/dir'], | ||
opts | ||
@@ -153,5 +153,5 @@ ); | ||
process.chdir(__dirname); | ||
require.paths.push(__dirname); | ||
var env = { | ||
mock_coffee_module: require('./fixtures/coffee/mock_coffee_module') | ||
mock_coffee_module: require(__dirname + | ||
'/fixtures/coffee/mock_coffee_module') | ||
}; | ||
@@ -213,3 +213,3 @@ | ||
nodeunit.runFiles( | ||
['fixtures/coffee/mock_coffee_module.coffee'], | ||
[__dirname + 'fixtures/coffee/mock_coffee_module.coffee'], | ||
opts | ||
@@ -216,0 +216,0 @@ ); |
@@ -68,2 +68,53 @@ /* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! | ||
exports.testRunModuleTestSpec = function (test) { | ||
test.expect(6); | ||
var call_order = []; | ||
var testmodule = { | ||
test1: function (test) { | ||
test.ok(true, 'ok true'); | ||
test.done(); | ||
}, | ||
test2: function (test) { | ||
call_order.push('test2'); | ||
test.ok(false, 'ok false'); | ||
test.ok(false, 'ok false'); | ||
test.done(); | ||
}, | ||
test3: function (test) { | ||
test.done(); | ||
} | ||
}; | ||
nodeunit.runModule('testmodule', testmodule, { | ||
testspec: "test2", | ||
log: function (assertion) { | ||
call_order.push('log'); | ||
}, | ||
testStart: function (name) { | ||
call_order.push('testStart'); | ||
test.ok( | ||
name.toString() === 'test2', | ||
'testStart called with test name ' | ||
); | ||
}, | ||
testDone: function (name, assertions) { | ||
call_order.push('testDone'); | ||
test.ok( | ||
name.toString() === 'test2', | ||
'testDone called with test name' | ||
); | ||
}, | ||
moduleDone: function (name, assertions) { | ||
call_order.push('moduleDone'); | ||
test.equals(assertions.length, 2); | ||
test.equals(name, 'testmodule'); | ||
test.ok(typeof assertions.duration === "number"); | ||
test.same(call_order, [ | ||
'testStart', 'test2', 'log', 'log', 'testDone', | ||
'moduleDone' | ||
]); | ||
} | ||
}, test.done); | ||
}; | ||
exports.testRunModuleEmpty = function (test) { | ||
@@ -89,2 +140,3 @@ nodeunit.runModule('module with no exports', {}, { | ||
exports.testNestedTests = function (test) { | ||
@@ -91,0 +143,0 @@ var call_order = []; |
@@ -8,3 +8,2 @@ /* THIS FILE SHOULD BE BROWSER-COMPATIBLE JS! | ||
var nodeunit = require('../lib/nodeunit'); // @REMOVE_LINE_FOR_BROWSER | ||
var testCase = nodeunit.testCase; | ||
@@ -14,6 +13,6 @@ exports.testTestCase = function (test) { | ||
var call_order = []; | ||
var s = testCase({ | ||
var s = { | ||
setUp: function (callback) { | ||
call_order.push('setUp'); | ||
test.equals(this.one, undefined); | ||
test.equals(this.one, undefined, 'in setUp, this.one not set'); | ||
this.one = 1; | ||
@@ -29,3 +28,3 @@ callback(); | ||
call_order.push('test1'); | ||
test.equals(this.one, 1); | ||
test.equals(this.one, 1, 'in test1, this.one is 1'); | ||
this.one = 2; | ||
@@ -36,6 +35,6 @@ t.done(); | ||
call_order.push('test2'); | ||
test.equals(this.one, 1); | ||
test.equals(this.one, 1, 'in test2, this.one is still 1'); | ||
t.done(); | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function () { | ||
@@ -52,3 +51,3 @@ test.same(call_order, [ | ||
test.expect(1); | ||
var s = testCase({ | ||
var s = { | ||
tearDown: function (callback) { | ||
@@ -61,3 +60,3 @@ test.ok(true, 'tearDown called'); | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function () { | ||
@@ -71,3 +70,3 @@ test.done(); | ||
var test_error = new Error('test error'); | ||
var s = testCase({ | ||
var s = { | ||
setUp: function (callback) { | ||
@@ -80,3 +79,3 @@ throw test_error; | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -92,3 +91,3 @@ test.equal(assertions.length, 1); | ||
var test_error = new Error('test error'); | ||
var s = testCase({ | ||
var s = { | ||
setUp: function (callback) { | ||
@@ -101,3 +100,3 @@ callback(test_error); | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -113,3 +112,3 @@ test.equal(assertions.length, 1); | ||
var test_error = new Error('test error'); | ||
var s = testCase({ | ||
var s = { | ||
tearDown: function (callback) { | ||
@@ -121,3 +120,3 @@ throw test_error; | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -133,3 +132,3 @@ test.equal(assertions.length, 1); | ||
var test_error = new Error('test error'); | ||
var s = testCase({ | ||
var s = { | ||
tearDown: function (callback) { | ||
@@ -141,3 +140,3 @@ callback(test_error); | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -154,3 +153,3 @@ test.equal(assertions.length, 1); | ||
var error2 = new Error('test error two'); | ||
var s = testCase({ | ||
var s = { | ||
tearDown: function (callback) { | ||
@@ -162,3 +161,3 @@ callback(error2); | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -174,3 +173,3 @@ test.equal(assertions.length, 2); | ||
var call_order = []; | ||
var s = testCase({ | ||
var s = { | ||
setUp: function (callback) { | ||
@@ -194,3 +193,3 @@ call_order.push('setUp'); | ||
} | ||
}); | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -211,3 +210,3 @@ test.same(call_order, [ | ||
var call_order = []; | ||
var s = testCase({ | ||
var s = { | ||
setUp: function (callback) { | ||
@@ -225,3 +224,3 @@ call_order.push('setUp'); | ||
}, | ||
group1: testCase({ | ||
group1: { | ||
setUp: function (callback) { | ||
@@ -239,4 +238,4 @@ call_order.push('group1.setUp'); | ||
} | ||
}) | ||
}); | ||
} | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
@@ -256,1 +255,24 @@ test.same(call_order, [ | ||
}; | ||
exports.deepNestedTestCases = function (test) { | ||
var val = 'foo'; | ||
var s = { | ||
setUp: function (callback) { | ||
val = 'bar'; | ||
callback(); | ||
}, | ||
group1: { | ||
test: { | ||
test2: function (test) { | ||
test.equal(val, 'bar'); | ||
test.done(); | ||
} | ||
} | ||
} | ||
}; | ||
nodeunit.runSuite(null, s, {}, function (err, assertions) { | ||
test.ok(!assertions[0].failed()); | ||
test.equal(assertions.length, 1); | ||
test.done(); | ||
}); | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found.
Found 1 instance in 1 package
2136994
136
1
80
13942
333
1
21