matcha 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +19 -0
  2. data/Gemfile +7 -0
  3. data/LICENSE +90 -0
  4. data/README.md +194 -0
  5. data/Rakefile +8 -0
  6. data/app/controllers/matcha/specs_controller.rb +22 -0
  7. data/app/models/matcha/spec.rb +25 -0
  8. data/app/views/layouts/matcha/specs.html.erb +31 -0
  9. data/app/views/matcha/specs/index.html.erb +1 -0
  10. data/app/views/matcha/specs/show.html.erb +1 -0
  11. data/config/routes.rb +4 -0
  12. data/lib/matcha.rb +41 -0
  13. data/lib/matcha/engine.rb +31 -0
  14. data/lib/matcha/runner.rb +151 -0
  15. data/lib/matcha/server.rb +7 -0
  16. data/lib/tasks/matcha.rake +11 -0
  17. data/matcha.gemspec +30 -0
  18. data/spec/controllers/specs_controller_spec.rb +46 -0
  19. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  20. data/spec/dummy/app/assets/javascripts/array_sum.js.coffee +4 -0
  21. data/spec/dummy/config.ru +4 -0
  22. data/spec/dummy/config/application.rb +17 -0
  23. data/spec/dummy/config/boot.rb +6 -0
  24. data/spec/dummy/config/environment.rb +5 -0
  25. data/spec/dummy/config/environments/test.rb +29 -0
  26. data/spec/dummy/config/initializers/matcha.rb +3 -0
  27. data/spec/dummy/spec/javascripts/array_sum_cs_spec.js.coffee +8 -0
  28. data/spec/dummy/spec/javascripts/array_sum_js_spec.js +11 -0
  29. data/spec/dummy/spec/javascripts/assert_spec.js.coffee +9 -0
  30. data/spec/dummy/spec/javascripts/failing_spec.js +5 -0
  31. data/spec/dummy/spec/javascripts/spec_helper.js +3 -0
  32. data/spec/dummy/spec/javascripts/spec_helper_spec.js +7 -0
  33. data/spec/dummy/spec/javascripts/subdirectory/subdirectory_spec.js +5 -0
  34. data/spec/dummy/spec/javascripts/templates/hello.jst.ejs +1 -0
  35. data/spec/dummy/spec/javascripts/templating_spec.js +8 -0
  36. data/spec/dummy/spec/javascripts/transactions_spec.js.coffee +7 -0
  37. data/spec/matcha_spec.rb +40 -0
  38. data/spec/models/spec_spec.rb +45 -0
  39. data/spec/runner_spec.rb +36 -0
  40. data/spec/server_spec.rb +41 -0
  41. data/spec/spec_helper.rb +18 -0
  42. data/spec/views/specs/index.html.erb_spec.rb +12 -0
  43. data/spec/views/specs/show.html.erb_spec.rb +10 -0
  44. data/spec/views/specs/specs.html.erb_spec.rb +15 -0
  45. data/vendor/assets/javascripts/chai.js +2007 -0
  46. data/vendor/assets/javascripts/matcha/runner.js +70 -0
  47. data/vendor/assets/javascripts/matcha/server.js +0 -0
  48. data/vendor/assets/javascripts/mocha.js +3290 -0
  49. data/vendor/assets/stylesheets/mocha.css +133 -0
  50. metadata +202 -0
@@ -0,0 +1,70 @@
1
+ (function () {
2
+ window.Matcha = {
3
+ dots:"",
4
+
5
+ Reporter:function (runner) {
6
+ window.mocha.reporters.Base.call(this, runner);
7
+
8
+ runner.on('start', function () {
9
+ Matcha.results = [];
10
+ });
11
+
12
+ runner.on('pass', function (test) {
13
+ Matcha.dots += ".";
14
+ Matcha.results.push({
15
+ name: test.title,
16
+ passed: true
17
+ });
18
+ });
19
+
20
+ runner.on('fail', function (test) {
21
+ Matcha.dots += "F";
22
+ Matcha.results.push({
23
+ name: test.title,
24
+ passed: false,
25
+ message: test.err.message,
26
+ trace: test.err.stack
27
+ });
28
+ });
29
+
30
+ runner.on('end', function () {
31
+ Matcha.done = true;
32
+ });
33
+ },
34
+
35
+ getResults:function () {
36
+ return JSON.stringify(Matcha.results);
37
+ }
38
+ };
39
+
40
+ var suite = new mocha.Suite
41
+ , utils = mocha.utils
42
+ , Reporter = Matcha.Reporter;
43
+
44
+ function parse(qs) {
45
+ return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
46
+ var i = pair.indexOf('=')
47
+ , key = pair.slice(0, i)
48
+ , val = pair.slice(++i);
49
+
50
+ obj[key] = decodeURIComponent(val);
51
+ return obj;
52
+ }, {});
53
+ }
54
+
55
+ mocha.setup = function (ui) {
56
+ ui = mocha.interfaces[ui];
57
+ if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
58
+ ui(suite);
59
+ suite.emit('pre-require', window);
60
+ };
61
+
62
+ mocha.run = function () {
63
+ suite.emit('run');
64
+ var runner = new mocha.Runner(suite);
65
+ var reporter = new Reporter(runner);
66
+ var query = parse(window.location.search || "");
67
+ if (query.grep) runner.grep(new RegExp(query.grep));
68
+ return runner.run();
69
+ };
70
+ })();
@@ -0,0 +1,3290 @@
1
+ ;(function(){
2
+
3
+
4
+ // CommonJS require()
5
+
6
+ function require(p){
7
+ var path = require.resolve(p)
8
+ , mod = require.modules[path];
9
+ if (!mod) throw new Error('failed to require "' + p + '"');
10
+ if (!mod.exports) {
11
+ mod.exports = {};
12
+ mod.call(mod.exports, mod, mod.exports, require.relative(path));
13
+ }
14
+ return mod.exports;
15
+ }
16
+
17
+ require.modules = {};
18
+
19
+ require.resolve = function (path){
20
+ var orig = path
21
+ , reg = path + '.js'
22
+ , index = path + '/index.js';
23
+ return require.modules[reg] && reg
24
+ || require.modules[index] && index
25
+ || orig;
26
+ };
27
+
28
+ require.register = function (path, fn){
29
+ require.modules[path] = fn;
30
+ };
31
+
32
+ require.relative = function (parent) {
33
+ return function(p){
34
+ if ('.' != p.charAt(0)) return require(p);
35
+
36
+ var path = parent.split('/')
37
+ , segs = p.split('/');
38
+ path.pop();
39
+
40
+ for (var i = 0; i < segs.length; i++) {
41
+ var seg = segs[i];
42
+ if ('..' == seg) path.pop();
43
+ else if ('.' != seg) path.push(seg);
44
+ }
45
+
46
+ return require(path.join('/'));
47
+ };
48
+ };
49
+
50
+
51
+ require.register("browser/debug.js", function(module, exports, require){
52
+
53
+ module.exports = function(type){
54
+ return function(){
55
+
56
+ }
57
+ };
58
+ }); // module: browser/debug.js
59
+
60
+ require.register("browser/events.js", function(module, exports, require){
61
+
62
+ /**
63
+ * Module exports.
64
+ */
65
+
66
+ exports.EventEmitter = EventEmitter;
67
+
68
+ /**
69
+ * Check if `obj` is an array.
70
+ */
71
+
72
+ function isArray(obj) {
73
+ return '[object Array]' == {}.toString.call(obj);
74
+ }
75
+
76
+ /**
77
+ * Event emitter constructor.
78
+ *
79
+ * @api public.
80
+ */
81
+
82
+ function EventEmitter(){};
83
+
84
+ /**
85
+ * Adds a listener.
86
+ *
87
+ * @api public
88
+ */
89
+
90
+ EventEmitter.prototype.on = function (name, fn) {
91
+ if (!this.$events) {
92
+ this.$events = {};
93
+ }
94
+
95
+ if (!this.$events[name]) {
96
+ this.$events[name] = fn;
97
+ } else if (isArray(this.$events[name])) {
98
+ this.$events[name].push(fn);
99
+ } else {
100
+ this.$events[name] = [this.$events[name], fn];
101
+ }
102
+
103
+ return this;
104
+ };
105
+
106
+ EventEmitter.prototype.addListener = EventEmitter.prototype.on;
107
+
108
+ /**
109
+ * Adds a volatile listener.
110
+ *
111
+ * @api public
112
+ */
113
+
114
+ EventEmitter.prototype.once = function (name, fn) {
115
+ var self = this;
116
+
117
+ function on () {
118
+ self.removeListener(name, on);
119
+ fn.apply(this, arguments);
120
+ };
121
+
122
+ on.listener = fn;
123
+ this.on(name, on);
124
+
125
+ return this;
126
+ };
127
+
128
+ /**
129
+ * Removes a listener.
130
+ *
131
+ * @api public
132
+ */
133
+
134
+ EventEmitter.prototype.removeListener = function (name, fn) {
135
+ if (this.$events && this.$events[name]) {
136
+ var list = this.$events[name];
137
+
138
+ if (isArray(list)) {
139
+ var pos = -1;
140
+
141
+ for (var i = 0, l = list.length; i < l; i++) {
142
+ if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
143
+ pos = i;
144
+ break;
145
+ }
146
+ }
147
+
148
+ if (pos < 0) {
149
+ return this;
150
+ }
151
+
152
+ list.splice(pos, 1);
153
+
154
+ if (!list.length) {
155
+ delete this.$events[name];
156
+ }
157
+ } else if (list === fn || (list.listener && list.listener === fn)) {
158
+ delete this.$events[name];
159
+ }
160
+ }
161
+
162
+ return this;
163
+ };
164
+
165
+ /**
166
+ * Removes all listeners for an event.
167
+ *
168
+ * @api public
169
+ */
170
+
171
+ EventEmitter.prototype.removeAllListeners = function (name) {
172
+ if (name === undefined) {
173
+ this.$events = {};
174
+ return this;
175
+ }
176
+
177
+ if (this.$events && this.$events[name]) {
178
+ this.$events[name] = null;
179
+ }
180
+
181
+ return this;
182
+ };
183
+
184
+ /**
185
+ * Gets all listeners for a certain event.
186
+ *
187
+ * @api publci
188
+ */
189
+
190
+ EventEmitter.prototype.listeners = function (name) {
191
+ if (!this.$events) {
192
+ this.$events = {};
193
+ }
194
+
195
+ if (!this.$events[name]) {
196
+ this.$events[name] = [];
197
+ }
198
+
199
+ if (!isArray(this.$events[name])) {
200
+ this.$events[name] = [this.$events[name]];
201
+ }
202
+
203
+ return this.$events[name];
204
+ };
205
+
206
+ /**
207
+ * Emits an event.
208
+ *
209
+ * @api public
210
+ */
211
+
212
+ EventEmitter.prototype.emit = function (name) {
213
+ if (!this.$events) {
214
+ return false;
215
+ }
216
+
217
+ var handler = this.$events[name];
218
+
219
+ if (!handler) {
220
+ return false;
221
+ }
222
+
223
+ var args = [].slice.call(arguments, 1);
224
+
225
+ if ('function' == typeof handler) {
226
+ handler.apply(this, args);
227
+ } else if (isArray(handler)) {
228
+ var listeners = handler.slice();
229
+
230
+ for (var i = 0, l = listeners.length; i < l; i++) {
231
+ listeners[i].apply(this, args);
232
+ }
233
+ } else {
234
+ return false;
235
+ }
236
+
237
+ return true;
238
+ };
239
+ }); // module: browser/events.js
240
+
241
+ require.register("browser/fs.js", function(module, exports, require){
242
+
243
+ }); // module: browser/fs.js
244
+
245
+ require.register("browser/path.js", function(module, exports, require){
246
+
247
+ }); // module: browser/path.js
248
+
249
+ require.register("browser/progress.js", function(module, exports, require){
250
+
251
+ /**
252
+ * Expose `Progress`.
253
+ */
254
+
255
+ module.exports = Progress;
256
+
257
+ /**
258
+ * Initialize a new `Progress` indicator.
259
+ */
260
+
261
+ function Progress() {
262
+ this.percent = 0;
263
+ this.size(0);
264
+ this.fontSize(11);
265
+ this.font('helvetica, arial, sans-serif');
266
+ }
267
+
268
+ /**
269
+ * Set progress size to `n`.
270
+ *
271
+ * @param {Number} n
272
+ * @return {Progress} for chaining
273
+ * @api public
274
+ */
275
+
276
+ Progress.prototype.size = function(n){
277
+ this._size = n;
278
+ return this;
279
+ };
280
+
281
+ /**
282
+ * Set text to `str`.
283
+ *
284
+ * @param {String} str
285
+ * @return {Progress} for chaining
286
+ * @api public
287
+ */
288
+
289
+ Progress.prototype.text = function(str){
290
+ this._text = str;
291
+ return this;
292
+ };
293
+
294
+ /**
295
+ * Set font size to `n`.
296
+ *
297
+ * @param {Number} n
298
+ * @return {Progress} for chaining
299
+ * @api public
300
+ */
301
+
302
+ Progress.prototype.fontSize = function(n){
303
+ this._fontSize = n;
304
+ return this;
305
+ };
306
+
307
+ /**
308
+ * Set font `family`.
309
+ *
310
+ * @param {String} family
311
+ * @return {Progress} for chaining
312
+ */
313
+
314
+ Progress.prototype.font = function(family){
315
+ this._font = family;
316
+ return this;
317
+ };
318
+
319
+ /**
320
+ * Update percentage to `n`.
321
+ *
322
+ * @param {Number} n
323
+ * @return {Progress} for chaining
324
+ */
325
+
326
+ Progress.prototype.update = function(n){
327
+ this.percent = n;
328
+ return this;
329
+ };
330
+
331
+ /**
332
+ * Draw on `ctx`.
333
+ *
334
+ * @param {CanvasRenderingContext2d} ctx
335
+ * @return {Progress} for chaining
336
+ */
337
+
338
+ Progress.prototype.draw = function(ctx){
339
+ var percent = Math.min(this.percent, 100)
340
+ , size = this._size
341
+ , half = size / 2
342
+ , x = half
343
+ , y = half
344
+ , rad = half - 1
345
+ , fontSize = this._fontSize;
346
+
347
+ ctx.font = fontSize + 'px ' + this._font;
348
+
349
+ var angle = Math.PI * 2 * (percent / 100);
350
+ ctx.clearRect(0, 0, size, size);
351
+
352
+ // outer circle
353
+ ctx.strokeStyle = '#9f9f9f';
354
+ ctx.beginPath();
355
+ ctx.arc(x, y, rad, 0, angle, false);
356
+ ctx.stroke();
357
+
358
+ // inner circle
359
+ ctx.strokeStyle = '#eee';
360
+ ctx.beginPath();
361
+ ctx.arc(x, y, rad - 1, 0, angle, true);
362
+ ctx.stroke();
363
+
364
+ // text
365
+ var text = this._text || (percent | 0) + '%'
366
+ , w = ctx.measureText(text).width;
367
+
368
+ ctx.fillText(
369
+ text
370
+ , x - w / 2 + 1
371
+ , y + fontSize / 2 - 1);
372
+
373
+ return this;
374
+ };
375
+
376
+ }); // module: browser/progress.js
377
+
378
+ require.register("browser/tty.js", function(module, exports, require){
379
+
380
+ exports.isatty = function(){
381
+ return true;
382
+ };
383
+
384
+ exports.getWindowSize = function(){
385
+ return [window.innerHeight, window.innerWidth];
386
+ };
387
+ }); // module: browser/tty.js
388
+
389
+ require.register("hook.js", function(module, exports, require){
390
+
391
+ /**
392
+ * Module dependencies.
393
+ */
394
+
395
+ var Runnable = require('./runnable');
396
+
397
+ /**
398
+ * Expose `Hook`.
399
+ */
400
+
401
+ module.exports = Hook;
402
+
403
+ /**
404
+ * Initialize a new `Hook` with the given `title` and callback `fn`.
405
+ *
406
+ * @param {String} title
407
+ * @param {Function} fn
408
+ * @api private
409
+ */
410
+
411
+ function Hook(title, fn) {
412
+ Runnable.call(this, title, fn);
413
+ }
414
+
415
+ /**
416
+ * Inherit from `Runnable.prototype`.
417
+ */
418
+
419
+ Hook.prototype = new Runnable;
420
+ Hook.prototype.constructor = Hook;
421
+
422
+
423
+ }); // module: hook.js
424
+
425
+ require.register("interfaces/bdd.js", function(module, exports, require){
426
+
427
+ /**
428
+ * Module dependencies.
429
+ */
430
+
431
+ var Suite = require('../suite')
432
+ , Test = require('../test');
433
+
434
+ /**
435
+ * BDD-style interface:
436
+ *
437
+ * describe('Array', function(){
438
+ * describe('#indexOf()', function(){
439
+ * it('should return -1 when not present', function(){
440
+ *
441
+ * });
442
+ *
443
+ * it('should return the index when present', function(){
444
+ *
445
+ * });
446
+ * });
447
+ * });
448
+ *
449
+ */
450
+
451
+ module.exports = function(suite){
452
+ var suites = [suite];
453
+
454
+ suite.on('pre-require', function(context){
455
+
456
+ /**
457
+ * Execute before running tests.
458
+ */
459
+
460
+ context.before = function(fn){
461
+ suites[0].beforeAll(fn);
462
+ };
463
+
464
+ /**
465
+ * Execute after running tests.
466
+ */
467
+
468
+ context.after = function(fn){
469
+ suites[0].afterAll(fn);
470
+ };
471
+
472
+ /**
473
+ * Execute before each test case.
474
+ */
475
+
476
+ context.beforeEach = function(fn){
477
+ suites[0].beforeEach(fn);
478
+ };
479
+
480
+ /**
481
+ * Execute after each test case.
482
+ */
483
+
484
+ context.afterEach = function(fn){
485
+ suites[0].afterEach(fn);
486
+ };
487
+
488
+ /**
489
+ * Describe a "suite" with the given `title`
490
+ * and callback `fn` containing nested suites
491
+ * and/or tests.
492
+ */
493
+
494
+ context.describe = function(title, fn){
495
+ var suite = Suite.create(suites[0], title);
496
+ suites.unshift(suite);
497
+ fn();
498
+ suites.shift();
499
+ };
500
+
501
+ /**
502
+ * Describe a specification or test-case
503
+ * with the given `title` and callback `fn`
504
+ * acting as a thunk.
505
+ */
506
+
507
+ context.it = function(title, fn){
508
+ suites[0].addTest(new Test(title, fn));
509
+ };
510
+ });
511
+ };
512
+
513
+ }); // module: interfaces/bdd.js
514
+
515
+ require.register("interfaces/exports.js", function(module, exports, require){
516
+
517
+ /**
518
+ * Module dependencies.
519
+ */
520
+
521
+ var Suite = require('../suite')
522
+ , Test = require('../test');
523
+
524
+ /**
525
+ * TDD-style interface:
526
+ *
527
+ * exports.Array = {
528
+ * '#indexOf()': {
529
+ * 'should return -1 when the value is not present': function(){
530
+ *
531
+ * },
532
+ *
533
+ * 'should return the correct index when the value is present': function(){
534
+ *
535
+ * }
536
+ * }
537
+ * };
538
+ *
539
+ */
540
+
541
+ module.exports = function(suite){
542
+ var suites = [suite];
543
+
544
+ suite.on('require', visit);
545
+
546
+ function visit(obj) {
547
+ var suite;
548
+ for (var key in obj) {
549
+ if ('function' == typeof obj[key]) {
550
+ var fn = obj[key];
551
+ switch (key) {
552
+ case 'before':
553
+ suites[0].beforeAll(fn);
554
+ break;
555
+ case 'after':
556
+ suites[0].afterAll(fn);
557
+ break;
558
+ case 'beforeEach':
559
+ suites[0].beforeEach(fn);
560
+ break;
561
+ case 'afterEach':
562
+ suites[0].afterEach(fn);
563
+ break;
564
+ default:
565
+ suites[0].addTest(new Test(key, fn));
566
+ }
567
+ } else {
568
+ var suite = Suite.create(suites[0], key);
569
+ suites.unshift(suite);
570
+ visit(obj[key]);
571
+ suites.shift();
572
+ }
573
+ }
574
+ }
575
+ };
576
+ }); // module: interfaces/exports.js
577
+
578
+ require.register("interfaces/index.js", function(module, exports, require){
579
+
580
+ exports.bdd = require('./bdd');
581
+ exports.tdd = require('./tdd');
582
+ exports.qunit = require('./qunit');
583
+ exports.exports = require('./exports');
584
+
585
+ }); // module: interfaces/index.js
586
+
587
+ require.register("interfaces/qunit.js", function(module, exports, require){
588
+
589
+ /**
590
+ * Module dependencies.
591
+ */
592
+
593
+ var Suite = require('../suite')
594
+ , Test = require('../test');
595
+
596
+ /**
597
+ * QUnit-style interface:
598
+ *
599
+ * suite('Array');
600
+ *
601
+ * test('#length', function(){
602
+ * var arr = [1,2,3];
603
+ * ok(arr.length == 3);
604
+ * });
605
+ *
606
+ * test('#indexOf()', function(){
607
+ * var arr = [1,2,3];
608
+ * ok(arr.indexOf(1) == 0);
609
+ * ok(arr.indexOf(2) == 1);
610
+ * ok(arr.indexOf(3) == 2);
611
+ * });
612
+ *
613
+ * suite('String');
614
+ *
615
+ * test('#length', function(){
616
+ * ok('foo'.length == 3);
617
+ * });
618
+ *
619
+ */
620
+
621
+ module.exports = function(suite){
622
+ var suites = [suite];
623
+
624
+ suite.on('pre-require', function(context){
625
+
626
+ /**
627
+ * Execute before running tests.
628
+ */
629
+
630
+ context.before = function(fn){
631
+ suites[0].beforeAll(fn);
632
+ };
633
+
634
+ /**
635
+ * Execute after running tests.
636
+ */
637
+
638
+ context.after = function(fn){
639
+ suites[0].afterAll(fn);
640
+ };
641
+
642
+ /**
643
+ * Execute before each test case.
644
+ */
645
+
646
+ context.beforeEach = function(fn){
647
+ suites[0].beforeEach(fn);
648
+ };
649
+
650
+ /**
651
+ * Execute after each test case.
652
+ */
653
+
654
+ context.afterEach = function(fn){
655
+ suites[0].afterEach(fn);
656
+ };
657
+
658
+ /**
659
+ * Describe a "suite" with the given `title`.
660
+ */
661
+
662
+ context.suite = function(title){
663
+ if (suites.length > 1) suites.shift();
664
+ var suite = Suite.create(suites[0], title);
665
+ suites.unshift(suite);
666
+ };
667
+
668
+ /**
669
+ * Describe a specification or test-case
670
+ * with the given `title` and callback `fn`
671
+ * acting as a thunk.
672
+ */
673
+
674
+ context.test = function(title, fn){
675
+ suites[0].addTest(new Test(title, fn));
676
+ };
677
+ });
678
+ };
679
+
680
+ }); // module: interfaces/qunit.js
681
+
682
+ require.register("interfaces/tdd.js", function(module, exports, require){
683
+
684
+ /**
685
+ * Module dependencies.
686
+ */
687
+
688
+ var Suite = require('../suite')
689
+ , Test = require('../test');
690
+
691
+ /**
692
+ * TDD-style interface:
693
+ *
694
+ * suite('Array', function(){
695
+ * suite('#indexOf()', function(){
696
+ * suiteSetup(function(){
697
+ *
698
+ * });
699
+ *
700
+ * test('should return -1 when not present', function(){
701
+ *
702
+ * });
703
+ *
704
+ * test('should return the index when present', function(){
705
+ *
706
+ * });
707
+ *
708
+ * suiteTeardown(function(){
709
+ *
710
+ * });
711
+ * });
712
+ * });
713
+ *
714
+ */
715
+
716
+ module.exports = function(suite){
717
+ var suites = [suite];
718
+
719
+ suite.on('pre-require', function(context){
720
+
721
+ /**
722
+ * Execute before each test case.
723
+ */
724
+
725
+ context.setup = function(fn){
726
+ suites[0].beforeEach(fn);
727
+ };
728
+
729
+ /**
730
+ * Execute after each test case.
731
+ */
732
+
733
+ context.teardown = function(fn){
734
+ suites[0].afterEach(fn);
735
+ };
736
+
737
+ /**
738
+ * Execute before the suite.
739
+ */
740
+
741
+ context.suiteSetup = function(fn){
742
+ suites[0].beforeAll(fn);
743
+ };
744
+
745
+ /**
746
+ * Execute after the suite.
747
+ */
748
+
749
+ context.suiteTeardown = function(fn){
750
+ suites[0].afterAll(fn);
751
+ };
752
+
753
+ /**
754
+ * Describe a "suite" with the given `title`
755
+ * and callback `fn` containing nested suites
756
+ * and/or tests.
757
+ */
758
+
759
+ context.suite = function(title, fn){
760
+ var suite = Suite.create(suites[0], title);
761
+ suites.unshift(suite);
762
+ fn();
763
+ suites.shift();
764
+ };
765
+
766
+ /**
767
+ * Describe a specification or test-case
768
+ * with the given `title` and callback `fn`
769
+ * acting as a thunk.
770
+ */
771
+
772
+ context.test = function(title, fn){
773
+ suites[0].addTest(new Test(title, fn));
774
+ };
775
+ });
776
+ };
777
+
778
+ }); // module: interfaces/tdd.js
779
+
780
+ require.register("mocha.js", function(module, exports, require){
781
+
782
+ /*!
783
+ * mocha
784
+ * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
785
+ * MIT Licensed
786
+ */
787
+
788
+ /**
789
+ * Library version.
790
+ */
791
+
792
+ exports.version = '0.12.0';
793
+
794
+ exports.utils = require('./utils');
795
+ exports.interfaces = require('./interfaces');
796
+ exports.reporters = require('./reporters');
797
+ exports.Runnable = require('./runnable');
798
+ exports.Runner = require('./runner');
799
+ exports.Suite = require('./suite');
800
+ exports.Hook = require('./hook');
801
+ exports.Test = require('./test');
802
+
803
+ }); // module: mocha.js
804
+
805
+ require.register("reporters/base.js", function(module, exports, require){
806
+
807
+ /**
808
+ * Module dependencies.
809
+ */
810
+
811
+ var tty = require('browser/tty');
812
+
813
+ /**
814
+ * Check if both stdio streams are associated with a tty.
815
+ */
816
+
817
+ var isatty = tty.isatty(1) && tty.isatty(2);
818
+
819
+ /**
820
+ * Expose `Base`.
821
+ */
822
+
823
+ exports = module.exports = Base;
824
+
825
+ /**
826
+ * Enable coloring by default.
827
+ */
828
+
829
+ exports.useColors = isatty;
830
+
831
+ /**
832
+ * Default color map.
833
+ */
834
+
835
+ exports.colors = {
836
+ 'pass': 90
837
+ , 'fail': 31
838
+ , 'bright pass': 92
839
+ , 'bright fail': 91
840
+ , 'bright yellow': 93
841
+ , 'pending': 36
842
+ , 'suite': 0
843
+ , 'error title': 0
844
+ , 'error message': 31
845
+ , 'error stack': 90
846
+ , 'checkmark': 32
847
+ , 'fast': 90
848
+ , 'medium': 33
849
+ , 'slow': 31
850
+ , 'green': 32
851
+ , 'light': 90
852
+ };
853
+
854
+ /**
855
+ * Color `str` with the given `type`,
856
+ * allowing colors to be disabled,
857
+ * as well as user-defined color
858
+ * schemes.
859
+ *
860
+ * @param {String} type
861
+ * @param {String} str
862
+ * @return {String}
863
+ * @api private
864
+ */
865
+
866
+ var color = exports.color = function(type, str) {
867
+ if (!exports.useColors) return str;
868
+ return '\033[' + exports.colors[type] + 'm' + str + '\033[0m';
869
+ };
870
+
871
+ /**
872
+ * Expose term window size, with some
873
+ * defaults for when stderr is not a tty.
874
+ */
875
+
876
+ exports.window = {
877
+ width: isatty
878
+ ? process.stdout.getWindowSize
879
+ ? process.stdout.getWindowSize(1)[0]
880
+ : tty.getWindowSize()[1]
881
+ : 75
882
+ };
883
+
884
+ /**
885
+ * Expose some basic cursor interactions
886
+ * that are common among reporters.
887
+ */
888
+
889
+ exports.cursor = {
890
+ hide: function(){
891
+ process.stdout.write('\033[?25l');
892
+ },
893
+
894
+ show: function(){
895
+ process.stdout.write('\033[?25h');
896
+ },
897
+
898
+ deleteLine: function(){
899
+ process.stdout.write('\033[2K');
900
+ },
901
+
902
+ beginningOfLine: function(){
903
+ process.stdout.write('\033[0G');
904
+ },
905
+
906
+ CR: function(){
907
+ exports.cursor.deleteLine();
908
+ exports.cursor.beginningOfLine();
909
+ }
910
+ };
911
+
912
+ /**
913
+ * A test is considered slow if it
914
+ * exceeds the following value in milliseconds.
915
+ */
916
+
917
+ exports.slow = 75;
918
+
919
+ /**
920
+ * Outut the given `failures` as a list.
921
+ *
922
+ * @param {Array} failures
923
+ * @api public
924
+ */
925
+
926
+ exports.list = function(failures){
927
+ console.error();
928
+ failures.forEach(function(test, i){
929
+ // format
930
+ var fmt = color('error title', ' %s) %s:\n')
931
+ + color('error message', ' %s')
932
+ + color('error stack', '\n%s\n');
933
+
934
+ // msg
935
+ var err = test.err
936
+ , message = err.message || ''
937
+ , stack = err.stack || message
938
+ , index = stack.indexOf(message) + message.length
939
+ , msg = stack.slice(0, index);
940
+
941
+ // indent stack trace without msg
942
+ stack = stack.slice(index + 1)
943
+ .replace(/^/gm, ' ');
944
+
945
+ console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
946
+ });
947
+ };
948
+
949
+ /**
950
+ * Initialize a new `Base` reporter.
951
+ *
952
+ * All other reporters generally
953
+ * inherit from this reporter, providing
954
+ * stats such as test duration, number
955
+ * of tests passed / failed etc.
956
+ *
957
+ * @param {Runner} runner
958
+ * @api public
959
+ */
960
+
961
+ function Base(runner) {
962
+ var self = this
963
+ , stats = this.stats = { suites: 0, tests: 0, passes: 0, failures: 0 }
964
+ , failures = this.failures = [];
965
+
966
+ if (!runner) return;
967
+ this.runner = runner;
968
+
969
+ runner.on('start', function(){
970
+ stats.start = new Date;
971
+ });
972
+
973
+ runner.on('suite', function(suite){
974
+ stats.suites = stats.suites || 0;
975
+ suite.root || stats.suites++;
976
+ });
977
+
978
+ runner.on('test end', function(test){
979
+ stats.tests = stats.tests || 0;
980
+ stats.tests++;
981
+ });
982
+
983
+ runner.on('pass', function(test){
984
+ stats.passes = stats.passes || 0;
985
+
986
+ var medium = exports.slow / 2;
987
+ test.speed = test.duration > exports.slow
988
+ ? 'slow'
989
+ : test.duration > medium
990
+ ? 'medium'
991
+ : 'fast';
992
+
993
+ stats.passes++;
994
+ });
995
+
996
+ runner.on('fail', function(test, err){
997
+ stats.failures = stats.failures || 0;
998
+ stats.failures++;
999
+ test.err = err;
1000
+ failures.push(test);
1001
+ });
1002
+
1003
+ runner.on('end', function(){
1004
+ stats.end = new Date;
1005
+ stats.duration = new Date - stats.start;
1006
+ });
1007
+ }
1008
+
1009
+ /**
1010
+ * Output common epilogue used by many of
1011
+ * the bundled reporters.
1012
+ *
1013
+ * @api public
1014
+ */
1015
+
1016
+ Base.prototype.epilogue = function(){
1017
+ var stats = this.stats
1018
+ , fmt;
1019
+
1020
+ console.log();
1021
+
1022
+ // failure
1023
+ if (stats.failures) {
1024
+ fmt = color('bright fail', ' ✖')
1025
+ + color('fail', ' %d of %d tests failed')
1026
+ + color('light', ':')
1027
+
1028
+ console.error(fmt, stats.failures, this.runner.total);
1029
+ Base.list(this.failures);
1030
+ console.error();
1031
+ return;
1032
+ }
1033
+
1034
+ // pass
1035
+ fmt = color('bright pass', ' ✔')
1036
+ + color('green', ' %d tests complete')
1037
+ + color('light', ' (%dms)');
1038
+
1039
+ console.log(fmt, stats.tests || 0, stats.duration);
1040
+ console.log();
1041
+ };
1042
+
1043
+ }); // module: reporters/base.js
1044
+
1045
+ require.register("reporters/doc.js", function(module, exports, require){
1046
+
1047
+ /**
1048
+ * Module dependencies.
1049
+ */
1050
+
1051
+ var Base = require('./base')
1052
+ , utils = require('../utils');
1053
+
1054
+ /**
1055
+ * Expose `Doc`.
1056
+ */
1057
+
1058
+ exports = module.exports = Doc;
1059
+
1060
+ /**
1061
+ * Initialize a new `Doc` reporter.
1062
+ *
1063
+ * @param {Runner} runner
1064
+ * @api public
1065
+ */
1066
+
1067
+ function Doc(runner) {
1068
+ Base.call(this, runner);
1069
+
1070
+ var self = this
1071
+ , stats = this.stats
1072
+ , total = runner.total
1073
+ , indents = 2;
1074
+
1075
+ function indent() {
1076
+ return Array(indents).join(' ');
1077
+ }
1078
+
1079
+ runner.on('suite', function(suite){
1080
+ if (suite.root) return;
1081
+ ++indents;
1082
+ console.log('%s<section class="suite">', indent());
1083
+ ++indents;
1084
+ console.log('%s<h1>%s</h1>', indent(), suite.title);
1085
+ console.log('%s<dl>', indent());
1086
+ });
1087
+
1088
+ runner.on('suite end', function(suite){
1089
+ if (suite.root) return;
1090
+ console.log('%s</dl>', indent());
1091
+ --indents;
1092
+ console.log('%s</section>', indent());
1093
+ --indents;
1094
+ });
1095
+
1096
+ runner.on('pass', function(test){
1097
+ console.log('%s <dt>%s</dt>', indent(), test.title);
1098
+ var code = utils.escape(clean(test.fn.toString()));
1099
+ console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
1100
+ });
1101
+ }
1102
+
1103
+ /**
1104
+ * Strip the function definition from `str`,
1105
+ * and re-indent for pre whitespace.
1106
+ */
1107
+
1108
+ function clean(str) {
1109
+ str = str
1110
+ .replace(/^function *\(.*\) *{/, '')
1111
+ .replace(/\s+\}$/, '');
1112
+
1113
+ var spaces = str.match(/^\n?( *)/)[1].length
1114
+ , re = new RegExp('^ {' + spaces + '}', 'gm');
1115
+
1116
+ str = str.replace(re, '');
1117
+
1118
+ return str;
1119
+ }
1120
+ }); // module: reporters/doc.js
1121
+
1122
+ require.register("reporters/dot.js", function(module, exports, require){
1123
+
1124
+ /**
1125
+ * Module dependencies.
1126
+ */
1127
+
1128
+ var Base = require('./base')
1129
+ , color = Base.color;
1130
+
1131
+ /**
1132
+ * Expose `Dot`.
1133
+ */
1134
+
1135
+ exports = module.exports = Dot;
1136
+
1137
+ /**
1138
+ * Initialize a new `Dot` matrix test reporter.
1139
+ *
1140
+ * @param {Runner} runner
1141
+ * @api public
1142
+ */
1143
+
1144
+ function Dot(runner) {
1145
+ Base.call(this, runner);
1146
+
1147
+ var self = this
1148
+ , stats = this.stats
1149
+ , width = Base.window.width * .75 | 0
1150
+ , n = 0;
1151
+
1152
+ runner.on('start', function(){
1153
+ process.stdout.write('\n ');
1154
+ });
1155
+
1156
+ runner.on('pending', function(test){
1157
+ process.stdout.write(color('pending', '.'));
1158
+ });
1159
+
1160
+ runner.on('pass', function(test){
1161
+ if (++n % width == 0) process.stdout.write('\n ');
1162
+ if ('slow' == test.speed) {
1163
+ process.stdout.write(color('bright yellow', '.'));
1164
+ } else {
1165
+ process.stdout.write(color(test.speed, '.'));
1166
+ }
1167
+ });
1168
+
1169
+ runner.on('fail', function(test, err){
1170
+ if (++n % width == 0) process.stdout.write('\n ');
1171
+ process.stdout.write(color('fail', '.'));
1172
+ });
1173
+
1174
+ runner.on('end', function(){
1175
+ console.log();
1176
+ self.epilogue();
1177
+ });
1178
+ }
1179
+
1180
+ /**
1181
+ * Inherit from `Base.prototype`.
1182
+ */
1183
+
1184
+ Dot.prototype = new Base;
1185
+ Dot.prototype.constructor = Dot;
1186
+
1187
+ }); // module: reporters/dot.js
1188
+
1189
+ require.register("reporters/html.js", function(module, exports, require){
1190
+
1191
+ /**
1192
+ * Module dependencies.
1193
+ */
1194
+
1195
+ var Base = require('./base')
1196
+ , utils = require('../utils')
1197
+ , Progress = require('../browser/progress')
1198
+ , escape = utils.escape;
1199
+
1200
+ /**
1201
+ * Expose `Doc`.
1202
+ */
1203
+
1204
+ exports = module.exports = HTML;
1205
+
1206
+ /**
1207
+ * Stats template.
1208
+ */
1209
+
1210
+ var statsTemplate = '<ul id="stats">'
1211
+ + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
1212
+ + '<li class="passes">passes: <em>0</em></li>'
1213
+ + '<li class="failures">failures: <em>0</em></li>'
1214
+ + '<li class="duration">duration: <em>0</em>s</li>'
1215
+ + '</ul>';
1216
+
1217
+ /**
1218
+ * Initialize a new `Doc` reporter.
1219
+ *
1220
+ * @param {Runner} runner
1221
+ * @api public
1222
+ */
1223
+
1224
+ function HTML(runner) {
1225
+ Base.call(this, runner);
1226
+
1227
+ // TODO: clean up
1228
+
1229
+ var self = this
1230
+ , stats = this.stats
1231
+ , total = runner.total
1232
+ , root = $('#mocha')
1233
+ , stack = [root]
1234
+ , stat = $(statsTemplate).appendTo(root)
1235
+ , canvas = stat.find('canvas').get(0)
1236
+ , progress
1237
+ , ctx
1238
+
1239
+ if (canvas.getContext) {
1240
+ ctx = canvas.getContext('2d');
1241
+ progress = new Progress;
1242
+ }
1243
+
1244
+ if (!root.length) return error('#mocha div missing, add it to your document');
1245
+
1246
+ if (progress) progress.size(40);
1247
+
1248
+ runner.on('suite', function(suite){
1249
+ if (suite.root) return;
1250
+
1251
+ // suite
1252
+ var el = $('<div class="suite"><h1>' + suite.title + '</h1></div>');
1253
+
1254
+ // container
1255
+ stack[0].append(el);
1256
+ stack.unshift($('<div>'));
1257
+ el.append(stack[0]);
1258
+ });
1259
+
1260
+ runner.on('suite end', function(suite){
1261
+ if (suite.root) return;
1262
+ stack.shift();
1263
+ });
1264
+
1265
+ runner.on('fail', function(test, err){
1266
+ if (err.uncaught) runner.emit('test end', test);
1267
+ });
1268
+
1269
+ runner.on('test end', function(test){
1270
+ // TODO: add to stats
1271
+ var percent = stats.tests / total * 100 | 0;
1272
+
1273
+ if (progress) {
1274
+ progress.update(percent).draw(ctx);
1275
+ }
1276
+
1277
+ // update stats
1278
+ var ms = new Date - stats.start;
1279
+ stat.find('.passes em').text(stats.passes);
1280
+ stat.find('.failures em').text(stats.failures);
1281
+ stat.find('.duration em').text((ms / 1000).toFixed(2));
1282
+
1283
+ // test
1284
+ if (test.passed) {
1285
+ var el = $('<div class="test pass"><h2>' + escape(test.title) + '</h2></div>')
1286
+ } else if (test.pending) {
1287
+ var el = $('<div class="test pass pending"><h2>' + escape(test.title) + '</h2></div>')
1288
+ } else {
1289
+ var el = $('<div class="test fail"><h2>' + escape(test.title) + '</h2></div>');
1290
+ var str = test.err.stack || test.err;
1291
+
1292
+ // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
1293
+ // check for the result of the stringifying.
1294
+ if ('[object Error]' == str) str = test.err.message;
1295
+
1296
+ $('<pre class="error">' + escape(str) + '</pre>').appendTo(el);
1297
+ }
1298
+
1299
+ // toggle code
1300
+ el.find('h2').toggle(function(){
1301
+ pre && pre.slideDown('fast');
1302
+ }, function(){
1303
+ pre && pre.slideUp('fast');
1304
+ });
1305
+
1306
+ // code
1307
+ // TODO: defer
1308
+ if (!test.pending) {
1309
+ var code = escape(clean(test.fn.toString()));
1310
+ var pre = $('<pre><code>' + code + '</code></pre>');
1311
+ pre.appendTo(el).hide();
1312
+ }
1313
+ stack[0].append(el);
1314
+ });
1315
+ }
1316
+
1317
+ /**
1318
+ * Display error `msg`.
1319
+ */
1320
+
1321
+ function error(msg) {
1322
+ $('<div id="error">' + msg + '</div>').appendTo('body');
1323
+ }
1324
+
1325
+ /**
1326
+ * Strip the function definition from `str`,
1327
+ * and re-indent for pre whitespace.
1328
+ */
1329
+
1330
+ function clean(str) {
1331
+ str = str
1332
+ .replace(/^function *\(.*\) *{/, '')
1333
+ .replace(/\s+\}$/, '');
1334
+
1335
+ var spaces = str.match(/^\n?( *)/)[1].length
1336
+ , re = new RegExp('^ {' + spaces + '}', 'gm');
1337
+
1338
+ str = str
1339
+ .replace(re, '')
1340
+ .replace(/^\s+/, '');
1341
+
1342
+ return str;
1343
+ }
1344
+
1345
+ }); // module: reporters/html.js
1346
+
1347
+ require.register("reporters/index.js", function(module, exports, require){
1348
+
1349
+ exports.Base = require('./base');
1350
+ exports.Dot = require('./dot');
1351
+ exports.Doc = require('./doc');
1352
+ exports.TAP = require('./tap');
1353
+ exports.JSON = require('./json');
1354
+ exports.HTML = require('./html');
1355
+ exports.List = require('./list');
1356
+ exports.Spec = require('./spec');
1357
+ exports.Progress = require('./progress');
1358
+ exports.Landing = require('./landing');
1359
+ exports.JSONStream = require('./json-stream');
1360
+ exports.XUnit = require('./xunit')
1361
+
1362
+ }); // module: reporters/index.js
1363
+
1364
+ require.register("reporters/json-stream.js", function(module, exports, require){
1365
+
1366
+ /**
1367
+ * Module dependencies.
1368
+ */
1369
+
1370
+ var Base = require('./base')
1371
+ , color = Base.color;
1372
+
1373
+ /**
1374
+ * Expose `List`.
1375
+ */
1376
+
1377
+ exports = module.exports = List;
1378
+
1379
+ /**
1380
+ * Initialize a new `List` test reporter.
1381
+ *
1382
+ * @param {Runner} runner
1383
+ * @api public
1384
+ */
1385
+
1386
+ function List(runner) {
1387
+ Base.call(this, runner);
1388
+
1389
+ var self = this
1390
+ , stats = this.stats
1391
+ , total = runner.total;
1392
+
1393
+ runner.on('start', function(){
1394
+ console.log(JSON.stringify(['start', { total: total }]));
1395
+ });
1396
+
1397
+ runner.on('pass', function(test){
1398
+ console.log(JSON.stringify(['pass', clean(test)]));
1399
+ });
1400
+
1401
+ runner.on('fail', function(test, err){
1402
+ console.log(JSON.stringify(['fail', clean(test)]));
1403
+ });
1404
+
1405
+ runner.on('end', function(){
1406
+ process.stdout.write(JSON.stringify(['end', self.stats]));
1407
+ });
1408
+ }
1409
+
1410
+ /**
1411
+ * Return a plain-object representation of `test`
1412
+ * free of cyclic properties etc.
1413
+ *
1414
+ * @param {Object} test
1415
+ * @return {Object}
1416
+ * @api private
1417
+ */
1418
+
1419
+ function clean(test) {
1420
+ return {
1421
+ title: test.title
1422
+ , fullTitle: test.fullTitle()
1423
+ , duration: test.duration
1424
+ }
1425
+ }
1426
+ }); // module: reporters/json-stream.js
1427
+
1428
+ require.register("reporters/json.js", function(module, exports, require){
1429
+
1430
+ /**
1431
+ * Module dependencies.
1432
+ */
1433
+
1434
+ var Base = require('./base')
1435
+ , cursor = Base.cursor
1436
+ , color = Base.color;
1437
+
1438
+ /**
1439
+ * Expose `JSON`.
1440
+ */
1441
+
1442
+ exports = module.exports = JSONReporter;
1443
+
1444
+ /**
1445
+ * Initialize a new `JSON` reporter.
1446
+ *
1447
+ * @param {Runner} runner
1448
+ * @api public
1449
+ */
1450
+
1451
+ function JSONReporter(runner) {
1452
+ var self = this;
1453
+ Base.call(this, runner);
1454
+
1455
+ var tests = []
1456
+ , failures = []
1457
+ , passes = [];
1458
+
1459
+ runner.on('test end', function(test){
1460
+ tests.push(test);
1461
+ });
1462
+
1463
+ runner.on('pass', function(test){
1464
+ passes.push(test);
1465
+ });
1466
+
1467
+ runner.on('fail', function(test){
1468
+ failures.push(test);
1469
+ });
1470
+
1471
+ runner.on('end', function(){
1472
+ var obj = {
1473
+ stats: self.stats
1474
+ , tests: tests.map(clean)
1475
+ , failures: failures.map(clean)
1476
+ , passes: passes.map(clean)
1477
+ };
1478
+
1479
+ process.stdout.write(JSON.stringify(obj));
1480
+ });
1481
+ }
1482
+
1483
+ /**
1484
+ * Return a plain-object representation of `test`
1485
+ * free of cyclic properties etc.
1486
+ *
1487
+ * @param {Object} test
1488
+ * @return {Object}
1489
+ * @api private
1490
+ */
1491
+
1492
+ function clean(test) {
1493
+ return {
1494
+ title: test.title
1495
+ , fullTitle: test.fullTitle()
1496
+ , duration: test.duration
1497
+ }
1498
+ }
1499
+ }); // module: reporters/json.js
1500
+
1501
+ require.register("reporters/landing.js", function(module, exports, require){
1502
+
1503
+ /**
1504
+ * Module dependencies.
1505
+ */
1506
+
1507
+ var Base = require('./base')
1508
+ , cursor = Base.cursor
1509
+ , color = Base.color;
1510
+
1511
+ /**
1512
+ * Expose `Landing`.
1513
+ */
1514
+
1515
+ exports = module.exports = Landing;
1516
+
1517
+ /**
1518
+ * Airplane color.
1519
+ */
1520
+
1521
+ Base.colors.plane = 0;
1522
+
1523
+ /**
1524
+ * Airplane crash color.
1525
+ */
1526
+
1527
+ Base.colors['plane crash'] = 31;
1528
+
1529
+ /**
1530
+ * Runway color.
1531
+ */
1532
+
1533
+ Base.colors.runway = 90;
1534
+
1535
+ /**
1536
+ * Initialize a new `Landing` reporter.
1537
+ *
1538
+ * @param {Runner} runner
1539
+ * @api public
1540
+ */
1541
+
1542
+ function Landing(runner) {
1543
+ Base.call(this, runner);
1544
+
1545
+ var self = this
1546
+ , stats = this.stats
1547
+ , width = Base.window.width * .75 | 0
1548
+ , total = runner.total
1549
+ , stream = process.stdout
1550
+ , plane = color('plane', '✈')
1551
+ , crashed = -1
1552
+ , n = 0;
1553
+
1554
+ function runway() {
1555
+ var buf = Array(width).join('-');
1556
+ return ' ' + color('runway', buf);
1557
+ }
1558
+
1559
+ runner.on('start', function(){
1560
+ stream.write('\n ');
1561
+ cursor.hide();
1562
+ });
1563
+
1564
+ runner.on('test end', function(test){
1565
+ // check if the plane crashed
1566
+ var col = -1 == crashed
1567
+ ? width * ++n / total | 0
1568
+ : crashed;
1569
+
1570
+ // show the crash
1571
+ if (test.failed) {
1572
+ plane = color('plane crash', '✈');
1573
+ crashed = col;
1574
+ }
1575
+
1576
+ // render landing strip
1577
+ stream.write('\033[4F\n\n');
1578
+ stream.write(runway());
1579
+ stream.write('\n ');
1580
+ stream.write(color('runway', Array(col).join('⋅')));
1581
+ stream.write(plane)
1582
+ stream.write(color('runway', Array(width - col).join('⋅') + '\n'));
1583
+ stream.write(runway());
1584
+ stream.write('\033[0m');
1585
+ });
1586
+
1587
+ runner.on('end', function(){
1588
+ cursor.show();
1589
+ console.log();
1590
+ self.epilogue();
1591
+ });
1592
+ }
1593
+
1594
+ /**
1595
+ * Inherit from `Base.prototype`.
1596
+ */
1597
+
1598
+ Landing.prototype = new Base;
1599
+ Landing.prototype.constructor = Landing;
1600
+
1601
+ }); // module: reporters/landing.js
1602
+
1603
+ require.register("reporters/list.js", function(module, exports, require){
1604
+
1605
+ /**
1606
+ * Module dependencies.
1607
+ */
1608
+
1609
+ var Base = require('./base')
1610
+ , cursor = Base.cursor
1611
+ , color = Base.color;
1612
+
1613
+ /**
1614
+ * Expose `List`.
1615
+ */
1616
+
1617
+ exports = module.exports = List;
1618
+
1619
+ /**
1620
+ * Initialize a new `List` test reporter.
1621
+ *
1622
+ * @param {Runner} runner
1623
+ * @api public
1624
+ */
1625
+
1626
+ function List(runner) {
1627
+ Base.call(this, runner);
1628
+
1629
+ var self = this
1630
+ , stats = this.stats
1631
+ , n = 0;
1632
+
1633
+ runner.on('start', function(){
1634
+ console.log();
1635
+ });
1636
+
1637
+ runner.on('test', function(test){
1638
+ process.stdout.write(color('pass', ' ' + test.fullTitle() + ': '));
1639
+ });
1640
+
1641
+ runner.on('pending', function(test){
1642
+ var fmt = color('checkmark', ' -')
1643
+ + color('pending', ' %s');
1644
+ console.log(fmt, test.fullTitle());
1645
+ });
1646
+
1647
+ runner.on('pass', function(test){
1648
+ var fmt = color('checkmark', ' ✓')
1649
+ + color('pass', ' %s: ')
1650
+ + color(test.speed, '%dms');
1651
+ cursor.CR();
1652
+ console.log(fmt, test.fullTitle(), test.duration);
1653
+ });
1654
+
1655
+ runner.on('fail', function(test, err){
1656
+ cursor.CR();
1657
+ console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
1658
+ });
1659
+
1660
+ runner.on('end', self.epilogue.bind(self));
1661
+ }
1662
+
1663
+ /**
1664
+ * Inherit from `Base.prototype`.
1665
+ */
1666
+
1667
+ List.prototype = new Base;
1668
+ List.prototype.constructor = List;
1669
+
1670
+
1671
+ }); // module: reporters/list.js
1672
+
1673
+ require.register("reporters/progress.js", function(module, exports, require){
1674
+
1675
+ /**
1676
+ * Module dependencies.
1677
+ */
1678
+
1679
+ var Base = require('./base')
1680
+ , cursor = Base.cursor
1681
+ , color = Base.color;
1682
+
1683
+ /**
1684
+ * Expose `Progress`.
1685
+ */
1686
+
1687
+ exports = module.exports = Progress;
1688
+
1689
+ /**
1690
+ * General progress bar color.
1691
+ */
1692
+
1693
+ Base.colors.progress = 90;
1694
+
1695
+ /**
1696
+ * Initialize a new `Progress` bar test reporter.
1697
+ *
1698
+ * @param {Runner} runner
1699
+ * @param {Object} options
1700
+ * @api public
1701
+ */
1702
+
1703
+ function Progress(runner, options) {
1704
+ Base.call(this, runner);
1705
+
1706
+ var self = this
1707
+ , options = options || {}
1708
+ , stats = this.stats
1709
+ , width = Base.window.width * .50 | 0
1710
+ , total = runner.total
1711
+ , complete = 0
1712
+ , max = Math.max;
1713
+
1714
+ // default chars
1715
+ options.open = options.open || '[';
1716
+ options.complete = options.complete || '▬';
1717
+ options.incomplete = options.incomplete || '⋅';
1718
+ options.close = options.close || ']';
1719
+ options.verbose = false;
1720
+
1721
+ // tests started
1722
+ runner.on('start', function(){
1723
+ console.log();
1724
+ cursor.hide();
1725
+ });
1726
+
1727
+ // tests complete
1728
+ runner.on('test end', function(){
1729
+ var incomplete = total - complete
1730
+ , percent = complete++ / total
1731
+ , n = width * percent | 0
1732
+ , i = width - n;
1733
+
1734
+ cursor.CR();
1735
+ process.stdout.write('\033[J');
1736
+ process.stdout.write(color('progress', ' ' + options.open));
1737
+ process.stdout.write(Array(n).join(options.complete));
1738
+ process.stdout.write(Array(i).join(options.incomplete));
1739
+ process.stdout.write(color('progress', options.close));
1740
+ if (options.verbose) {
1741
+ process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
1742
+ }
1743
+ });
1744
+
1745
+ // tests are complete, output some stats
1746
+ // and the failures if any
1747
+ runner.on('end', function(){
1748
+ cursor.show();
1749
+ console.log();
1750
+ self.epilogue();
1751
+ });
1752
+ }
1753
+
1754
+ /**
1755
+ * Inherit from `Base.prototype`.
1756
+ */
1757
+
1758
+ Progress.prototype = new Base;
1759
+ Progress.prototype.constructor = Progress;
1760
+
1761
+
1762
+ }); // module: reporters/progress.js
1763
+
1764
+ require.register("reporters/spec.js", function(module, exports, require){
1765
+
1766
+ /**
1767
+ * Module dependencies.
1768
+ */
1769
+
1770
+ var Base = require('./base')
1771
+ , cursor = Base.cursor
1772
+ , color = Base.color;
1773
+
1774
+ /**
1775
+ * Expose `Spec`.
1776
+ */
1777
+
1778
+ exports = module.exports = Spec;
1779
+
1780
+ /**
1781
+ * Initialize a new `Spec` test reporter.
1782
+ *
1783
+ * @param {Runner} runner
1784
+ * @api public
1785
+ */
1786
+
1787
+ function Spec(runner) {
1788
+ Base.call(this, runner);
1789
+
1790
+ var self = this
1791
+ , stats = this.stats
1792
+ , indents = 0
1793
+ , n = 0;
1794
+
1795
+ function indent() {
1796
+ return Array(indents).join(' ')
1797
+ }
1798
+
1799
+ runner.on('start', function(){
1800
+ console.log();
1801
+ });
1802
+
1803
+ runner.on('suite', function(suite){
1804
+ ++indents;
1805
+ console.log(color('suite', '%s%s'), indent(), suite.title);
1806
+ });
1807
+
1808
+ runner.on('suite end', function(suite){
1809
+ --indents;
1810
+ if (1 == indents) console.log();
1811
+ });
1812
+
1813
+ runner.on('test', function(test){
1814
+ process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': '));
1815
+ });
1816
+
1817
+ runner.on('pending', function(test){
1818
+ var fmt = indent() + color('pending', ' - %s');
1819
+ console.log(fmt, test.title);
1820
+ });
1821
+
1822
+ runner.on('pass', function(test){
1823
+ if ('fast' == test.speed) {
1824
+ var fmt = indent()
1825
+ + color('checkmark', ' ✓')
1826
+ + color('pass', ' %s ');
1827
+ cursor.CR();
1828
+ console.log(fmt, test.title);
1829
+ } else {
1830
+ var fmt = indent()
1831
+ + color('checkmark', ' ✓')
1832
+ + color('pass', ' %s ')
1833
+ + color(test.speed, '(%dms)');
1834
+ cursor.CR();
1835
+ console.log(fmt, test.title, test.duration);
1836
+ }
1837
+ });
1838
+
1839
+ runner.on('fail', function(test, err){
1840
+ cursor.CR();
1841
+ console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
1842
+ });
1843
+
1844
+ runner.on('end', self.epilogue.bind(self));
1845
+ }
1846
+
1847
+ /**
1848
+ * Inherit from `Base.prototype`.
1849
+ */
1850
+
1851
+ Spec.prototype = new Base;
1852
+ Spec.prototype.constructor = Spec;
1853
+
1854
+
1855
+ }); // module: reporters/spec.js
1856
+
1857
+ require.register("reporters/tap.js", function(module, exports, require){
1858
+
1859
+ /**
1860
+ * Module dependencies.
1861
+ */
1862
+
1863
+ var Base = require('./base')
1864
+ , cursor = Base.cursor
1865
+ , color = Base.color;
1866
+
1867
+ /**
1868
+ * Expose `TAP`.
1869
+ */
1870
+
1871
+ exports = module.exports = TAP;
1872
+
1873
+ /**
1874
+ * Initialize a new `TAP` reporter.
1875
+ *
1876
+ * @param {Runner} runner
1877
+ * @api public
1878
+ */
1879
+
1880
+ function TAP(runner) {
1881
+ Base.call(this, runner);
1882
+
1883
+ var self = this
1884
+ , stats = this.stats
1885
+ , total = runner.total
1886
+ , n = 1;
1887
+
1888
+ runner.on('start', function(){
1889
+ console.log('%d..%d', 1, total);
1890
+ });
1891
+
1892
+ runner.on('test end', function(){
1893
+ ++n;
1894
+ });
1895
+
1896
+ runner.on('pending', function(test){
1897
+ console.log('ok %d %s # SKIP -', n, title(test));
1898
+ });
1899
+
1900
+ runner.on('pass', function(test){
1901
+ console.log('ok %d %s', n, title(test));
1902
+ });
1903
+
1904
+ runner.on('fail', function(test, err){
1905
+ console.log('not ok %d %s', n, title(test));
1906
+ console.log(err.stack.replace(/^/gm, ' '));
1907
+ });
1908
+ }
1909
+
1910
+ /**
1911
+ * Return a TAP-safe title of `test`
1912
+ *
1913
+ * @param {Object} test
1914
+ * @return {String}
1915
+ * @api private
1916
+ */
1917
+
1918
+ function title(test) {
1919
+ return test.fullTitle().replace(/#/g, '');
1920
+ }
1921
+
1922
+ }); // module: reporters/tap.js
1923
+
1924
+ require.register("reporters/teamcity.js", function(module, exports, require){
1925
+
1926
+ /**
1927
+ * Module dependencies.
1928
+ */
1929
+
1930
+ var Base = require('./base');
1931
+
1932
+ /**
1933
+ * Expose `Teamcity`.
1934
+ */
1935
+
1936
+ exports = module.exports = Teamcity;
1937
+
1938
+ /**
1939
+ * Initialize a new `Teamcity` reporter.
1940
+ *
1941
+ * @param {Runner} runner
1942
+ * @api public
1943
+ */
1944
+
1945
+ function Teamcity(runner) {
1946
+ Base.call(this, runner);
1947
+ var stats = this.stats;
1948
+
1949
+ runner.on('start', function() {
1950
+ console.log("##teamcity[testSuiteStarted name='mocha.suite']");
1951
+ });
1952
+
1953
+ runner.on('test', function(test) {
1954
+ console.log("##teamcity[testStarted name='%s']", escape(test.fullTitle()));
1955
+ });
1956
+
1957
+ runner.on('fail', function(test, err) {
1958
+ console.log("##teamcity[testFailed name='%s' message='%s']", escape(test.fullTitle()), escape(err.message));
1959
+ });
1960
+
1961
+ runner.on('pending', function(test) {
1962
+ console.log("##teamcity[testIgnored name='%s' message='pending']", escape(test.fullTitle()));
1963
+ });
1964
+
1965
+ runner.on('test end', function(test) {
1966
+ console.log("##teamcity[testFinished name='%s' duration='%s']", escape(test.fullTitle()), test.duration);
1967
+ });
1968
+
1969
+ runner.on('end', function() {
1970
+ console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='%s']", stats.duration);
1971
+ });
1972
+ }
1973
+
1974
+ /**
1975
+ * Escape the given `str`.
1976
+ */
1977
+
1978
+ function escape(str) {
1979
+ return str.replace(/'/g, "|'");
1980
+ }
1981
+ }); // module: reporters/teamcity.js
1982
+
1983
+ require.register("reporters/xunit.js", function(module, exports, require){
1984
+
1985
+ /**
1986
+ * Module dependencies.
1987
+ */
1988
+
1989
+ var Base = require('./base')
1990
+ , utils = require('../utils')
1991
+ , escape = utils.escape;
1992
+
1993
+ /**
1994
+ * Expose `XUnit`.
1995
+ */
1996
+
1997
+ exports = module.exports = XUnit;
1998
+
1999
+ /**
2000
+ * Initialize a new `XUnit` reporter.
2001
+ *
2002
+ * @param {Runner} runner
2003
+ * @api public
2004
+ */
2005
+
2006
+ function XUnit(runner) {
2007
+ Base.call(this, runner);
2008
+ var stats = this.stats
2009
+ , tests = []
2010
+ , self = this;
2011
+
2012
+ runner.on('test end', function(test){
2013
+ tests.push(test);
2014
+ });
2015
+
2016
+ runner.on('end', function(){
2017
+ console.log(tag('testsuite', {
2018
+ name: 'Mocha Tests'
2019
+ , tests: stats.tests
2020
+ , failures: stats.failures
2021
+ , errors: stats.failures
2022
+ , skip: stats.tests - stats.failures - stats.passes
2023
+ , timestamp: (new Date).toUTCString()
2024
+ , time: stats.duration / 1000
2025
+ }, false));
2026
+
2027
+ tests.forEach(test);
2028
+ console.log('</testsuite>');
2029
+ });
2030
+ }
2031
+
2032
+ /**
2033
+ * Inherit from `Base.prototype`.
2034
+ */
2035
+
2036
+ XUnit.prototype = new Base;
2037
+ XUnit.prototype.constructor = XUnit;
2038
+
2039
+
2040
+ /**
2041
+ * Output tag for the given `test.`
2042
+ */
2043
+
2044
+ function test(test) {
2045
+ var attrs = {
2046
+ classname: test.parent.fullTitle()
2047
+ , name: test.title
2048
+ , time: test.duration / 1000
2049
+ };
2050
+
2051
+ if (test.failed) {
2052
+ var err = test.err;
2053
+ attrs.message = escape(err.message);
2054
+ console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
2055
+ } else if (test.pending) {
2056
+ console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
2057
+ } else {
2058
+ console.log(tag('testcase', attrs, true) );
2059
+ }
2060
+ }
2061
+
2062
+ /**
2063
+ * HTML tag helper.
2064
+ */
2065
+
2066
+ function tag(name, attrs, close, content) {
2067
+ var end = close ? '/>' : '>'
2068
+ , pairs = []
2069
+ , tag;
2070
+
2071
+ for (var key in attrs) {
2072
+ pairs.push(key + '="' + escape(attrs[key]) + '"');
2073
+ }
2074
+
2075
+ tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
2076
+ if (content) tag += content + '</' + name + end;
2077
+ return tag;
2078
+ }
2079
+
2080
+ /**
2081
+ * Return cdata escaped CDATA `str`.
2082
+ */
2083
+
2084
+ function cdata(str) {
2085
+ return '<![CDATA[' + escape(str) + ']]>';
2086
+ }
2087
+
2088
+ }); // module: reporters/xunit.js
2089
+
2090
+ require.register("runnable.js", function(module, exports, require){
2091
+
2092
+ /**
2093
+ * Module dependencies.
2094
+ */
2095
+
2096
+ var EventEmitter = require('browser/events').EventEmitter
2097
+ , debug = require('browser/debug')('runnable');
2098
+
2099
+ /**
2100
+ * Expose `Runnable`.
2101
+ */
2102
+
2103
+ module.exports = Runnable;
2104
+
2105
+ /**
2106
+ * Initialize a new `Runnable` with the given `title` and callback `fn`.
2107
+ *
2108
+ * @param {String} title
2109
+ * @param {Function} fn
2110
+ * @api private
2111
+ */
2112
+
2113
+ function Runnable(title, fn) {
2114
+ this.title = title;
2115
+ this.fn = fn;
2116
+ this.async = fn && fn.length;
2117
+ this.sync = ! this.async;
2118
+ this._timeout = 2000;
2119
+ this.timedOut = false;
2120
+ this.context = this;
2121
+ }
2122
+
2123
+ /**
2124
+ * Inherit from `EventEmitter.prototype`.
2125
+ */
2126
+
2127
+ Runnable.prototype = new EventEmitter;
2128
+ Runnable.prototype.constructor = Runnable;
2129
+
2130
+
2131
+ /**
2132
+ * Set & get timeout `ms`.
2133
+ *
2134
+ * @param {Number} ms
2135
+ * @return {Runnable|Number} ms or self
2136
+ * @api private
2137
+ */
2138
+
2139
+ Runnable.prototype.timeout = function(ms){
2140
+ if (0 == arguments.length) return this._timeout;
2141
+ debug('timeout %d', ms);
2142
+ this._timeout = ms;
2143
+ if (this.timer) this.resetTimeout();
2144
+ return this;
2145
+ };
2146
+
2147
+ /**
2148
+ * Return the full title generated by recursively
2149
+ * concatenating the parent's full title.
2150
+ *
2151
+ * @return {String}
2152
+ * @api public
2153
+ */
2154
+
2155
+ Runnable.prototype.fullTitle = function(){
2156
+ return this.parent.fullTitle() + ' ' + this.title;
2157
+ };
2158
+
2159
+ /**
2160
+ * Clear the timeout.
2161
+ *
2162
+ * @api private
2163
+ */
2164
+
2165
+ Runnable.prototype.clearTimeout = function(){
2166
+ clearTimeout(this.timer);
2167
+ };
2168
+
2169
+ /**
2170
+ * Reset the timeout.
2171
+ *
2172
+ * @api private
2173
+ */
2174
+
2175
+ Runnable.prototype.resetTimeout = function(){
2176
+ var self = this
2177
+ , ms = this.timeout();
2178
+
2179
+ this.clearTimeout();
2180
+ if (ms) {
2181
+ this.timer = setTimeout(function(){
2182
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
2183
+ self.timedOut = true;
2184
+ }, ms);
2185
+ }
2186
+ };
2187
+
2188
+ /**
2189
+ * Run the test and invoke `fn(err)`.
2190
+ *
2191
+ * @param {Function} fn
2192
+ * @api private
2193
+ */
2194
+
2195
+ Runnable.prototype.run = function(fn){
2196
+ var self = this
2197
+ , ms = this.timeout()
2198
+ , start = new Date
2199
+ , ctx = this.context
2200
+ , finished
2201
+ , emitted;
2202
+
2203
+ // timeout
2204
+ if (this.async) {
2205
+ if (ms) {
2206
+ this.timer = setTimeout(function(){
2207
+ done(new Error('timeout of ' + ms + 'ms exceeded'));
2208
+ self.timedOut = true;
2209
+ }, ms);
2210
+ }
2211
+ }
2212
+
2213
+ // called multiple times
2214
+ function multiple() {
2215
+ if (emitted) return;
2216
+ emitted = true;
2217
+ self.emit('error', new Error('done() called multiple times'));
2218
+ }
2219
+
2220
+ // finished
2221
+ function done(err) {
2222
+ if (self.timedOut) return;
2223
+ if (finished) return multiple();
2224
+ self.clearTimeout();
2225
+ self.duration = new Date - start;
2226
+ finished = true;
2227
+ fn(err);
2228
+ }
2229
+
2230
+ // for .resetTimeout()
2231
+ this.callback = done;
2232
+
2233
+ // async
2234
+ if (this.async) {
2235
+ try {
2236
+ this.fn.call(ctx, function(err){
2237
+ if (err instanceof Error) return done(err);
2238
+ if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
2239
+ done();
2240
+ });
2241
+ } catch (err) {
2242
+ done(err);
2243
+ }
2244
+ return;
2245
+ }
2246
+
2247
+ // sync
2248
+ try {
2249
+ if (!this.pending) this.fn.call(ctx);
2250
+ this.duration = new Date - start;
2251
+ fn();
2252
+ } catch (err) {
2253
+ fn(err);
2254
+ }
2255
+ };
2256
+
2257
+ }); // module: runnable.js
2258
+
2259
+ require.register("runner.js", function(module, exports, require){
2260
+
2261
+ /**
2262
+ * Module dependencies.
2263
+ */
2264
+
2265
+ var EventEmitter = require('browser/events').EventEmitter
2266
+ , debug = require('browser/debug')('runner')
2267
+ , Test = require('./test')
2268
+ , utils = require('./utils')
2269
+ , noop = function(){};
2270
+
2271
+ /**
2272
+ * Expose `Runner`.
2273
+ */
2274
+
2275
+ module.exports = Runner;
2276
+
2277
+ /**
2278
+ * Initialize a `Runner` for the given `suite`.
2279
+ *
2280
+ * Events:
2281
+ *
2282
+ * - `start` execution started
2283
+ * - `end` execution complete
2284
+ * - `suite` (suite) test suite execution started
2285
+ * - `suite end` (suite) all tests (and sub-suites) have finished
2286
+ * - `test` (test) test execution started
2287
+ * - `test end` (test) test completed
2288
+ * - `hook` (hook) hook execution started
2289
+ * - `hook end` (hook) hook complete
2290
+ * - `pass` (test) test passed
2291
+ * - `fail` (test, err) test failed
2292
+ *
2293
+ * @api public
2294
+ */
2295
+
2296
+ function Runner(suite) {
2297
+ var self = this;
2298
+ this._globals = [];
2299
+ this.suite = suite;
2300
+ this.total = suite.total();
2301
+ this.failures = 0;
2302
+ this.on('test end', function(test){ self.checkGlobals(test); });
2303
+ this.on('hook end', function(hook){ self.checkGlobals(hook); });
2304
+ this.grep(/.*/);
2305
+ this.globals(utils.keys(global).concat(['errno']));
2306
+ }
2307
+
2308
+ /**
2309
+ * Inherit from `EventEmitter.prototype`.
2310
+ */
2311
+
2312
+ Runner.prototype = new EventEmitter;
2313
+ Runner.prototype.constructor = Runner;
2314
+
2315
+
2316
+ /**
2317
+ * Run tests with full titles matching `re`.
2318
+ *
2319
+ * @param {RegExp} re
2320
+ * @return {Runner} for chaining
2321
+ * @api public
2322
+ */
2323
+
2324
+ Runner.prototype.grep = function(re){
2325
+ debug('grep %s', re);
2326
+ this._grep = re;
2327
+ return this;
2328
+ };
2329
+
2330
+ /**
2331
+ * Allow the given `arr` of globals.
2332
+ *
2333
+ * @param {Array} arr
2334
+ * @return {Runner} for chaining
2335
+ * @api public
2336
+ */
2337
+
2338
+ Runner.prototype.globals = function(arr){
2339
+ if (0 == arguments.length) return this._globals;
2340
+ debug('globals %j', arr);
2341
+ utils.forEach(arr, function(arr){
2342
+ this._globals.push(arr);
2343
+ }, this);
2344
+ return this;
2345
+ };
2346
+
2347
+ /**
2348
+ * Check for global variable leaks.
2349
+ *
2350
+ * @api private
2351
+ */
2352
+
2353
+ Runner.prototype.checkGlobals = function(test){
2354
+ if (this.ignoreLeaks) return;
2355
+
2356
+ var leaks = utils.filter(utils.keys(global), function(key){
2357
+ return !~utils.indexOf(this._globals, key) && (!global.navigator || 'onerror' !== key);
2358
+ }, this);
2359
+
2360
+ this._globals = this._globals.concat(leaks);
2361
+
2362
+ if (leaks.length > 1) {
2363
+ this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
2364
+ } else if (leaks.length) {
2365
+ this.fail(test, new Error('global leak detected: ' + leaks[0]));
2366
+ }
2367
+ };
2368
+
2369
+ /**
2370
+ * Fail the given `test`.
2371
+ *
2372
+ * @param {Test} test
2373
+ * @param {Error} err
2374
+ * @api private
2375
+ */
2376
+
2377
+ Runner.prototype.fail = function(test, err){
2378
+ ++this.failures;
2379
+ test.failed = true;
2380
+ this.emit('fail', test, err);
2381
+ };
2382
+
2383
+ /**
2384
+ * Fail the given `hook` with `err`.
2385
+ *
2386
+ * Hook failures (currently) hard-end due
2387
+ * to that fact that a failing hook will
2388
+ * surely cause subsequent tests to fail,
2389
+ * causing jumbled reporting.
2390
+ *
2391
+ * @param {Hook} hook
2392
+ * @param {Error} err
2393
+ * @api private
2394
+ */
2395
+
2396
+ Runner.prototype.failHook = function(hook, err){
2397
+ this.fail(hook, err);
2398
+ this.emit('end');
2399
+ };
2400
+
2401
+ /**
2402
+ * Run hook `name` callbacks and then invoke `fn()`.
2403
+ *
2404
+ * @param {String} name
2405
+ * @param {Function} function
2406
+ * @api private
2407
+ */
2408
+
2409
+ Runner.prototype.hook = function(name, fn){
2410
+ var suite = this.suite
2411
+ , hooks = suite['_' + name]
2412
+ , ms = suite._timeout
2413
+ , self = this
2414
+ , timer;
2415
+
2416
+ function next(i) {
2417
+ var hook = hooks[i];
2418
+ if (!hook) return fn();
2419
+ self.currentRunnable = hook;
2420
+ hook.context = self.test;
2421
+
2422
+ self.emit('hook', hook);
2423
+
2424
+ hook.on('error', function(err){
2425
+ self.failHook(hook, err);
2426
+ });
2427
+
2428
+ hook.run(function(err){
2429
+ hook.removeAllListeners('error');
2430
+ if (err) return self.failHook(hook, err);
2431
+ self.emit('hook end', hook);
2432
+ next(++i);
2433
+ });
2434
+ }
2435
+
2436
+ process.nextTick(function(){
2437
+ next(0);
2438
+ });
2439
+ };
2440
+
2441
+ /**
2442
+ * Run hook `name` for the given array of `suites`
2443
+ * in order, and callback `fn(err)`.
2444
+ *
2445
+ * @param {String} name
2446
+ * @param {Array} suites
2447
+ * @param {Function} fn
2448
+ * @api private
2449
+ */
2450
+
2451
+ Runner.prototype.hooks = function(name, suites, fn){
2452
+ var self = this
2453
+ , orig = this.suite;
2454
+
2455
+ function next(suite) {
2456
+ self.suite = suite;
2457
+
2458
+ if (!suite) {
2459
+ self.suite = orig;
2460
+ return fn();
2461
+ }
2462
+
2463
+ self.hook(name, function(err){
2464
+ if (err) {
2465
+ self.suite = orig;
2466
+ return fn(err);
2467
+ }
2468
+
2469
+ next(suites.pop());
2470
+ });
2471
+ }
2472
+
2473
+ next(suites.pop());
2474
+ };
2475
+
2476
+ /**
2477
+ * Run hooks from the top level down.
2478
+ *
2479
+ * @param {String} name
2480
+ * @param {Function} fn
2481
+ * @api private
2482
+ */
2483
+
2484
+ Runner.prototype.hookUp = function(name, fn){
2485
+ var suites = [this.suite].concat(this.parents()).reverse();
2486
+ this.hooks(name, suites, fn);
2487
+ };
2488
+
2489
+ /**
2490
+ * Run hooks from the bottom up.
2491
+ *
2492
+ * @param {String} name
2493
+ * @param {Function} fn
2494
+ * @api private
2495
+ */
2496
+
2497
+ Runner.prototype.hookDown = function(name, fn){
2498
+ var suites = [this.suite].concat(this.parents());
2499
+ this.hooks(name, suites, fn);
2500
+ };
2501
+
2502
+ /**
2503
+ * Return an array of parent Suites from
2504
+ * closest to furthest.
2505
+ *
2506
+ * @return {Array}
2507
+ * @api private
2508
+ */
2509
+
2510
+ Runner.prototype.parents = function(){
2511
+ var suite = this.suite
2512
+ , suites = [];
2513
+ while (suite = suite.parent) suites.push(suite);
2514
+ return suites;
2515
+ };
2516
+
2517
+ /**
2518
+ * Run the current test and callback `fn(err)`.
2519
+ *
2520
+ * @param {Function} fn
2521
+ * @api private
2522
+ */
2523
+
2524
+ Runner.prototype.runTest = function(fn){
2525
+ var test = this.test
2526
+ , self = this;
2527
+
2528
+ try {
2529
+ test.on('error', function(err){
2530
+ self.fail(test, err);
2531
+ });
2532
+ test.run(fn);
2533
+ } catch (err) {
2534
+ fn(err);
2535
+ }
2536
+ };
2537
+
2538
+ /**
2539
+ * Run tests in the given `suite` and invoke
2540
+ * the callback `fn()` when complete.
2541
+ *
2542
+ * @param {Suite} suite
2543
+ * @param {Function} fn
2544
+ * @api private
2545
+ */
2546
+
2547
+ Runner.prototype.runTests = function(suite, fn){
2548
+ var self = this
2549
+ , tests = suite.tests
2550
+ , test;
2551
+
2552
+ function next(err) {
2553
+ // if we bail after first err
2554
+ if (self.failures && suite._bail) return fn();
2555
+
2556
+ // next test
2557
+ test = tests.shift();
2558
+
2559
+ // all done
2560
+ if (!test) return fn();
2561
+
2562
+ // grep
2563
+ if (!self._grep.test(test.fullTitle())) return next();
2564
+
2565
+ // pending
2566
+ if (test.pending) {
2567
+ self.emit('pending', test);
2568
+ self.emit('test end', test);
2569
+ return next();
2570
+ }
2571
+
2572
+ // execute test and hook(s)
2573
+ self.emit('test', self.test = test);
2574
+ self.hookDown('beforeEach', function(){
2575
+ self.currentRunnable = self.test;
2576
+ self.runTest(function(err){
2577
+ test = self.test;
2578
+
2579
+ if (err) {
2580
+ self.fail(test, err);
2581
+ self.emit('test end', test);
2582
+ return self.hookUp('afterEach', next);
2583
+ }
2584
+
2585
+ test.passed = true;
2586
+ self.emit('pass', test);
2587
+ self.emit('test end', test);
2588
+ self.hookUp('afterEach', next);
2589
+ });
2590
+ });
2591
+ }
2592
+
2593
+ this.next = next;
2594
+ next();
2595
+ };
2596
+
2597
+ /**
2598
+ * Run the given `suite` and invoke the
2599
+ * callback `fn()` when complete.
2600
+ *
2601
+ * @param {Suite} suite
2602
+ * @param {Function} fn
2603
+ * @api private
2604
+ */
2605
+
2606
+ Runner.prototype.runSuite = function(suite, fn){
2607
+ var self = this
2608
+ , i = 0;
2609
+
2610
+ debug('run suite %s', suite.fullTitle());
2611
+ this.emit('suite', this.suite = suite);
2612
+
2613
+ function next() {
2614
+ var curr = suite.suites[i++];
2615
+ if (!curr) return done();
2616
+ self.runSuite(curr, next);
2617
+ }
2618
+
2619
+ function done() {
2620
+ self.suite = suite;
2621
+ self.hook('afterAll', function(){
2622
+ self.emit('suite end', suite);
2623
+ fn();
2624
+ });
2625
+ }
2626
+
2627
+ this.hook('beforeAll', function(){
2628
+ self.runTests(suite, next);
2629
+ });
2630
+ };
2631
+
2632
+ /**
2633
+ * Handle uncaught exceptions.
2634
+ *
2635
+ * @param {Error} err
2636
+ * @api private
2637
+ */
2638
+
2639
+ Runner.prototype.uncaught = function(err){
2640
+ debug('uncaught exception');
2641
+ var runnable = this.currentRunnable;
2642
+ if (runnable.failed) return;
2643
+ runnable.clearTimeout();
2644
+ err.uncaught = true;
2645
+ this.fail(runnable, err);
2646
+
2647
+ // recover from test
2648
+ if ('test' == runnable.type) {
2649
+ this.emit('test end', runnable);
2650
+ this.hookUp('afterEach', this.next);
2651
+ return;
2652
+ }
2653
+
2654
+ // bail on hooks
2655
+ this.emit('end');
2656
+ };
2657
+
2658
+ /**
2659
+ * Run the root suite and invoke `fn(failures)`
2660
+ * on completion.
2661
+ *
2662
+ * @param {Function} fn
2663
+ * @return {Runner} for chaining
2664
+ * @api public
2665
+ */
2666
+
2667
+ Runner.prototype.run = function(fn){
2668
+ var self = this
2669
+ , fn = fn || function(){};
2670
+
2671
+ debug('start');
2672
+
2673
+ // callback
2674
+ this.on('end', function(){
2675
+ debug('end');
2676
+ process.removeListener('uncaughtException', this.uncaught);
2677
+ fn(self.failures);
2678
+ });
2679
+
2680
+ // run suites
2681
+ this.emit('start');
2682
+ this.runSuite(this.suite, function(){
2683
+ debug('finished running');
2684
+ self.emit('end');
2685
+ });
2686
+
2687
+ // uncaught exception
2688
+ process.on('uncaughtException', function(err){
2689
+ self.uncaught(err);
2690
+ });
2691
+
2692
+ return this;
2693
+ };
2694
+
2695
+ }); // module: runner.js
2696
+
2697
+ require.register("suite.js", function(module, exports, require){
2698
+
2699
+ /**
2700
+ * Module dependencies.
2701
+ */
2702
+
2703
+ var EventEmitter = require('browser/events').EventEmitter
2704
+ , debug = require('browser/debug')('suite')
2705
+ , utils = require('./utils')
2706
+ , Hook = require('./hook');
2707
+
2708
+ /**
2709
+ * Expose `Suite`.
2710
+ */
2711
+
2712
+ exports = module.exports = Suite;
2713
+
2714
+ /**
2715
+ * Create a new `Suite` with the given `title`
2716
+ * and parent `Suite`. When a suite with the
2717
+ * same title is already present, that suite
2718
+ * is returned to provide nicer reporter
2719
+ * and more flexible meta-testing.
2720
+ *
2721
+ * @param {Suite} parent
2722
+ * @param {String} title
2723
+ * @return {Suite}
2724
+ * @api public
2725
+ */
2726
+
2727
+ exports.create = function(parent, title){
2728
+ var suite = new Suite(title);
2729
+ suite.parent = parent;
2730
+ title = suite.fullTitle();
2731
+ parent.addSuite(suite);
2732
+ return suite;
2733
+ };
2734
+
2735
+ /**
2736
+ * Initialize a new `Suite` with the given `title`.
2737
+ *
2738
+ * @param {String} title
2739
+ * @api private
2740
+ */
2741
+
2742
+ function Suite(title) {
2743
+ this.title = title;
2744
+ this.suites = [];
2745
+ this.tests = [];
2746
+ this._beforeEach = [];
2747
+ this._beforeAll = [];
2748
+ this._afterEach = [];
2749
+ this._afterAll = [];
2750
+ this.root = !title;
2751
+ this._timeout = 2000;
2752
+ this._bail = false;
2753
+ }
2754
+
2755
+ /**
2756
+ * Inherit from `EventEmitter.prototype`.
2757
+ */
2758
+
2759
+ Suite.prototype = new EventEmitter;
2760
+ Suite.prototype.constructor = Suite;
2761
+
2762
+
2763
+ /**
2764
+ * Return a clone of this `Suite`.
2765
+ *
2766
+ * @return {Suite}
2767
+ * @api private
2768
+ */
2769
+
2770
+ Suite.prototype.clone = function(){
2771
+ var suite = new Suite(this.title);
2772
+ debug('clone');
2773
+ suite.timeout(this.timeout());
2774
+ suite.bail(this.bail());
2775
+ return suite;
2776
+ };
2777
+
2778
+ /**
2779
+ * Set timeout `ms` or short-hand such as "2s".
2780
+ *
2781
+ * @param {Number|String} ms
2782
+ * @return {Suite|Number} for chaining
2783
+ * @api private
2784
+ */
2785
+
2786
+ Suite.prototype.timeout = function(ms){
2787
+ if (0 == arguments.length) return this._timeout;
2788
+ if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000;
2789
+ debug('timeout %d', ms);
2790
+ this._timeout = parseInt(ms, 10);
2791
+ return this;
2792
+ };
2793
+
2794
+ /**
2795
+ * Sets whether to bail after first error.
2796
+ *
2797
+ * @parma {Boolean} bail
2798
+ * @return {Suite|Number} for chaining
2799
+ * @api private
2800
+ */
2801
+
2802
+ Suite.prototype.bail = function(bail){
2803
+ if (0 == arguments.length) return this._bail;
2804
+ debug('bail %s', bail);
2805
+ this._bail = bail;
2806
+ return this;
2807
+ };
2808
+
2809
+ /**
2810
+ * Run `fn(test[, done])` before running tests.
2811
+ *
2812
+ * @param {Function} fn
2813
+ * @return {Suite} for chaining
2814
+ * @api private
2815
+ */
2816
+
2817
+ Suite.prototype.beforeAll = function(fn){
2818
+ var hook = new Hook('"before all" hook', fn);
2819
+ hook.parent = this;
2820
+ hook.timeout(this.timeout());
2821
+ this._beforeAll.push(hook);
2822
+ this.emit('beforeAll', hook);
2823
+ return this;
2824
+ };
2825
+
2826
+ /**
2827
+ * Run `fn(test[, done])` after running tests.
2828
+ *
2829
+ * @param {Function} fn
2830
+ * @return {Suite} for chaining
2831
+ * @api private
2832
+ */
2833
+
2834
+ Suite.prototype.afterAll = function(fn){
2835
+ var hook = new Hook('"after all" hook', fn);
2836
+ hook.parent = this;
2837
+ hook.timeout(this.timeout());
2838
+ this._afterAll.push(hook);
2839
+ this.emit('afterAll', hook);
2840
+ return this;
2841
+ };
2842
+
2843
+ /**
2844
+ * Run `fn(test[, done])` before each test case.
2845
+ *
2846
+ * @param {Function} fn
2847
+ * @return {Suite} for chaining
2848
+ * @api private
2849
+ */
2850
+
2851
+ Suite.prototype.beforeEach = function(fn){
2852
+ var hook = new Hook('"before each" hook', fn);
2853
+ hook.parent = this;
2854
+ hook.timeout(this.timeout());
2855
+ this._beforeEach.push(hook);
2856
+ this.emit('beforeEach', hook);
2857
+ return this;
2858
+ };
2859
+
2860
+ /**
2861
+ * Run `fn(test[, done])` after each test case.
2862
+ *
2863
+ * @param {Function} fn
2864
+ * @return {Suite} for chaining
2865
+ * @api private
2866
+ */
2867
+
2868
+ Suite.prototype.afterEach = function(fn){
2869
+ var hook = new Hook('"after each" hook', fn);
2870
+ hook.parent = this;
2871
+ hook.timeout(this.timeout());
2872
+ this._afterEach.push(hook);
2873
+ this.emit('afterEach', hook);
2874
+ return this;
2875
+ };
2876
+
2877
+ /**
2878
+ * Add a test `suite`.
2879
+ *
2880
+ * @param {Suite} suite
2881
+ * @return {Suite} for chaining
2882
+ * @api private
2883
+ */
2884
+
2885
+ Suite.prototype.addSuite = function(suite){
2886
+ suite.parent = this;
2887
+ suite.timeout(this.timeout());
2888
+ suite.bail(this.bail());
2889
+ this.suites.push(suite);
2890
+ this.emit('suite', suite);
2891
+ return this;
2892
+ };
2893
+
2894
+ /**
2895
+ * Add a `test` to this suite.
2896
+ *
2897
+ * @param {Test} test
2898
+ * @return {Suite} for chaining
2899
+ * @api private
2900
+ */
2901
+
2902
+ Suite.prototype.addTest = function(test){
2903
+ test.parent = this;
2904
+ test.timeout(this.timeout());
2905
+ this.tests.push(test);
2906
+ this.emit('test', test);
2907
+ return this;
2908
+ };
2909
+
2910
+ /**
2911
+ * Return the full title generated by recursively
2912
+ * concatenating the parent's full title.
2913
+ *
2914
+ * @return {String}
2915
+ * @api public
2916
+ */
2917
+
2918
+ Suite.prototype.fullTitle = function(){
2919
+ if (this.parent) {
2920
+ var full = this.parent.fullTitle();
2921
+ if (full) return full + ' ' + this.title;
2922
+ }
2923
+ return this.title;
2924
+ };
2925
+
2926
+ /**
2927
+ * Return the total number of tests.
2928
+ *
2929
+ * @return {Number}
2930
+ * @api public
2931
+ */
2932
+
2933
+ Suite.prototype.total = function(){
2934
+ return utils.reduce(this.suites, function(sum, suite){
2935
+ return sum + suite.total();
2936
+ }, 0) + this.tests.length;
2937
+ };
2938
+
2939
+ }); // module: suite.js
2940
+
2941
+ require.register("test.js", function(module, exports, require){
2942
+
2943
+ /**
2944
+ * Module dependencies.
2945
+ */
2946
+
2947
+ var Runnable = require('./runnable');
2948
+
2949
+ /**
2950
+ * Expose `Test`.
2951
+ */
2952
+
2953
+ module.exports = Test;
2954
+
2955
+ /**
2956
+ * Initialize a new `Test` with the given `title` and callback `fn`.
2957
+ *
2958
+ * @param {String} title
2959
+ * @param {Function} fn
2960
+ * @api private
2961
+ */
2962
+
2963
+ function Test(title, fn) {
2964
+ Runnable.call(this, title, fn);
2965
+ this.pending = !fn;
2966
+ this.type = 'test';
2967
+ }
2968
+
2969
+ /**
2970
+ * Inherit from `Runnable.prototype`.
2971
+ */
2972
+
2973
+ Test.prototype = new Runnable;
2974
+ Test.prototype.constructor = Test;
2975
+
2976
+
2977
+ }); // module: test.js
2978
+
2979
+ require.register("utils.js", function(module, exports, require){
2980
+
2981
+ /**
2982
+ * Module dependencies.
2983
+ */
2984
+
2985
+ var fs = require('browser/fs')
2986
+ , path = require('browser/path')
2987
+ , join = path.join
2988
+ , debug = require('browser/debug')('watch');
2989
+
2990
+ /**
2991
+ * Ignored directories.
2992
+ */
2993
+
2994
+ var ignore = ['node_modules', '.git'];
2995
+
2996
+ /**
2997
+ * Escape special characters in the given string of html.
2998
+ *
2999
+ * @param {String} html
3000
+ * @return {String}
3001
+ * @api private
3002
+ */
3003
+
3004
+ exports.escape = function(html) {
3005
+ return String(html)
3006
+ .replace(/&/g, '&amp;')
3007
+ .replace(/"/g, '&quot;')
3008
+ .replace(/</g, '&lt;')
3009
+ .replace(/>/g, '&gt;');
3010
+ };
3011
+
3012
+ /**
3013
+ * Array#forEach (<=IE8)
3014
+ *
3015
+ * @param {Array} array
3016
+ * @param {Function} fn
3017
+ * @param {Object} scope
3018
+ * @api private
3019
+ */
3020
+
3021
+ exports.forEach = function(arr, fn, scope) {
3022
+ for (var i = 0, l = arr.length; i < l; i++)
3023
+ fn.call(scope, arr[i], i);
3024
+ };
3025
+
3026
+ /**
3027
+ * Array#indexOf (<=IE8)
3028
+ *
3029
+ * @parma {Array} arr
3030
+ * @param {Object} obj to find index of
3031
+ * @param {Number} start
3032
+ * @api private
3033
+ */
3034
+
3035
+ exports.indexOf = function (arr, obj, start) {
3036
+ for (var i = start || 0, l = arr.length; i < l; i++) {
3037
+ if (arr[i] === obj)
3038
+ return i;
3039
+ }
3040
+ return -1;
3041
+ };
3042
+
3043
+ /**
3044
+ * Array#reduce (<=IE8)
3045
+ *
3046
+ * @param {Array} array
3047
+ * @param {Function} fn
3048
+ * @param {Object} initial value
3049
+ * @param {Object} scope
3050
+ * @api private
3051
+ */
3052
+
3053
+ exports.reduce = function(arr, fn, val, scope) {
3054
+ var rval = val;
3055
+
3056
+ for (var i = 0, l = arr.length; i < l; i++) {
3057
+ rval = fn.call(scope, rval, arr[i], i, arr);
3058
+ }
3059
+
3060
+ return rval;
3061
+ };
3062
+
3063
+ /**
3064
+ * Array#filter (<=IE8)
3065
+ *
3066
+ * @param {Array} array
3067
+ * @param {Function} fn
3068
+ * @param {Object} scope
3069
+ * @api private
3070
+ */
3071
+
3072
+ exports.filter = function(arr, fn, scope) {
3073
+ var ret = [];
3074
+
3075
+ for (var i = 0, l = arr.length; i < l; i++) {
3076
+ var val = arr[i];
3077
+ if (fn.call(scope, val, i, arr))
3078
+ ret.push(val);
3079
+ }
3080
+
3081
+ return ret;
3082
+ };
3083
+
3084
+ /**
3085
+ * Object.keys (<=IE8)
3086
+ *
3087
+ * @param {Object} obj
3088
+ * @return {Array} keys
3089
+ * @api private
3090
+ */
3091
+
3092
+ exports.keys = Object.keys || function(obj) {
3093
+ var keys = []
3094
+ , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
3095
+
3096
+ for (var i in obj) {
3097
+ if (has.call(obj, i)) {
3098
+ keys.push(i);
3099
+ }
3100
+ }
3101
+
3102
+ return keys;
3103
+ };
3104
+
3105
+ /**
3106
+ * Watch the given `files` for changes
3107
+ * and invoke `fn(file)` on modification.
3108
+ *
3109
+ * @param {Array} files
3110
+ * @param {Function} fn
3111
+ * @api private
3112
+ */
3113
+
3114
+ exports.watch = function(files, fn){
3115
+ var options = { interval: 100 };
3116
+ files.forEach(function(file){
3117
+ debug('file %s', file);
3118
+ fs.watchFile(file, options, function(curr, prev){
3119
+ if (prev.mtime < curr.mtime) fn(file);
3120
+ });
3121
+ });
3122
+ };
3123
+
3124
+ /**
3125
+ * Ignored files.
3126
+ */
3127
+
3128
+ function ignored(path){
3129
+ return !~ignore.indexOf(path);
3130
+ }
3131
+
3132
+ /**
3133
+ * Lookup files in the given `dir`.
3134
+ *
3135
+ * @return {Array}
3136
+ * @api public
3137
+ */
3138
+
3139
+ exports.files = function(dir, ret){
3140
+ ret = ret || [];
3141
+
3142
+ fs.readdirSync(dir)
3143
+ .filter(ignored)
3144
+ .forEach(function(path){
3145
+ path = join(dir, path);
3146
+ if (fs.statSync(path).isDirectory()) {
3147
+ exports.files(path, ret);
3148
+ } else if (path.match(/\.(js|coffee)$/)) {
3149
+ ret.push(path);
3150
+ }
3151
+ });
3152
+
3153
+ return ret;
3154
+ };
3155
+ }); // module: utils.js
3156
+
3157
+ /**
3158
+ * Node shims.
3159
+ *
3160
+ * These are meant only to allow
3161
+ * mocha.js to run untouched, not
3162
+ * to allow running node code in
3163
+ * the browser.
3164
+ */
3165
+
3166
+ process = {};
3167
+ process.exit = function(status){};
3168
+ process.stdout = {};
3169
+ global = window;
3170
+
3171
+ /**
3172
+ * next tick implementation.
3173
+ */
3174
+
3175
+ process.nextTick = (function(){
3176
+ // postMessage behaves badly on IE8
3177
+ if (window.ActiveXObject || !window.postMessage) {
3178
+ return function(fn){ fn() };
3179
+ }
3180
+
3181
+ // based on setZeroTimeout by David Baron
3182
+ // - http://dbaron.org/log/20100309-faster-timeouts
3183
+ var timeouts = []
3184
+ , name = 'mocha-zero-timeout'
3185
+
3186
+ return function(fn){
3187
+ timeouts.push(fn);
3188
+ window.postMessage(name, '*');
3189
+ window.addEventListener('message', function(e){
3190
+ if (e.source == window && e.data == name) {
3191
+ if (e.stopPropagation) e.stopPropagation();
3192
+ if (timeouts.length) timeouts.shift()();
3193
+ }
3194
+ }, true);
3195
+ }
3196
+ })();
3197
+
3198
+ /**
3199
+ * Remove uncaughtException listener.
3200
+ */
3201
+
3202
+ process.removeListener = function(e){
3203
+ if ('uncaughtException' == e) {
3204
+ window.onerror = null;
3205
+ }
3206
+ };
3207
+
3208
+ /**
3209
+ * Implements uncaughtException listener.
3210
+ */
3211
+
3212
+ process.on = function(e, fn){
3213
+ if ('uncaughtException' == e) {
3214
+ window.onerror = fn;
3215
+ }
3216
+ };
3217
+
3218
+ /**
3219
+ * Expose mocha.
3220
+ */
3221
+
3222
+ window.mocha = require('mocha');
3223
+
3224
+ // boot
3225
+ ;(function(){
3226
+ var suite = new mocha.Suite
3227
+ , utils = mocha.utils
3228
+ , Reporter = mocha.reporters.HTML
3229
+
3230
+ /**
3231
+ * Highlight the given string of `js`.
3232
+ */
3233
+
3234
+ function highlight(js) {
3235
+ return js
3236
+ .replace(/</g, '&lt;')
3237
+ .replace(/>/g, '&gt;')
3238
+ .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
3239
+ .replace(/('.*')/gm, '<span class="string">$1</span>')
3240
+ .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
3241
+ .replace(/(\d+)/gm, '<span class="number">$1</span>')
3242
+ .replace(/\bnew *(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
3243
+ .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>')
3244
+ }
3245
+
3246
+ /**
3247
+ * Parse the given `qs`.
3248
+ */
3249
+
3250
+ function parse(qs) {
3251
+ return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
3252
+ var i = pair.indexOf('=')
3253
+ , key = pair.slice(0, i)
3254
+ , val = pair.slice(++i);
3255
+
3256
+ obj[key] = decodeURIComponent(val);
3257
+ return obj;
3258
+ }, {});
3259
+ }
3260
+
3261
+ /**
3262
+ * Setup mocha with the give `ui` name.
3263
+ */
3264
+
3265
+ mocha.setup = function(ui){
3266
+ ui = mocha.interfaces[ui];
3267
+ if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
3268
+ ui(suite);
3269
+ suite.emit('pre-require', window);
3270
+ };
3271
+
3272
+ /**
3273
+ * Run mocha, returning the Runner.
3274
+ */
3275
+
3276
+ mocha.run = function(){
3277
+ suite.emit('run');
3278
+ var runner = new mocha.Runner(suite);
3279
+ var reporter = new Reporter(runner);
3280
+ var query = parse(window.location.search || "");
3281
+ if (query.grep) runner.grep(new RegExp(query.grep));
3282
+ runner.on('end', function(){
3283
+ $('code').each(function(){
3284
+ $(this).html(highlight($(this).text()));
3285
+ });
3286
+ });
3287
+ return runner.run();
3288
+ };
3289
+ })();
3290
+ })();