UNPKG

63.1 kBJavaScriptView Raw
1/*!
2 * Nodeunit
3 * https://github.com/caolan/nodeunit
4 * Copyright (c) 2010 Caolan McMahon
5 * MIT Licensed
6 *
7 * json2.js
8 * http://www.JSON.org/json2.js
9 * Public Domain.
10 * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
11 */
12nodeunit = (function(){
13/*
14 http://www.JSON.org/json2.js
15 2010-11-17
16
17 Public Domain.
18
19 NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
20
21 See http://www.JSON.org/js.html
22
23
24 This code should be minified before deployment.
25 See http://javascript.crockford.com/jsmin.html
26
27 USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
28 NOT CONTROL.
29
30
31 This file creates a global JSON object containing two methods: stringify
32 and parse.
33
34 JSON.stringify(value, replacer, space)
35 value any JavaScript value, usually an object or array.
36
37 replacer an optional parameter that determines how object
38 values are stringified for objects. It can be a
39 function or an array of strings.
40
41 space an optional parameter that specifies the indentation
42 of nested structures. If it is omitted, the text will
43 be packed without extra whitespace. If it is a number,
44 it will specify the number of spaces to indent at each
45 level. If it is a string (such as '\t' or ' '),
46 it contains the characters used to indent at each level.
47
48 This method produces a JSON text from a JavaScript value.
49
50 When an object value is found, if the object contains a toJSON
51 method, its toJSON method will be called and the result will be
52 stringified. A toJSON method does not serialize: it returns the
53 value represented by the name/value pair that should be serialized,
54 or undefined if nothing should be serialized. The toJSON method
55 will be passed the key associated with the value, and this will be
56 bound to the value
57
58 For example, this would serialize Dates as ISO strings.
59
60 Date.prototype.toJSON = function (key) {
61 function f(n) {
62 // Format integers to have at least two digits.
63 return n < 10 ? '0' + n : n;
64 }
65
66 return this.getUTCFullYear() + '-' +
67 f(this.getUTCMonth() + 1) + '-' +
68 f(this.getUTCDate()) + 'T' +
69 f(this.getUTCHours()) + ':' +
70 f(this.getUTCMinutes()) + ':' +
71 f(this.getUTCSeconds()) + 'Z';
72 };
73
74 You can provide an optional replacer method. It will be passed the
75 key and value of each member, with this bound to the containing
76 object. The value that is returned from your method will be
77 serialized. If your method returns undefined, then the member will
78 be excluded from the serialization.
79
80 If the replacer parameter is an array of strings, then it will be
81 used to select the members to be serialized. It filters the results
82 such that only members with keys listed in the replacer array are
83 stringified.
84
85 Values that do not have JSON representations, such as undefined or
86 functions, will not be serialized. Such values in objects will be
87 dropped; in arrays they will be replaced with null. You can use
88 a replacer function to replace those with JSON values.
89 JSON.stringify(undefined) returns undefined.
90
91 The optional space parameter produces a stringification of the
92 value that is filled with line breaks and indentation to make it
93 easier to read.
94
95 If the space parameter is a non-empty string, then that string will
96 be used for indentation. If the space parameter is a number, then
97 the indentation will be that many spaces.
98
99 Example:
100
101 text = JSON.stringify(['e', {pluribus: 'unum'}]);
102 // text is '["e",{"pluribus":"unum"}]'
103
104
105 text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
106 // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
107
108 text = JSON.stringify([new Date()], function (key, value) {
109 return this[key] instanceof Date ?
110 'Date(' + this[key] + ')' : value;
111 });
112 // text is '["Date(---current time---)"]'
113
114
115 JSON.parse(text, reviver)
116 This method parses a JSON text to produce an object or array.
117 It can throw a SyntaxError exception.
118
119 The optional reviver parameter is a function that can filter and
120 transform the results. It receives each of the keys and values,
121 and its return value is used instead of the original value.
122 If it returns what it received, then the structure is not modified.
123 If it returns undefined then the member is deleted.
124
125 Example:
126
127 // Parse the text. Values that look like ISO date strings will
128 // be converted to Date objects.
129
130 myData = JSON.parse(text, function (key, value) {
131 var a;
132 if (typeof value === 'string') {
133 a =
134/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
135 if (a) {
136 return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
137 +a[5], +a[6]));
138 }
139 }
140 return value;
141 });
142
143 myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
144 var d;
145 if (typeof value === 'string' &&
146 value.slice(0, 5) === 'Date(' &&
147 value.slice(-1) === ')') {
148 d = new Date(value.slice(5, -1));
149 if (d) {
150 return d;
151 }
152 }
153 return value;
154 });
155
156
157 This is a reference implementation. You are free to copy, modify, or
158 redistribute.
159*/
160
161/*jslint evil: true, strict: false, regexp: false */
162
163/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
164 call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
165 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
166 lastIndex, length, parse, prototype, push, replace, slice, stringify,
167 test, toJSON, toString, valueOf
168*/
169
170
171// Create a JSON object only if one does not already exist. We create the
172// methods in a closure to avoid creating global variables.
173
174var JSON = {};
175
176(function () {
177 "use strict";
178
179 function f(n) {
180 // Format integers to have at least two digits.
181 return n < 10 ? '0' + n : n;
182 }
183
184 if (typeof Date.prototype.toJSON !== 'function') {
185
186 Date.prototype.toJSON = function (key) {
187
188 return isFinite(this.valueOf()) ?
189 this.getUTCFullYear() + '-' +
190 f(this.getUTCMonth() + 1) + '-' +
191 f(this.getUTCDate()) + 'T' +
192 f(this.getUTCHours()) + ':' +
193 f(this.getUTCMinutes()) + ':' +
194 f(this.getUTCSeconds()) + 'Z' : null;
195 };
196
197 String.prototype.toJSON =
198 Number.prototype.toJSON =
199 Boolean.prototype.toJSON = function (key) {
200 return this.valueOf();
201 };
202 }
203
204 var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
205 escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
206 gap,
207 indent,
208 meta = { // table of character substitutions
209 '\b': '\\b',
210 '\t': '\\t',
211 '\n': '\\n',
212 '\f': '\\f',
213 '\r': '\\r',
214 '"' : '\\"',
215 '\\': '\\\\'
216 },
217 rep;
218
219
220 function quote(string) {
221
222// If the string contains no control characters, no quote characters, and no
223// backslash characters, then we can safely slap some quotes around it.
224// Otherwise we must also replace the offending characters with safe escape
225// sequences.
226
227 escapable.lastIndex = 0;
228 return escapable.test(string) ?
229 '"' + string.replace(escapable, function (a) {
230 var c = meta[a];
231 return typeof c === 'string' ? c :
232 '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
233 }) + '"' :
234 '"' + string + '"';
235 }
236
237
238 function str(key, holder) {
239
240// Produce a string from holder[key].
241
242 var i, // The loop counter.
243 k, // The member key.
244 v, // The member value.
245 length,
246 mind = gap,
247 partial,
248 value = holder[key];
249
250// If the value has a toJSON method, call it to obtain a replacement value.
251
252 if (value && typeof value === 'object' &&
253 typeof value.toJSON === 'function') {
254 value = value.toJSON(key);
255 }
256
257// If we were called with a replacer function, then call the replacer to
258// obtain a replacement value.
259
260 if (typeof rep === 'function') {
261 value = rep.call(holder, key, value);
262 }
263
264// What happens next depends on the value's type.
265
266 switch (typeof value) {
267 case 'string':
268 return quote(value);
269
270 case 'number':
271
272// JSON numbers must be finite. Encode non-finite numbers as null.
273
274 return isFinite(value) ? String(value) : 'null';
275
276 case 'boolean':
277 case 'null':
278
279// If the value is a boolean or null, convert it to a string. Note:
280// typeof null does not produce 'null'. The case is included here in
281// the remote chance that this gets fixed someday.
282
283 return String(value);
284
285// If the type is 'object', we might be dealing with an object or an array or
286// null.
287
288 case 'object':
289
290// Due to a specification blunder in ECMAScript, typeof null is 'object',
291// so watch out for that case.
292
293 if (!value) {
294 return 'null';
295 }
296
297// Make an array to hold the partial results of stringifying this object value.
298
299 gap += indent;
300 partial = [];
301
302// Is the value an array?
303
304 if (Object.prototype.toString.apply(value) === '[object Array]') {
305
306// The value is an array. Stringify every element. Use null as a placeholder
307// for non-JSON values.
308
309 length = value.length;
310 for (i = 0; i < length; i += 1) {
311 partial[i] = str(i, value) || 'null';
312 }
313
314// Join all of the elements together, separated with commas, and wrap them in
315// brackets.
316
317 v = partial.length === 0 ? '[]' :
318 gap ? '[\n' + gap +
319 partial.join(',\n' + gap) + '\n' +
320 mind + ']' :
321 '[' + partial.join(',') + ']';
322 gap = mind;
323 return v;
324 }
325
326// If the replacer is an array, use it to select the members to be stringified.
327
328 if (rep && typeof rep === 'object') {
329 length = rep.length;
330 for (i = 0; i < length; i += 1) {
331 k = rep[i];
332 if (typeof k === 'string') {
333 v = str(k, value);
334 if (v) {
335 partial.push(quote(k) + (gap ? ': ' : ':') + v);
336 }
337 }
338 }
339 } else {
340
341// Otherwise, iterate through all of the keys in the object.
342
343 for (k in value) {
344 if (Object.hasOwnProperty.call(value, k)) {
345 v = str(k, value);
346 if (v) {
347 partial.push(quote(k) + (gap ? ': ' : ':') + v);
348 }
349 }
350 }
351 }
352
353// Join all of the member texts together, separated with commas,
354// and wrap them in braces.
355
356 v = partial.length === 0 ? '{}' :
357 gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
358 mind + '}' : '{' + partial.join(',') + '}';
359 gap = mind;
360 return v;
361 }
362 }
363
364// If the JSON object does not yet have a stringify method, give it one.
365
366 if (typeof JSON.stringify !== 'function') {
367 JSON.stringify = function (value, replacer, space) {
368
369// The stringify method takes a value and an optional replacer, and an optional
370// space parameter, and returns a JSON text. The replacer can be a function
371// that can replace values, or an array of strings that will select the keys.
372// A default replacer method can be provided. Use of the space parameter can
373// produce text that is more easily readable.
374
375 var i;
376 gap = '';
377 indent = '';
378
379// If the space parameter is a number, make an indent string containing that
380// many spaces.
381
382 if (typeof space === 'number') {
383 for (i = 0; i < space; i += 1) {
384 indent += ' ';
385 }
386
387// If the space parameter is a string, it will be used as the indent string.
388
389 } else if (typeof space === 'string') {
390 indent = space;
391 }
392
393// If there is a replacer, it must be a function or an array.
394// Otherwise, throw an error.
395
396 rep = replacer;
397 if (replacer && typeof replacer !== 'function' &&
398 (typeof replacer !== 'object' ||
399 typeof replacer.length !== 'number')) {
400 throw new Error('JSON.stringify');
401 }
402
403// Make a fake root object containing our value under the key of ''.
404// Return the result of stringifying the value.
405
406 return str('', {'': value});
407 };
408 }
409
410
411// If the JSON object does not yet have a parse method, give it one.
412
413 if (typeof JSON.parse !== 'function') {
414 JSON.parse = function (text, reviver) {
415
416// The parse method takes a text and an optional reviver function, and returns
417// a JavaScript value if the text is a valid JSON text.
418
419 var j;
420
421 function walk(holder, key) {
422
423// The walk method is used to recursively walk the resulting structure so
424// that modifications can be made.
425
426 var k, v, value = holder[key];
427 if (value && typeof value === 'object') {
428 for (k in value) {
429 if (Object.hasOwnProperty.call(value, k)) {
430 v = walk(value, k);
431 if (v !== undefined) {
432 value[k] = v;
433 } else {
434 delete value[k];
435 }
436 }
437 }
438 }
439 return reviver.call(holder, key, value);
440 }
441
442
443// Parsing happens in four stages. In the first stage, we replace certain
444// Unicode characters with escape sequences. JavaScript handles many characters
445// incorrectly, either silently deleting them, or treating them as line endings.
446
447 text = String(text);
448 cx.lastIndex = 0;
449 if (cx.test(text)) {
450 text = text.replace(cx, function (a) {
451 return '\\u' +
452 ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
453 });
454 }
455
456// In the second stage, we run the text against regular expressions that look
457// for non-JSON patterns. We are especially concerned with '()' and 'new'
458// because they can cause invocation, and '=' because it can cause mutation.
459// But just to be safe, we want to reject all unexpected forms.
460
461// We split the second stage into 4 regexp operations in order to work around
462// crippling inefficiencies in IE's and Safari's regexp engines. First we
463// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
464// replace all simple value tokens with ']' characters. Third, we delete all
465// open brackets that follow a colon or comma or that begin the text. Finally,
466// we look to see that the remaining characters are only whitespace or ']' or
467// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
468
469 if (/^[\],:{}\s]*$/
470.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
471.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
472.replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
473
474// In the third stage we use the eval function to compile the text into a
475// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
476// in JavaScript: it can begin a block or an object literal. We wrap the text
477// in parens to eliminate the ambiguity.
478
479 j = eval('(' + text + ')');
480
481// In the optional fourth stage, we recursively walk the new structure, passing
482// each name/value pair to a reviver function for possible transformation.
483
484 return typeof reviver === 'function' ?
485 walk({'': j}, '') : j;
486 }
487
488// If the text is not JSON parseable, then a SyntaxError is thrown.
489
490 throw new SyntaxError('JSON.parse');
491 };
492 }
493}());
494var assert = this.assert = {};
495var types = {};
496var core = {};
497var nodeunit = {};
498var reporter = {};
499/*global setTimeout: false, console: false */
500(function () {
501
502 var async = {};
503
504 // global on the server, window in the browser
505 var root = this,
506 previous_async = root.async;
507
508 if (typeof module !== 'undefined' && module.exports) {
509 module.exports = async;
510 }
511 else {
512 root.async = async;
513 }
514
515 async.noConflict = function () {
516 root.async = previous_async;
517 return async;
518 };
519
520 //// cross-browser compatiblity functions ////
521
522 var _forEach = function (arr, iterator) {
523 if (arr.forEach) {
524 return arr.forEach(iterator);
525 }
526 for (var i = 0; i < arr.length; i += 1) {
527 iterator(arr[i], i, arr);
528 }
529 };
530
531 var _map = function (arr, iterator) {
532 if (arr.map) {
533 return arr.map(iterator);
534 }
535 var results = [];
536 _forEach(arr, function (x, i, a) {
537 results.push(iterator(x, i, a));
538 });
539 return results;
540 };
541
542 var _reduce = function (arr, iterator, memo) {
543 if (arr.reduce) {
544 return arr.reduce(iterator, memo);
545 }
546 _forEach(arr, function (x, i, a) {
547 memo = iterator(memo, x, i, a);
548 });
549 return memo;
550 };
551
552 var _keys = function (obj) {
553 if (Object.keys) {
554 return Object.keys(obj);
555 }
556 var keys = [];
557 for (var k in obj) {
558 if (obj.hasOwnProperty(k)) {
559 keys.push(k);
560 }
561 }
562 return keys;
563 };
564
565 var _indexOf = function (arr, item) {
566 if (arr.indexOf) {
567 return arr.indexOf(item);
568 }
569 for (var i = 0; i < arr.length; i += 1) {
570 if (arr[i] === item) {
571 return i;
572 }
573 }
574 return -1;
575 };
576
577 //// exported async module functions ////
578
579 //// nextTick implementation with browser-compatible fallback ////
580 if (typeof process === 'undefined' || !(process.nextTick)) {
581 async.nextTick = function (fn) {
582 setTimeout(fn, 0);
583 };
584 }
585 else {
586 async.nextTick = process.nextTick;
587 }
588
589 async.forEach = function (arr, iterator, callback) {
590 if (!arr.length) {
591 return callback();
592 }
593 var completed = 0;
594 _forEach(arr, function (x) {
595 iterator(x, function (err) {
596 if (err) {
597 callback(err);
598 callback = function () {};
599 }
600 else {
601 completed += 1;
602 if (completed === arr.length) {
603 callback();
604 }
605 }
606 });
607 });
608 };
609
610 async.forEachSeries = function (arr, iterator, callback) {
611 if (!arr.length) {
612 return callback();
613 }
614 var completed = 0;
615 var iterate = function () {
616 iterator(arr[completed], function (err) {
617 if (err) {
618 callback(err);
619 callback = function () {};
620 }
621 else {
622 completed += 1;
623 if (completed === arr.length) {
624 callback();
625 }
626 else {
627 iterate();
628 }
629 }
630 });
631 };
632 iterate();
633 };
634
635
636 var doParallel = function (fn) {
637 return function () {
638 var args = Array.prototype.slice.call(arguments);
639 return fn.apply(null, [async.forEach].concat(args));
640 };
641 };
642 var doSeries = function (fn) {
643 return function () {
644 var args = Array.prototype.slice.call(arguments);
645 return fn.apply(null, [async.forEachSeries].concat(args));
646 };
647 };
648
649
650 var _asyncMap = function (eachfn, arr, iterator, callback) {
651 var results = [];
652 arr = _map(arr, function (x, i) {
653 return {index: i, value: x};
654 });
655 eachfn(arr, function (x, callback) {
656 iterator(x.value, function (err, v) {
657 results[x.index] = v;
658 callback(err);
659 });
660 }, function (err) {
661 callback(err, results);
662 });
663 };
664 async.map = doParallel(_asyncMap);
665 async.mapSeries = doSeries(_asyncMap);
666
667
668 // reduce only has a series version, as doing reduce in parallel won't
669 // work in many situations.
670 async.reduce = function (arr, memo, iterator, callback) {
671 async.forEachSeries(arr, function (x, callback) {
672 iterator(memo, x, function (err, v) {
673 memo = v;
674 callback(err);
675 });
676 }, function (err) {
677 callback(err, memo);
678 });
679 };
680 // inject alias
681 async.inject = async.reduce;
682 // foldl alias
683 async.foldl = async.reduce;
684
685 async.reduceRight = function (arr, memo, iterator, callback) {
686 var reversed = _map(arr, function (x) {
687 return x;
688 }).reverse();
689 async.reduce(reversed, memo, iterator, callback);
690 };
691 // foldr alias
692 async.foldr = async.reduceRight;
693
694 var _filter = function (eachfn, arr, iterator, callback) {
695 var results = [];
696 arr = _map(arr, function (x, i) {
697 return {index: i, value: x};
698 });
699 eachfn(arr, function (x, callback) {
700 iterator(x.value, function (v) {
701 if (v) {
702 results.push(x);
703 }
704 callback();
705 });
706 }, function (err) {
707 callback(_map(results.sort(function (a, b) {
708 return a.index - b.index;
709 }), function (x) {
710 return x.value;
711 }));
712 });
713 };
714 async.filter = doParallel(_filter);
715 async.filterSeries = doSeries(_filter);
716 // select alias
717 async.select = async.filter;
718 async.selectSeries = async.filterSeries;
719
720 var _reject = function (eachfn, arr, iterator, callback) {
721 var results = [];
722 arr = _map(arr, function (x, i) {
723 return {index: i, value: x};
724 });
725 eachfn(arr, function (x, callback) {
726 iterator(x.value, function (v) {
727 if (!v) {
728 results.push(x);
729 }
730 callback();
731 });
732 }, function (err) {
733 callback(_map(results.sort(function (a, b) {
734 return a.index - b.index;
735 }), function (x) {
736 return x.value;
737 }));
738 });
739 };
740 async.reject = doParallel(_reject);
741 async.rejectSeries = doSeries(_reject);
742
743 var _detect = function (eachfn, arr, iterator, main_callback) {
744 eachfn(arr, function (x, callback) {
745 iterator(x, function (result) {
746 if (result) {
747 main_callback(x);
748 }
749 else {
750 callback();
751 }
752 });
753 }, function (err) {
754 main_callback();
755 });
756 };
757 async.detect = doParallel(_detect);
758 async.detectSeries = doSeries(_detect);
759
760 async.some = function (arr, iterator, main_callback) {
761 async.forEach(arr, function (x, callback) {
762 iterator(x, function (v) {
763 if (v) {
764 main_callback(true);
765 main_callback = function () {};
766 }
767 callback();
768 });
769 }, function (err) {
770 main_callback(false);
771 });
772 };
773 // any alias
774 async.any = async.some;
775
776 async.every = function (arr, iterator, main_callback) {
777 async.forEach(arr, function (x, callback) {
778 iterator(x, function (v) {
779 if (!v) {
780 main_callback(false);
781 main_callback = function () {};
782 }
783 callback();
784 });
785 }, function (err) {
786 main_callback(true);
787 });
788 };
789 // all alias
790 async.all = async.every;
791
792 async.sortBy = function (arr, iterator, callback) {
793 async.map(arr, function (x, callback) {
794 iterator(x, function (err, criteria) {
795 if (err) {
796 callback(err);
797 }
798 else {
799 callback(null, {value: x, criteria: criteria});
800 }
801 });
802 }, function (err, results) {
803 if (err) {
804 return callback(err);
805 }
806 else {
807 var fn = function (left, right) {
808 var a = left.criteria, b = right.criteria;
809 return a < b ? -1 : a > b ? 1 : 0;
810 };
811 callback(null, _map(results.sort(fn), function (x) {
812 return x.value;
813 }));
814 }
815 });
816 };
817
818 async.auto = function (tasks, callback) {
819 callback = callback || function () {};
820 var keys = _keys(tasks);
821 if (!keys.length) {
822 return callback(null);
823 }
824
825 var completed = [];
826
827 var listeners = [];
828 var addListener = function (fn) {
829 listeners.unshift(fn);
830 };
831 var removeListener = function (fn) {
832 for (var i = 0; i < listeners.length; i += 1) {
833 if (listeners[i] === fn) {
834 listeners.splice(i, 1);
835 return;
836 }
837 }
838 };
839 var taskComplete = function () {
840 _forEach(listeners, function (fn) {
841 fn();
842 });
843 };
844
845 addListener(function () {
846 if (completed.length === keys.length) {
847 callback(null);
848 }
849 });
850
851 _forEach(keys, function (k) {
852 var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k];
853 var taskCallback = function (err) {
854 if (err) {
855 callback(err);
856 // stop subsequent errors hitting callback multiple times
857 callback = function () {};
858 }
859 else {
860 completed.push(k);
861 taskComplete();
862 }
863 };
864 var requires = task.slice(0, Math.abs(task.length - 1)) || [];
865 var ready = function () {
866 return _reduce(requires, function (a, x) {
867 return (a && _indexOf(completed, x) !== -1);
868 }, true);
869 };
870 if (ready()) {
871 task[task.length - 1](taskCallback);
872 }
873 else {
874 var listener = function () {
875 if (ready()) {
876 removeListener(listener);
877 task[task.length - 1](taskCallback);
878 }
879 };
880 addListener(listener);
881 }
882 });
883 };
884
885 async.waterfall = function (tasks, callback) {
886 if (!tasks.length) {
887 return callback();
888 }
889 callback = callback || function () {};
890 var wrapIterator = function (iterator) {
891 return function (err) {
892 if (err) {
893 callback(err);
894 callback = function () {};
895 }
896 else {
897 var args = Array.prototype.slice.call(arguments, 1);
898 var next = iterator.next();
899 if (next) {
900 args.push(wrapIterator(next));
901 }
902 else {
903 args.push(callback);
904 }
905 async.nextTick(function () {
906 iterator.apply(null, args);
907 });
908 }
909 };
910 };
911 wrapIterator(async.iterator(tasks))();
912 };
913
914 async.parallel = function (tasks, callback) {
915 callback = callback || function () {};
916 if (tasks.constructor === Array) {
917 async.map(tasks, function (fn, callback) {
918 if (fn) {
919 fn(function (err) {
920 var args = Array.prototype.slice.call(arguments, 1);
921 if (args.length <= 1) {
922 args = args[0];
923 }
924 callback.call(null, err, args || null);
925 });
926 }
927 }, callback);
928 }
929 else {
930 var results = {};
931 async.forEach(_keys(tasks), function (k, callback) {
932 tasks[k](function (err) {
933 var args = Array.prototype.slice.call(arguments, 1);
934 if (args.length <= 1) {
935 args = args[0];
936 }
937 results[k] = args;
938 callback(err);
939 });
940 }, function (err) {
941 callback(err, results);
942 });
943 }
944 };
945
946 async.series = function (tasks, callback) {
947 callback = callback || function () {};
948 if (tasks.constructor === Array) {
949 async.mapSeries(tasks, function (fn, callback) {
950 if (fn) {
951 fn(function (err) {
952 var args = Array.prototype.slice.call(arguments, 1);
953 if (args.length <= 1) {
954 args = args[0];
955 }
956 callback.call(null, err, args || null);
957 });
958 }
959 }, callback);
960 }
961 else {
962 var results = {};
963 async.forEachSeries(_keys(tasks), function (k, callback) {
964 tasks[k](function (err) {
965 var args = Array.prototype.slice.call(arguments, 1);
966 if (args.length <= 1) {
967 args = args[0];
968 }
969 results[k] = args;
970 callback(err);
971 });
972 }, function (err) {
973 callback(err, results);
974 });
975 }
976 };
977
978 async.iterator = function (tasks) {
979 var makeCallback = function (index) {
980 var fn = function () {
981 if (tasks.length) {
982 tasks[index].apply(null, arguments);
983 }
984 return fn.next();
985 };
986 fn.next = function () {
987 return (index < tasks.length - 1) ? makeCallback(index + 1): null;
988 };
989 return fn;
990 };
991 return makeCallback(0);
992 };
993
994 async.apply = function (fn) {
995 var args = Array.prototype.slice.call(arguments, 1);
996 return function () {
997 return fn.apply(
998 null, args.concat(Array.prototype.slice.call(arguments))
999 );
1000 };
1001 };
1002
1003 var _concat = function (eachfn, arr, fn, callback) {
1004 var r = [];
1005 eachfn(arr, function (x, cb) {
1006 fn(x, function (err, y) {
1007 r = r.concat(y || []);
1008 cb(err);
1009 });
1010 }, function (err) {
1011 callback(err, r);
1012 });
1013 };
1014 async.concat = doParallel(_concat);
1015 async.concatSeries = doSeries(_concat);
1016
1017 async.whilst = function (test, iterator, callback) {
1018 if (test()) {
1019 iterator(function (err) {
1020 if (err) {
1021 return callback(err);
1022 }
1023 async.whilst(test, iterator, callback);
1024 });
1025 }
1026 else {
1027 callback();
1028 }
1029 };
1030
1031 async.until = function (test, iterator, callback) {
1032 if (!test()) {
1033 iterator(function (err) {
1034 if (err) {
1035 return callback(err);
1036 }
1037 async.until(test, iterator, callback);
1038 });
1039 }
1040 else {
1041 callback();
1042 }
1043 };
1044
1045 async.queue = function (worker, concurrency) {
1046 var workers = 0;
1047 var tasks = [];
1048 var q = {
1049 concurrency: concurrency,
1050 push: function (data, callback) {
1051 tasks.push({data: data, callback: callback});
1052 async.nextTick(q.process);
1053 },
1054 process: function () {
1055 if (workers < q.concurrency && tasks.length) {
1056 var task = tasks.splice(0, 1)[0];
1057 workers += 1;
1058 worker(task.data, function () {
1059 workers -= 1;
1060 if (task.callback) {
1061 task.callback.apply(task, arguments);
1062 }
1063 q.process();
1064 });
1065 }
1066 },
1067 length: function () {
1068 return tasks.length;
1069 }
1070 };
1071 return q;
1072 };
1073
1074 var _console_fn = function (name) {
1075 return function (fn) {
1076 var args = Array.prototype.slice.call(arguments, 1);
1077 fn.apply(null, args.concat([function (err) {
1078 var args = Array.prototype.slice.call(arguments, 1);
1079 if (typeof console !== 'undefined') {
1080 if (err) {
1081 if (console.error) {
1082 console.error(err);
1083 }
1084 }
1085 else if (console[name]) {
1086 _forEach(args, function (x) {
1087 console[name](x);
1088 });
1089 }
1090 }
1091 }]));
1092 };
1093 };
1094 async.log = _console_fn('log');
1095 async.dir = _console_fn('dir');
1096 /*async.info = _console_fn('info');
1097 async.warn = _console_fn('warn');
1098 async.error = _console_fn('error');*/
1099
1100 async.memoize = function (fn, hasher) {
1101 var memo = {};
1102 hasher = hasher || function (x) {
1103 return x;
1104 };
1105 return function () {
1106 var args = Array.prototype.slice.call(arguments);
1107 var callback = args.pop();
1108 var key = hasher.apply(null, args);
1109 if (key in memo) {
1110 callback.apply(null, memo[key]);
1111 }
1112 else {
1113 fn.apply(null, args.concat([function () {
1114 memo[key] = arguments;
1115 callback.apply(null, arguments);
1116 }]));
1117 }
1118 };
1119 };
1120
1121}());
1122(function(exports){
1123/**
1124 * This file is based on the node.js assert module, but with some small
1125 * changes for browser-compatibility
1126 * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1127 */
1128
1129
1130/**
1131 * Added for browser compatibility
1132 */
1133
1134var _keys = function(obj){
1135 if(Object.keys) return Object.keys(obj);
1136 if (typeof obj != 'object' && typeof obj != 'function') {
1137 throw new TypeError('-');
1138 }
1139 var keys = [];
1140 for(var k in obj){
1141 if(obj.hasOwnProperty(k)) keys.push(k);
1142 }
1143 return keys;
1144};
1145
1146
1147
1148// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
1149//
1150// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
1151//
1152// Originally from narwhal.js (http://narwhaljs.org)
1153// Copyright (c) 2009 Thomas Robinson <280north.com>
1154//
1155// Permission is hereby granted, free of charge, to any person obtaining a copy
1156// of this software and associated documentation files (the 'Software'), to
1157// deal in the Software without restriction, including without limitation the
1158// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
1159// sell copies of the Software, and to permit persons to whom the Software is
1160// furnished to do so, subject to the following conditions:
1161//
1162// The above copyright notice and this permission notice shall be included in
1163// all copies or substantial portions of the Software.
1164//
1165// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1166// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1167// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1168// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1169// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1170// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1171
1172
1173var pSlice = Array.prototype.slice;
1174
1175// 1. The assert module provides functions that throw
1176// AssertionError's when particular conditions are not met. The
1177// assert module must conform to the following interface.
1178
1179var assert = exports;
1180
1181// 2. The AssertionError is defined in assert.
1182// new assert.AssertionError({message: message, actual: actual, expected: expected})
1183
1184assert.AssertionError = function AssertionError (options) {
1185 this.name = "AssertionError";
1186 this.message = options.message;
1187 this.actual = options.actual;
1188 this.expected = options.expected;
1189 this.operator = options.operator;
1190 var stackStartFunction = options.stackStartFunction || fail;
1191
1192 if (Error.captureStackTrace) {
1193 Error.captureStackTrace(this, stackStartFunction);
1194 }
1195};
1196// code from util.inherits in node
1197assert.AssertionError.super_ = Error;
1198
1199
1200// EDITED FOR BROWSER COMPATIBILITY: replaced Object.create call
1201// TODO: test what effect this may have
1202var ctor = function () { this.constructor = assert.AssertionError; };
1203ctor.prototype = Error.prototype;
1204assert.AssertionError.prototype = new ctor();
1205
1206
1207assert.AssertionError.prototype.toString = function() {
1208 if (this.message) {
1209 return [this.name+":", this.message].join(' ');
1210 } else {
1211 return [ this.name+":"
1212 , JSON.stringify(this.expected )
1213 , this.operator
1214 , JSON.stringify(this.actual)
1215 ].join(" ");
1216 }
1217};
1218
1219// assert.AssertionError instanceof Error
1220
1221assert.AssertionError.__proto__ = Error.prototype;
1222
1223// At present only the three keys mentioned above are used and
1224// understood by the spec. Implementations or sub modules can pass
1225// other keys to the AssertionError's constructor - they will be
1226// ignored.
1227
1228// 3. All of the following functions must throw an AssertionError
1229// when a corresponding condition is not met, with a message that
1230// may be undefined if not provided. All assertion methods provide
1231// both the actual and expected values to the assertion error for
1232// display purposes.
1233
1234function fail(actual, expected, message, operator, stackStartFunction) {
1235 throw new assert.AssertionError({
1236 message: message,
1237 actual: actual,
1238 expected: expected,
1239 operator: operator,
1240 stackStartFunction: stackStartFunction
1241 });
1242}
1243
1244// EXTENSION! allows for well behaved errors defined elsewhere.
1245assert.fail = fail;
1246
1247// 4. Pure assertion tests whether a value is truthy, as determined
1248// by !!guard.
1249// assert.ok(guard, message_opt);
1250// This statement is equivalent to assert.equal(true, guard,
1251// message_opt);. To test strictly for the value true, use
1252// assert.strictEqual(true, guard, message_opt);.
1253
1254assert.ok = function ok(value, message) {
1255 if (!!!value) fail(value, true, message, "==", assert.ok);
1256};
1257
1258// 5. The equality assertion tests shallow, coercive equality with
1259// ==.
1260// assert.equal(actual, expected, message_opt);
1261
1262assert.equal = function equal(actual, expected, message) {
1263 if (actual != expected) fail(actual, expected, message, "==", assert.equal);
1264};
1265
1266// 6. The non-equality assertion tests for whether two objects are not equal
1267// with != assert.notEqual(actual, expected, message_opt);
1268
1269assert.notEqual = function notEqual(actual, expected, message) {
1270 if (actual == expected) {
1271 fail(actual, expected, message, "!=", assert.notEqual);
1272 }
1273};
1274
1275// 7. The equivalence assertion tests a deep equality relation.
1276// assert.deepEqual(actual, expected, message_opt);
1277
1278assert.deepEqual = function deepEqual(actual, expected, message) {
1279 if (!_deepEqual(actual, expected)) {
1280 fail(actual, expected, message, "deepEqual", assert.deepEqual);
1281 }
1282};
1283
1284function _deepEqual(actual, expected) {
1285 // 7.1. All identical values are equivalent, as determined by ===.
1286 if (actual === expected) {
1287 return true;
1288 // 7.2. If the expected value is a Date object, the actual value is
1289 // equivalent if it is also a Date object that refers to the same time.
1290 } else if (actual instanceof Date && expected instanceof Date) {
1291 return actual.getTime() === expected.getTime();
1292
1293 // 7.3. Other pairs that do not both pass typeof value == "object",
1294 // equivalence is determined by ==.
1295 } else if (typeof actual != 'object' && typeof expected != 'object') {
1296 return actual == expected;
1297
1298 // 7.4. For all other Object pairs, including Array objects, equivalence is
1299 // determined by having the same number of owned properties (as verified
1300 // with Object.prototype.hasOwnProperty.call), the same set of keys
1301 // (although not necessarily the same order), equivalent values for every
1302 // corresponding key, and an identical "prototype" property. Note: this
1303 // accounts for both named and indexed properties on Arrays.
1304 } else {
1305 return objEquiv(actual, expected);
1306 }
1307}
1308
1309function isUndefinedOrNull (value) {
1310 return value === null || value === undefined;
1311}
1312
1313function isArguments (object) {
1314 return Object.prototype.toString.call(object) == '[object Arguments]';
1315}
1316
1317function objEquiv (a, b) {
1318 if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
1319 return false;
1320 // an identical "prototype" property.
1321 if (a.prototype !== b.prototype) return false;
1322 //~~~I've managed to break Object.keys through screwy arguments passing.
1323 // Converting to array solves the problem.
1324 if (isArguments(a)) {
1325 if (!isArguments(b)) {
1326 return false;
1327 }
1328 a = pSlice.call(a);
1329 b = pSlice.call(b);
1330 return _deepEqual(a, b);
1331 }
1332 try{
1333 var ka = _keys(a),
1334 kb = _keys(b),
1335 key, i;
1336 } catch (e) {//happens when one is a string literal and the other isn't
1337 return false;
1338 }
1339 // having the same number of owned properties (keys incorporates hasOwnProperty)
1340 if (ka.length != kb.length)
1341 return false;
1342 //the same set of keys (although not necessarily the same order),
1343 ka.sort();
1344 kb.sort();
1345 //~~~cheap key test
1346 for (i = ka.length - 1; i >= 0; i--) {
1347 if (ka[i] != kb[i])
1348 return false;
1349 }
1350 //equivalent values for every corresponding key, and
1351 //~~~possibly expensive deep test
1352 for (i = ka.length - 1; i >= 0; i--) {
1353 key = ka[i];
1354 if (!_deepEqual(a[key], b[key] ))
1355 return false;
1356 }
1357 return true;
1358}
1359
1360// 8. The non-equivalence assertion tests for any deep inequality.
1361// assert.notDeepEqual(actual, expected, message_opt);
1362
1363assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
1364 if (_deepEqual(actual, expected)) {
1365 fail(actual, expected, message, "notDeepEqual", assert.notDeepEqual);
1366 }
1367};
1368
1369// 9. The strict equality assertion tests strict equality, as determined by ===.
1370// assert.strictEqual(actual, expected, message_opt);
1371
1372assert.strictEqual = function strictEqual(actual, expected, message) {
1373 if (actual !== expected) {
1374 fail(actual, expected, message, "===", assert.strictEqual);
1375 }
1376};
1377
1378// 10. The strict non-equality assertion tests for strict inequality, as determined by !==.
1379// assert.notStrictEqual(actual, expected, message_opt);
1380
1381assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
1382 if (actual === expected) {
1383 fail(actual, expected, message, "!==", assert.notStrictEqual);
1384 }
1385};
1386
1387function _throws (shouldThrow, block, err, message) {
1388 var exception = null,
1389 threw = false,
1390 typematters = true;
1391
1392 message = message || "";
1393
1394 //handle optional arguments
1395 if (arguments.length == 3) {
1396 if (typeof(err) == "string") {
1397 message = err;
1398 typematters = false;
1399 }
1400 } else if (arguments.length == 2) {
1401 typematters = false;
1402 }
1403
1404 try {
1405 block();
1406 } catch (e) {
1407 threw = true;
1408 exception = e;
1409 }
1410
1411 if (shouldThrow && !threw) {
1412 fail( "Missing expected exception"
1413 + (err && err.name ? " ("+err.name+")." : '.')
1414 + (message ? " " + message : "")
1415 );
1416 }
1417 if (!shouldThrow && threw && typematters && exception instanceof err) {
1418 fail( "Got unwanted exception"
1419 + (err && err.name ? " ("+err.name+")." : '.')
1420 + (message ? " " + message : "")
1421 );
1422 }
1423 if ((shouldThrow && threw && typematters && !(exception instanceof err)) ||
1424 (!shouldThrow && threw)) {
1425 throw exception;
1426 }
1427};
1428
1429// 11. Expected to throw an error:
1430// assert.throws(block, Error_opt, message_opt);
1431
1432assert.throws = function(block, /*optional*/error, /*optional*/message) {
1433 _throws.apply(this, [true].concat(pSlice.call(arguments)));
1434};
1435
1436// EXTENSION! This is annoying to write outside this module.
1437assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
1438 _throws.apply(this, [false].concat(pSlice.call(arguments)));
1439};
1440
1441assert.ifError = function (err) { if (err) {throw err;}};
1442})(assert);
1443(function(exports){
1444/*!
1445 * Nodeunit
1446 * Copyright (c) 2010 Caolan McMahon
1447 * MIT Licensed
1448 *
1449 * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1450 * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
1451 * Only code on that line will be removed, its mostly to avoid requiring code
1452 * that is node specific
1453 */
1454
1455/**
1456 * Module dependencies
1457 */
1458
1459//var assert = require('./assert'), //@REMOVE_LINE_FOR_BROWSER
1460// async = require('../deps/async'); //@REMOVE_LINE_FOR_BROWSER
1461
1462
1463/**
1464 * Creates assertion objects representing the result of an assert call.
1465 * Accepts an object or AssertionError as its argument.
1466 *
1467 * @param {object} obj
1468 * @api public
1469 */
1470
1471exports.assertion = function (obj) {
1472 return {
1473 method: obj.method || '',
1474 message: obj.message || (obj.error && obj.error.message) || '',
1475 error: obj.error,
1476 passed: function () {
1477 return !this.error;
1478 },
1479 failed: function () {
1480 return Boolean(this.error);
1481 }
1482 };
1483};
1484
1485/**
1486 * Creates an assertion list object representing a group of assertions.
1487 * Accepts an array of assertion objects.
1488 *
1489 * @param {Array} arr
1490 * @param {Number} duration
1491 * @api public
1492 */
1493
1494exports.assertionList = function (arr, duration) {
1495 var that = arr || [];
1496 that.failures = function () {
1497 var failures = 0;
1498 for (var i = 0; i < this.length; i += 1) {
1499 if (this[i].failed()) {
1500 failures += 1;
1501 }
1502 }
1503 return failures;
1504 };
1505 that.passes = function () {
1506 return that.length - that.failures();
1507 };
1508 that.duration = duration || 0;
1509 return that;
1510};
1511
1512/**
1513 * Create a wrapper function for assert module methods. Executes a callback
1514 * after the it's complete with an assertion object representing the result.
1515 *
1516 * @param {Function} callback
1517 * @api private
1518 */
1519
1520var assertWrapper = function (callback) {
1521 return function (new_method, assert_method, arity) {
1522 return function () {
1523 var message = arguments[arity - 1];
1524 var a = exports.assertion({method: new_method, message: message});
1525 try {
1526 assert[assert_method].apply(null, arguments);
1527 }
1528 catch (e) {
1529 a.error = e;
1530 }
1531 callback(a);
1532 };
1533 };
1534};
1535
1536/**
1537 * Creates the 'test' object that gets passed to every test function.
1538 * Accepts the name of the test function as its first argument, followed by
1539 * the start time in ms, the options object and a callback function.
1540 *
1541 * @param {String} name
1542 * @param {Number} start
1543 * @param {Object} options
1544 * @param {Function} callback
1545 * @api public
1546 */
1547
1548exports.test = function (name, start, options, callback) {
1549 var expecting;
1550 var a_list = [];
1551
1552 var wrapAssert = assertWrapper(function (a) {
1553 a_list.push(a);
1554 if (options.log) {
1555 async.nextTick(function () {
1556 options.log(a);
1557 });
1558 }
1559 });
1560
1561 var test = {
1562 done: function (err) {
1563 if (expecting !== undefined && expecting !== a_list.length) {
1564 var e = new Error(
1565 'Expected ' + expecting + ' assertions, ' +
1566 a_list.length + ' ran'
1567 );
1568 var a1 = exports.assertion({method: 'expect', error: e});
1569 a_list.push(a1);
1570 if (options.log) {
1571 async.nextTick(function () {
1572 options.log(a1);
1573 });
1574 }
1575 }
1576 if (err) {
1577 var a2 = exports.assertion({error: err});
1578 a_list.push(a2);
1579 if (options.log) {
1580 async.nextTick(function () {
1581 options.log(a2);
1582 });
1583 }
1584 }
1585 var end = new Date().getTime();
1586 async.nextTick(function () {
1587 var assertion_list = exports.assertionList(a_list, end - start);
1588 options.testDone(name, assertion_list);
1589 callback(null, a_list);
1590 });
1591 },
1592 ok: wrapAssert('ok', 'ok', 2),
1593 same: wrapAssert('same', 'deepEqual', 3),
1594 equals: wrapAssert('equals', 'equal', 3),
1595 expect: function (num) {
1596 expecting = num;
1597 },
1598 _assertion_list: a_list
1599 };
1600 // add all functions from the assert module
1601 for (var k in assert) {
1602 if (assert.hasOwnProperty(k)) {
1603 test[k] = wrapAssert(k, k, assert[k].length);
1604 }
1605 }
1606 return test;
1607};
1608
1609/**
1610 * Ensures an options object has all callbacks, adding empty callback functions
1611 * if any are missing.
1612 *
1613 * @param {Object} opt
1614 * @return {Object}
1615 * @api public
1616 */
1617
1618exports.options = function (opt) {
1619 var optionalCallback = function (name) {
1620 opt[name] = opt[name] || function () {};
1621 };
1622
1623 optionalCallback('moduleStart');
1624 optionalCallback('moduleDone');
1625 optionalCallback('testStart');
1626 optionalCallback('testDone');
1627 //optionalCallback('log');
1628
1629 // 'done' callback is not optional.
1630
1631 return opt;
1632};
1633})(types);
1634(function(exports){
1635/*!
1636 * Nodeunit
1637 * Copyright (c) 2010 Caolan McMahon
1638 * MIT Licensed
1639 *
1640 * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1641 * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
1642 * Only code on that line will be removed, its mostly to avoid requiring code
1643 * that is node specific
1644 */
1645
1646/**
1647 * Module dependencies
1648 */
1649
1650//var async = require('../deps/async'), //@REMOVE_LINE_FOR_BROWSER
1651// types = require('./types'); //@REMOVE_LINE_FOR_BROWSER
1652
1653
1654/**
1655 * Added for browser compatibility
1656 */
1657
1658var _keys = function (obj) {
1659 if (Object.keys) {
1660 return Object.keys(obj);
1661 }
1662 var keys = [];
1663 for (var k in obj) {
1664 if (obj.hasOwnProperty(k)) {
1665 keys.push(k);
1666 }
1667 }
1668 return keys;
1669};
1670
1671
1672var _copy = function (obj) {
1673 var nobj = {};
1674 var keys = _keys(obj);
1675 for (var i = 0; i < keys.length; i += 1) {
1676 nobj[keys[i]] = obj[keys[i]];
1677 }
1678 return nobj;
1679};
1680
1681
1682/**
1683 * Runs a test function (fn) from a loaded module. After the test function
1684 * calls test.done(), the callback is executed with an assertionList as its
1685 * second argument.
1686 *
1687 * @param {String} name
1688 * @param {Function} fn
1689 * @param {Object} opt
1690 * @param {Function} callback
1691 * @api public
1692 */
1693
1694exports.runTest = function (name, fn, opt, callback) {
1695 var options = types.options(opt);
1696
1697 options.testStart(name);
1698 var start = new Date().getTime();
1699 var test = types.test(name, start, options, callback);
1700
1701 try {
1702 fn(test);
1703 }
1704 catch (e) {
1705 test.done(e);
1706 }
1707};
1708
1709/**
1710 * Takes an object containing test functions or other test suites as properties
1711 * and runs each in series. After all tests have completed, the callback is
1712 * called with a list of all assertions as the second argument.
1713 *
1714 * If a name is passed to this function it is prepended to all test and suite
1715 * names that run within it.
1716 *
1717 * @param {String} name
1718 * @param {Object} suite
1719 * @param {Object} opt
1720 * @param {Function} callback
1721 * @api public
1722 */
1723
1724exports.runSuite = function (name, suite, opt, callback) {
1725 var keys = _keys(suite);
1726
1727 async.concatSeries(keys, function (k, cb) {
1728 var prop = suite[k], _name;
1729
1730 _name = name ? [].concat(name, k) : [k];
1731
1732 _name.toString = function () {
1733 // fallback for old one
1734 return this.join(' - ');
1735 };
1736
1737 if (typeof prop === 'function') {
1738 var in_name = false;
1739 for (var i = 0; i < _name.length; i += 1) {
1740 if (_name[i] === opt.testspec) {
1741 in_name = true;
1742 }
1743 }
1744 if (!opt.testspec || in_name) {
1745 if (opt.moduleStart) {
1746 opt.moduleStart();
1747 }
1748 exports.runTest(_name, suite[k], opt, cb);
1749 }
1750 else {
1751 return cb();
1752 }
1753 }
1754 else {
1755 exports.runSuite(_name, suite[k], opt, cb);
1756 }
1757 }, callback);
1758};
1759
1760/**
1761 * Run each exported test function or test suite from a loaded module.
1762 *
1763 * @param {String} name
1764 * @param {Object} mod
1765 * @param {Object} opt
1766 * @param {Function} callback
1767 * @api public
1768 */
1769
1770exports.runModule = function (name, mod, opt, callback) {
1771 var options = _copy(types.options(opt));
1772
1773 var _run = false;
1774 var _moduleStart = options.moduleStart;
1775 function run_once() {
1776 if (!_run) {
1777 _run = true;
1778 _moduleStart(name);
1779 }
1780 }
1781 options.moduleStart = run_once;
1782
1783 var start = new Date().getTime();
1784
1785 exports.runSuite(null, mod, options, function (err, a_list) {
1786 var end = new Date().getTime();
1787 var assertion_list = types.assertionList(a_list, end - start);
1788 options.moduleDone(name, assertion_list);
1789 callback(null, a_list);
1790 });
1791};
1792
1793/**
1794 * Treats an object literal as a list of modules keyed by name. Runs each
1795 * module and finished with calling 'done'. You can think of this as a browser
1796 * safe alternative to runFiles in the nodeunit module.
1797 *
1798 * @param {Object} modules
1799 * @param {Object} opt
1800 * @api public
1801 */
1802
1803// TODO: add proper unit tests for this function
1804exports.runModules = function (modules, opt) {
1805 var all_assertions = [];
1806 var options = types.options(opt);
1807 var start = new Date().getTime();
1808
1809 async.concatSeries(_keys(modules), function (k, cb) {
1810 exports.runModule(k, modules[k], options, cb);
1811 },
1812 function (err, all_assertions) {
1813 var end = new Date().getTime();
1814 options.done(types.assertionList(all_assertions, end - start));
1815 });
1816};
1817
1818
1819/**
1820 * Wraps a test function with setUp and tearDown functions.
1821 * Used by testCase.
1822 *
1823 * @param {Function} setUp
1824 * @param {Function} tearDown
1825 * @param {Function} fn
1826 * @api private
1827 */
1828
1829var wrapTest = function (setUp, tearDown, fn) {
1830 return function (test) {
1831 var context = {};
1832 if (tearDown) {
1833 var done = test.done;
1834 test.done = function (err) {
1835 try {
1836 tearDown.call(context, function (err2) {
1837 if (err && err2) {
1838 test._assertion_list.push(
1839 types.assertion({error: err})
1840 );
1841 return done(err2);
1842 }
1843 done(err || err2);
1844 });
1845 }
1846 catch (e) {
1847 done(e);
1848 }
1849 };
1850 }
1851 if (setUp) {
1852 setUp.call(context, function (err) {
1853 if (err) {
1854 return test.done(err);
1855 }
1856 fn.call(context, test);
1857 });
1858 }
1859 else {
1860 fn.call(context, test);
1861 }
1862 };
1863};
1864
1865
1866/**
1867 * Wraps a group of tests with setUp and tearDown functions.
1868 * Used by testCase.
1869 *
1870 * @param {Function} setUp
1871 * @param {Function} tearDown
1872 * @param {Object} group
1873 * @api private
1874 */
1875
1876var wrapGroup = function (setUp, tearDown, group) {
1877 var tests = {};
1878 var keys = _keys(group);
1879 for (var i = 0; i < keys.length; i += 1) {
1880 var k = keys[i];
1881 if (typeof group[k] === 'function') {
1882 tests[k] = wrapTest(setUp, tearDown, group[k]);
1883 }
1884 else if (typeof group[k] === 'object') {
1885 tests[k] = wrapGroup(setUp, tearDown, group[k]);
1886 }
1887 }
1888 return tests;
1889};
1890
1891
1892/**
1893 * Utility for wrapping a suite of test functions with setUp and tearDown
1894 * functions.
1895 *
1896 * @param {Object} suite
1897 * @return {Object}
1898 * @api public
1899 */
1900
1901exports.testCase = function (suite) {
1902 var setUp = suite.setUp;
1903 var tearDown = suite.tearDown;
1904 delete suite.setUp;
1905 delete suite.tearDown;
1906 return wrapGroup(setUp, tearDown, suite);
1907};
1908})(core);
1909(function(exports){
1910/*!
1911 * Nodeunit
1912 * Copyright (c) 2010 Caolan McMahon
1913 * MIT Licensed
1914 *
1915 * THIS FILE SHOULD BE BROWSER-COMPATIBLE JS!
1916 * You can use @REMOVE_LINE_FOR_BROWSER to remove code from the browser build.
1917 * Only code on that line will be removed, its mostly to avoid requiring code
1918 * that is node specific
1919 */
1920
1921
1922/**
1923 * NOTE: this test runner is not listed in index.js because it cannot be
1924 * used with the command-line tool, only inside the browser.
1925 */
1926
1927
1928/**
1929 * Reporter info string
1930 */
1931
1932exports.info = "Browser-based test reporter";
1933
1934
1935/**
1936 * Run all tests within each module, reporting the results
1937 *
1938 * @param {Array} files
1939 * @api public
1940 */
1941
1942exports.run = function (modules, options) {
1943 options = options || {};
1944 var start = new Date().getTime();
1945 var textareas = options.textareas;
1946 var displayErrorsByDefault = options.displayErrorsByDefault;
1947
1948 function setText(el, txt) {
1949 if ('innerText' in el) {
1950 el.innerText = txt;
1951 }
1952 else if ('textContent' in el){
1953 el.textContent = txt;
1954 }
1955 }
1956
1957 function getOrCreate(tag, id) {
1958 var el = document.getElementById(id);
1959 if (!el) {
1960 el = document.createElement(tag);
1961 el.id = id;
1962 document.body.appendChild(el);
1963 }
1964 return el;
1965 };
1966
1967 var header = getOrCreate('h1', 'nodeunit-header');
1968 var banner = getOrCreate('h2', 'nodeunit-banner');
1969 var userAgent = getOrCreate('h2', 'nodeunit-userAgent');
1970 var tests = getOrCreate('ol', 'nodeunit-tests');
1971 var result = getOrCreate('p', 'nodeunit-testresult');
1972
1973 setText(userAgent, navigator.userAgent);
1974
1975 nodeunit.runModules(modules, {
1976 moduleStart: function (name) {
1977 /*var mheading = document.createElement('h2');
1978 mheading.innerText = name;
1979 results.appendChild(mheading);
1980 module = document.createElement('ol');
1981 results.appendChild(module);*/
1982 },
1983 testDone: function (name, assertions) {
1984 var test = document.createElement('li');
1985 var strong = document.createElement('strong');
1986 strong.innerHTML = name + ' <b style="color: black;">(' +
1987 '<b class="fail">' + assertions.failures() + '</b>, ' +
1988 '<b class="pass">' + assertions.passes() + '</b>, ' +
1989 assertions.length +
1990 ')</b>';
1991 test.className = assertions.failures() ? 'fail': 'pass';
1992 test.appendChild(strong);
1993
1994 var aList = document.createElement('ol');
1995 aList.style.display = displayErrorsByDefault ? 'block' : 'none';
1996 (displayErrorsByDefault ? strong : test).onclick = function () {
1997 var d = aList.style.display;
1998 aList.style.display = (d == 'none') ? 'block': 'none';
1999 };
2000 for (var i=0; i<assertions.length; i++) {
2001 var li = document.createElement('li');
2002 var a = assertions[i];
2003 if (a.failed()) {
2004 li.innerHTML = (a.message || a.method || 'no message') +
2005 (textareas ?
2006 '<textarea rows="20" cols="100">' + (a.error.stack || a.error) + '</textarea>' :
2007 '<pre>' + (a.error.stack || a.error) + '</pre>');
2008 li.className = 'fail';
2009 }
2010 else {
2011 li.innerHTML = a.message || a.method || 'no message';
2012 li.className = 'pass';
2013 }
2014 aList.appendChild(li);
2015 }
2016 test.appendChild(aList);
2017 tests.appendChild(test);
2018 },
2019 done: function (assertions) {
2020 var end = new Date().getTime();
2021 var duration = end - start;
2022
2023 var failures = assertions.failures();
2024 banner.className = failures ? 'fail': 'pass';
2025
2026 result.innerHTML = 'Tests completed in ' + duration +
2027 ' milliseconds.<br/><span class="passed">' +
2028 assertions.passes() + '</span> assertions of ' +
2029 '<span class="all">' + assertions.length + '<span> passed, ' +
2030 assertions.failures() + ' failed.';
2031 }
2032 });
2033};
2034})(reporter);
2035nodeunit = core;
2036nodeunit.assert = assert;
2037nodeunit.reporter = reporter;
2038nodeunit.run = reporter.run;
2039return nodeunit; })();