Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 1 commit
  • 6 files changed
  • 0 comments
  • 1 contributor
Jul 04, 2012
Benjamin Arthur Lupton v1.11.1. balUtilFlow improvements to Group, and fixes to Block
- v1.11.1 July 4, 2012
	- `balUtilFlow` changes:
		- `Group` changes:
			- Cleaned up the context handling code
		- `Block` changes:
			- Block constructor as well as `createSubBlock` arguments is now a
single `opts` object, accepting the options `name`, `fn`, `parentBlock`
and the new `complete`
			- Fixed bug introduced in v1.11.0 causing blocks to complete
instantly (instead of once their tasks are finished)
4bd2c2c
8  History.md
Source Rendered
... ...
@@ -1,5 +1,13 @@
1 1
 ## History
2 2
 
  3
+- v1.11.1 July 4, 2012
  4
+	- `balUtilFlow` changes:
  5
+		- `Group` changes:
  6
+			- Cleaned up the context handling code
  7
+		- `Block` changes:
  8
+			- Block constructor as well as `createSubBlock` arguments is now a single `opts` object, acceping the options `name`, `fn`, `parentBlock` and the new `complete`
  9
+			- Fixed bug introduced in v1.11.0 causing blocks to complete instantly (instead of once their tasks are finished)
  10
+
3 11
 - v1.11.0 July 1, 2012
4 12
 	- Added `balUtilHTML`:
5 13
 		- `getAttribute(attributes,attribute)`
123  out/lib/flow.js
@@ -217,13 +217,20 @@
217 217
       return this.exited === true;
218 218
     };
219 219
 
  220
+    _Class.prototype.logError = function(err) {
  221
+      if (this.errors[this.errors.length - 1] !== err) {
  222
+        this.errors.push(err);
  223
+      }
  224
+      return this;
  225
+    };
  226
+
220 227
     _Class.prototype.complete = function() {
221 228
       var args, err;
222 229
       args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
223 230
       err = args[0] || void 0;
224 231
       this.lastResult = args;
225 232
       if (err) {
226  
-        this.errors.push(err);
  233
+        this.logError(err);
227 234
       }
228 235
       this.results.push(args);
229 236
       if (this.running !== 0) {
@@ -260,15 +267,21 @@
260 267
       if (err == null) {
261 268
         err = null;
262 269
       }
  270
+      if (err) {
  271
+        this.logError(err);
  272
+      }
263 273
       if (this.hasExited()) {
264 274
 
265 275
       } else {
266 276
         lastResult = this.lastResult;
267  
-        errors = this.errors.length !== 0 ? this.errors : null;
268  
-        if (this.errors.length === 1) {
269  
-          errors = errors[0];
270  
-        }
271 277
         results = this.results;
  278
+        if (this.errors.length === 0) {
  279
+          errors = null;
  280
+        } else if (this.errors.length === 1) {
  281
+          errors = this.errors[0];
  282
+        } else {
  283
+          errors = this.errors;
  284
+        }
272 285
         if (this.autoClear) {
273 286
           this.clear();
274 287
         } else {
@@ -289,39 +302,21 @@
289 302
     };
290 303
 
291 304
     _Class.prototype.push = function() {
292  
-      var args, context, task, _task;
  305
+      var args;
293 306
       args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
294 307
       ++this.total;
295  
-      if (args.length === 2) {
296  
-        context = args[0];
297  
-        _task = args[1];
298  
-        task = function(complete) {
299  
-          return balUtilFlow.fireWithOptionalCallback(_task, [complete], context);
300  
-        };
301  
-      } else {
302  
-        task = args[0];
303  
-      }
304  
-      this.queue.push(task);
  308
+      this.queue.push(args);
305 309
       return this;
306 310
     };
307 311
 
308 312
     _Class.prototype.pushAndRun = function() {
309  
-      var args, context, task, _task;
  313
+      var args;
310 314
       args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
311  
-      if (args.length === 2) {
312  
-        context = args[0];
313  
-        _task = args[1];
314  
-        task = function(complete) {
315  
-          return balUtilFlow.fireWithOptionalCallback(_task, [complete], context);
316  
-        };
317  
-      } else {
318  
-        task = args[0];
319  
-      }
320 315
       if (this.mode === 'sync' && this.isRunning()) {
321  
-        this.push(task);
  316
+        this.push.apply(this, args);
322 317
       } else {
323 318
         ++this.total;
324  
-        this.runTask(task);
  319
+        this.runTask(args);
325 320
       }
326 321
       return this;
327 322
     };
@@ -340,10 +335,23 @@
340 335
       me = this;
341 336
       try {
342 337
         run = function() {
343  
-          var complete;
  338
+          var complete, _context, _task;
344 339
           ++me.running;
345 340
           complete = me.completer();
346  
-          return balUtilFlow.fireWithOptionalCallback(task, [complete]);
  341
+          if (balUtilFlow.isArray(task)) {
  342
+            if (task.length === 2) {
  343
+              _context = task[0];
  344
+              _task = task[1];
  345
+            } else if (task.length === 1) {
  346
+              _task = task[0];
  347
+              _context = null;
  348
+            } else {
  349
+              throw new Error('balUtilFlow.Group an invalid task was pushed');
  350
+            }
  351
+          } else {
  352
+            _task = task;
  353
+          }
  354
+          return balUtilFlow.fireWithOptionalCallback(_task, [complete], _context);
347 355
         };
348 356
         if (this.completed !== 0 && (this.mode === 'async' || (this.completed % 100) === 0)) {
349 357
           setTimeout(run, 0);
@@ -405,39 +413,39 @@
405 413
 
406 414
     _Class.prototype.blockTaskAfter = function(block, task, err) {};
407 415
 
408  
-    function _Class(name, initFunction, parentBlock) {
409  
-      var block;
  416
+    function _Class(opts) {
  417
+      var block, complete, fn, name, parentBlock;
410 418
       block = this;
411  
-      _Class.__super__.constructor.call(this, function(err) {
412  
-        var _ref;
413  
-        block.blockAfter(block, err);
414  
-        return (_ref = block.parentBlock) != null ? _ref.complete(err) : void 0;
415  
-      });
  419
+      name = opts.name, fn = opts.fn, parentBlock = opts.parentBlock, complete = opts.complete;
416 420
       block.blockName = name;
417 421
       if (parentBlock != null) {
418 422
         block.parentBlock = parentBlock;
419 423
       }
420 424
       block.mode = 'sync';
421  
-      block.initFunction = initFunction;
  425
+      block.fn = fn;
  426
+      _Class.__super__.constructor.call(this, function(err) {
  427
+        block.blockAfter(block, err);
  428
+        return typeof complete === "function" ? complete(err) : void 0;
  429
+      });
422 430
       block.blockBefore(block);
423  
-      if (block.initFunction != null) {
424  
-        if (block.initFunction.length === 3) {
  431
+      if (block.fn != null) {
  432
+        if (block.fn.length === 3) {
425 433
           block.total = Infinity;
426 434
         }
427 435
         try {
428  
-          block.initFunction(function(name, fn) {
  436
+          block.fn(function(name, fn) {
429 437
             return block.block(name, fn);
430 438
           }, function(name, fn) {
431 439
             return block.task(name, fn);
432 440
           }, function(err) {
433 441
             return block.exit(err);
434 442
           });
  443
+          if (block.fn.length !== 3) {
  444
+            block.run();
  445
+          }
435 446
         } catch (err) {
436 447
           block.exit(err);
437 448
         }
438  
-        if (block.initFunction.length !== 3) {
439  
-          block.run();
440  
-        }
441 449
       } else {
442 450
         block.total = Infinity;
443 451
       }
@@ -446,34 +454,39 @@
446 454
     }
447 455
 
448 456
     _Class.prototype.block = function(name, fn) {
449  
-      var block, push;
  457
+      var block, pushBlock;
450 458
       block = this;
451  
-      push = function(complete) {
  459
+      pushBlock = function(fn) {
452 460
         if (block.total === Infinity) {
453  
-          return block.pushAndRun(complete);
  461
+          return block.pushAndRun(fn);
454 462
         } else {
455  
-          return block.push(complete);
  463
+          return block.push(fn);
456 464
         }
457 465
       };
458  
-      push(function() {
  466
+      pushBlock(function(complete) {
459 467
         var subBlock;
460  
-        return subBlock = block.createSubBlock(name, fn, block);
  468
+        return subBlock = block.createSubBlock({
  469
+          name: name,
  470
+          fn: fn,
  471
+          complete: complete
  472
+        });
461 473
       });
462 474
       return this;
463 475
     };
464 476
 
465  
-    _Class.prototype.createSubBlock = function(name, fn, parentBlock) {
466  
-      return new balUtilFlow.Block(name, fn, parentBlock);
  477
+    _Class.prototype.createSubBlock = function(opts) {
  478
+      opts.parentBlock = this;
  479
+      return new balUtilFlow.Block(opts);
467 480
     };
468 481
 
469 482
     _Class.prototype.task = function(name, fn) {
470 483
       var block, pushTask;
471 484
       block = this;
472  
-      pushTask = function(complete) {
  485
+      pushTask = function(fn) {
473 486
         if (block.total === Infinity) {
474  
-          return block.pushAndRun(complete);
  487
+          return block.pushAndRun(fn);
475 488
         } else {
476  
-          return block.push(complete);
  489
+          return block.push(fn);
477 490
         }
478 491
       };
479 492
       pushTask(function(complete) {
193  out/test/flow.test.js
@@ -51,14 +51,17 @@
51 51
 
52 52
   joe.describe('Group', function(describe, it) {
53 53
     it('should work when tasks are specified manually', function(done) {
54  
-      var finished, firstTaskFinished, secondTaskFinished, tasks;
  54
+      var finished, firstTaskFinished, secondTaskFinished, tasks, total;
55 55
       firstTaskFinished = false;
56 56
       secondTaskFinished = false;
57 57
       finished = false;
  58
+      total = 2;
58 59
       tasks = new balUtil.Group(function(err) {
  60
+        if (err) {
  61
+          return done(err);
  62
+        }
59 63
         assert.equal(false, finished, 'the group of tasks only finished once');
60  
-        finished = true;
61  
-        return assert.equal(false, err != null, 'no error is present');
  64
+        return finished = true;
62 65
       });
63 66
       tasks.total = 2;
64 67
       wait(1000, function() {
@@ -73,7 +76,7 @@
73 76
       });
74 77
       assert.equal(0, tasks.completed, 'no tasks should have started yet');
75 78
       return wait(2000, function() {
76  
-        assert.equal(2, tasks.completed, 'only the expected number of tasks ran');
  79
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
77 80
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
78 81
         assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
79 82
         assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
@@ -81,16 +84,19 @@
81 84
       });
82 85
     });
83 86
     it('should work when run synchronously', function(done) {
84  
-      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks;
  87
+      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks, total;
85 88
       firstTaskRun = false;
86 89
       secondTaskRun = false;
87 90
       firstTaskFinished = false;
88 91
       secondTaskFinished = false;
89 92
       finished = false;
  93
+      total = 2;
90 94
       tasks = new balUtil.Group(function(err) {
  95
+        if (err) {
  96
+          return done(err);
  97
+        }
91 98
         assert.equal(false, finished, 'the group of tasks only finished once');
92  
-        finished = true;
93  
-        return assert.equal(false, err != null, 'no error is present');
  99
+        return finished = true;
94 100
       });
95 101
       tasks.push(function(complete) {
96 102
         firstTaskRun = true;
@@ -114,7 +120,7 @@
114 120
       tasks.sync();
115 121
       assert.equal(true, tasks.isRunning(), 'isRunning() returned true');
116 122
       return wait(2000, function() {
117  
-        assert.equal(2, tasks.completed, 'only the expected number of tasks ran');
  123
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
118 124
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
119 125
         assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
120 126
         assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
@@ -122,16 +128,19 @@
122 128
       });
123 129
     });
124 130
     it('should work when run asynchronously', function(done) {
125  
-      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks;
  131
+      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks, total;
126 132
       firstTaskRun = false;
127 133
       secondTaskRun = false;
128 134
       firstTaskFinished = false;
129 135
       secondTaskFinished = false;
130 136
       finished = false;
  137
+      total = 2;
131 138
       tasks = new balUtil.Group(function(err) {
  139
+        if (err) {
  140
+          return done(err);
  141
+        }
132 142
         assert.equal(false, finished, 'the group of tasks only finished once');
133  
-        finished = true;
134  
-        return assert.equal(false, err != null, 'no error is present');
  143
+        return finished = true;
135 144
       });
136 145
       tasks.push(function(complete) {
137 146
         firstTaskRun = true;
@@ -155,7 +164,7 @@
155 164
       tasks.async();
156 165
       assert.equal(true, tasks.isRunning(), 'isRunning() returned true');
157 166
       return wait(2000, function() {
158  
-        assert.equal(2, tasks.completed, 'only the expected number of tasks ran');
  167
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
159 168
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
160 169
         assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
161 170
         assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
@@ -163,16 +172,17 @@
163 172
       });
164 173
     });
165 174
     it('should handle errors correctly', function(done) {
166  
-      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks;
  175
+      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks, total;
167 176
       firstTaskRun = false;
168 177
       secondTaskRun = false;
169 178
       firstTaskFinished = false;
170 179
       secondTaskFinished = false;
171 180
       finished = false;
  181
+      total = 1;
172 182
       tasks = new balUtil.Group(function(err) {
  183
+        assert.equal(true, err !== null, 'an error is present');
173 184
         assert.equal(false, finished, 'the group of tasks only finished once');
174  
-        finished = true;
175  
-        return assert.equal(true, err != null, 'an error is present');
  185
+        return finished = true;
176 186
       });
177 187
       tasks.push(function(complete) {
178 188
         firstTaskRun = true;
@@ -196,7 +206,7 @@
196 206
       tasks.sync();
197 207
       assert.equal(true, tasks.isRunning(), 'isRunning() returned true');
198 208
       return wait(2000, function() {
199  
-        assert.equal(1, tasks.completed, 'only the expected number of tasks ran');
  209
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
200 210
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
201 211
         assert.equal(false, tasks.hasCompleted(), 'hasCompleted() returned true');
202 212
         assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
@@ -205,12 +215,14 @@
205 215
     });
206 216
     it('should work with optional completion callbacks', function(done) {
207 217
       var finished, tasks, total;
208  
-      total = 2;
209 218
       finished = false;
  219
+      total = 2;
210 220
       tasks = new balUtil.Group(function(err) {
  221
+        if (err) {
  222
+          return done(err);
  223
+        }
211 224
         assert.equal(false, finished, 'the group of tasks only finished once');
212  
-        finished = true;
213  
-        return assert.equal(false, err != null, 'no error is present');
  225
+        return finished = true;
214 226
       });
215 227
       tasks.push(function(done) {
216 228
         return done();
@@ -228,12 +240,14 @@
228 240
     });
229 241
     it('should work when specifying contexts', function(done) {
230 242
       var finished, tasks, total;
231  
-      total = 2;
232 243
       finished = false;
  244
+      total = 2;
233 245
       tasks = new balUtil.Group(function(err) {
  246
+        if (err) {
  247
+          return done(err);
  248
+        }
234 249
         assert.equal(false, finished, 'the group of tasks only finished once');
235  
-        finished = true;
236  
-        return assert.equal(false, err != null, 'no error is present');
  250
+        return finished = true;
237 251
       });
238 252
       tasks.push({
239 253
         blah: 1
@@ -255,65 +269,20 @@
255 269
         return done();
256 270
       });
257 271
     });
258  
-    it('should work when running ten thousand tasks synchronously', function(done) {
259  
-      var finished, i, tasks, total, _i;
260  
-      total = 10000;
261  
-      finished = false;
262  
-      tasks = new balUtil.Group(function(err) {
263  
-        assert.equal(false, finished, 'the group of tasks only finished once');
264  
-        finished = true;
265  
-        return assert.equal(false, err != null, 'no error is present');
266  
-      });
267  
-      for (i = _i = 0; 0 <= total ? _i < total : _i > total; i = 0 <= total ? ++_i : --_i) {
268  
-        tasks.push(function(complete) {
269  
-          return complete();
270  
-        });
271  
-      }
272  
-      assert.equal(0, tasks.completed, 'no tasks should have started yet');
273  
-      tasks.sync();
274  
-      return wait(5000, function() {
275  
-        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
276  
-        assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
277  
-        assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
278  
-        assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
279  
-        return done();
280  
-      });
281  
-    });
282  
-    it('should work when running ten thousand tasks asynchronously', function(done) {
283  
-      var finished, i, tasks, total, _i;
284  
-      total = 10000;
285  
-      finished = false;
286  
-      tasks = new balUtil.Group(function(err) {
287  
-        assert.equal(false, finished, 'the group of tasks only finished once');
288  
-        finished = true;
289  
-        return assert.equal(false, err != null, 'no error is present');
290  
-      });
291  
-      for (i = _i = 0; 0 <= total ? _i < total : _i > total; i = 0 <= total ? ++_i : --_i) {
292  
-        tasks.push(function(complete) {
293  
-          return setTimeout(complete, 50);
294  
-        });
295  
-      }
296  
-      assert.equal(0, tasks.completed, 'no tasks should have started yet');
297  
-      tasks.async();
298  
-      return wait(5000, function() {
299  
-        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
300  
-        assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
301  
-        assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
302  
-        assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
303  
-        return done();
304  
-      });
305  
-    });
306 272
     it('should push and run synchronous tasks correctly', function(done) {
307  
-      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks;
  273
+      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks, total;
308 274
       firstTaskRun = false;
309 275
       secondTaskRun = false;
310 276
       firstTaskFinished = false;
311 277
       secondTaskFinished = false;
312 278
       finished = false;
  279
+      total = 2;
313 280
       tasks = new balUtil.Group('sync', function(err) {
  281
+        if (err) {
  282
+          return done(err);
  283
+        }
314 284
         assert.equal(false, finished, 'the group of tasks only finished once');
315  
-        finished = true;
316  
-        return assert.equal(false, err != null, 'no error is present');
  285
+        return finished = true;
317 286
       });
318 287
       assert.equal('sync', tasks.mode, 'mode was correctly set to sync');
319 288
       tasks.pushAndRun(function(complete) {
@@ -336,7 +305,7 @@
336 305
         });
337 306
       });
338 307
       return wait(4000, function() {
339  
-        assert.equal(2, tasks.completed, 'only the expected number of tasks ran');
  308
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
340 309
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
341 310
         assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
342 311
         assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
@@ -344,16 +313,19 @@
344 313
       });
345 314
     });
346 315
     it('should push and run asynchronous tasks correctly (queued)', function(done) {
347  
-      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks;
  316
+      var finished, firstTaskFinished, firstTaskRun, secondTaskFinished, secondTaskRun, tasks, total;
348 317
       firstTaskRun = false;
349 318
       secondTaskRun = false;
350 319
       firstTaskFinished = false;
351 320
       secondTaskFinished = false;
352 321
       finished = false;
  322
+      total = 2;
353 323
       tasks = new balUtil.Group('async', function(err) {
  324
+        if (err) {
  325
+          return done(err);
  326
+        }
354 327
         assert.equal(false, finished, 'the group of tasks only finished once');
355  
-        finished = true;
356  
-        return assert.equal(false, err != null, 'no error is present');
  328
+        return finished = true;
357 329
       });
358 330
       assert.equal('async', tasks.mode, 'mode was correctly set to async');
359 331
       tasks.pushAndRun(function(complete) {
@@ -376,21 +348,24 @@
376 348
         });
377 349
       });
378 350
       return wait(4000, function() {
379  
-        assert.equal(2, tasks.completed, 'only the expected number of tasks ran');
  351
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
380 352
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
381 353
         assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
382 354
         assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
383 355
         return done();
384 356
       });
385 357
     });
386  
-    return it('should push and run synchronous tasks correctly (multiple times)', function(done) {
387  
-      var finished, tasks;
  358
+    it('should push and run synchronous tasks correctly (multiple times)', function(done) {
  359
+      var finished, tasks, total;
388 360
       finished = 0;
  361
+      total = 2;
389 362
       tasks = new balUtil.Group('sync', {
390 363
         autoClear: true
391 364
       }, function(err) {
392  
-        ++finished;
393  
-        return assert.equal(false, err != null, 'no error is present');
  365
+        if (err) {
  366
+          return done(err);
  367
+        }
  368
+        return ++finished;
394 369
       });
395 370
       assert.equal('sync', tasks.mode, 'mode was correctly set to sync');
396 371
       assert.equal(true, tasks.autoClear, 'autoClear was correctly set to true');
@@ -406,13 +381,65 @@
406 381
         return assert.equal(true, tasks.isRunning(), 'isRunning() returned true');
407 382
       });
408 383
       return wait(2000, function() {
409  
-        assert.equal(2, finished, 'it exited the correct number of times');
  384
+        assert.equal(total, finished, 'it exited the correct number of times');
410 385
         assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
411 386
         assert.equal(false, tasks.hasCompleted(), 'hasCompleted() returned false');
412 387
         assert.equal(false, tasks.hasExited(), 'hasExited() returned false');
413 388
         return done();
414 389
       });
415 390
     });
  391
+    it('should work when running ten thousand tasks synchronously', function(done) {
  392
+      var finished, i, tasks, total, _i;
  393
+      finished = false;
  394
+      total = 10000;
  395
+      tasks = new balUtil.Group(function(err) {
  396
+        if (err) {
  397
+          return done(err);
  398
+        }
  399
+        assert.equal(false, finished, 'the group of tasks only finished once');
  400
+        return finished = true;
  401
+      });
  402
+      for (i = _i = 0; 0 <= total ? _i < total : _i > total; i = 0 <= total ? ++_i : --_i) {
  403
+        tasks.push(function(complete) {
  404
+          return complete();
  405
+        });
  406
+      }
  407
+      assert.equal(0, tasks.completed, 'no tasks should have started yet');
  408
+      tasks.sync();
  409
+      return wait(5000, function() {
  410
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
  411
+        assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
  412
+        assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
  413
+        assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
  414
+        return done();
  415
+      });
  416
+    });
  417
+    return it('should work when running ten thousand tasks asynchronously', function(done) {
  418
+      var finished, i, tasks, total, _i;
  419
+      finished = false;
  420
+      total = 10000;
  421
+      tasks = new balUtil.Group(function(err) {
  422
+        if (err) {
  423
+          return done(err);
  424
+        }
  425
+        assert.equal(false, finished, 'the group of tasks only finished once');
  426
+        return finished = true;
  427
+      });
  428
+      for (i = _i = 0; 0 <= total ? _i < total : _i > total; i = 0 <= total ? ++_i : --_i) {
  429
+        tasks.push(function(complete) {
  430
+          return setTimeout(complete, 50);
  431
+        });
  432
+      }
  433
+      assert.equal(0, tasks.completed, 'no tasks should have started yet');
  434
+      tasks.async();
  435
+      return wait(5000, function() {
  436
+        assert.equal(total, tasks.completed, 'the expected number of tasks ran ' + ("" + tasks.completed + "/" + total));
  437
+        assert.equal(false, tasks.isRunning(), 'isRunning() returned false');
  438
+        assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true');
  439
+        assert.equal(true, tasks.hasExited(), 'hasExited() returned true');
  440
+        return done();
  441
+      });
  442
+    });
416 443
   });
417 444
 
418 445
 }).call(this);
4  package.json
... ...
@@ -1,6 +1,6 @@
1 1
 {
2 2
 	"name": "bal-util",
3  
-	"version": "1.11.0",
  3
+	"version": "1.11.1",
4 4
 	"description": "Common utility functions for Node.js used and maintained by Benjamin Lupton",
5 5
 	"homepage": "https://github.com/balupton/bal-util",
6 6
 	"keywords": [
@@ -50,7 +50,7 @@
50 50
 		"lib": "./out/lib"
51 51
 	},
52 52
 	"scripts": {
53  
-		"test": "node ./out/test/everything.test.js --joe-reporter=list"
  53
+		"test": "node ./out/test/everything.test.js --joe-reporter=console"
54 54
 	},
55 55
 	"main": "./out/lib/balutil"
56 56
 }
128  src/lib/flow.coffee
@@ -234,13 +234,20 @@ balUtilFlow.Group = class
234 234
 		@exited = value  if value?
235 235
 		return @exited is true
236 236
 
  237
+	# Log an error
  238
+	logError: (err) ->
  239
+		# Only push the error if we haven't already added it
  240
+		if @errors[@errors.length-1] isnt err
  241
+			@errors.push(err)
  242
+		# Chain
  243
+		@
  244
+
237 245
 	# A task has completed
238 246
 	complete: (args...) ->
239 247
 		# Push the result
240 248
 		err = args[0] or undefined
241  
-		# console.log(err)  if err
242 249
 		@lastResult = args
243  
-		@errors.push(err)  if err
  250
+		@logError(err)  if err
244 251
 		@results.push(args)
245 252
 
246 253
 		# We are one less running task
@@ -249,7 +256,7 @@ balUtilFlow.Group = class
249 256
 
250 257
 		# Check if we have already completed
251 258
 		if @hasExited()
252  
-			# if so, do nothing
  259
+			# do nothing
253 260
 
254 261
 		# Otherwise
255 262
 		else
@@ -276,6 +283,9 @@ balUtilFlow.Group = class
276 283
 
277 284
 	# The group has finished
278 285
 	exit: (err=null) ->
  286
+		# Push the error if we were passed one
  287
+		@logError(err)  if err
  288
+
279 289
 		# Check if we have already exited, if so, ignore
280 290
 		if @hasExited()
281 291
 			# do nothing
@@ -284,10 +294,18 @@ balUtilFlow.Group = class
284 294
 		else
285 295
 			# Fetch the results
286 296
 			lastResult = @lastResult
287  
-			errors = if @errors.length isnt 0 then @errors else null
288  
-			errors = errors[0]  if @errors.length is 1
289 297
 			results = @results
290 298
 
  299
+			# If have multiple errors, return an array
  300
+			# If we have one error, return that error
  301
+			# If we have no errors, retur null
  302
+			if @errors.length is 0
  303
+				errors = null
  304
+			else if @errors.length is 1
  305
+				errors = @errors[0]
  306
+			else
  307
+				errors = @errors
  308
+
291 309
 			# Clear, and exit with the results
292 310
 			if @autoClear
293 311
 				@clear()
@@ -311,40 +329,22 @@ balUtilFlow.Group = class
311 329
 		# Add the task and increment the count
312 330
 		++@total
313 331
 
314  
-		# Bind
315  
-		if args.length is 2
316  
-			context = args[0]
317  
-			_task = args[1]
318  
-			task = (complete) ->
319  
-				balUtilFlow.fireWithOptionalCallback(_task,[complete],context)
320  
-		else
321  
-			task = args[0]
322  
-
323 332
 		# Queue
324  
-		@queue.push(task)
  333
+		@queue.push(args)
325 334
 
326 335
 		# Chain
327 336
 		@
328 337
 
329 338
 	# Push and run
330 339
 	pushAndRun: (args...) ->
331  
-		# Bind
332  
-		if args.length is 2
333  
-			context = args[0]
334  
-			_task = args[1]
335  
-			task = (complete) ->
336  
-				balUtilFlow.fireWithOptionalCallback(_task,[complete],context)
337  
-		else
338  
-			task = args[0]
339  
-
340 340
 		# Check if we are currently running in sync mode
341 341
 		if @mode is 'sync' and @isRunning()
342 342
 			# push the task for later
343  
-			@push(task)
  343
+			@push(args...)
344 344
 		else
345 345
 			# run the task now
346 346
 			++@total
347  
-			@runTask(task)
  347
+			@runTask(args)
348 348
 
349 349
 		# Chain
350 350
 		@
@@ -369,7 +369,18 @@ balUtilFlow.Group = class
369 369
 			run = ->
370 370
 				++me.running
371 371
 				complete = me.completer()
372  
-				balUtilFlow.fireWithOptionalCallback(task,[complete])
  372
+				if balUtilFlow.isArray(task)
  373
+					if task.length is 2
  374
+						_context = task[0]
  375
+						_task = task[1]
  376
+					else if task.length is 1
  377
+						_task = task[0]
  378
+						_context = null
  379
+					else
  380
+						throw new Error('balUtilFlow.Group an invalid task was pushed')
  381
+				else
  382
+					_task = task
  383
+				balUtilFlow.fireWithOptionalCallback(_task,[complete],_context)
373 384
 
374 385
 			# Fire with an immediate timeout for async loads, and every hundredth sync task, except for the first
375 386
 			# otherwise if we are under a stressful load node will crash with
@@ -426,47 +437,53 @@ balUtilFlow.Block = class extends balUtilFlow.Group
426 437
 
427 438
 	# Create a new block and run it
428 439
 	# fn(block.block, block.task, block.exit)
429  
-	constructor: (name, initFunction, parentBlock) ->
  440
+	# complete(err)
  441
+	constructor: (opts) ->
430 442
 		# Prepare
431 443
 		block = @
  444
+		{name, fn, parentBlock, complete} = opts
432 445
 
433  
-		# Apply
434  
-		super (err) ->
435  
-			block.blockAfter(block,err)
436  
-			block.parentBlock?.complete(err)
  446
+		# Apply options
437 447
 		block.blockName = name
438 448
 		block.parentBlock = parentBlock  if parentBlock?
439 449
 		block.mode = 'sync'
440  
-		block.initFunction = initFunction
  450
+		block.fn = fn
  451
+
  452
+		# Create group
  453
+		super (err) ->
  454
+			block.blockAfter(block,err)
  455
+			complete?(err)
441 456
 
442 457
 		# Event
443 458
 		block.blockBefore(block)
444 459
 
445  
-		# If we have an initFunction
446  
-		if block.initFunction?
447  
-			# If our initFunction has a completion callback
  460
+		# If we have an fn
  461
+		if block.fn?
  462
+			# If our fn has a completion callback
448 463
 			# then set the total tasks to infinity
449 464
 			# so we wait for the competion callback instead of completeling automatically
450  
-			if block.initFunction.length is 3
  465
+			if block.fn.length is 3
451 466
 				block.total = Infinity
452 467
 
453 468
 			# Fire the init function
454 469
 			try
455  
-				block.initFunction(
  470
+				block.fn(
  471
+					# Create sub block
456 472
 					(name,fn) -> block.block(name,fn)
  473
+					# Create sub task
457 474
 					(name,fn) -> block.task(name,fn)
  475
+					# Complete
458 476
 					(err) -> block.exit(err)
459 477
 				)
  478
+
  479
+				# If our fn completion callback is synchronous
  480
+				# then fire our tasks right away
  481
+				if block.fn.length isnt 3
  482
+					block.run()
460 483
 			catch err
461 484
 				block.exit(err)
462  
-
463  
-			# If our initFunction completion callback
464  
-			# then fire our tasks right away
465  
-			if block.initFunction.length isnt 3
466  
-				block.run()
467  
-
468 485
 		else
469  
-			# We don't have an initFunction
  486
+			# We don't have an fn
470 487
 			# So lets set our total tasks to infinity
471 488
 			block.total = Infinity
472 489
 
@@ -478,29 +495,30 @@ balUtilFlow.Block = class extends balUtilFlow.Group
478 495
 	block: (name,fn) ->
479 496
 		# Push the creation of our subBlock to our block's queue
480 497
 		block = @
481  
-		push = (complete) ->
  498
+		pushBlock = (fn) ->
482 499
 			if block.total is Infinity
483  
-				block.pushAndRun(complete)
  500
+				block.pushAndRun(fn)
484 501
 			else
485  
-				block.push(complete)
486  
-		push ->
487  
-			subBlock = block.createSubBlock(name,fn,block)
  502
+				block.push(fn)
  503
+		pushBlock (complete) ->
  504
+			subBlock = block.createSubBlock({name,fn,complete})
488 505
 		@
489 506
 
490 507
 	# Create a sub block
491  
-	createSubBlock: (name,fn,parentBlock) ->
492  
-		new balUtilFlow.Block(name,fn,parentBlock)
  508
+	createSubBlock: (opts) ->
  509
+		opts.parentBlock = @
  510
+		new balUtilFlow.Block(opts)
493 511
 
494 512
 	# Create a task for our current block
495 513
 	# fn(complete)
496 514
 	task: (name,fn) ->
497 515
 		# Prepare
498 516
 		block = @
499  
-		pushTask = (complete) ->
  517
+		pushTask = (fn) ->
500 518
 			if block.total is Infinity
501  
-				block.pushAndRun(complete)
  519
+				block.pushAndRun(fn)
502 520
 			else
503  
-				block.push(complete)
  521
+				block.push(fn)
504 522
 
505 523
 		# Push the task to the correct place
506 524
 		pushTask (complete) ->
167  src/test/flow.test.coffee
@@ -53,12 +53,13 @@ joe.describe 'Group', (describe,it) ->
53 53
 		firstTaskFinished = false
54 54
 		secondTaskFinished = false
55 55
 		finished = false
  56
+		total = 2
56 57
 
57 58
 		# Create our group
58 59
 		tasks = new balUtil.Group (err) ->
  60
+			return done(err)  if err
59 61
 			assert.equal(false, finished, 'the group of tasks only finished once')
60 62
 			finished = true
61  
-			assert.equal(false, err?, 'no error is present')
62 63
 		tasks.total = 2
63 64
 
64 65
 		# Make the first task finish after the second task
@@ -78,7 +79,7 @@ joe.describe 'Group', (describe,it) ->
78 79
 
79 80
 		# Check all tasks ran
80 81
 		wait 2000, ->
81  
-			assert.equal(2, tasks.completed, 'only the expected number of tasks ran')
  82
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
82 83
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
83 84
 			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
84 85
 			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
@@ -92,12 +93,13 @@ joe.describe 'Group', (describe,it) ->
92 93
 		firstTaskFinished = false
93 94
 		secondTaskFinished = false
94 95
 		finished = false
  96
+		total = 2
95 97
 
96 98
 		# Create our group
97 99
 		tasks = new balUtil.Group (err) ->
  100
+			return done(err)  if err
98 101
 			assert.equal(false, finished, 'the group of tasks only finished once')
99 102
 			finished = true
100  
-			assert.equal(false, err?, 'no error is present')
101 103
 
102 104
 		# Make the first task take longer than the second task, but as we run synchronously, it should still finish first
103 105
 		tasks.push (complete) ->
@@ -126,7 +128,7 @@ joe.describe 'Group', (describe,it) ->
126 128
 
127 129
 		# Check all tasks ran
128 130
 		wait 2000, ->
129  
-			assert.equal(2, tasks.completed, 'only the expected number of tasks ran')
  131
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
130 132
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
131 133
 			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
132 134
 			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
@@ -140,12 +142,13 @@ joe.describe 'Group', (describe,it) ->
140 142
 		firstTaskFinished = false
141 143
 		secondTaskFinished = false
142 144
 		finished = false
  145
+		total = 2
143 146
 
144 147
 		# Create our group
145 148
 		tasks = new balUtil.Group (err) ->
  149
+			return done(err)  if err
146 150
 			assert.equal(false, finished, 'the group of tasks only finished once')
147 151
 			finished = true
148  
-			assert.equal(false, err?, 'no error is present')
149 152
 
150 153
 		# Make the first task take longer than the second task, and as we run asynchronously, it should finish last
151 154
 		tasks.push (complete) ->
@@ -174,7 +177,7 @@ joe.describe 'Group', (describe,it) ->
174 177
 
175 178
 		# Check all tasks ran
176 179
 		wait 2000, ->
177  
-			assert.equal(2, tasks.completed, 'only the expected number of tasks ran')
  180
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
178 181
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
179 182
 			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
180 183
 			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
@@ -189,12 +192,13 @@ joe.describe 'Group', (describe,it) ->
189 192
 		firstTaskFinished = false
190 193
 		secondTaskFinished = false
191 194
 		finished = false
  195
+		total = 1
192 196
 
193 197
 		# Create our group
194 198
 		tasks = new balUtil.Group (err) ->
  199
+			assert.equal(true, err != null, 'an error is present');
195 200
 			assert.equal(false, finished, 'the group of tasks only finished once')
196 201
 			finished = true
197  
-			assert.equal(true, err?, 'an error is present')
198 202
 
199 203
 		# Make the first task take longer than the second task, but as we run synchronously, it should still finish first
200 204
 		tasks.push (complete) ->
@@ -223,7 +227,7 @@ joe.describe 'Group', (describe,it) ->
223 227
 
224 228
 		# Check all tasks ran
225 229
 		wait 2000, ->
226  
-			assert.equal(1, tasks.completed, 'only the expected number of tasks ran')
  230
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
227 231
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
228 232
 			assert.equal(false, tasks.hasCompleted(), 'hasCompleted() returned true')
229 233
 			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
@@ -232,14 +236,14 @@ joe.describe 'Group', (describe,it) ->
232 236
 
233 237
 	it 'should work with optional completion callbacks', (done) ->
234 238
 		# Prepare
235  
-		total = 2
236 239
 		finished = false
  240
+		total = 2
237 241
 
238 242
 		# Create our group
239 243
 		tasks = new balUtil.Group (err) ->
  244
+			return done(err)  if err
240 245
 			assert.equal(false, finished, 'the group of tasks only finished once')
241 246
 			finished = true
242  
-			assert.equal(false, err?, 'no error is present')
243 247
 
244 248
 		# Add the first task
245 249
 		tasks.push (done) -> done()
@@ -263,14 +267,14 @@ joe.describe 'Group', (describe,it) ->
263 267
 
264 268
 	it 'should work when specifying contexts', (done) ->
265 269
 		# Prepare
266  
-		total = 2
267 270
 		finished = false
  271
+		total = 2
268 272
 
269 273
 		# Create our group
270 274
 		tasks = new balUtil.Group (err) ->
  275
+			return done(err)  if err
271 276
 			assert.equal(false, finished, 'the group of tasks only finished once')
272 277
 			finished = true
273  
-			assert.equal(false, err?, 'no error is present')
274 278
 
275 279
 		# Add the first task
276 280
 		tasks.push {blah:1}, ->
@@ -295,67 +299,6 @@ joe.describe 'Group', (describe,it) ->
295 299
 			done()
296 300
 
297 301
 
298  
-	it 'should work when running ten thousand tasks synchronously', (done) ->
299  
-		# Prepare
300  
-		total = 10000
301  
-		finished = false
302  
-
303  
-		# Create our group
304  
-		tasks = new balUtil.Group (err) ->
305  
-			assert.equal(false, finished, 'the group of tasks only finished once')
306  
-			finished = true
307  
-			assert.equal(false, err?, 'no error is present')
308  
-
309  
-		# Add the tasks
310  
-		for i in [0...total]
311  
-			tasks.push (complete) ->
312  
-				complete()
313  
-
314  
-		# Check no tasks have run
315  
-		assert.equal(0, tasks.completed, 'no tasks should have started yet')
316  
-
317  
-		# Run the tasks
318  
-		tasks.sync()
319  
-
320  
-		# Check all tasks ran
321  
-		wait 5000, ->
322  
-			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
323  
-			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
324  
-			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
325  
-			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
326  
-			done()
327  
-
328  
-
329  
-	it 'should work when running ten thousand tasks asynchronously', (done) ->
330  
-		# Prepare
331  
-		total = 10000
332  
-		finished = false
333  
-
334  
-		# Create our group
335  
-		tasks = new balUtil.Group (err) ->
336  
-			assert.equal(false, finished, 'the group of tasks only finished once')
337  
-			finished = true
338  
-			assert.equal(false, err?, 'no error is present')
339  
-
340  
-		# Add the tasks
341  
-		for i in [0...total]
342  
-			tasks.push (complete) ->
343  
-				setTimeout(complete,50)
344  
-
345  
-		# Check no tasks have run
346  
-		assert.equal(0, tasks.completed, 'no tasks should have started yet')
347  
-
348  
-		# Run the tasks
349  
-		tasks.async()
350  
-
351  
-		# Check all tasks ran
352  
-		wait 5000, ->
353  
-			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
354  
-			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
355  
-			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
356  
-			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
357  
-			done()
358  
-
359 302
 
360 303
 	it 'should push and run synchronous tasks correctly', (done) ->
361 304
 		# Prepare
@@ -364,12 +307,13 @@ joe.describe 'Group', (describe,it) ->
364 307
 		firstTaskFinished = false
365 308
 		secondTaskFinished = false
366 309
 		finished = false
  310
+		total = 2
367 311
 
368 312
 		# Create our group
369 313
 		tasks = new balUtil.Group 'sync', (err) ->
  314
+			return done(err)  if err
370 315
 			assert.equal(false, finished, 'the group of tasks only finished once')
371 316
 			finished = true
372  
-			assert.equal(false, err?, 'no error is present')
373 317
 		assert.equal('sync', tasks.mode, 'mode was correctly set to sync')
374 318
 
375 319
 		# Make the first task take longer than the second task, but as we run synchronously, it should still finish first
@@ -395,7 +339,7 @@ joe.describe 'Group', (describe,it) ->
395 339
 
396 340
 		# Check all tasks ran
397 341
 		wait 4000, ->
398  
-			assert.equal(2, tasks.completed, 'only the expected number of tasks ran')
  342
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
399 343
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
400 344
 			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
401 345
 			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
@@ -410,12 +354,13 @@ joe.describe 'Group', (describe,it) ->
410 354
 		firstTaskFinished = false
411 355
 		secondTaskFinished = false
412 356
 		finished = false
  357
+		total = 2
413 358
 
414 359
 		# Create our group
415 360
 		tasks = new balUtil.Group 'async', (err) ->
  361
+			return done(err)  if err
416 362
 			assert.equal(false, finished, 'the group of tasks only finished once')
417 363
 			finished = true
418  
-			assert.equal(false, err?, 'no error is present')
419 364
 		assert.equal('async', tasks.mode, 'mode was correctly set to async')
420 365
 
421 366
 		# Make the first task take longer than the second task, but as we run synchronously, it should still finish first
@@ -441,7 +386,7 @@ joe.describe 'Group', (describe,it) ->
441 386
 
442 387
 		# Check all tasks ran
443 388
 		wait 4000, ->
444  
-			assert.equal(2, tasks.completed, 'only the expected number of tasks ran')
  389
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
445 390
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
446 391
 			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
447 392
 			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
@@ -451,11 +396,12 @@ joe.describe 'Group', (describe,it) ->
451 396
 	it 'should push and run synchronous tasks correctly (multiple times)', (done) ->
452 397
 		# Prepare
453 398
 		finished = 0
  399
+		total = 2
454 400
 
455 401
 		# Create our group
456 402
 		tasks = new balUtil.Group 'sync', {autoClear: true}, (err) ->
  403
+			return done(err)  if err
457 404
 			++finished
458  
-			assert.equal(false, err?, 'no error is present')
459 405
 		assert.equal('sync', tasks.mode, 'mode was correctly set to sync')
460 406
 		assert.equal(true, tasks.autoClear, 'autoClear was correctly set to true')
461 407
 
@@ -469,8 +415,71 @@ joe.describe 'Group', (describe,it) ->
469 415
 
470 416
 		# Check all tasks ran
471 417
 		wait 2000, ->
472  
-			assert.equal(2, finished, 'it exited the correct number of times')
  418
+			assert.equal(total, finished, 'it exited the correct number of times')
473 419
 			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
474 420
 			assert.equal(false, tasks.hasCompleted(), 'hasCompleted() returned false')
475 421
 			assert.equal(false, tasks.hasExited(), 'hasExited() returned false')
476 422
 			done()
  423
+
  424
+
  425
+
  426
+	it 'should work when running ten thousand tasks synchronously', (done) ->
  427
+		# Prepare
  428
+		finished = false
  429
+		total = 10000
  430
+
  431
+		# Create our group
  432
+		tasks = new balUtil.Group (err) ->
  433
+			return done(err)  if err
  434
+			assert.equal(false, finished, 'the group of tasks only finished once')
  435
+			finished = true
  436
+
  437
+		# Add the tasks
  438
+		for i in [0...total]
  439
+			tasks.push (complete) ->
  440
+				complete()
  441
+
  442
+		# Check no tasks have run
  443
+		assert.equal(0, tasks.completed, 'no tasks should have started yet')
  444
+
  445
+		# Run the tasks
  446
+		tasks.sync()
  447
+
  448
+		# Check all tasks ran
  449
+		wait 5000, ->
  450
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
  451
+			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
  452
+			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
  453
+			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
  454
+			done()
  455
+
  456
+
  457
+	it 'should work when running ten thousand tasks asynchronously', (done) ->
  458
+		# Prepare
  459
+		finished = false
  460
+		total = 10000
  461
+
  462
+		# Create our group
  463
+		tasks = new balUtil.Group (err) ->
  464
+			return done(err)  if err
  465
+			assert.equal(false, finished, 'the group of tasks only finished once')
  466
+			finished = true
  467
+
  468
+		# Add the tasks
  469
+		for i in [0...total]
  470
+			tasks.push (complete) ->
  471
+				setTimeout(complete,50)
  472
+
  473
+		# Check no tasks have run
  474
+		assert.equal(0, tasks.completed, 'no tasks should have started yet')
  475
+
  476
+		# Run the tasks
  477
+		tasks.async()
  478
+
  479
+		# Check all tasks ran
  480
+		wait 5000, ->
  481
+			assert.equal(total, tasks.completed, 'the expected number of tasks ran '+"#{tasks.completed}/#{total}")
  482
+			assert.equal(false, tasks.isRunning(), 'isRunning() returned false')
  483
+			assert.equal(true, tasks.hasCompleted(), 'hasCompleted() returned true')
  484
+			assert.equal(true, tasks.hasExited(), 'hasExited() returned true')
  485
+			done()

No commit comments for this range

Something went wrong with that request. Please try again.