.finished()` to mark test as finished. All the tests has to have it. Without this you won't be able to write solid asynchronous tests, because you can't ask only "is a and b the same?", but also "did the callback run?".
16 | * Run `node foo_test.js` to get the results.
17 |
18 | # Example
19 |
20 | var minitest = require("minitest");
21 | var assert = require("assert");
22 |
23 | minitest.setupListeners();
24 |
25 | minitest.context("Context#setup()", function () {
26 | this.setup(function () {
27 | this.user = {name: "Jakub"};
28 | });
29 |
30 | this.assertion("it should setup listeners", function (test) {
31 | // test something via the standard assert module
32 | assert.ok(this.user)
33 |
34 | // mark test as finished
35 | test.finished();
36 | });
37 |
38 | this.assertion("it should be able to count", function (test) {
39 | if (2 !== 4) {
40 | // manually fail the test
41 | throw new Error("You can't count, can you?");
42 | };
43 | });
44 | });
45 |
46 | ## Formatters
47 |
48 | If you don't like minitest output, you can simply override following methods:
49 |
50 | * `Context.prototype.contextHeader()`
51 | * `Test.prototype.reportSuccess()`
52 | * `Test.prototype.reportError(error)`
53 | * `Test.prototype.reportNotRun()`
54 |
55 | All this methods are supposed to return a string and all these methods have access to `this.description`.
56 |
57 | # Common Problems in Testing Asynchronous Code
58 |
59 | ## Exceptions in Callbacks
60 |
61 | Obviously you can't catch errors which occured in callbacks. Consider following:
62 |
63 | try {
64 | db.get("botanicus", function (user) {
65 | throw new Error("You can't catch me!");
66 | });
67 | } catch(error) {
68 | // you'll never get in here
69 | };
70 |
71 | ## Testing Exceptions
72 |
73 | this.assertion("should throw an error", function (test) {
74 | assert.throws(function () {
75 | throw new Error("Error occured!");
76 | test.finished();
77 | });
78 | });
79 |
80 | This obviously can't work, because exception interrupts the anonymous function we are passing as an argument for `assert.throws()`.
81 |
82 | this.assertion("should throw an error", function (test) {
83 | assert.throws(function () {
84 | throw new Error("Error occured!");
85 | });
86 | test.finished();
87 | });
88 |
89 | This is better, it will at least work, but what if there will be an error in the `assert.throws()` function and it doesn't call the anonymous function?
90 |
91 | this.assertion("should throw an error", function (test) {
92 | assert.throws(function () {
93 | test.finished();
94 | throw new Error("Error occured!");
95 | });
96 | });
97 |
98 | OK, this is better, `test.finished()` doesn't jump out of the test, so in case that the assertion will fail, we will get the proper result. However it's not perfect, because I can change `test.finished()` in future to actually jump out of the function (I probably won't do that but you can't know) plus if there would be a bug, so `test.finished()` would cause an exception, it would satisfy `assert.throws()` without actually testing the code. Well, you'd probably noticed in other tests, but still.
99 |
100 | Fortunatelly you can specify error class and expected message for `assert.throws()` in this order: `assert.throws(block, error, message)`.
101 |
--------------------------------------------------------------------------------
/file/vendor/minitest.js/colours.js:
--------------------------------------------------------------------------------
1 | /*
2 | Simple module for coloured output for POSIX shells.
3 |
4 | @example
5 | colours.bold.green + "OK: " + colours.reset + description
6 | */
7 |
8 | colours = {
9 | reset: "\x1B[0m",
10 |
11 | grey: "\x1B[0;30m",
12 | red: "\x1B[0;31m",
13 | green: "\x1B[0;32m",
14 | yellow: "\x1B[0;33m",
15 | blue: "\x1B[0;34m",
16 | magenta: "\x1B[0;35m",
17 | cyan: "\x1B[0;36m",
18 | white: "\x1B[0;37m",
19 |
20 | bold: {
21 | grey: "\x1B[1;30m",
22 | red: "\x1B[1;31m",
23 | green: "\x1B[1;32m",
24 | yellow: "\x1B[1;33m",
25 | blue: "\x1B[1;34m",
26 | magenta: "\x1B[1;35m",
27 | cyan: "\x1B[1;36m",
28 | white: "\x1B[1;37m",
29 | }
30 | };
31 |
32 | // exports
33 | for (colour in colours) {
34 | exports[colour] = colours[colour];
35 | };
36 |
--------------------------------------------------------------------------------
/file/vendor/minitest.js/minitest.js:
--------------------------------------------------------------------------------
1 | var sys = require("sys");
2 | var colours = require("./colours");
3 |
4 | /* suite */
5 | function Suite () {
6 | this.contexts = [];
7 | };
8 |
9 | Suite.prototype.report = function () {
10 | var suite = this;
11 | this.contexts.forEach(function(context, index) {
12 | sys.puts(context.contextHeader());
13 | context.report();
14 | if (suite.contexts.length === index) {
15 | sys.puts("");
16 | };
17 | });
18 | };
19 |
20 | Suite.prototype.register = function (context) {
21 | this.contexts.push(context);
22 | };
23 |
24 | // there is only one suite instance
25 | var suite = exports.suite = new Suite();
26 |
27 | /* context */
28 | function Context (description, block) {
29 | this.tests = [];
30 | this.block = block;
31 | this.description = description;
32 | };
33 |
34 | Context.prototype.run = function () {
35 | this.block.call(this);
36 | };
37 |
38 | Context.prototype.register = function (test) {
39 | this.tests.push(test);
40 | };
41 |
42 | Context.prototype.report = function () {
43 | this.tests.forEach(function (test) {
44 | test.report();
45 | });
46 | };
47 |
48 | /* test */
49 | function Test (description, block, setupBlock) {
50 | this.description = description;
51 | this.block = block;
52 | this.setupBlock = setupBlock;
53 | };
54 |
55 | Test.prototype.run = function () {
56 | try {
57 | if (this.setupBlock) {
58 | this.setupBlock.call(this);
59 | };
60 |
61 | this.block.call(this, this);
62 | } catch(error) {
63 | this.failed(error);
64 | };
65 | };
66 |
67 | Test.prototype.finished = function () {
68 | this.result = this.reportSuccess();
69 | };
70 |
71 | Test.prototype.failed = function (error) {
72 | this.result = this.reportError(error);
73 | };
74 |
75 | Test.prototype.report = function () {
76 | if (this.result) {
77 | sys.puts(this.result);
78 | } else {
79 | sys.puts(this.reportNotFinished());
80 | };
81 | };
82 |
83 | /* output formatters */
84 | Context.prototype.contextHeader = function () {
85 | return colours.bold.yellow + "[= " + this.description + " =]" + colours.reset;
86 | };
87 |
88 | Test.prototype.reportSuccess = function () {
89 | // return colours.bold.green + " ✔ OK: " + colours.reset + this.description;
90 | return colours.bold.green + " OK: " + colours.reset + this.description;
91 | };
92 |
93 | Test.prototype.reportError = function (error) {
94 | var stack = error.stack.replace(/^/, " ");
95 | // return colours.bold.red + " ✖ Error: " + colours.reset + this.description + "\n" + stack;
96 | return colours.bold.red + " Error: " + colours.reset + this.description + "\n" + stack;
97 | };
98 |
99 | Test.prototype.reportNotFinished = function () {
100 | // return colours.bold.magenta + " ✖ Didn't finished: " + colours.reset + this.description;
101 | return colours.bold.magenta + " Didn't finished: " + colours.reset + this.description;
102 | };
103 |
104 | /* DSL */
105 | function context (description, block) {
106 | var context = new Context(description, block);
107 | suite.register(context);
108 | context.run();
109 | };
110 |
111 | /*
112 | Run an example and print if it was successful or not.
113 |
114 | @example
115 | minitest.context("setup()", function () {
116 | this.assertion("Default value should be 0", function (test) {
117 | assert.equal(value, 0);
118 | test.finished();
119 | });
120 | });
121 | */
122 | Context.prototype.assertion = function (description, block) {
123 | var test = new Test(description, block, this.setupBlock);
124 | this.register(test);
125 | test.run();
126 | };
127 |
128 | Context.prototype.setup = function (block) {
129 | this.setupBlock = block;
130 | };
131 |
132 | function runAtExit () {
133 | process.addListener("exit", function () {
134 | suite.report();
135 | });
136 | };
137 |
138 | function setupUncaughtExceptionListener () {
139 | // TODO: is there any way how to get the test instance,
140 | // so we could just set test.result, so everything would be
141 | // reported properly on the correct place, not in the middle of tests
142 | process.addListener("uncaughtException", function (error) {
143 | sys.puts(Test.prototype.reportError(error));
144 | });
145 | };
146 |
147 | function setupListeners () {
148 | setupUncaughtExceptionListener();
149 | runAtExit();
150 | };
151 |
152 | /* exports */
153 | exports.Context = Context;
154 | exports.Test = Test;
155 | exports.context = context;
156 | exports.runAtExit = runAtExit;
157 | exports.setupUncaughtExceptionListener = setupUncaughtExceptionListener;
158 | exports.setupListeners = setupListeners;
159 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeal/node-utils/3ff43df540a266bebf3fd3349b35ca7f23e80b4d/package.json
--------------------------------------------------------------------------------
/pool/README.md:
--------------------------------------------------------------------------------
1 | # Pool -- Simple HTTP client pooling
2 |
3 | ## Install
4 |
5 |
6 | npm install pool
7 |
8 |
9 | ## Super simple to use
10 |
11 | Pool has two core usage scenarios: creating a pool and creating a set of pools. Creating a pool is easy:
12 |
13 |
14 | var pool = require('pool'),
15 | sys = require('sys'),
16 | local = pool.createPool('80', 'localhost');
17 |
18 | client = local.request('GET', '/', function (request) {
19 | // You can work with the request here just as you would as if it
20 | // was returned from http.createClient
21 | request.on('end', function () {
22 | sys.puts('Request ended');
23 | });
24 | });
25 |
26 |
27 | Creating a set of pools can be accomplished using a PoolManager:
28 |
29 |
30 | var pool = require('pool'),
31 | manager = pool.createPoolManager(),
32 | local = manager.getPool('80', 'localhost');
33 |
34 | client = local.request('GET', '/', function (request) {
35 | // You can work with the request here just as you would as if it
36 | // was returned from http.createClient
37 | request.on('end', function () {
38 | sys.puts('Request ended');
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/pool/main.js:
--------------------------------------------------------------------------------
1 | var sys = require('sys')
2 | , http = require('http')
3 | , events = require('events')
4 | ;
5 |
6 | function Pool (port, host, https, credentials) {
7 | this.port = port;
8 | this.host = host;
9 | this.https = https;
10 | this.credentials = credentials;
11 | this.clients = [];
12 | this.pending = [];
13 | this.minClients = 0;
14 | this.maxClients = 8;
15 | }
16 | sys.inherits(Pool, events.EventEmitter);
17 | Pool.prototype.getClient = function (cb) {
18 | for (var i=0;i this.maxClients) {
27 | this.clients[i].end();
28 | this.clients.splice(i, 1);
29 | i-=1;
30 | } else {
31 | return cb(this.clients[i]);
32 | }
33 | }
34 | }
35 | if (this.clients.length >= this.maxClients) {
36 | this.pending.push(cb);
37 | } else {
38 | var client = http.createClient(this.port, this.host, this.https, this.credentials);
39 | this.clients.push(client);
40 | cb(client);
41 | }
42 | };
43 | Pool.prototype.request = function () {
44 | // Argument parsing. This gets a little dicey with the
45 | // differences in defaults
46 | var method, url, headers, callback, args;
47 | var self = this;
48 | args = Array.prototype.slice.call(arguments);
49 |
50 | if (typeof args[args.length - 1] === 'function') {
51 | callback = args.pop();
52 | }
53 | if (args[0]) method = args[0];
54 | if (args[1]) url = args[1];
55 | if (args[2]) headers = args[2];
56 |
57 | if (!headers) headers = {};
58 | if (!headers.Connection) headers.Connection = 'keep-alive';
59 |
60 | self.getClient(function (client) {
61 | var request = client.request(method, url, headers);
62 | var errorListener = function (error) {
63 | self.emit("error", error);
64 | request.emit("error", error);
65 | }
66 | client.on("error", errorListener);
67 | request.on("response", function (response) {
68 | response.on("end", function () {
69 | client.removeListener("error", errorListener);
70 | client.busy = false;
71 | self.onFree(client);
72 | })
73 | })
74 | client.busy = true;
75 | callback(request);
76 | });
77 | };
78 | Pool.prototype.onFree = function (client) {
79 | if (this.pending.length > 0) this.pending.shift()(client);
80 | };
81 | Pool.prototype.setMinClients = function (num) {
82 | this.minClients = num;
83 | if (this.clients.length < num) {
84 | for (var i=this.clients.length;i"
6 | , "repository" :
7 | { "type" : "git"
8 | , "url" : "http://github.com/mikeal/node-utils.git"
9 | }
10 | , "bugs" :
11 | { "web" : "http://github.com/mikeal/node-utils/issues" }
12 | , "engines" : ["node >=0.1.90"]
13 | , "main" : "./main"
14 | }
15 |
--------------------------------------------------------------------------------
/streams/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeal/node-utils/3ff43df540a266bebf3fd3349b35ca7f23e80b4d/streams/README.md
--------------------------------------------------------------------------------
/streams/lib/main.js:
--------------------------------------------------------------------------------
1 | var sys = require('sys')
2 | , events = require('events');
3 |
4 | /*
5 |
6 | Experimental
7 |
8 | Simplified API for creating a Stream compatible object that can mutate data coming through the stream.
9 |
10 | // Write 4 chunks at a time.
11 | var b = [];
12 | var filter = sys.createFilter(function (chunk, write) {
13 | if (!chunk || b.length === 4) {
14 | b.forEach( function (c) {write(c)} );
15 | } else {
16 | b.push(chunk);
17 | }
18 | });
19 | sys.pump(readable, filter);
20 | sys.pump(filter, writable);
21 | */
22 |
23 | function Filter(handler) {
24 | var self = this;
25 | var write = function(chunk) {
26 | self.emit('data', chunk)
27 | }
28 |
29 | self.write = function(chunk) {
30 | handler(chunk, write);
31 | }
32 | self.addListener("end", function() {
33 | handler(null, write)
34 | })
35 | };
36 | Filter.prototype.pause = function() {
37 | this.emit("pause")
38 | }
39 | Filter.prototype.resume = function() {
40 | this.emit("resume")
41 | }
42 | sys.inherits(Filter, events.EventEmitter)
43 |
44 | function createFilter (handler) {
45 | return new Filter(handler);
46 | };
47 |
48 | function createMultiPump (readables, writables) {
49 | var mpump = new events.EventEmitter();
50 |
51 | for (var i;i= readables.length) {
64 | mpump.emit("end", writable);
65 | return;
66 | }
67 | var readable = readables[writable.readableIndex]
68 | readable.resume();
69 | if (readable.writers) {
70 | readable.writers += 1;
71 | readable.buffers.forEach(function(chunk){writable.write(chunk)});
72 | if (readable.writers == writables.length) readable.removeListener("data", readable.bufferListener);
73 | }
74 | var pump = createPump(readable, writable);
75 | readable.pumps.push(pump);
76 | pump.removeDefaults();
77 | pump.paused = false;
78 | pump.addListener('pause', function () {
79 | pump.paused = true;
80 | var pcount = 0;
81 | readable.pumps.forEach(function(p) {if (p.paused) pcount += 1;});
82 | if (pcount == readable.pumps.length) readable.pause();
83 | })
84 | pump.addListener('resume', function () {
85 | pump.paused = false;
86 | pump.resumeListener()
87 | });
88 | pump.addListener('end', function () {
89 | writable.readableIndex += 1;
90 | readables.pumps.splice(readables.pumps.indexOf(pump), 1);
91 | startPump(writable);
92 | })
93 | mpump.emit("pump", pump);
94 | }
95 |
96 | writeables.forEach(function (writable) {
97 | var self = this;
98 | writable.readableIndex = 0;
99 | startPump(writable);
100 | })
101 |
102 | mpump.endListener = function (writable) { writable.end(); };
103 | mpump.addListener("end", mpump.endListener);
104 |
105 | return mpump;
106 | }
107 |
108 | exports.Filter = Filter;
109 | exports.createFilter = createFilter;
110 | exports.createMultiPump = createMultiPump;
--------------------------------------------------------------------------------
/streams/package.json:
--------------------------------------------------------------------------------
1 | { "name" : "streams"
2 | , "description" : "Stream utilities."
3 | , "tags" : ["streams", "simple", "util", "utility"]
4 | , "version" : "0.3.0"
5 | , "author" : "Mikeal Rogers "
6 | , "repository" :
7 | { "type" : "git"
8 | , "url" : "http://github.com/mikeal/node-utils.git"
9 | }
10 | , "bugs" :
11 | { "web" : "http://github.com/mikeal/node-utils/issues" }
12 | , "engines" : ["node >=0.1.90"]
13 | , "main" : "./lib/main"
14 | }
15 |
--------------------------------------------------------------------------------