├── client
├── easierStorage.js
├── index.html
├── mocha
│ ├── mocha.css
│ └── mocha.js
└── easierStorage_test.js
├── LICENSE
├── README.md
└── src
└── easierStorage.js
/client/easierStorage.js:
--------------------------------------------------------------------------------
1 | ../src/easierStorage.js
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This software is available under version 2.0 of the MPL:
2 |
3 | https://www.mozilla.org/MPL/
4 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Test!
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # easierStorage
2 | easierStorage makes it dead simple to work with tree structures that are stored in localStorage.
3 |
4 | ## Examples
5 | ```
6 | // Write an item 3 levels deep without ever checking whether top or middle
7 | // exist. calling setItem like this will automatically create any nodes that
8 | // are needed.
9 | easierStorage.setItem("top", "middle", "leaf", "oooh!");
10 |
11 | // Write into a new branch off of the top, this will not destroy the middle
12 | // branch.
13 | easierStorage.setItem("top", "right", "end", "wee!");
14 |
15 | // Go directly to the item you want to get, without checking whether top or
16 | // middle exist. Returns undefined if any nodes do not exist.
17 | var leafValue = easierStorage.getItem("top", "middle", "leaf");
18 | // leafValue === "oooh!"
19 |
20 |
21 | ```
22 | ## License:
23 | Mozilla MPL 2.0
24 |
25 | ## Author
26 | * Shane Tomlinson
27 | * @shane_tomlinson
28 | * shane@shanetomlinson.com
29 | * set117@yahoo.com
30 | * stomlinson@mozilla.com
31 | * http://shanetomlinson.com
32 |
33 |
--------------------------------------------------------------------------------
/client/mocha/mocha.css:
--------------------------------------------------------------------------------
1 |
2 | body {
3 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
4 | padding: 60px 50px;
5 | }
6 |
7 | #mocha h1, h2 {
8 | margin: 0;
9 | }
10 |
11 | #mocha h1 {
12 | margin-top: 15px;
13 | font-size: 1em;
14 | font-weight: 200;
15 | }
16 |
17 | #mocha .suite .suite h1 {
18 | margin-top: 0;
19 | font-size: .8em;
20 | }
21 |
22 | #mocha h2 {
23 | font-size: 12px;
24 | font-weight: normal;
25 | cursor: pointer;
26 | }
27 |
28 | #mocha .suite {
29 | margin-left: 15px;
30 | }
31 |
32 | #mocha .test {
33 | margin-left: 15px;
34 | }
35 |
36 | #mocha .test:hover h2::after {
37 | position: relative;
38 | top: 0;
39 | right: -10px;
40 | content: '(view source)';
41 | font-size: 12px;
42 | font-family: arial;
43 | color: #888;
44 | }
45 |
46 | #mocha .test.pending:hover h2::after {
47 | content: '(pending)';
48 | font-family: arial;
49 | }
50 |
51 | #mocha .test.pass::before {
52 | content: '✓';
53 | font-size: 12px;
54 | display: block;
55 | float: left;
56 | margin-right: 5px;
57 | color: #00c41c;
58 | }
59 |
60 | #mocha .test.pending {
61 | color: #0b97c4;
62 | }
63 |
64 | #mocha .test.pending::before {
65 | content: '◦';
66 | color: #0b97c4;
67 | }
68 |
69 | #mocha .test.fail {
70 | color: #c00;
71 | }
72 |
73 | #mocha .test.fail pre {
74 | color: black;
75 | }
76 |
77 | #mocha .test.fail::before {
78 | content: '✖';
79 | font-size: 12px;
80 | display: block;
81 | float: left;
82 | margin-right: 5px;
83 | color: #c00;
84 | }
85 |
86 | #mocha .test pre.error {
87 | color: #c00;
88 | }
89 |
90 | #mocha .test pre {
91 | display: inline-block;
92 | font: 12px/1.5 monaco, monospace;
93 | margin: 5px;
94 | padding: 15px;
95 | border: 1px solid #eee;
96 | border-bottom-color: #ddd;
97 | -webkit-border-radius: 3px;
98 | -webkit-box-shadow: 0 1px 3px #eee;
99 | }
100 |
101 | #error {
102 | color: #c00;
103 | font-size: 1.5 em;
104 | font-weight: 100;
105 | letter-spacing: 1px;
106 | }
107 |
108 | #stats {
109 | position: fixed;
110 | top: 15px;
111 | right: 10px;
112 | font-size: 12px;
113 | margin: 0;
114 | color: #888;
115 | }
116 |
117 | #stats .progress {
118 | float: right;
119 | padding-top: 0;
120 | }
121 |
122 | #stats em {
123 | color: black;
124 | }
125 |
126 | #stats li {
127 | display: inline-block;
128 | margin: 0 5px;
129 | list-style: none;
130 | padding-top: 11px;
131 | }
132 |
133 | code .comment { color: #ddd }
134 | code .init { color: #2F6FAD }
135 | code .string { color: #5890AD }
136 | code .keyword { color: #8A6343 }
137 | code .number { color: #2F6FAD }
138 |
--------------------------------------------------------------------------------
/src/easierStorage.js:
--------------------------------------------------------------------------------
1 | (function(exports) {
2 | "use strict";
3 |
4 | function setItem() {
5 | var args = [].slice.call(arguments, 0),
6 | rootname = args[0],
7 | value = args.pop(),
8 | obj,
9 | root,
10 | len = args.length;
11 |
12 | if(!len) {
13 | throw "setItem must be called with at least one key and a value";
14 | }
15 | else {
16 | root = obj = JSON.parse(localStorage[rootname] || "{}");
17 |
18 | if(len === 1) {
19 | root = value;
20 | }
21 | else {
22 | for(var index = 1, key, max = len - 1; key = args[index]; ++index) {
23 | if(index === max) {
24 | obj[key] = value;
25 | }
26 | else {
27 | obj = obj[key] = obj[key] || {};
28 | }
29 | }
30 | }
31 |
32 | localStorage[rootname] = JSON.stringify(root);
33 | }
34 | }
35 |
36 | function getItem(key) {
37 | var args = [].slice.call(arguments, 0),
38 | rootname = args[0],
39 | len = args.length,
40 | max = len - 1;
41 |
42 | if(len === 0) {
43 | throw "getItem must be called with at least one key";
44 | }
45 | else if(len === 1) {
46 | var value = localStorage[rootname],
47 | undef;
48 | return (typeof value !== "undefined" && value !== null) ? JSON.parse(value) : undef;
49 | }
50 | else {
51 | var obj = JSON.parse(localStorage[rootname] || "{}");
52 |
53 | for(var index = 1, key; obj && (key = args[index]); ++index) {
54 | if(index === max) {
55 | return obj[key];
56 | }
57 | else {
58 | obj = obj[key];
59 | }
60 | }
61 | }
62 | }
63 |
64 | function removeItem() {
65 | var args = [].slice.call(arguments, 0),
66 | rootname = args[0],
67 | len = args.length;
68 |
69 | if(len === 0) {
70 | throw "removeItem must be called with at least one key";
71 | }
72 | else if(len === 1) {
73 | localStorage.removeItem(rootname);
74 | }
75 | else {
76 | var root = JSON.parse(localStorage[rootname] || "{}"),
77 | obj = root;
78 |
79 | for(var index = 1, key, max = len - 1; obj && (key = args[index]); ++index) {
80 | if(index === max) {
81 | obj[key] = null;
82 | delete obj[key];
83 | }
84 | else {
85 | obj = obj[key];
86 | }
87 | }
88 |
89 | localStorage[rootname] = JSON.stringify(root);
90 | }
91 |
92 | }
93 |
94 | exports.easierStorage = {
95 | setItem: setItem,
96 | getItem: getItem,
97 | removeItem: removeItem
98 | };
99 | }(window || exports));
100 |
--------------------------------------------------------------------------------
/client/easierStorage_test.js:
--------------------------------------------------------------------------------
1 |
2 | (function() {
3 |
4 | describe("easierStorage", function() {
5 | it("should exist", function() {
6 | assert(typeof easierStorage !== "undefined", "easierStorage exists");
7 | });
8 |
9 | beforeEach(function() {
10 | for(var key in localStorage) {
11 | localStorage.removeItem(key);
12 | }
13 | });
14 |
15 |
16 | describe("setItem/getItem", function() {
17 | it("setItem must have at least one key and one value", function() {
18 | var err;
19 | try {
20 | easierStorage.setItem("first");
21 | } catch(e) {
22 | err = e;
23 | }
24 |
25 | assert(err.toString() === "setItem must be called with at least one key and a value");
26 | });
27 |
28 | it("setItem setItems value, getItem getItems value", function() {
29 | easierStorage.setItem("first", "value");
30 | assert(easierStorage.getItem("first") === "value", "correct getItem after setItem");
31 | });
32 |
33 | it("getItem with no keys throws an exception", function() {
34 | var err;
35 | try {
36 | easierStorage.getItem()
37 | } catch(e) {
38 | err = e;
39 | }
40 | assert(err);
41 | });
42 |
43 | it("setItem/getItem with 2 keys", function() {
44 | easierStorage.setItem("first", "second", "some value");
45 | assert(easierStorage.getItem("first", "second") === "some value", "setItem/getItem with 2 keys");
46 | });
47 |
48 | it("getItem of undefined leaf returns undefined", function() {
49 | assert(typeof easierStorage.getItem("unknown") === "undefined");
50 | assert(typeof easierStorage.getItem("unknown", "unknown") === "undefined");
51 | });
52 | });
53 |
54 | describe("removeItem", function() {
55 | it("removeItem without a key - throw exception", function() {
56 | var err;
57 | try {
58 | easierStorage.removeItem();
59 | } catch(e) {
60 | err = e;
61 | }
62 |
63 | assert(err.toString() === "removeItem must be called with at least one key");
64 |
65 | });
66 |
67 | it("removeItems an unknown item - does not cause problem", function() {
68 | var err;
69 | try {
70 | easierStorage.removeItem("first");
71 | } catch(e) {
72 | err = e;
73 | }
74 |
75 | assert(typeof err === "undefined");
76 | });
77 |
78 | it("removeItems a leaf", function() {
79 | easierStorage.setItem("first", "second", "third", "value");
80 | easierStorage.removeItem("first", "second", "third");
81 | assert(typeof easierStorage.getItem("first", "second", "third") === "undefined");
82 | });
83 |
84 | it("removeItems a branch", function() {
85 | easierStorage.setItem("first", "second", "third", "value");
86 | easierStorage.removeItem("first", "second");
87 | assert(typeof easierStorage.getItem("first", "second") === "undefined");
88 | assert(typeof easierStorage.getItem("first").second === "undefined");
89 | });
90 | });
91 | });
92 | }());
93 |
94 |
95 |
--------------------------------------------------------------------------------
/client/mocha/mocha.js:
--------------------------------------------------------------------------------
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/diff.js", function(module, exports, require){
61 |
62 | }); // module: browser/diff.js
63 |
64 | require.register("browser/events.js", function(module, exports, require){
65 |
66 | /**
67 | * Module exports.
68 | */
69 |
70 | exports.EventEmitter = EventEmitter;
71 |
72 | /**
73 | * Check if `obj` is an array.
74 | */
75 |
76 | function isArray(obj) {
77 | return '[object Array]' == {}.toString.call(obj);
78 | }
79 |
80 | /**
81 | * Event emitter constructor.
82 | *
83 | * @api public.
84 | */
85 |
86 | function EventEmitter(){};
87 |
88 | /**
89 | * Adds a listener.
90 | *
91 | * @api public
92 | */
93 |
94 | EventEmitter.prototype.on = function (name, fn) {
95 | if (!this.$events) {
96 | this.$events = {};
97 | }
98 |
99 | if (!this.$events[name]) {
100 | this.$events[name] = fn;
101 | } else if (isArray(this.$events[name])) {
102 | this.$events[name].push(fn);
103 | } else {
104 | this.$events[name] = [this.$events[name], fn];
105 | }
106 |
107 | return this;
108 | };
109 |
110 | EventEmitter.prototype.addListener = EventEmitter.prototype.on;
111 |
112 | /**
113 | * Adds a volatile listener.
114 | *
115 | * @api public
116 | */
117 |
118 | EventEmitter.prototype.once = function (name, fn) {
119 | var self = this;
120 |
121 | function on () {
122 | self.removeListener(name, on);
123 | fn.apply(this, arguments);
124 | };
125 |
126 | on.listener = fn;
127 | this.on(name, on);
128 |
129 | return this;
130 | };
131 |
132 | /**
133 | * Removes a listener.
134 | *
135 | * @api public
136 | */
137 |
138 | EventEmitter.prototype.removeListener = function (name, fn) {
139 | if (this.$events && this.$events[name]) {
140 | var list = this.$events[name];
141 |
142 | if (isArray(list)) {
143 | var pos = -1;
144 |
145 | for (var i = 0, l = list.length; i < l; i++) {
146 | if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
147 | pos = i;
148 | break;
149 | }
150 | }
151 |
152 | if (pos < 0) {
153 | return this;
154 | }
155 |
156 | list.splice(pos, 1);
157 |
158 | if (!list.length) {
159 | delete this.$events[name];
160 | }
161 | } else if (list === fn || (list.listener && list.listener === fn)) {
162 | delete this.$events[name];
163 | }
164 | }
165 |
166 | return this;
167 | };
168 |
169 | /**
170 | * Removes all listeners for an event.
171 | *
172 | * @api public
173 | */
174 |
175 | EventEmitter.prototype.removeAllListeners = function (name) {
176 | if (name === undefined) {
177 | this.$events = {};
178 | return this;
179 | }
180 |
181 | if (this.$events && this.$events[name]) {
182 | this.$events[name] = null;
183 | }
184 |
185 | return this;
186 | };
187 |
188 | /**
189 | * Gets all listeners for a certain event.
190 | *
191 | * @api publci
192 | */
193 |
194 | EventEmitter.prototype.listeners = function (name) {
195 | if (!this.$events) {
196 | this.$events = {};
197 | }
198 |
199 | if (!this.$events[name]) {
200 | this.$events[name] = [];
201 | }
202 |
203 | if (!isArray(this.$events[name])) {
204 | this.$events[name] = [this.$events[name]];
205 | }
206 |
207 | return this.$events[name];
208 | };
209 |
210 | /**
211 | * Emits an event.
212 | *
213 | * @api public
214 | */
215 |
216 | EventEmitter.prototype.emit = function (name) {
217 | if (!this.$events) {
218 | return false;
219 | }
220 |
221 | var handler = this.$events[name];
222 |
223 | if (!handler) {
224 | return false;
225 | }
226 |
227 | var args = [].slice.call(arguments, 1);
228 |
229 | if ('function' == typeof handler) {
230 | handler.apply(this, args);
231 | } else if (isArray(handler)) {
232 | var listeners = handler.slice();
233 |
234 | for (var i = 0, l = listeners.length; i < l; i++) {
235 | listeners[i].apply(this, args);
236 | }
237 | } else {
238 | return false;
239 | }
240 |
241 | return true;
242 | };
243 | }); // module: browser/events.js
244 |
245 | require.register("browser/fs.js", function(module, exports, require){
246 |
247 | }); // module: browser/fs.js
248 |
249 | require.register("browser/path.js", function(module, exports, require){
250 |
251 | }); // module: browser/path.js
252 |
253 | require.register("browser/progress.js", function(module, exports, require){
254 |
255 | /**
256 | * Expose `Progress`.
257 | */
258 |
259 | module.exports = Progress;
260 |
261 | /**
262 | * Initialize a new `Progress` indicator.
263 | */
264 |
265 | function Progress() {
266 | this.percent = 0;
267 | this.size(0);
268 | this.fontSize(11);
269 | this.font('helvetica, arial, sans-serif');
270 | }
271 |
272 | /**
273 | * Set progress size to `n`.
274 | *
275 | * @param {Number} n
276 | * @return {Progress} for chaining
277 | * @api public
278 | */
279 |
280 | Progress.prototype.size = function(n){
281 | this._size = n;
282 | return this;
283 | };
284 |
285 | /**
286 | * Set text to `str`.
287 | *
288 | * @param {String} str
289 | * @return {Progress} for chaining
290 | * @api public
291 | */
292 |
293 | Progress.prototype.text = function(str){
294 | this._text = str;
295 | return this;
296 | };
297 |
298 | /**
299 | * Set font size to `n`.
300 | *
301 | * @param {Number} n
302 | * @return {Progress} for chaining
303 | * @api public
304 | */
305 |
306 | Progress.prototype.fontSize = function(n){
307 | this._fontSize = n;
308 | return this;
309 | };
310 |
311 | /**
312 | * Set font `family`.
313 | *
314 | * @param {String} family
315 | * @return {Progress} for chaining
316 | */
317 |
318 | Progress.prototype.font = function(family){
319 | this._font = family;
320 | return this;
321 | };
322 |
323 | /**
324 | * Update percentage to `n`.
325 | *
326 | * @param {Number} n
327 | * @return {Progress} for chaining
328 | */
329 |
330 | Progress.prototype.update = function(n){
331 | this.percent = n;
332 | return this;
333 | };
334 |
335 | /**
336 | * Draw on `ctx`.
337 | *
338 | * @param {CanvasRenderingContext2d} ctx
339 | * @return {Progress} for chaining
340 | */
341 |
342 | Progress.prototype.draw = function(ctx){
343 | var percent = Math.min(this.percent, 100)
344 | , size = this._size
345 | , half = size / 2
346 | , x = half
347 | , y = half
348 | , rad = half - 1
349 | , fontSize = this._fontSize;
350 |
351 | ctx.font = fontSize + 'px ' + this._font;
352 |
353 | var angle = Math.PI * 2 * (percent / 100);
354 | ctx.clearRect(0, 0, size, size);
355 |
356 | // outer circle
357 | ctx.strokeStyle = '#9f9f9f';
358 | ctx.beginPath();
359 | ctx.arc(x, y, rad, 0, angle, false);
360 | ctx.stroke();
361 |
362 | // inner circle
363 | ctx.strokeStyle = '#eee';
364 | ctx.beginPath();
365 | ctx.arc(x, y, rad - 1, 0, angle, true);
366 | ctx.stroke();
367 |
368 | // text
369 | var text = this._text || (percent | 0) + '%'
370 | , w = ctx.measureText(text).width;
371 |
372 | ctx.fillText(
373 | text
374 | , x - w / 2 + 1
375 | , y + fontSize / 2 - 1);
376 |
377 | return this;
378 | };
379 |
380 | }); // module: browser/progress.js
381 |
382 | require.register("browser/tty.js", function(module, exports, require){
383 |
384 | exports.isatty = function(){
385 | return true;
386 | };
387 |
388 | exports.getWindowSize = function(){
389 | return [window.innerHeight, window.innerWidth];
390 | };
391 | }); // module: browser/tty.js
392 |
393 | require.register("context.js", function(module, exports, require){
394 |
395 | /**
396 | * Expose `Context`.
397 | */
398 |
399 | module.exports = Context;
400 |
401 | /**
402 | * Initialize a new `Context`.
403 | *
404 | * @api private
405 | */
406 |
407 | function Context(){}
408 |
409 | /**
410 | * Set the context `Runnable` to `runnable`.
411 | *
412 | * @param {Runnable} runnable
413 | * @return {Context}
414 | * @api private
415 | */
416 |
417 | Context.prototype.runnable = function(runnable){
418 | this._runnable = runnable;
419 | return this;
420 | };
421 |
422 | /**
423 | * Set test timeout `ms`.
424 | *
425 | * @param {Number} ms
426 | * @return {Context} self
427 | * @api private
428 | */
429 |
430 | Context.prototype.timeout = function(ms){
431 | this._runnable.timeout(ms);
432 | return this;
433 | };
434 |
435 | /**
436 | * Inspect the context void of `._runnable`.
437 | *
438 | * @return {String}
439 | * @api private
440 | */
441 |
442 | Context.prototype.inspect = function(){
443 | return JSON.stringify(this, function(key, val){
444 | return '_runnable' == key
445 | ? undefined
446 | : val;
447 | }, 2);
448 | };
449 |
450 | }); // module: context.js
451 |
452 | require.register("hook.js", function(module, exports, require){
453 |
454 | /**
455 | * Module dependencies.
456 | */
457 |
458 | var Runnable = require('./runnable');
459 |
460 | /**
461 | * Expose `Hook`.
462 | */
463 |
464 | module.exports = Hook;
465 |
466 | /**
467 | * Initialize a new `Hook` with the given `title` and callback `fn`.
468 | *
469 | * @param {String} title
470 | * @param {Function} fn
471 | * @api private
472 | */
473 |
474 | function Hook(title, fn) {
475 | Runnable.call(this, title, fn);
476 | this.type = 'hook';
477 | }
478 |
479 | /**
480 | * Inherit from `Runnable.prototype`.
481 | */
482 |
483 | Hook.prototype = new Runnable;
484 | Hook.prototype.constructor = Hook;
485 |
486 |
487 | }); // module: hook.js
488 |
489 | require.register("interfaces/bdd.js", function(module, exports, require){
490 |
491 | /**
492 | * Module dependencies.
493 | */
494 |
495 | var Suite = require('../suite')
496 | , Test = require('../test');
497 |
498 | /**
499 | * BDD-style interface:
500 | *
501 | * describe('Array', function(){
502 | * describe('#indexOf()', function(){
503 | * it('should return -1 when not present', function(){
504 | *
505 | * });
506 | *
507 | * it('should return the index when present', function(){
508 | *
509 | * });
510 | * });
511 | * });
512 | *
513 | */
514 |
515 | module.exports = function(suite){
516 | var suites = [suite];
517 |
518 | suite.on('pre-require', function(context){
519 |
520 | // noop variants
521 |
522 | context.xdescribe = function(){};
523 | context.xit = function(){};
524 |
525 | /**
526 | * Execute before running tests.
527 | */
528 |
529 | context.before = function(fn){
530 | suites[0].beforeAll(fn);
531 | };
532 |
533 | /**
534 | * Execute after running tests.
535 | */
536 |
537 | context.after = function(fn){
538 | suites[0].afterAll(fn);
539 | };
540 |
541 | /**
542 | * Execute before each test case.
543 | */
544 |
545 | context.beforeEach = function(fn){
546 | suites[0].beforeEach(fn);
547 | };
548 |
549 | /**
550 | * Execute after each test case.
551 | */
552 |
553 | context.afterEach = function(fn){
554 | suites[0].afterEach(fn);
555 | };
556 |
557 | /**
558 | * Describe a "suite" with the given `title`
559 | * and callback `fn` containing nested suites
560 | * and/or tests.
561 | */
562 |
563 | context.describe = function(title, fn){
564 | var suite = Suite.create(suites[0], title);
565 | suites.unshift(suite);
566 | fn();
567 | suites.shift();
568 | };
569 |
570 | /**
571 | * Describe a specification or test-case
572 | * with the given `title` and callback `fn`
573 | * acting as a thunk.
574 | */
575 |
576 | context.it = function(title, fn){
577 | suites[0].addTest(new Test(title, fn));
578 | };
579 | });
580 | };
581 |
582 | }); // module: interfaces/bdd.js
583 |
584 | require.register("interfaces/exports.js", function(module, exports, require){
585 |
586 | /**
587 | * Module dependencies.
588 | */
589 |
590 | var Suite = require('../suite')
591 | , Test = require('../test');
592 |
593 | /**
594 | * TDD-style interface:
595 | *
596 | * exports.Array = {
597 | * '#indexOf()': {
598 | * 'should return -1 when the value is not present': function(){
599 | *
600 | * },
601 | *
602 | * 'should return the correct index when the value is present': function(){
603 | *
604 | * }
605 | * }
606 | * };
607 | *
608 | */
609 |
610 | module.exports = function(suite){
611 | var suites = [suite];
612 |
613 | suite.on('require', visit);
614 |
615 | function visit(obj) {
616 | var suite;
617 | for (var key in obj) {
618 | if ('function' == typeof obj[key]) {
619 | var fn = obj[key];
620 | switch (key) {
621 | case 'before':
622 | suites[0].beforeAll(fn);
623 | break;
624 | case 'after':
625 | suites[0].afterAll(fn);
626 | break;
627 | case 'beforeEach':
628 | suites[0].beforeEach(fn);
629 | break;
630 | case 'afterEach':
631 | suites[0].afterEach(fn);
632 | break;
633 | default:
634 | suites[0].addTest(new Test(key, fn));
635 | }
636 | } else {
637 | var suite = Suite.create(suites[0], key);
638 | suites.unshift(suite);
639 | visit(obj[key]);
640 | suites.shift();
641 | }
642 | }
643 | }
644 | };
645 | }); // module: interfaces/exports.js
646 |
647 | require.register("interfaces/index.js", function(module, exports, require){
648 |
649 | exports.bdd = require('./bdd');
650 | exports.tdd = require('./tdd');
651 | exports.qunit = require('./qunit');
652 | exports.exports = require('./exports');
653 |
654 | }); // module: interfaces/index.js
655 |
656 | require.register("interfaces/qunit.js", function(module, exports, require){
657 |
658 | /**
659 | * Module dependencies.
660 | */
661 |
662 | var Suite = require('../suite')
663 | , Test = require('../test');
664 |
665 | /**
666 | * QUnit-style interface:
667 | *
668 | * suite('Array');
669 | *
670 | * test('#length', function(){
671 | * var arr = [1,2,3];
672 | * ok(arr.length == 3);
673 | * });
674 | *
675 | * test('#indexOf()', function(){
676 | * var arr = [1,2,3];
677 | * ok(arr.indexOf(1) == 0);
678 | * ok(arr.indexOf(2) == 1);
679 | * ok(arr.indexOf(3) == 2);
680 | * });
681 | *
682 | * suite('String');
683 | *
684 | * test('#length', function(){
685 | * ok('foo'.length == 3);
686 | * });
687 | *
688 | */
689 |
690 | module.exports = function(suite){
691 | var suites = [suite];
692 |
693 | suite.on('pre-require', function(context){
694 |
695 | /**
696 | * Execute before running tests.
697 | */
698 |
699 | context.before = function(fn){
700 | suites[0].beforeAll(fn);
701 | };
702 |
703 | /**
704 | * Execute after running tests.
705 | */
706 |
707 | context.after = function(fn){
708 | suites[0].afterAll(fn);
709 | };
710 |
711 | /**
712 | * Execute before each test case.
713 | */
714 |
715 | context.beforeEach = function(fn){
716 | suites[0].beforeEach(fn);
717 | };
718 |
719 | /**
720 | * Execute after each test case.
721 | */
722 |
723 | context.afterEach = function(fn){
724 | suites[0].afterEach(fn);
725 | };
726 |
727 | /**
728 | * Describe a "suite" with the given `title`.
729 | */
730 |
731 | context.suite = function(title){
732 | if (suites.length > 1) suites.shift();
733 | var suite = Suite.create(suites[0], title);
734 | suites.unshift(suite);
735 | };
736 |
737 | /**
738 | * Describe a specification or test-case
739 | * with the given `title` and callback `fn`
740 | * acting as a thunk.
741 | */
742 |
743 | context.test = function(title, fn){
744 | suites[0].addTest(new Test(title, fn));
745 | };
746 | });
747 | };
748 |
749 | }); // module: interfaces/qunit.js
750 |
751 | require.register("interfaces/tdd.js", function(module, exports, require){
752 |
753 | /**
754 | * Module dependencies.
755 | */
756 |
757 | var Suite = require('../suite')
758 | , Test = require('../test');
759 |
760 | /**
761 | * TDD-style interface:
762 | *
763 | * suite('Array', function(){
764 | * suite('#indexOf()', function(){
765 | * suiteSetup(function(){
766 | *
767 | * });
768 | *
769 | * test('should return -1 when not present', function(){
770 | *
771 | * });
772 | *
773 | * test('should return the index when present', function(){
774 | *
775 | * });
776 | *
777 | * suiteTeardown(function(){
778 | *
779 | * });
780 | * });
781 | * });
782 | *
783 | */
784 |
785 | module.exports = function(suite){
786 | var suites = [suite];
787 |
788 | suite.on('pre-require', function(context){
789 |
790 | /**
791 | * Execute before each test case.
792 | */
793 |
794 | context.setup = function(fn){
795 | suites[0].beforeEach(fn);
796 | };
797 |
798 | /**
799 | * Execute after each test case.
800 | */
801 |
802 | context.teardown = function(fn){
803 | suites[0].afterEach(fn);
804 | };
805 |
806 | /**
807 | * Execute before the suite.
808 | */
809 |
810 | context.suiteSetup = function(fn){
811 | suites[0].beforeAll(fn);
812 | };
813 |
814 | /**
815 | * Execute after the suite.
816 | */
817 |
818 | context.suiteTeardown = function(fn){
819 | suites[0].afterAll(fn);
820 | };
821 |
822 | /**
823 | * Describe a "suite" with the given `title`
824 | * and callback `fn` containing nested suites
825 | * and/or tests.
826 | */
827 |
828 | context.suite = function(title, fn){
829 | var suite = Suite.create(suites[0], title);
830 | suites.unshift(suite);
831 | fn();
832 | suites.shift();
833 | };
834 |
835 | /**
836 | * Describe a specification or test-case
837 | * with the given `title` and callback `fn`
838 | * acting as a thunk.
839 | */
840 |
841 | context.test = function(title, fn){
842 | suites[0].addTest(new Test(title, fn));
843 | };
844 | });
845 | };
846 |
847 | }); // module: interfaces/tdd.js
848 |
849 | require.register("mocha.js", function(module, exports, require){
850 |
851 | /*!
852 | * mocha
853 | * Copyright(c) 2011 TJ Holowaychuk
854 | * MIT Licensed
855 | */
856 |
857 | /**
858 | * Module dependencies.
859 | */
860 |
861 | var path = require('browser/path');
862 |
863 | /**
864 | * Expose `Mocha`.
865 | */
866 |
867 | exports = module.exports = Mocha;
868 |
869 | /**
870 | * Library version.
871 | */
872 |
873 | exports.version = '1.0.1';
874 |
875 | /**
876 | * Expose internals.
877 | */
878 |
879 | exports.utils = require('./utils');
880 | exports.interfaces = require('./interfaces');
881 | exports.reporters = require('./reporters');
882 | exports.Runnable = require('./runnable');
883 | exports.Context = require('./context');
884 | exports.Runner = require('./runner');
885 | exports.Suite = require('./suite');
886 | exports.Hook = require('./hook');
887 | exports.Test = require('./test');
888 |
889 | /**
890 | * Return image `name` path.
891 | *
892 | * @param {String} name
893 | * @return {String}
894 | * @api private
895 | */
896 |
897 | function image(name) {
898 | return __dirname + '/../images/' + name + '.png';
899 | }
900 |
901 | /**
902 | * Setup mocha with `options`.
903 | *
904 | * Options:
905 | *
906 | * - `ui` name "bdd", "tdd", "exports" etc
907 | * - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
908 | * - `globals` array of accepted globals
909 | * - `timeout` timeout in milliseconds
910 | * - `ignoreLeaks` ignore global leaks
911 | *
912 | * @param {Object} options
913 | * @api public
914 | */
915 |
916 | function Mocha(options) {
917 | options = options || {};
918 | this.files = [];
919 | this.options = options;
920 | this.suite = new exports.Suite('', new exports.Context);
921 | this.ui(options.ui);
922 | this.reporter(options.reporter);
923 | if (options.timeout) this.suite.timeout(options.timeout);
924 | }
925 |
926 | /**
927 | * Add test `file`.
928 | *
929 | * @param {String} file
930 | * @api public
931 | */
932 |
933 | Mocha.prototype.addFile = function(file){
934 | this.files.push(file);
935 | return this;
936 | };
937 |
938 | /**
939 | * Set reporter to `name`, defaults to "dot".
940 | *
941 | * @param {String} name
942 | * @api public
943 | */
944 |
945 | Mocha.prototype.reporter = function(name){
946 | name = name || 'dot';
947 | this._reporter = require('./reporters/' + name);
948 | if (!this._reporter) throw new Error('invalid reporter "' + name + '"');
949 | return this;
950 | };
951 |
952 | /**
953 | * Set test UI `name`, defaults to "bdd".
954 | *
955 | * @param {String} bdd
956 | * @api public
957 | */
958 |
959 | Mocha.prototype.ui = function(name){
960 | name = name || 'bdd';
961 | this._ui = exports.interfaces[name];
962 | if (!this._ui) throw new Error('invalid interface "' + name + '"');
963 | this._ui = this._ui(this.suite);
964 | return this;
965 | };
966 |
967 | /**
968 | * Load registered files.
969 | *
970 | * @api private
971 | */
972 |
973 | Mocha.prototype.loadFiles = function(){
974 | var suite = this.suite;
975 | this.files.forEach(function(file){
976 | file = path.resolve(file);
977 | suite.emit('pre-require', global, file);
978 | suite.emit('require', require(file), file);
979 | suite.emit('post-require', global, file);
980 | });
981 | };
982 |
983 | /**
984 | * Enable growl support.
985 | *
986 | * @api private
987 | */
988 |
989 | Mocha.prototype.growl = function(runner, reporter) {
990 | var notify = require('growl');
991 |
992 | runner.on('end', function(){
993 | var stats = reporter.stats;
994 | if (stats.failures) {
995 | var msg = stats.failures + ' of ' + runner.total + ' tests failed';
996 | notify(msg, { title: 'Failed', image: image('fail') });
997 | } else {
998 | notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
999 | title: 'Passed'
1000 | , image: image('pass')
1001 | });
1002 | }
1003 | });
1004 | };
1005 |
1006 | /**
1007 | * Run tests and invoke `fn()` when complete.
1008 | *
1009 | * @param {Function} fn
1010 | * @return {Runner}
1011 | * @api public
1012 | */
1013 |
1014 | Mocha.prototype.run = function(fn){
1015 | this.loadFiles();
1016 | var suite = this.suite;
1017 | var options = this.options;
1018 | var runner = new exports.Runner(suite);
1019 | var reporter = new this._reporter(runner);
1020 | runner.ignoreLeaks = options.ignoreLeaks;
1021 | if (options.grep) runner.grep(options.grep);
1022 | if (options.globals) runner.globals(options.globals);
1023 | if (options.growl) this.growl(runner, reporter);
1024 | return runner.run(fn);
1025 | };
1026 |
1027 | }); // module: mocha.js
1028 |
1029 | require.register("reporters/base.js", function(module, exports, require){
1030 |
1031 | /**
1032 | * Module dependencies.
1033 | */
1034 |
1035 | var tty = require('browser/tty')
1036 | , diff = require('browser/diff');
1037 |
1038 | /**
1039 | * Check if both stdio streams are associated with a tty.
1040 | */
1041 |
1042 | var isatty = tty.isatty(1) && tty.isatty(2);
1043 |
1044 | /**
1045 | * Expose `Base`.
1046 | */
1047 |
1048 | exports = module.exports = Base;
1049 |
1050 | /**
1051 | * Enable coloring by default.
1052 | */
1053 |
1054 | exports.useColors = isatty;
1055 |
1056 | /**
1057 | * Default color map.
1058 | */
1059 |
1060 | exports.colors = {
1061 | 'pass': 90
1062 | , 'fail': 31
1063 | , 'bright pass': 92
1064 | , 'bright fail': 91
1065 | , 'bright yellow': 93
1066 | , 'pending': 36
1067 | , 'suite': 0
1068 | , 'error title': 0
1069 | , 'error message': 31
1070 | , 'error stack': 90
1071 | , 'checkmark': 32
1072 | , 'fast': 90
1073 | , 'medium': 33
1074 | , 'slow': 31
1075 | , 'green': 32
1076 | , 'light': 90
1077 | , 'diff gutter': 90
1078 | , 'diff added': 42
1079 | , 'diff removed': 41
1080 | };
1081 |
1082 | /**
1083 | * Color `str` with the given `type`,
1084 | * allowing colors to be disabled,
1085 | * as well as user-defined color
1086 | * schemes.
1087 | *
1088 | * @param {String} type
1089 | * @param {String} str
1090 | * @return {String}
1091 | * @api private
1092 | */
1093 |
1094 | var color = exports.color = function(type, str) {
1095 | if (!exports.useColors) return str;
1096 | return '\033[' + exports.colors[type] + 'm' + str + '\033[0m';
1097 | };
1098 |
1099 | /**
1100 | * Expose term window size, with some
1101 | * defaults for when stderr is not a tty.
1102 | */
1103 |
1104 | exports.window = {
1105 | width: isatty
1106 | ? process.stdout.getWindowSize
1107 | ? process.stdout.getWindowSize(1)[0]
1108 | : tty.getWindowSize()[1]
1109 | : 75
1110 | };
1111 |
1112 | /**
1113 | * Expose some basic cursor interactions
1114 | * that are common among reporters.
1115 | */
1116 |
1117 | exports.cursor = {
1118 | hide: function(){
1119 | process.stdout.write('\033[?25l');
1120 | },
1121 |
1122 | show: function(){
1123 | process.stdout.write('\033[?25h');
1124 | },
1125 |
1126 | deleteLine: function(){
1127 | process.stdout.write('\033[2K');
1128 | },
1129 |
1130 | beginningOfLine: function(){
1131 | process.stdout.write('\033[0G');
1132 | },
1133 |
1134 | CR: function(){
1135 | exports.cursor.deleteLine();
1136 | exports.cursor.beginningOfLine();
1137 | }
1138 | };
1139 |
1140 | /**
1141 | * A test is considered slow if it
1142 | * exceeds the following value in milliseconds.
1143 | */
1144 |
1145 | exports.slow = 75;
1146 |
1147 | /**
1148 | * Outut the given `failures` as a list.
1149 | *
1150 | * @param {Array} failures
1151 | * @api public
1152 | */
1153 |
1154 | exports.list = function(failures){
1155 | console.error();
1156 | failures.forEach(function(test, i){
1157 | // format
1158 | var fmt = color('error title', ' %s) %s:\n')
1159 | + color('error message', ' %s')
1160 | + color('error stack', '\n%s\n');
1161 |
1162 | // msg
1163 | var err = test.err
1164 | , message = err.message || ''
1165 | , stack = err.stack || message
1166 | , index = stack.indexOf(message) + message.length
1167 | , msg = stack.slice(0, index)
1168 | , actual = err.actual
1169 | , expected = err.expected;
1170 |
1171 | // actual / expected diff
1172 | if ('string' == typeof actual && 'string' == typeof expected) {
1173 | var len = Math.max(actual.length, expected.length);
1174 |
1175 | if (len < 20) msg = errorDiff(err, 'Chars');
1176 | else msg = errorDiff(err, 'Words');
1177 |
1178 | // linenos
1179 | var lines = msg.split('\n');
1180 | if (lines.length > 4) {
1181 | var width = String(lines.length).length;
1182 | msg = lines.map(function(str, i){
1183 | return pad(++i, width) + ' |' + ' ' + str;
1184 | }).join('\n');
1185 | }
1186 |
1187 | // legend
1188 | msg = '\n'
1189 | + color('diff removed', 'actual')
1190 | + ' '
1191 | + color('diff added', 'expected')
1192 | + '\n\n'
1193 | + msg
1194 | + '\n';
1195 |
1196 | // indent
1197 | msg = msg.replace(/^/gm, ' ');
1198 |
1199 | fmt = color('error title', ' %s) %s:\n%s')
1200 | + color('error stack', '\n%s\n');
1201 | }
1202 |
1203 | // indent stack trace without msg
1204 | stack = stack.slice(index ? index + 1 : index)
1205 | .replace(/^/gm, ' ');
1206 |
1207 | console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
1208 | });
1209 | };
1210 |
1211 | /**
1212 | * Initialize a new `Base` reporter.
1213 | *
1214 | * All other reporters generally
1215 | * inherit from this reporter, providing
1216 | * stats such as test duration, number
1217 | * of tests passed / failed etc.
1218 | *
1219 | * @param {Runner} runner
1220 | * @api public
1221 | */
1222 |
1223 | function Base(runner) {
1224 | var self = this
1225 | , stats = this.stats = { suites: 0, tests: 0, passes: 0, failures: 0 }
1226 | , failures = this.failures = [];
1227 |
1228 | if (!runner) return;
1229 | this.runner = runner;
1230 |
1231 | runner.on('start', function(){
1232 | stats.start = new Date;
1233 | });
1234 |
1235 | runner.on('suite', function(suite){
1236 | stats.suites = stats.suites || 0;
1237 | suite.root || stats.suites++;
1238 | });
1239 |
1240 | runner.on('test end', function(test){
1241 | stats.tests = stats.tests || 0;
1242 | stats.tests++;
1243 | });
1244 |
1245 | runner.on('pass', function(test){
1246 | stats.passes = stats.passes || 0;
1247 |
1248 | var medium = exports.slow / 2;
1249 | test.speed = test.duration > exports.slow
1250 | ? 'slow'
1251 | : test.duration > medium
1252 | ? 'medium'
1253 | : 'fast';
1254 |
1255 | stats.passes++;
1256 | });
1257 |
1258 | runner.on('fail', function(test, err){
1259 | stats.failures = stats.failures || 0;
1260 | stats.failures++;
1261 | test.err = err;
1262 | failures.push(test);
1263 | });
1264 |
1265 | runner.on('end', function(){
1266 | stats.end = new Date;
1267 | stats.duration = new Date - stats.start;
1268 | });
1269 | }
1270 |
1271 | /**
1272 | * Output common epilogue used by many of
1273 | * the bundled reporters.
1274 | *
1275 | * @api public
1276 | */
1277 |
1278 | Base.prototype.epilogue = function(){
1279 | var stats = this.stats
1280 | , fmt;
1281 |
1282 | console.log();
1283 |
1284 | // failure
1285 | if (stats.failures) {
1286 | fmt = color('bright fail', ' ✖')
1287 | + color('fail', ' %d of %d tests failed')
1288 | + color('light', ':')
1289 |
1290 | console.error(fmt, stats.failures, this.runner.total);
1291 | Base.list(this.failures);
1292 | console.error();
1293 | return;
1294 | }
1295 |
1296 | // pass
1297 | fmt = color('bright pass', ' ✔')
1298 | + color('green', ' %d tests complete')
1299 | + color('light', ' (%dms)');
1300 |
1301 | console.log(fmt, stats.tests || 0, stats.duration);
1302 | console.log();
1303 | };
1304 |
1305 | /**
1306 | * Pad the given `str` to `len`.
1307 | *
1308 | * @param {String} str
1309 | * @param {String} len
1310 | * @return {String}
1311 | * @api private
1312 | */
1313 |
1314 | function pad(str, len) {
1315 | str = String(str);
1316 | return Array(len - str.length + 1).join(' ') + str;
1317 | }
1318 |
1319 | /**
1320 | * Return a character diff for `err`.
1321 | *
1322 | * @param {Error} err
1323 | * @return {String}
1324 | * @api private
1325 | */
1326 |
1327 | function errorDiff(err, type) {
1328 | return diff['diff' + type](err.actual, err.expected).map(function(str){
1329 | if (str.added) return colorLines('diff added', str.value);
1330 | if (str.removed) return colorLines('diff removed', str.value);
1331 | return str.value;
1332 | }).join('');
1333 | }
1334 |
1335 | /**
1336 | * Color lines for `str`, using the color `name`.
1337 | *
1338 | * @param {String} name
1339 | * @param {String} str
1340 | * @return {String}
1341 | * @api private
1342 | */
1343 |
1344 | function colorLines(name, str) {
1345 | return str.split('\n').map(function(str){
1346 | return color(name, str);
1347 | }).join('\n');
1348 | }
1349 |
1350 | }); // module: reporters/base.js
1351 |
1352 | require.register("reporters/doc.js", function(module, exports, require){
1353 |
1354 | /**
1355 | * Module dependencies.
1356 | */
1357 |
1358 | var Base = require('./base')
1359 | , utils = require('../utils');
1360 |
1361 | /**
1362 | * Expose `Doc`.
1363 | */
1364 |
1365 | exports = module.exports = Doc;
1366 |
1367 | /**
1368 | * Initialize a new `Doc` reporter.
1369 | *
1370 | * @param {Runner} runner
1371 | * @api public
1372 | */
1373 |
1374 | function Doc(runner) {
1375 | Base.call(this, runner);
1376 |
1377 | var self = this
1378 | , stats = this.stats
1379 | , total = runner.total
1380 | , indents = 2;
1381 |
1382 | function indent() {
1383 | return Array(indents).join(' ');
1384 | }
1385 |
1386 | runner.on('suite', function(suite){
1387 | if (suite.root) return;
1388 | ++indents;
1389 | console.log('%s', indent());
1390 | ++indents;
1391 | console.log('%s%s ', indent(), suite.title);
1392 | console.log('%s', indent());
1393 | });
1394 |
1395 | runner.on('suite end', function(suite){
1396 | if (suite.root) return;
1397 | console.log('%s ', indent());
1398 | --indents;
1399 | console.log('%s ', indent());
1400 | --indents;
1401 | });
1402 |
1403 | runner.on('pass', function(test){
1404 | console.log('%s %s ', indent(), test.title);
1405 | var code = utils.escape(clean(test.fn.toString()));
1406 | console.log('%s %s ', indent(), code);
1407 | });
1408 | }
1409 |
1410 | /**
1411 | * Strip the function definition from `str`,
1412 | * and re-indent for pre whitespace.
1413 | */
1414 |
1415 | function clean(str) {
1416 | str = str
1417 | .replace(/^function *\(.*\) *{/, '')
1418 | .replace(/\s+\}$/, '');
1419 |
1420 | var spaces = str.match(/^\n?( *)/)[1].length
1421 | , re = new RegExp('^ {' + spaces + '}', 'gm');
1422 |
1423 | str = str.replace(re, '');
1424 |
1425 | return str;
1426 | }
1427 | }); // module: reporters/doc.js
1428 |
1429 | require.register("reporters/dot.js", function(module, exports, require){
1430 |
1431 | /**
1432 | * Module dependencies.
1433 | */
1434 |
1435 | var Base = require('./base')
1436 | , color = Base.color;
1437 |
1438 | /**
1439 | * Expose `Dot`.
1440 | */
1441 |
1442 | exports = module.exports = Dot;
1443 |
1444 | /**
1445 | * Initialize a new `Dot` matrix test reporter.
1446 | *
1447 | * @param {Runner} runner
1448 | * @api public
1449 | */
1450 |
1451 | function Dot(runner) {
1452 | Base.call(this, runner);
1453 |
1454 | var self = this
1455 | , stats = this.stats
1456 | , width = Base.window.width * .75 | 0
1457 | , n = 0;
1458 |
1459 | runner.on('start', function(){
1460 | process.stdout.write('\n ');
1461 | });
1462 |
1463 | runner.on('pending', function(test){
1464 | process.stdout.write(color('pending', '.'));
1465 | });
1466 |
1467 | runner.on('pass', function(test){
1468 | if (++n % width == 0) process.stdout.write('\n ');
1469 | if ('slow' == test.speed) {
1470 | process.stdout.write(color('bright yellow', '.'));
1471 | } else {
1472 | process.stdout.write(color(test.speed, '.'));
1473 | }
1474 | });
1475 |
1476 | runner.on('fail', function(test, err){
1477 | if (++n % width == 0) process.stdout.write('\n ');
1478 | process.stdout.write(color('fail', '.'));
1479 | });
1480 |
1481 | runner.on('end', function(){
1482 | console.log();
1483 | self.epilogue();
1484 | });
1485 | }
1486 |
1487 | /**
1488 | * Inherit from `Base.prototype`.
1489 | */
1490 |
1491 | Dot.prototype = new Base;
1492 | Dot.prototype.constructor = Dot;
1493 |
1494 | }); // module: reporters/dot.js
1495 |
1496 | require.register("reporters/html-cov.js", function(module, exports, require){
1497 |
1498 | /**
1499 | * Module dependencies.
1500 | */
1501 |
1502 | var JSONCov = require('./json-cov')
1503 | , fs = require('browser/fs');
1504 |
1505 | /**
1506 | * Expose `HTMLCov`.
1507 | */
1508 |
1509 | exports = module.exports = HTMLCov;
1510 |
1511 | /**
1512 | * Initialize a new `JsCoverage` reporter.
1513 | *
1514 | * @param {Runner} runner
1515 | * @api public
1516 | */
1517 |
1518 | function HTMLCov(runner) {
1519 | var jade = require('jade')
1520 | , file = __dirname + '/templates/coverage.jade'
1521 | , str = fs.readFileSync(file, 'utf8')
1522 | , fn = jade.compile(str, { filename: file })
1523 | , self = this;
1524 |
1525 | JSONCov.call(this, runner, false);
1526 |
1527 | runner.on('end', function(){
1528 | process.stdout.write(fn({
1529 | cov: self.cov
1530 | , coverageClass: coverageClass
1531 | }));
1532 | });
1533 | }
1534 |
1535 | function coverageClass(n) {
1536 | if (n >= 75) return 'high';
1537 | if (n >= 50) return 'medium';
1538 | if (n >= 25) return 'low';
1539 | return 'terrible';
1540 | }
1541 | }); // module: reporters/html-cov.js
1542 |
1543 | require.register("reporters/html.js", function(module, exports, require){
1544 |
1545 | /**
1546 | * Module dependencies.
1547 | */
1548 |
1549 | var Base = require('./base')
1550 | , utils = require('../utils')
1551 | , Progress = require('../browser/progress')
1552 | , escape = utils.escape;
1553 |
1554 | /**
1555 | * Expose `Doc`.
1556 | */
1557 |
1558 | exports = module.exports = HTML;
1559 |
1560 | /**
1561 | * Stats template.
1562 | */
1563 |
1564 | var statsTemplate = ''
1565 | + ' '
1566 | + 'passes: 0 '
1567 | + 'failures: 0 '
1568 | + 'duration: 0 s '
1569 | + ' ';
1570 |
1571 | /**
1572 | * Initialize a new `Doc` reporter.
1573 | *
1574 | * @param {Runner} runner
1575 | * @api public
1576 | */
1577 |
1578 | function HTML(runner) {
1579 | Base.call(this, runner);
1580 |
1581 | var self = this
1582 | , stats = this.stats
1583 | , total = runner.total
1584 | , root = document.getElementById('mocha')
1585 | , stat = fragment(statsTemplate)
1586 | , items = stat.getElementsByTagName('li')
1587 | , passes = items[1].getElementsByTagName('em')[0]
1588 | , failures = items[2].getElementsByTagName('em')[0]
1589 | , duration = items[3].getElementsByTagName('em')[0]
1590 | , canvas = stat.getElementsByTagName('canvas')[0]
1591 | , stack = [root]
1592 | , progress
1593 | , ctx
1594 |
1595 | if (canvas.getContext) {
1596 | ctx = canvas.getContext('2d');
1597 | progress = new Progress;
1598 | }
1599 |
1600 | if (!root) return error('#mocha div missing, add it to your document');
1601 |
1602 | root.appendChild(stat);
1603 |
1604 | if (progress) progress.size(40);
1605 |
1606 | runner.on('suite', function(suite){
1607 | if (suite.root) return;
1608 |
1609 | // suite
1610 | var el = fragment('
%s ', suite.title);
1611 |
1612 | // container
1613 | stack[0].appendChild(el);
1614 | stack.unshift(document.createElement('div'));
1615 | el.appendChild(stack[0]);
1616 | });
1617 |
1618 | runner.on('suite end', function(suite){
1619 | if (suite.root) return;
1620 | stack.shift();
1621 | });
1622 |
1623 | runner.on('fail', function(test, err){
1624 | if ('hook' == test.type || err.uncaught) runner.emit('test end', test);
1625 | });
1626 |
1627 | runner.on('test end', function(test){
1628 | // TODO: add to stats
1629 | var percent = stats.tests / total * 100 | 0;
1630 | if (progress) progress.update(percent).draw(ctx);
1631 |
1632 | // update stats
1633 | var ms = new Date - stats.start;
1634 | text(passes, stats.passes);
1635 | text(failures, stats.failures);
1636 | text(duration, (ms / 1000).toFixed(2));
1637 |
1638 | // test
1639 | if ('passed' == test.state) {
1640 | var el = fragment('
%e ', test.title);
1641 | } else if (test.pending) {
1642 | var el = fragment('
%e ', test.title);
1643 | } else {
1644 | var el = fragment('
%e ', test.title);
1645 | var str = test.err.stack || test.err.toString();
1646 |
1647 | // FF / Opera do not add the message
1648 | if (!~str.indexOf(test.err.message)) {
1649 | str = test.err.message + '\n' + str;
1650 | }
1651 |
1652 | // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
1653 | // check for the result of the stringifying.
1654 | if ('[object Error]' == str) str = test.err.message;
1655 |
1656 | // Safari doesn't give you a stack. Let's at least provide a source line.
1657 | if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
1658 | str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")";
1659 | }
1660 |
1661 | el.appendChild(fragment('%e ', str));
1662 | }
1663 |
1664 | // toggle code
1665 | var h2 = el.getElementsByTagName('h2')[0];
1666 |
1667 | on(h2, 'click', function(){
1668 | pre.style.display = 'none' == pre.style.display
1669 | ? 'block'
1670 | : 'none';
1671 | });
1672 |
1673 | // code
1674 | // TODO: defer
1675 | if (!test.pending) {
1676 | var pre = fragment('%e ', clean(test.fn.toString()));
1677 | el.appendChild(pre);
1678 | pre.style.display = 'none';
1679 | }
1680 |
1681 | stack[0].appendChild(el);
1682 | });
1683 | }
1684 |
1685 | /**
1686 | * Display error `msg`.
1687 | */
1688 |
1689 | function error(msg) {
1690 | document.body.appendChild(fragment('%s
', msg));
1691 | }
1692 |
1693 | /**
1694 | * Return a DOM fragment from `html`.
1695 | */
1696 |
1697 | function fragment(html) {
1698 | var args = arguments
1699 | , div = document.createElement('div')
1700 | , i = 1;
1701 |
1702 | div.innerHTML = html.replace(/%([se])/g, function(_, type){
1703 | switch (type) {
1704 | case 's': return String(args[i++]);
1705 | case 'e': return escape(args[i++]);
1706 | }
1707 | });
1708 |
1709 | return div.firstChild;
1710 | }
1711 |
1712 | /**
1713 | * Set `el` text to `str`.
1714 | */
1715 |
1716 | function text(el, str) {
1717 | if (el.textContent) {
1718 | el.textContent = str;
1719 | } else {
1720 | el.innerText = str;
1721 | }
1722 | }
1723 |
1724 | /**
1725 | * Listen on `event` with callback `fn`.
1726 | */
1727 |
1728 | function on(el, event, fn) {
1729 | if (el.addEventListener) {
1730 | el.addEventListener(event, fn, false);
1731 | } else {
1732 | el.attachEvent('on' + event, fn);
1733 | }
1734 | }
1735 |
1736 | /**
1737 | * Strip the function definition from `str`,
1738 | * and re-indent for pre whitespace.
1739 | */
1740 |
1741 | function clean(str) {
1742 | str = str
1743 | .replace(/^function *\(.*\) *{/, '')
1744 | .replace(/\s+\}$/, '');
1745 |
1746 | var spaces = str.match(/^\n?( *)/)[1].length
1747 | , re = new RegExp('^ {' + spaces + '}', 'gm');
1748 |
1749 | str = str
1750 | .replace(re, '')
1751 | .replace(/^\s+/, '');
1752 |
1753 | return str;
1754 | }
1755 |
1756 | }); // module: reporters/html.js
1757 |
1758 | require.register("reporters/index.js", function(module, exports, require){
1759 |
1760 | exports.Base = require('./base');
1761 | exports.Dot = require('./dot');
1762 | exports.Doc = require('./doc');
1763 | exports.TAP = require('./tap');
1764 | exports.JSON = require('./json');
1765 | exports.HTML = require('./html');
1766 | exports.List = require('./list');
1767 | exports.Min = require('./min');
1768 | exports.Spec = require('./spec');
1769 | exports.Progress = require('./progress');
1770 | exports.Landing = require('./landing');
1771 | exports.JSONCov = require('./json-cov');
1772 | exports.HTMLCov = require('./html-cov');
1773 | exports.JSONStream = require('./json-stream');
1774 | exports.XUnit = require('./xunit')
1775 | exports.Teamcity = require('./teamcity')
1776 |
1777 | }); // module: reporters/index.js
1778 |
1779 | require.register("reporters/json-cov.js", function(module, exports, require){
1780 |
1781 | /**
1782 | * Module dependencies.
1783 | */
1784 |
1785 | var Base = require('./base');
1786 |
1787 | /**
1788 | * Expose `JSONCov`.
1789 | */
1790 |
1791 | exports = module.exports = JSONCov;
1792 |
1793 | /**
1794 | * Initialize a new `JsCoverage` reporter.
1795 | *
1796 | * @param {Runner} runner
1797 | * @param {Boolean} output
1798 | * @api public
1799 | */
1800 |
1801 | function JSONCov(runner, output) {
1802 | var self = this
1803 | , output = 1 == arguments.length ? true : output;
1804 |
1805 | Base.call(this, runner);
1806 |
1807 | var tests = []
1808 | , failures = []
1809 | , passes = [];
1810 |
1811 | runner.on('test end', function(test){
1812 | tests.push(test);
1813 | });
1814 |
1815 | runner.on('pass', function(test){
1816 | passes.push(test);
1817 | });
1818 |
1819 | runner.on('fail', function(test){
1820 | failures.push(test);
1821 | });
1822 |
1823 | runner.on('end', function(){
1824 | var cov = global._$jscoverage || {};
1825 | var result = self.cov = map(cov);
1826 | result.stats = self.stats;
1827 | result.tests = tests.map(clean);
1828 | result.failures = failures.map(clean);
1829 | result.passes = passes.map(clean);
1830 | if (!output) return;
1831 | process.stdout.write(JSON.stringify(result, null, 2 ));
1832 | });
1833 | }
1834 |
1835 | /**
1836 | * Map jscoverage data to a JSON structure
1837 | * suitable for reporting.
1838 | *
1839 | * @param {Object} cov
1840 | * @return {Object}
1841 | * @api private
1842 | */
1843 |
1844 | function map(cov) {
1845 | var ret = {
1846 | instrumentation: 'node-jscoverage'
1847 | , sloc: 0
1848 | , hits: 0
1849 | , misses: 0
1850 | , coverage: 0
1851 | , files: []
1852 | };
1853 |
1854 | for (var filename in cov) {
1855 | var data = coverage(filename, cov[filename]);
1856 | ret.files.push(data);
1857 | ret.hits += data.hits;
1858 | ret.misses += data.misses;
1859 | ret.sloc += data.sloc;
1860 | }
1861 |
1862 | if (ret.sloc > 0) {
1863 | ret.coverage = (ret.hits / ret.sloc) * 100;
1864 | }
1865 |
1866 | return ret;
1867 | };
1868 |
1869 | /**
1870 | * Map jscoverage data for a single source file
1871 | * to a JSON structure suitable for reporting.
1872 | *
1873 | * @param {String} filename name of the source file
1874 | * @param {Object} data jscoverage coverage data
1875 | * @return {Object}
1876 | * @api private
1877 | */
1878 |
1879 | function coverage(filename, data) {
1880 | var ret = {
1881 | filename: filename,
1882 | coverage: 0,
1883 | hits: 0,
1884 | misses: 0,
1885 | sloc: 0,
1886 | source: {}
1887 | };
1888 |
1889 | data.source.forEach(function(line, num){
1890 | num++;
1891 |
1892 | if (data[num] === 0) {
1893 | ret.misses++;
1894 | ret.sloc++;
1895 | } else if (data[num] !== undefined) {
1896 | ret.hits++;
1897 | ret.sloc++;
1898 | }
1899 |
1900 | ret.source[num] = {
1901 | source: line
1902 | , coverage: data[num] === undefined
1903 | ? ''
1904 | : data[num]
1905 | };
1906 | });
1907 |
1908 | ret.coverage = ret.hits / ret.sloc * 100;
1909 |
1910 | return ret;
1911 | }
1912 |
1913 | /**
1914 | * Return a plain-object representation of `test`
1915 | * free of cyclic properties etc.
1916 | *
1917 | * @param {Object} test
1918 | * @return {Object}
1919 | * @api private
1920 | */
1921 |
1922 | function clean(test) {
1923 | return {
1924 | title: test.title
1925 | , fullTitle: test.fullTitle()
1926 | , duration: test.duration
1927 | }
1928 | }
1929 |
1930 | }); // module: reporters/json-cov.js
1931 |
1932 | require.register("reporters/json-stream.js", function(module, exports, require){
1933 |
1934 | /**
1935 | * Module dependencies.
1936 | */
1937 |
1938 | var Base = require('./base')
1939 | , color = Base.color;
1940 |
1941 | /**
1942 | * Expose `List`.
1943 | */
1944 |
1945 | exports = module.exports = List;
1946 |
1947 | /**
1948 | * Initialize a new `List` test reporter.
1949 | *
1950 | * @param {Runner} runner
1951 | * @api public
1952 | */
1953 |
1954 | function List(runner) {
1955 | Base.call(this, runner);
1956 |
1957 | var self = this
1958 | , stats = this.stats
1959 | , total = runner.total;
1960 |
1961 | runner.on('start', function(){
1962 | console.log(JSON.stringify(['start', { total: total }]));
1963 | });
1964 |
1965 | runner.on('pass', function(test){
1966 | console.log(JSON.stringify(['pass', clean(test)]));
1967 | });
1968 |
1969 | runner.on('fail', function(test, err){
1970 | console.log(JSON.stringify(['fail', clean(test)]));
1971 | });
1972 |
1973 | runner.on('end', function(){
1974 | process.stdout.write(JSON.stringify(['end', self.stats]));
1975 | });
1976 | }
1977 |
1978 | /**
1979 | * Return a plain-object representation of `test`
1980 | * free of cyclic properties etc.
1981 | *
1982 | * @param {Object} test
1983 | * @return {Object}
1984 | * @api private
1985 | */
1986 |
1987 | function clean(test) {
1988 | return {
1989 | title: test.title
1990 | , fullTitle: test.fullTitle()
1991 | , duration: test.duration
1992 | }
1993 | }
1994 | }); // module: reporters/json-stream.js
1995 |
1996 | require.register("reporters/json.js", function(module, exports, require){
1997 |
1998 | /**
1999 | * Module dependencies.
2000 | */
2001 |
2002 | var Base = require('./base')
2003 | , cursor = Base.cursor
2004 | , color = Base.color;
2005 |
2006 | /**
2007 | * Expose `JSON`.
2008 | */
2009 |
2010 | exports = module.exports = JSONReporter;
2011 |
2012 | /**
2013 | * Initialize a new `JSON` reporter.
2014 | *
2015 | * @param {Runner} runner
2016 | * @api public
2017 | */
2018 |
2019 | function JSONReporter(runner) {
2020 | var self = this;
2021 | Base.call(this, runner);
2022 |
2023 | var tests = []
2024 | , failures = []
2025 | , passes = [];
2026 |
2027 | runner.on('test end', function(test){
2028 | tests.push(test);
2029 | });
2030 |
2031 | runner.on('pass', function(test){
2032 | passes.push(test);
2033 | });
2034 |
2035 | runner.on('fail', function(test){
2036 | failures.push(test);
2037 | });
2038 |
2039 | runner.on('end', function(){
2040 | var obj = {
2041 | stats: self.stats
2042 | , tests: tests.map(clean)
2043 | , failures: failures.map(clean)
2044 | , passes: passes.map(clean)
2045 | };
2046 |
2047 | process.stdout.write(JSON.stringify(obj, null, 2));
2048 | });
2049 | }
2050 |
2051 | /**
2052 | * Return a plain-object representation of `test`
2053 | * free of cyclic properties etc.
2054 | *
2055 | * @param {Object} test
2056 | * @return {Object}
2057 | * @api private
2058 | */
2059 |
2060 | function clean(test) {
2061 | return {
2062 | title: test.title
2063 | , fullTitle: test.fullTitle()
2064 | , duration: test.duration
2065 | }
2066 | }
2067 | }); // module: reporters/json.js
2068 |
2069 | require.register("reporters/landing.js", function(module, exports, require){
2070 |
2071 | /**
2072 | * Module dependencies.
2073 | */
2074 |
2075 | var Base = require('./base')
2076 | , cursor = Base.cursor
2077 | , color = Base.color;
2078 |
2079 | /**
2080 | * Expose `Landing`.
2081 | */
2082 |
2083 | exports = module.exports = Landing;
2084 |
2085 | /**
2086 | * Airplane color.
2087 | */
2088 |
2089 | Base.colors.plane = 0;
2090 |
2091 | /**
2092 | * Airplane crash color.
2093 | */
2094 |
2095 | Base.colors['plane crash'] = 31;
2096 |
2097 | /**
2098 | * Runway color.
2099 | */
2100 |
2101 | Base.colors.runway = 90;
2102 |
2103 | /**
2104 | * Initialize a new `Landing` reporter.
2105 | *
2106 | * @param {Runner} runner
2107 | * @api public
2108 | */
2109 |
2110 | function Landing(runner) {
2111 | Base.call(this, runner);
2112 |
2113 | var self = this
2114 | , stats = this.stats
2115 | , width = Base.window.width * .75 | 0
2116 | , total = runner.total
2117 | , stream = process.stdout
2118 | , plane = color('plane', '✈')
2119 | , crashed = -1
2120 | , n = 0;
2121 |
2122 | function runway() {
2123 | var buf = Array(width).join('-');
2124 | return ' ' + color('runway', buf);
2125 | }
2126 |
2127 | runner.on('start', function(){
2128 | stream.write('\n ');
2129 | cursor.hide();
2130 | });
2131 |
2132 | runner.on('test end', function(test){
2133 | // check if the plane crashed
2134 | var col = -1 == crashed
2135 | ? width * ++n / total | 0
2136 | : crashed;
2137 |
2138 | // show the crash
2139 | if ('failed' == test.state) {
2140 | plane = color('plane crash', '✈');
2141 | crashed = col;
2142 | }
2143 |
2144 | // render landing strip
2145 | stream.write('\033[4F\n\n');
2146 | stream.write(runway());
2147 | stream.write('\n ');
2148 | stream.write(color('runway', Array(col).join('⋅')));
2149 | stream.write(plane)
2150 | stream.write(color('runway', Array(width - col).join('⋅') + '\n'));
2151 | stream.write(runway());
2152 | stream.write('\033[0m');
2153 | });
2154 |
2155 | runner.on('end', function(){
2156 | cursor.show();
2157 | console.log();
2158 | self.epilogue();
2159 | });
2160 | }
2161 |
2162 | /**
2163 | * Inherit from `Base.prototype`.
2164 | */
2165 |
2166 | Landing.prototype = new Base;
2167 | Landing.prototype.constructor = Landing;
2168 |
2169 | }); // module: reporters/landing.js
2170 |
2171 | require.register("reporters/list.js", function(module, exports, require){
2172 |
2173 | /**
2174 | * Module dependencies.
2175 | */
2176 |
2177 | var Base = require('./base')
2178 | , cursor = Base.cursor
2179 | , color = Base.color;
2180 |
2181 | /**
2182 | * Expose `List`.
2183 | */
2184 |
2185 | exports = module.exports = List;
2186 |
2187 | /**
2188 | * Initialize a new `List` test reporter.
2189 | *
2190 | * @param {Runner} runner
2191 | * @api public
2192 | */
2193 |
2194 | function List(runner) {
2195 | Base.call(this, runner);
2196 |
2197 | var self = this
2198 | , stats = this.stats
2199 | , n = 0;
2200 |
2201 | runner.on('start', function(){
2202 | console.log();
2203 | });
2204 |
2205 | runner.on('test', function(test){
2206 | process.stdout.write(color('pass', ' ' + test.fullTitle() + ': '));
2207 | });
2208 |
2209 | runner.on('pending', function(test){
2210 | var fmt = color('checkmark', ' -')
2211 | + color('pending', ' %s');
2212 | console.log(fmt, test.fullTitle());
2213 | });
2214 |
2215 | runner.on('pass', function(test){
2216 | var fmt = color('checkmark', ' ✓')
2217 | + color('pass', ' %s: ')
2218 | + color(test.speed, '%dms');
2219 | cursor.CR();
2220 | console.log(fmt, test.fullTitle(), test.duration);
2221 | });
2222 |
2223 | runner.on('fail', function(test, err){
2224 | cursor.CR();
2225 | console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
2226 | });
2227 |
2228 | runner.on('end', self.epilogue.bind(self));
2229 | }
2230 |
2231 | /**
2232 | * Inherit from `Base.prototype`.
2233 | */
2234 |
2235 | List.prototype = new Base;
2236 | List.prototype.constructor = List;
2237 |
2238 |
2239 | }); // module: reporters/list.js
2240 |
2241 | require.register("reporters/markdown.js", function(module, exports, require){
2242 |
2243 | /**
2244 | * Module dependencies.
2245 | */
2246 |
2247 | var Base = require('./base')
2248 | , utils = require('../utils');
2249 |
2250 | /**
2251 | * Expose `Markdown`.
2252 | */
2253 |
2254 | exports = module.exports = Markdown;
2255 |
2256 | /**
2257 | * Initialize a new `Markdown` reporter.
2258 | *
2259 | * @param {Runner} runner
2260 | * @api public
2261 | */
2262 |
2263 | function Markdown(runner) {
2264 | Base.call(this, runner);
2265 |
2266 | var self = this
2267 | , stats = this.stats
2268 | , total = runner.total
2269 | , level = 0
2270 | , buf = '';
2271 |
2272 | function title(str) {
2273 | return Array(level).join('#') + ' ' + str;
2274 | }
2275 |
2276 | function indent() {
2277 | return Array(level).join(' ');
2278 | }
2279 |
2280 | function mapTOC(suite, obj) {
2281 | var ret = obj;
2282 | obj = obj[suite.title] = obj[suite.title] || { suite: suite };
2283 | suite.suites.forEach(function(suite){
2284 | mapTOC(suite, obj);
2285 | });
2286 | return ret;
2287 | }
2288 |
2289 | function stringifyTOC(obj, level) {
2290 | ++level;
2291 | var buf = '';
2292 | var link;
2293 | for (var key in obj) {
2294 | if ('suite' == key) continue;
2295 | if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
2296 | if (key) buf += Array(level).join(' ') + link;
2297 | buf += stringifyTOC(obj[key], level);
2298 | }
2299 | --level;
2300 | return buf;
2301 | }
2302 |
2303 | function generateTOC(suite) {
2304 | var obj = mapTOC(suite, {});
2305 | return stringifyTOC(obj, 0);
2306 | }
2307 |
2308 | generateTOC(runner.suite);
2309 |
2310 | runner.on('suite', function(suite){
2311 | ++level;
2312 | var slug = utils.slug(suite.fullTitle());
2313 | buf += ' ' + '\n';
2314 | buf += title(suite.title) + '\n';
2315 | });
2316 |
2317 | runner.on('suite end', function(suite){
2318 | --level;
2319 | });
2320 |
2321 | runner.on('pass', function(test){
2322 | var code = clean(test.fn.toString());
2323 | buf += test.title + '.\n';
2324 | buf += '\n```js';
2325 | buf += code + '\n';
2326 | buf += '```\n\n';
2327 | });
2328 |
2329 | runner.on('end', function(){
2330 | process.stdout.write('# TOC\n');
2331 | process.stdout.write(generateTOC(runner.suite));
2332 | process.stdout.write(buf);
2333 | });
2334 | }
2335 |
2336 | /**
2337 | * Strip the function definition from `str`,
2338 | * and re-indent for pre whitespace.
2339 | */
2340 |
2341 | function clean(str) {
2342 | str = str
2343 | .replace(/^function *\(.*\) *{/, '')
2344 | .replace(/\s+\}$/, '');
2345 |
2346 | var spaces = str.match(/^\n?( *)/)[1].length
2347 | , re = new RegExp('^ {' + spaces + '}', 'gm');
2348 |
2349 | str = str.replace(re, '');
2350 |
2351 | return str;
2352 | }
2353 | }); // module: reporters/markdown.js
2354 |
2355 | require.register("reporters/min.js", function(module, exports, require){
2356 | /**
2357 | * Module dependencies.
2358 | */
2359 |
2360 | var Base = require('./base');
2361 |
2362 | /**
2363 | * Expose `Min`.
2364 | */
2365 |
2366 | exports = module.exports = Min;
2367 |
2368 | /**
2369 | * Initialize a new `Min` minimal test reporter (best used with --watch).
2370 | *
2371 | * @param {Runner} runner
2372 | * @api public
2373 | */
2374 |
2375 | function Min(runner) {
2376 | Base.call(this, runner);
2377 |
2378 | runner.on('start', function(){
2379 | // clear screen
2380 | process.stdout.write('\033[2J');
2381 | // set cursor position
2382 | process.stdout.write('\033[1;3H');
2383 | });
2384 |
2385 | runner.on('end', this.epilogue.bind(this));
2386 | }
2387 |
2388 | /**
2389 | * Inherit from `Base.prototype`.
2390 | */
2391 |
2392 | Min.prototype = new Base;
2393 | Min.prototype.constructor = Min;
2394 |
2395 | }); // module: reporters/min.js
2396 |
2397 | require.register("reporters/progress.js", function(module, exports, require){
2398 |
2399 | /**
2400 | * Module dependencies.
2401 | */
2402 |
2403 | var Base = require('./base')
2404 | , cursor = Base.cursor
2405 | , color = Base.color;
2406 |
2407 | /**
2408 | * Expose `Progress`.
2409 | */
2410 |
2411 | exports = module.exports = Progress;
2412 |
2413 | /**
2414 | * General progress bar color.
2415 | */
2416 |
2417 | Base.colors.progress = 90;
2418 |
2419 | /**
2420 | * Initialize a new `Progress` bar test reporter.
2421 | *
2422 | * @param {Runner} runner
2423 | * @param {Object} options
2424 | * @api public
2425 | */
2426 |
2427 | function Progress(runner, options) {
2428 | Base.call(this, runner);
2429 |
2430 | var self = this
2431 | , options = options || {}
2432 | , stats = this.stats
2433 | , width = Base.window.width * .50 | 0
2434 | , total = runner.total
2435 | , complete = 0
2436 | , max = Math.max;
2437 |
2438 | // default chars
2439 | options.open = options.open || '[';
2440 | options.complete = options.complete || '▬';
2441 | options.incomplete = options.incomplete || '⋅';
2442 | options.close = options.close || ']';
2443 | options.verbose = false;
2444 |
2445 | // tests started
2446 | runner.on('start', function(){
2447 | console.log();
2448 | cursor.hide();
2449 | });
2450 |
2451 | // tests complete
2452 | runner.on('test end', function(){
2453 | complete++;
2454 | var incomplete = total - complete
2455 | , percent = complete / total
2456 | , n = width * percent | 0
2457 | , i = width - n;
2458 |
2459 | cursor.CR();
2460 | process.stdout.write('\033[J');
2461 | process.stdout.write(color('progress', ' ' + options.open));
2462 | process.stdout.write(Array(n).join(options.complete));
2463 | process.stdout.write(Array(i).join(options.incomplete));
2464 | process.stdout.write(color('progress', options.close));
2465 | if (options.verbose) {
2466 | process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
2467 | }
2468 | });
2469 |
2470 | // tests are complete, output some stats
2471 | // and the failures if any
2472 | runner.on('end', function(){
2473 | cursor.show();
2474 | console.log();
2475 | self.epilogue();
2476 | });
2477 | }
2478 |
2479 | /**
2480 | * Inherit from `Base.prototype`.
2481 | */
2482 |
2483 | Progress.prototype = new Base;
2484 | Progress.prototype.constructor = Progress;
2485 |
2486 |
2487 | }); // module: reporters/progress.js
2488 |
2489 | require.register("reporters/spec.js", function(module, exports, require){
2490 |
2491 | /**
2492 | * Module dependencies.
2493 | */
2494 |
2495 | var Base = require('./base')
2496 | , cursor = Base.cursor
2497 | , color = Base.color;
2498 |
2499 | /**
2500 | * Expose `Spec`.
2501 | */
2502 |
2503 | exports = module.exports = Spec;
2504 |
2505 | /**
2506 | * Initialize a new `Spec` test reporter.
2507 | *
2508 | * @param {Runner} runner
2509 | * @api public
2510 | */
2511 |
2512 | function Spec(runner) {
2513 | Base.call(this, runner);
2514 |
2515 | var self = this
2516 | , stats = this.stats
2517 | , indents = 0
2518 | , n = 0;
2519 |
2520 | function indent() {
2521 | return Array(indents).join(' ')
2522 | }
2523 |
2524 | runner.on('start', function(){
2525 | console.log();
2526 | });
2527 |
2528 | runner.on('suite', function(suite){
2529 | ++indents;
2530 | console.log(color('suite', '%s%s'), indent(), suite.title);
2531 | });
2532 |
2533 | runner.on('suite end', function(suite){
2534 | --indents;
2535 | if (1 == indents) console.log();
2536 | });
2537 |
2538 | runner.on('test', function(test){
2539 | process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': '));
2540 | });
2541 |
2542 | runner.on('pending', function(test){
2543 | var fmt = indent() + color('pending', ' - %s');
2544 | console.log(fmt, test.title);
2545 | });
2546 |
2547 | runner.on('pass', function(test){
2548 | if ('fast' == test.speed) {
2549 | var fmt = indent()
2550 | + color('checkmark', ' ✓')
2551 | + color('pass', ' %s ');
2552 | cursor.CR();
2553 | console.log(fmt, test.title);
2554 | } else {
2555 | var fmt = indent()
2556 | + color('checkmark', ' ✓')
2557 | + color('pass', ' %s ')
2558 | + color(test.speed, '(%dms)');
2559 | cursor.CR();
2560 | console.log(fmt, test.title, test.duration);
2561 | }
2562 | });
2563 |
2564 | runner.on('fail', function(test, err){
2565 | cursor.CR();
2566 | console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
2567 | });
2568 |
2569 | runner.on('end', self.epilogue.bind(self));
2570 | }
2571 |
2572 | /**
2573 | * Inherit from `Base.prototype`.
2574 | */
2575 |
2576 | Spec.prototype = new Base;
2577 | Spec.prototype.constructor = Spec;
2578 |
2579 |
2580 | }); // module: reporters/spec.js
2581 |
2582 | require.register("reporters/tap.js", function(module, exports, require){
2583 |
2584 | /**
2585 | * Module dependencies.
2586 | */
2587 |
2588 | var Base = require('./base')
2589 | , cursor = Base.cursor
2590 | , color = Base.color;
2591 |
2592 | /**
2593 | * Expose `TAP`.
2594 | */
2595 |
2596 | exports = module.exports = TAP;
2597 |
2598 | /**
2599 | * Initialize a new `TAP` reporter.
2600 | *
2601 | * @param {Runner} runner
2602 | * @api public
2603 | */
2604 |
2605 | function TAP(runner) {
2606 | Base.call(this, runner);
2607 |
2608 | var self = this
2609 | , stats = this.stats
2610 | , total = runner.total
2611 | , n = 1;
2612 |
2613 | runner.on('start', function(){
2614 | console.log('%d..%d', 1, total);
2615 | });
2616 |
2617 | runner.on('test end', function(){
2618 | ++n;
2619 | });
2620 |
2621 | runner.on('pending', function(test){
2622 | console.log('ok %d %s # SKIP -', n, title(test));
2623 | });
2624 |
2625 | runner.on('pass', function(test){
2626 | console.log('ok %d %s', n, title(test));
2627 | });
2628 |
2629 | runner.on('fail', function(test, err){
2630 | console.log('not ok %d %s', n, title(test));
2631 | console.log(err.stack.replace(/^/gm, ' '));
2632 | });
2633 | }
2634 |
2635 | /**
2636 | * Return a TAP-safe title of `test`
2637 | *
2638 | * @param {Object} test
2639 | * @return {String}
2640 | * @api private
2641 | */
2642 |
2643 | function title(test) {
2644 | return test.fullTitle().replace(/#/g, '');
2645 | }
2646 |
2647 | }); // module: reporters/tap.js
2648 |
2649 | require.register("reporters/teamcity.js", function(module, exports, require){
2650 |
2651 | /**
2652 | * Module dependencies.
2653 | */
2654 |
2655 | var Base = require('./base');
2656 |
2657 | /**
2658 | * Expose `Teamcity`.
2659 | */
2660 |
2661 | exports = module.exports = Teamcity;
2662 |
2663 | /**
2664 | * Initialize a new `Teamcity` reporter.
2665 | *
2666 | * @param {Runner} runner
2667 | * @api public
2668 | */
2669 |
2670 | function Teamcity(runner) {
2671 | Base.call(this, runner);
2672 | var stats = this.stats;
2673 |
2674 | runner.on('start', function() {
2675 | console.log("##teamcity[testSuiteStarted name='mocha.suite']");
2676 | });
2677 |
2678 | runner.on('test', function(test) {
2679 | console.log("##teamcity[testStarted name='%s']", escape(test.fullTitle()));
2680 | });
2681 |
2682 | runner.on('fail', function(test, err) {
2683 | console.log("##teamcity[testFailed name='%s' message='%s']", escape(test.fullTitle()), escape(err.message));
2684 | });
2685 |
2686 | runner.on('pending', function(test) {
2687 | console.log("##teamcity[testIgnored name='%s' message='pending']", escape(test.fullTitle()));
2688 | });
2689 |
2690 | runner.on('test end', function(test) {
2691 | console.log("##teamcity[testFinished name='%s' duration='%s']", escape(test.fullTitle()), test.duration);
2692 | });
2693 |
2694 | runner.on('end', function() {
2695 | console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='%s']", stats.duration);
2696 | });
2697 | }
2698 |
2699 | /**
2700 | * Escape the given `str`.
2701 | */
2702 |
2703 | function escape(str) {
2704 | return str.replace(/'/g, "|'");
2705 | }
2706 | }); // module: reporters/teamcity.js
2707 |
2708 | require.register("reporters/xunit.js", function(module, exports, require){
2709 |
2710 | /**
2711 | * Module dependencies.
2712 | */
2713 |
2714 | var Base = require('./base')
2715 | , utils = require('../utils')
2716 | , escape = utils.escape;
2717 |
2718 | /**
2719 | * Expose `XUnit`.
2720 | */
2721 |
2722 | exports = module.exports = XUnit;
2723 |
2724 | /**
2725 | * Initialize a new `XUnit` reporter.
2726 | *
2727 | * @param {Runner} runner
2728 | * @api public
2729 | */
2730 |
2731 | function XUnit(runner) {
2732 | Base.call(this, runner);
2733 | var stats = this.stats
2734 | , tests = []
2735 | , self = this;
2736 |
2737 | runner.on('test end', function(test){
2738 | tests.push(test);
2739 | });
2740 |
2741 | runner.on('end', function(){
2742 | console.log(tag('testsuite', {
2743 | name: 'Mocha Tests'
2744 | , tests: stats.tests
2745 | , failures: stats.failures
2746 | , errors: stats.failures
2747 | , skip: stats.tests - stats.failures - stats.passes
2748 | , timestamp: (new Date).toUTCString()
2749 | , time: stats.duration / 1000
2750 | }, false));
2751 |
2752 | tests.forEach(test);
2753 | console.log('');
2754 | });
2755 | }
2756 |
2757 | /**
2758 | * Inherit from `Base.prototype`.
2759 | */
2760 |
2761 | XUnit.prototype = new Base;
2762 | XUnit.prototype.constructor = XUnit;
2763 |
2764 |
2765 | /**
2766 | * Output tag for the given `test.`
2767 | */
2768 |
2769 | function test(test) {
2770 | var attrs = {
2771 | classname: test.parent.fullTitle()
2772 | , name: test.title
2773 | , time: test.duration / 1000
2774 | };
2775 |
2776 | if ('failed' == test.state) {
2777 | var err = test.err;
2778 | attrs.message = escape(err.message);
2779 | console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
2780 | } else if (test.pending) {
2781 | console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
2782 | } else {
2783 | console.log(tag('testcase', attrs, true) );
2784 | }
2785 | }
2786 |
2787 | /**
2788 | * HTML tag helper.
2789 | */
2790 |
2791 | function tag(name, attrs, close, content) {
2792 | var end = close ? '/>' : '>'
2793 | , pairs = []
2794 | , tag;
2795 |
2796 | for (var key in attrs) {
2797 | pairs.push(key + '="' + escape(attrs[key]) + '"');
2798 | }
2799 |
2800 | tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
2801 | if (content) tag += content + '' + name + end;
2802 | return tag;
2803 | }
2804 |
2805 | /**
2806 | * Return cdata escaped CDATA `str`.
2807 | */
2808 |
2809 | function cdata(str) {
2810 | return '';
2811 | }
2812 |
2813 | }); // module: reporters/xunit.js
2814 |
2815 | require.register("runnable.js", function(module, exports, require){
2816 |
2817 | /**
2818 | * Module dependencies.
2819 | */
2820 |
2821 | var EventEmitter = require('browser/events').EventEmitter
2822 | , debug = require('browser/debug')('runnable');
2823 |
2824 | /**
2825 | * Expose `Runnable`.
2826 | */
2827 |
2828 | module.exports = Runnable;
2829 |
2830 | /**
2831 | * Initialize a new `Runnable` with the given `title` and callback `fn`.
2832 | *
2833 | * @param {String} title
2834 | * @param {Function} fn
2835 | * @api private
2836 | */
2837 |
2838 | function Runnable(title, fn) {
2839 | this.title = title;
2840 | this.fn = fn;
2841 | this.async = fn && fn.length;
2842 | this.sync = ! this.async;
2843 | this._timeout = 2000;
2844 | this.timedOut = false;
2845 | }
2846 |
2847 | /**
2848 | * Inherit from `EventEmitter.prototype`.
2849 | */
2850 |
2851 | Runnable.prototype = new EventEmitter;
2852 | Runnable.prototype.constructor = Runnable;
2853 |
2854 |
2855 | /**
2856 | * Set & get timeout `ms`.
2857 | *
2858 | * @param {Number} ms
2859 | * @return {Runnable|Number} ms or self
2860 | * @api private
2861 | */
2862 |
2863 | Runnable.prototype.timeout = function(ms){
2864 | if (0 == arguments.length) return this._timeout;
2865 | debug('timeout %d', ms);
2866 | this._timeout = ms;
2867 | if (this.timer) this.resetTimeout();
2868 | return this;
2869 | };
2870 |
2871 | /**
2872 | * Return the full title generated by recursively
2873 | * concatenating the parent's full title.
2874 | *
2875 | * @return {String}
2876 | * @api public
2877 | */
2878 |
2879 | Runnable.prototype.fullTitle = function(){
2880 | return this.parent.fullTitle() + ' ' + this.title;
2881 | };
2882 |
2883 | /**
2884 | * Clear the timeout.
2885 | *
2886 | * @api private
2887 | */
2888 |
2889 | Runnable.prototype.clearTimeout = function(){
2890 | clearTimeout(this.timer);
2891 | };
2892 |
2893 | /**
2894 | * Reset the timeout.
2895 | *
2896 | * @api private
2897 | */
2898 |
2899 | Runnable.prototype.resetTimeout = function(){
2900 | var self = this
2901 | , ms = this.timeout();
2902 |
2903 | this.clearTimeout();
2904 | if (ms) {
2905 | this.timer = setTimeout(function(){
2906 | self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
2907 | self.timedOut = true;
2908 | }, ms);
2909 | }
2910 | };
2911 |
2912 | /**
2913 | * Run the test and invoke `fn(err)`.
2914 | *
2915 | * @param {Function} fn
2916 | * @api private
2917 | */
2918 |
2919 | Runnable.prototype.run = function(fn){
2920 | var self = this
2921 | , ms = this.timeout()
2922 | , start = new Date
2923 | , ctx = this.ctx
2924 | , finished
2925 | , emitted;
2926 |
2927 | if (ctx) ctx.runnable(this);
2928 |
2929 | // timeout
2930 | if (this.async) {
2931 | if (ms) {
2932 | this.timer = setTimeout(function(){
2933 | done(new Error('timeout of ' + ms + 'ms exceeded'));
2934 | self.timedOut = true;
2935 | }, ms);
2936 | }
2937 | }
2938 |
2939 | // called multiple times
2940 | function multiple() {
2941 | if (emitted) return;
2942 | emitted = true;
2943 | self.emit('error', new Error('done() called multiple times'));
2944 | }
2945 |
2946 | // finished
2947 | function done(err) {
2948 | if (self.timedOut) return;
2949 | if (finished) return multiple();
2950 | self.clearTimeout();
2951 | self.duration = new Date - start;
2952 | finished = true;
2953 | fn(err);
2954 | }
2955 |
2956 | // for .resetTimeout()
2957 | this.callback = done;
2958 |
2959 | // async
2960 | if (this.async) {
2961 | try {
2962 | this.fn.call(ctx, function(err){
2963 | if (err instanceof Error) return done(err);
2964 | if (null != err) return done(new Error('done() invoked with non-Error: ' + err));
2965 | done();
2966 | });
2967 | } catch (err) {
2968 | done(err);
2969 | }
2970 | return;
2971 | }
2972 |
2973 | // sync
2974 | try {
2975 | if (!this.pending) this.fn.call(ctx);
2976 | this.duration = new Date - start;
2977 | fn();
2978 | } catch (err) {
2979 | fn(err);
2980 | }
2981 | };
2982 |
2983 | }); // module: runnable.js
2984 |
2985 | require.register("runner.js", function(module, exports, require){
2986 |
2987 | /**
2988 | * Module dependencies.
2989 | */
2990 |
2991 | var EventEmitter = require('browser/events').EventEmitter
2992 | , debug = require('browser/debug')('runner')
2993 | , Test = require('./test')
2994 | , utils = require('./utils')
2995 | , noop = function(){};
2996 |
2997 | /**
2998 | * Expose `Runner`.
2999 | */
3000 |
3001 | module.exports = Runner;
3002 |
3003 | /**
3004 | * Initialize a `Runner` for the given `suite`.
3005 | *
3006 | * Events:
3007 | *
3008 | * - `start` execution started
3009 | * - `end` execution complete
3010 | * - `suite` (suite) test suite execution started
3011 | * - `suite end` (suite) all tests (and sub-suites) have finished
3012 | * - `test` (test) test execution started
3013 | * - `test end` (test) test completed
3014 | * - `hook` (hook) hook execution started
3015 | * - `hook end` (hook) hook complete
3016 | * - `pass` (test) test passed
3017 | * - `fail` (test, err) test failed
3018 | *
3019 | * @api public
3020 | */
3021 |
3022 | function Runner(suite) {
3023 | var self = this;
3024 | this._globals = [];
3025 | this.suite = suite;
3026 | this.total = suite.total();
3027 | this.failures = 0;
3028 | this.on('test end', function(test){ self.checkGlobals(test); });
3029 | this.on('hook end', function(hook){ self.checkGlobals(hook); });
3030 | this.grep(/.*/);
3031 | this.globals(utils.keys(global).concat(['errno']));
3032 | }
3033 |
3034 | /**
3035 | * Inherit from `EventEmitter.prototype`.
3036 | */
3037 |
3038 | Runner.prototype = new EventEmitter;
3039 | Runner.prototype.constructor = Runner;
3040 |
3041 |
3042 | /**
3043 | * Run tests with full titles matching `re`. Updates runner.total
3044 | * with number of tests matched.
3045 | *
3046 | * @param {RegExp} re
3047 | * @return {Runner} for chaining
3048 | * @api public
3049 | */
3050 |
3051 | Runner.prototype.grep = function(re){
3052 | debug('grep %s', re);
3053 | this._grep = re;
3054 | this.total = this.grepTotal(this.suite);
3055 | return this;
3056 | };
3057 |
3058 | /**
3059 | * Returns the number of tests matching the grep search for the
3060 | * given suite.
3061 | *
3062 | * @param {Suite} suite
3063 | * @return {Number}
3064 | * @api public
3065 | */
3066 |
3067 | Runner.prototype.grepTotal = function(suite) {
3068 | var self = this;
3069 | var total = 0;
3070 |
3071 | suite.eachTest(function(test){
3072 | if (self._grep.test(test.fullTitle())) total++;
3073 | });
3074 |
3075 | return total;
3076 | };
3077 |
3078 | /**
3079 | * Allow the given `arr` of globals.
3080 | *
3081 | * @param {Array} arr
3082 | * @return {Runner} for chaining
3083 | * @api public
3084 | */
3085 |
3086 | Runner.prototype.globals = function(arr){
3087 | if (0 == arguments.length) return this._globals;
3088 | debug('globals %j', arr);
3089 | utils.forEach(arr, function(arr){
3090 | this._globals.push(arr);
3091 | }, this);
3092 | return this;
3093 | };
3094 |
3095 | /**
3096 | * Check for global variable leaks.
3097 | *
3098 | * @api private
3099 | */
3100 |
3101 | Runner.prototype.checkGlobals = function(test){
3102 | if (this.ignoreLeaks) return;
3103 |
3104 | var leaks = utils.filter(utils.keys(global), function(key){
3105 | return !~utils.indexOf(this._globals, key) && (!global.navigator || 'onerror' !== key);
3106 | }, this);
3107 |
3108 | this._globals = this._globals.concat(leaks);
3109 |
3110 | if (leaks.length > 1) {
3111 | this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
3112 | } else if (leaks.length) {
3113 | this.fail(test, new Error('global leak detected: ' + leaks[0]));
3114 | }
3115 | };
3116 |
3117 | /**
3118 | * Fail the given `test`.
3119 | *
3120 | * @param {Test} test
3121 | * @param {Error} err
3122 | * @api private
3123 | */
3124 |
3125 | Runner.prototype.fail = function(test, err){
3126 | ++this.failures;
3127 | test.state = 'failed';
3128 | this.emit('fail', test, err);
3129 | };
3130 |
3131 | /**
3132 | * Fail the given `hook` with `err`.
3133 | *
3134 | * Hook failures (currently) hard-end due
3135 | * to that fact that a failing hook will
3136 | * surely cause subsequent tests to fail,
3137 | * causing jumbled reporting.
3138 | *
3139 | * @param {Hook} hook
3140 | * @param {Error} err
3141 | * @api private
3142 | */
3143 |
3144 | Runner.prototype.failHook = function(hook, err){
3145 | this.fail(hook, err);
3146 | this.emit('end');
3147 | };
3148 |
3149 | /**
3150 | * Run hook `name` callbacks and then invoke `fn()`.
3151 | *
3152 | * @param {String} name
3153 | * @param {Function} function
3154 | * @api private
3155 | */
3156 |
3157 | Runner.prototype.hook = function(name, fn){
3158 | var suite = this.suite
3159 | , hooks = suite['_' + name]
3160 | , ms = suite._timeout
3161 | , self = this
3162 | , timer;
3163 |
3164 | function next(i) {
3165 | var hook = hooks[i];
3166 | if (!hook) return fn();
3167 | self.currentRunnable = hook;
3168 |
3169 | self.emit('hook', hook);
3170 |
3171 | hook.on('error', function(err){
3172 | self.failHook(hook, err);
3173 | });
3174 |
3175 | hook.run(function(err){
3176 | hook.removeAllListeners('error');
3177 | if (err) return self.failHook(hook, err);
3178 | self.emit('hook end', hook);
3179 | next(++i);
3180 | });
3181 | }
3182 |
3183 | process.nextTick(function(){
3184 | next(0);
3185 | });
3186 | };
3187 |
3188 | /**
3189 | * Run hook `name` for the given array of `suites`
3190 | * in order, and callback `fn(err)`.
3191 | *
3192 | * @param {String} name
3193 | * @param {Array} suites
3194 | * @param {Function} fn
3195 | * @api private
3196 | */
3197 |
3198 | Runner.prototype.hooks = function(name, suites, fn){
3199 | var self = this
3200 | , orig = this.suite;
3201 |
3202 | function next(suite) {
3203 | self.suite = suite;
3204 |
3205 | if (!suite) {
3206 | self.suite = orig;
3207 | return fn();
3208 | }
3209 |
3210 | self.hook(name, function(err){
3211 | if (err) {
3212 | self.suite = orig;
3213 | return fn(err);
3214 | }
3215 |
3216 | next(suites.pop());
3217 | });
3218 | }
3219 |
3220 | next(suites.pop());
3221 | };
3222 |
3223 | /**
3224 | * Run hooks from the top level down.
3225 | *
3226 | * @param {String} name
3227 | * @param {Function} fn
3228 | * @api private
3229 | */
3230 |
3231 | Runner.prototype.hookUp = function(name, fn){
3232 | var suites = [this.suite].concat(this.parents()).reverse();
3233 | this.hooks(name, suites, fn);
3234 | };
3235 |
3236 | /**
3237 | * Run hooks from the bottom up.
3238 | *
3239 | * @param {String} name
3240 | * @param {Function} fn
3241 | * @api private
3242 | */
3243 |
3244 | Runner.prototype.hookDown = function(name, fn){
3245 | var suites = [this.suite].concat(this.parents());
3246 | this.hooks(name, suites, fn);
3247 | };
3248 |
3249 | /**
3250 | * Return an array of parent Suites from
3251 | * closest to furthest.
3252 | *
3253 | * @return {Array}
3254 | * @api private
3255 | */
3256 |
3257 | Runner.prototype.parents = function(){
3258 | var suite = this.suite
3259 | , suites = [];
3260 | while (suite = suite.parent) suites.push(suite);
3261 | return suites;
3262 | };
3263 |
3264 | /**
3265 | * Run the current test and callback `fn(err)`.
3266 | *
3267 | * @param {Function} fn
3268 | * @api private
3269 | */
3270 |
3271 | Runner.prototype.runTest = function(fn){
3272 | var test = this.test
3273 | , self = this;
3274 |
3275 | try {
3276 | test.on('error', function(err){
3277 | self.fail(test, err);
3278 | });
3279 | test.run(fn);
3280 | } catch (err) {
3281 | fn(err);
3282 | }
3283 | };
3284 |
3285 | /**
3286 | * Run tests in the given `suite` and invoke
3287 | * the callback `fn()` when complete.
3288 | *
3289 | * @param {Suite} suite
3290 | * @param {Function} fn
3291 | * @api private
3292 | */
3293 |
3294 | Runner.prototype.runTests = function(suite, fn){
3295 | var self = this
3296 | , tests = suite.tests
3297 | , test;
3298 |
3299 | function next(err) {
3300 | // if we bail after first err
3301 | if (self.failures && suite._bail) return fn();
3302 |
3303 | // next test
3304 | test = tests.shift();
3305 |
3306 | // all done
3307 | if (!test) return fn();
3308 |
3309 | // grep
3310 | if (!self._grep.test(test.fullTitle())) return next();
3311 |
3312 | // pending
3313 | if (test.pending) {
3314 | self.emit('pending', test);
3315 | self.emit('test end', test);
3316 | return next();
3317 | }
3318 |
3319 | // execute test and hook(s)
3320 | self.emit('test', self.test = test);
3321 | self.hookDown('beforeEach', function(){
3322 | self.currentRunnable = self.test;
3323 | self.runTest(function(err){
3324 | test = self.test;
3325 |
3326 | if (err) {
3327 | self.fail(test, err);
3328 | self.emit('test end', test);
3329 | return self.hookUp('afterEach', next);
3330 | }
3331 |
3332 | test.state = 'passed';
3333 | self.emit('pass', test);
3334 | self.emit('test end', test);
3335 | self.hookUp('afterEach', next);
3336 | });
3337 | });
3338 | }
3339 |
3340 | this.next = next;
3341 | next();
3342 | };
3343 |
3344 | /**
3345 | * Run the given `suite` and invoke the
3346 | * callback `fn()` when complete.
3347 | *
3348 | * @param {Suite} suite
3349 | * @param {Function} fn
3350 | * @api private
3351 | */
3352 |
3353 | Runner.prototype.runSuite = function(suite, fn){
3354 | var total = this.grepTotal(suite)
3355 | , self = this
3356 | , i = 0;
3357 |
3358 | debug('run suite %s', suite.fullTitle());
3359 |
3360 | if (!total) return fn();
3361 |
3362 | this.emit('suite', this.suite = suite);
3363 |
3364 | function next() {
3365 | var curr = suite.suites[i++];
3366 | if (!curr) return done();
3367 | self.runSuite(curr, next);
3368 | }
3369 |
3370 | function done() {
3371 | self.suite = suite;
3372 | self.hook('afterAll', function(){
3373 | self.emit('suite end', suite);
3374 | fn();
3375 | });
3376 | }
3377 |
3378 | this.hook('beforeAll', function(){
3379 | self.runTests(suite, next);
3380 | });
3381 | };
3382 |
3383 | /**
3384 | * Handle uncaught exceptions.
3385 | *
3386 | * @param {Error} err
3387 | * @api private
3388 | */
3389 |
3390 | Runner.prototype.uncaught = function(err){
3391 | debug('uncaught exception');
3392 | var runnable = this.currentRunnable;
3393 | if ('failed' == runnable.state) return;
3394 | runnable.clearTimeout();
3395 | err.uncaught = true;
3396 | this.fail(runnable, err);
3397 |
3398 | // recover from test
3399 | if ('test' == runnable.type) {
3400 | this.emit('test end', runnable);
3401 | this.hookUp('afterEach', this.next);
3402 | return;
3403 | }
3404 |
3405 | // bail on hooks
3406 | this.emit('end');
3407 | };
3408 |
3409 | /**
3410 | * Run the root suite and invoke `fn(failures)`
3411 | * on completion.
3412 | *
3413 | * @param {Function} fn
3414 | * @return {Runner} for chaining
3415 | * @api public
3416 | */
3417 |
3418 | Runner.prototype.run = function(fn){
3419 | var self = this
3420 | , fn = fn || function(){};
3421 |
3422 | debug('start');
3423 |
3424 | // callback
3425 | this.on('end', function(){
3426 | debug('end');
3427 | process.removeListener('uncaughtException', this.uncaught);
3428 | fn(self.failures);
3429 | });
3430 |
3431 | // run suites
3432 | this.emit('start');
3433 | this.runSuite(this.suite, function(){
3434 | debug('finished running');
3435 | self.emit('end');
3436 | });
3437 |
3438 | // uncaught exception
3439 | process.on('uncaughtException', function(err){
3440 | self.uncaught(err);
3441 | });
3442 |
3443 | return this;
3444 | };
3445 |
3446 | }); // module: runner.js
3447 |
3448 | require.register("suite.js", function(module, exports, require){
3449 |
3450 | /**
3451 | * Module dependencies.
3452 | */
3453 |
3454 | var EventEmitter = require('browser/events').EventEmitter
3455 | , debug = require('browser/debug')('suite')
3456 | , utils = require('./utils')
3457 | , Hook = require('./hook');
3458 |
3459 | /**
3460 | * Expose `Suite`.
3461 | */
3462 |
3463 | exports = module.exports = Suite;
3464 |
3465 | /**
3466 | * Create a new `Suite` with the given `title`
3467 | * and parent `Suite`. When a suite with the
3468 | * same title is already present, that suite
3469 | * is returned to provide nicer reporter
3470 | * and more flexible meta-testing.
3471 | *
3472 | * @param {Suite} parent
3473 | * @param {String} title
3474 | * @return {Suite}
3475 | * @api public
3476 | */
3477 |
3478 | exports.create = function(parent, title){
3479 | var suite = new Suite(title, parent.ctx);
3480 | suite.parent = parent;
3481 | title = suite.fullTitle();
3482 | parent.addSuite(suite);
3483 | return suite;
3484 | };
3485 |
3486 | /**
3487 | * Initialize a new `Suite` with the given
3488 | * `title` and `ctx`.
3489 | *
3490 | * @param {String} title
3491 | * @param {Context} ctx
3492 | * @api private
3493 | */
3494 |
3495 | function Suite(title, ctx) {
3496 | this.title = title;
3497 | this.ctx = ctx;
3498 | this.suites = [];
3499 | this.tests = [];
3500 | this._beforeEach = [];
3501 | this._beforeAll = [];
3502 | this._afterEach = [];
3503 | this._afterAll = [];
3504 | this.root = !title;
3505 | this._timeout = 2000;
3506 | this._bail = false;
3507 | }
3508 |
3509 | /**
3510 | * Inherit from `EventEmitter.prototype`.
3511 | */
3512 |
3513 | Suite.prototype = new EventEmitter;
3514 | Suite.prototype.constructor = Suite;
3515 |
3516 |
3517 | /**
3518 | * Return a clone of this `Suite`.
3519 | *
3520 | * @return {Suite}
3521 | * @api private
3522 | */
3523 |
3524 | Suite.prototype.clone = function(){
3525 | var suite = new Suite(this.title);
3526 | debug('clone');
3527 | suite.ctx = this.ctx;
3528 | suite.timeout(this.timeout());
3529 | suite.bail(this.bail());
3530 | return suite;
3531 | };
3532 |
3533 | /**
3534 | * Set timeout `ms` or short-hand such as "2s".
3535 | *
3536 | * @param {Number|String} ms
3537 | * @return {Suite|Number} for chaining
3538 | * @api private
3539 | */
3540 |
3541 | Suite.prototype.timeout = function(ms){
3542 | if (0 == arguments.length) return this._timeout;
3543 | if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000;
3544 | debug('timeout %d', ms);
3545 | this._timeout = parseInt(ms, 10);
3546 | return this;
3547 | };
3548 |
3549 | /**
3550 | * Sets whether to bail after first error.
3551 | *
3552 | * @parma {Boolean} bail
3553 | * @return {Suite|Number} for chaining
3554 | * @api private
3555 | */
3556 |
3557 | Suite.prototype.bail = function(bail){
3558 | if (0 == arguments.length) return this._bail;
3559 | debug('bail %s', bail);
3560 | this._bail = bail;
3561 | return this;
3562 | };
3563 |
3564 | /**
3565 | * Run `fn(test[, done])` before running tests.
3566 | *
3567 | * @param {Function} fn
3568 | * @return {Suite} for chaining
3569 | * @api private
3570 | */
3571 |
3572 | Suite.prototype.beforeAll = function(fn){
3573 | var hook = new Hook('"before all" hook', fn);
3574 | hook.parent = this;
3575 | hook.timeout(this.timeout());
3576 | hook.ctx = this.ctx;
3577 | this._beforeAll.push(hook);
3578 | this.emit('beforeAll', hook);
3579 | return this;
3580 | };
3581 |
3582 | /**
3583 | * Run `fn(test[, done])` after running tests.
3584 | *
3585 | * @param {Function} fn
3586 | * @return {Suite} for chaining
3587 | * @api private
3588 | */
3589 |
3590 | Suite.prototype.afterAll = function(fn){
3591 | var hook = new Hook('"after all" hook', fn);
3592 | hook.parent = this;
3593 | hook.timeout(this.timeout());
3594 | hook.ctx = this.ctx;
3595 | this._afterAll.push(hook);
3596 | this.emit('afterAll', hook);
3597 | return this;
3598 | };
3599 |
3600 | /**
3601 | * Run `fn(test[, done])` before each test case.
3602 | *
3603 | * @param {Function} fn
3604 | * @return {Suite} for chaining
3605 | * @api private
3606 | */
3607 |
3608 | Suite.prototype.beforeEach = function(fn){
3609 | var hook = new Hook('"before each" hook', fn);
3610 | hook.parent = this;
3611 | hook.timeout(this.timeout());
3612 | hook.ctx = this.ctx;
3613 | this._beforeEach.push(hook);
3614 | this.emit('beforeEach', hook);
3615 | return this;
3616 | };
3617 |
3618 | /**
3619 | * Run `fn(test[, done])` after each test case.
3620 | *
3621 | * @param {Function} fn
3622 | * @return {Suite} for chaining
3623 | * @api private
3624 | */
3625 |
3626 | Suite.prototype.afterEach = function(fn){
3627 | var hook = new Hook('"after each" hook', fn);
3628 | hook.parent = this;
3629 | hook.timeout(this.timeout());
3630 | hook.ctx = this.ctx;
3631 | this._afterEach.push(hook);
3632 | this.emit('afterEach', hook);
3633 | return this;
3634 | };
3635 |
3636 | /**
3637 | * Add a test `suite`.
3638 | *
3639 | * @param {Suite} suite
3640 | * @return {Suite} for chaining
3641 | * @api private
3642 | */
3643 |
3644 | Suite.prototype.addSuite = function(suite){
3645 | suite.parent = this;
3646 | suite.timeout(this.timeout());
3647 | suite.bail(this.bail());
3648 | this.suites.push(suite);
3649 | this.emit('suite', suite);
3650 | return this;
3651 | };
3652 |
3653 | /**
3654 | * Add a `test` to this suite.
3655 | *
3656 | * @param {Test} test
3657 | * @return {Suite} for chaining
3658 | * @api private
3659 | */
3660 |
3661 | Suite.prototype.addTest = function(test){
3662 | test.parent = this;
3663 | test.timeout(this.timeout());
3664 | test.ctx = this.ctx;
3665 | this.tests.push(test);
3666 | this.emit('test', test);
3667 | return this;
3668 | };
3669 |
3670 | /**
3671 | * Return the full title generated by recursively
3672 | * concatenating the parent's full title.
3673 | *
3674 | * @return {String}
3675 | * @api public
3676 | */
3677 |
3678 | Suite.prototype.fullTitle = function(){
3679 | if (this.parent) {
3680 | var full = this.parent.fullTitle();
3681 | if (full) return full + ' ' + this.title;
3682 | }
3683 | return this.title;
3684 | };
3685 |
3686 | /**
3687 | * Return the total number of tests.
3688 | *
3689 | * @return {Number}
3690 | * @api public
3691 | */
3692 |
3693 | Suite.prototype.total = function(){
3694 | return utils.reduce(this.suites, function(sum, suite){
3695 | return sum + suite.total();
3696 | }, 0) + this.tests.length;
3697 | };
3698 |
3699 | /**
3700 | * Iterates through each suite recursively to find
3701 | * all tests. Applies a function in the format
3702 | * `fn(test)`.
3703 | *
3704 | * @param {Function} fn
3705 | * @return {Suite}
3706 | * @api private
3707 | */
3708 |
3709 | Suite.prototype.eachTest = function(fn){
3710 | utils.forEach(this.tests, fn);
3711 | utils.forEach(this.suites, function(suite){
3712 | suite.eachTest(fn);
3713 | });
3714 | return this;
3715 | };
3716 |
3717 | }); // module: suite.js
3718 |
3719 | require.register("test.js", function(module, exports, require){
3720 |
3721 | /**
3722 | * Module dependencies.
3723 | */
3724 |
3725 | var Runnable = require('./runnable');
3726 |
3727 | /**
3728 | * Expose `Test`.
3729 | */
3730 |
3731 | module.exports = Test;
3732 |
3733 | /**
3734 | * Initialize a new `Test` with the given `title` and callback `fn`.
3735 | *
3736 | * @param {String} title
3737 | * @param {Function} fn
3738 | * @api private
3739 | */
3740 |
3741 | function Test(title, fn) {
3742 | Runnable.call(this, title, fn);
3743 | this.pending = !fn;
3744 | this.type = 'test';
3745 | }
3746 |
3747 | /**
3748 | * Inherit from `Runnable.prototype`.
3749 | */
3750 |
3751 | Test.prototype = new Runnable;
3752 | Test.prototype.constructor = Test;
3753 |
3754 |
3755 | /**
3756 | * Inspect the context void of private properties.
3757 | *
3758 | * @return {String}
3759 | * @api private
3760 | */
3761 |
3762 | Test.prototype.inspect = function(){
3763 | return JSON.stringify(this, function(key, val){
3764 | return '_' == key[0]
3765 | ? undefined
3766 | : 'parent' == key
3767 | ? '#'
3768 | : val;
3769 | }, 2);
3770 | };
3771 | }); // module: test.js
3772 |
3773 | require.register("utils.js", function(module, exports, require){
3774 |
3775 | /**
3776 | * Module dependencies.
3777 | */
3778 |
3779 | var fs = require('browser/fs')
3780 | , path = require('browser/path')
3781 | , join = path.join
3782 | , debug = require('browser/debug')('watch');
3783 |
3784 | /**
3785 | * Ignored directories.
3786 | */
3787 |
3788 | var ignore = ['node_modules', '.git'];
3789 |
3790 | /**
3791 | * Escape special characters in the given string of html.
3792 | *
3793 | * @param {String} html
3794 | * @return {String}
3795 | * @api private
3796 | */
3797 |
3798 | exports.escape = function(html) {
3799 | return String(html)
3800 | .replace(/&/g, '&')
3801 | .replace(/"/g, '"')
3802 | .replace(//g, '>');
3804 | };
3805 |
3806 | /**
3807 | * Array#forEach (<=IE8)
3808 | *
3809 | * @param {Array} array
3810 | * @param {Function} fn
3811 | * @param {Object} scope
3812 | * @api private
3813 | */
3814 |
3815 | exports.forEach = function(arr, fn, scope) {
3816 | for (var i = 0, l = arr.length; i < l; i++)
3817 | fn.call(scope, arr[i], i);
3818 | };
3819 |
3820 | /**
3821 | * Array#indexOf (<=IE8)
3822 | *
3823 | * @parma {Array} arr
3824 | * @param {Object} obj to find index of
3825 | * @param {Number} start
3826 | * @api private
3827 | */
3828 |
3829 | exports.indexOf = function (arr, obj, start) {
3830 | for (var i = start || 0, l = arr.length; i < l; i++) {
3831 | if (arr[i] === obj)
3832 | return i;
3833 | }
3834 | return -1;
3835 | };
3836 |
3837 | /**
3838 | * Array#reduce (<=IE8)
3839 | *
3840 | * @param {Array} array
3841 | * @param {Function} fn
3842 | * @param {Object} initial value
3843 | * @param {Object} scope
3844 | * @api private
3845 | */
3846 |
3847 | exports.reduce = function(arr, fn, val, scope) {
3848 | var rval = val;
3849 |
3850 | for (var i = 0, l = arr.length; i < l; i++) {
3851 | rval = fn.call(scope, rval, arr[i], i, arr);
3852 | }
3853 |
3854 | return rval;
3855 | };
3856 |
3857 | /**
3858 | * Array#filter (<=IE8)
3859 | *
3860 | * @param {Array} array
3861 | * @param {Function} fn
3862 | * @param {Object} scope
3863 | * @api private
3864 | */
3865 |
3866 | exports.filter = function(arr, fn, scope) {
3867 | var ret = [];
3868 |
3869 | for (var i = 0, l = arr.length; i < l; i++) {
3870 | var val = arr[i];
3871 | if (fn.call(scope, val, i, arr))
3872 | ret.push(val);
3873 | }
3874 |
3875 | return ret;
3876 | };
3877 |
3878 | /**
3879 | * Object.keys (<=IE8)
3880 | *
3881 | * @param {Object} obj
3882 | * @return {Array} keys
3883 | * @api private
3884 | */
3885 |
3886 | exports.keys = Object.keys || function(obj) {
3887 | var keys = []
3888 | , has = Object.prototype.hasOwnProperty // for `window` on <=IE8
3889 |
3890 | for (var key in obj) {
3891 | if (has.call(obj, key)) {
3892 | keys.push(key);
3893 | }
3894 | }
3895 |
3896 | return keys;
3897 | };
3898 |
3899 | /**
3900 | * Watch the given `files` for changes
3901 | * and invoke `fn(file)` on modification.
3902 | *
3903 | * @param {Array} files
3904 | * @param {Function} fn
3905 | * @api private
3906 | */
3907 |
3908 | exports.watch = function(files, fn){
3909 | var options = { interval: 100 };
3910 | files.forEach(function(file){
3911 | debug('file %s', file);
3912 | fs.watchFile(file, options, function(curr, prev){
3913 | if (prev.mtime < curr.mtime) fn(file);
3914 | });
3915 | });
3916 | };
3917 |
3918 | /**
3919 | * Ignored files.
3920 | */
3921 |
3922 | function ignored(path){
3923 | return !~ignore.indexOf(path);
3924 | }
3925 |
3926 | /**
3927 | * Lookup files in the given `dir`.
3928 | *
3929 | * @return {Array}
3930 | * @api private
3931 | */
3932 |
3933 | exports.files = function(dir, ret){
3934 | ret = ret || [];
3935 |
3936 | fs.readdirSync(dir)
3937 | .filter(ignored)
3938 | .forEach(function(path){
3939 | path = join(dir, path);
3940 | if (fs.statSync(path).isDirectory()) {
3941 | exports.files(path, ret);
3942 | } else if (path.match(/\.(js|coffee)$/)) {
3943 | ret.push(path);
3944 | }
3945 | });
3946 |
3947 | return ret;
3948 | };
3949 |
3950 | /**
3951 | * Compute a slug from the given `str`.
3952 | *
3953 | * @param {String} str
3954 | * @return {String}
3955 | */
3956 |
3957 | exports.slug = function(str){
3958 | return str
3959 | .toLowerCase()
3960 | .replace(/ +/g, '-')
3961 | .replace(/[^-\w]/g, '');
3962 | };
3963 | }); // module: utils.js
3964 | /**
3965 | * Node shims.
3966 | *
3967 | * These are meant only to allow
3968 | * mocha.js to run untouched, not
3969 | * to allow running node code in
3970 | * the browser.
3971 | */
3972 |
3973 | process = {};
3974 | process.exit = function(status){};
3975 | process.stdout = {};
3976 | global = window;
3977 |
3978 | /**
3979 | * next tick implementation.
3980 | */
3981 |
3982 | process.nextTick = (function(){
3983 | // postMessage behaves badly on IE8
3984 | if (window.ActiveXObject || !window.postMessage) {
3985 | return function(fn){ fn() };
3986 | }
3987 |
3988 | // based on setZeroTimeout by David Baron
3989 | // - http://dbaron.org/log/20100309-faster-timeouts
3990 | var timeouts = []
3991 | , name = 'mocha-zero-timeout'
3992 |
3993 | return function(fn){
3994 | timeouts.push(fn);
3995 | window.postMessage(name, '*');
3996 | window.addEventListener('message', function(e){
3997 | if (e.source == window && e.data == name) {
3998 | if (e.stopPropagation) e.stopPropagation();
3999 | if (timeouts.length) timeouts.shift()();
4000 | }
4001 | }, true);
4002 | }
4003 | })();
4004 |
4005 | /**
4006 | * Remove uncaughtException listener.
4007 | */
4008 |
4009 | process.removeListener = function(e){
4010 | if ('uncaughtException' == e) {
4011 | window.onerror = null;
4012 | }
4013 | };
4014 |
4015 | /**
4016 | * Implements uncaughtException listener.
4017 | */
4018 |
4019 | process.on = function(e, fn){
4020 | if ('uncaughtException' == e) {
4021 | window.onerror = fn;
4022 | }
4023 | };
4024 |
4025 | /**
4026 | * Expose mocha.
4027 | */
4028 |
4029 | window.mocha = require('mocha');
4030 |
4031 | // boot
4032 | ;(function(){
4033 | var suite = new mocha.Suite('', new mocha.Context)
4034 | , utils = mocha.utils
4035 | , options = {}
4036 |
4037 | /**
4038 | * Highlight the given string of `js`.
4039 | */
4040 |
4041 | function highlight(js) {
4042 | return js
4043 | .replace(//g, '>')
4045 | .replace(/\/\/(.*)/gm, '')
4046 | .replace(/('.*?')/gm, '$1 ')
4047 | .replace(/(\d+\.\d+)/gm, '$1 ')
4048 | .replace(/(\d+)/gm, '$1 ')
4049 | .replace(/\bnew *(\w+)/gm, 'new $1 ')
4050 | .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1 ')
4051 | }
4052 |
4053 | /**
4054 | * Highlight code contents.
4055 | */
4056 |
4057 | function highlightCode() {
4058 | var code = document.getElementsByTagName('code');
4059 | for (var i = 0, len = code.length; i < len; ++i) {
4060 | code[i].innerHTML = highlight(code[i].innerHTML);
4061 | }
4062 | }
4063 |
4064 | /**
4065 | * Parse the given `qs`.
4066 | */
4067 |
4068 | function parse(qs) {
4069 | return utils.reduce(qs.replace('?', '').split('&'), function(obj, pair){
4070 | var i = pair.indexOf('=')
4071 | , key = pair.slice(0, i)
4072 | , val = pair.slice(++i);
4073 |
4074 | obj[key] = decodeURIComponent(val);
4075 | return obj;
4076 | }, {});
4077 | }
4078 |
4079 | /**
4080 | * Setup mocha with the given setting options.
4081 | */
4082 |
4083 | mocha.setup = function(opts){
4084 | if ('string' === typeof opts) options.ui = opts;
4085 | else options = opts;
4086 |
4087 | ui = mocha.interfaces[options.ui];
4088 | if (!ui) throw new Error('invalid mocha interface "' + ui + '"');
4089 | if (options.timeout) suite.timeout(options.timeout);
4090 | ui(suite);
4091 | suite.emit('pre-require', window);
4092 | };
4093 |
4094 | /**
4095 | * Run mocha, returning the Runner.
4096 | */
4097 |
4098 | mocha.run = function(fn){
4099 | suite.emit('run');
4100 | var runner = new mocha.Runner(suite);
4101 | var Reporter = options.reporter || mocha.reporters.HTML;
4102 | var reporter = new Reporter(runner);
4103 | var query = parse(window.location.search || "");
4104 | if (query.grep) runner.grep(new RegExp(query.grep));
4105 | if (options.ignoreLeaks) runner.ignoreLeaks = true;
4106 | if (options.globals) runner.globals(options.globals);
4107 | runner.globals(['location']);
4108 | runner.on('end', highlightCode);
4109 | return runner.run(fn);
4110 | };
4111 | })();
4112 | })();
--------------------------------------------------------------------------------