smparkes-jazrb 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/README.rdoc +2 -0
  2. data/bin/jazrb +46 -14
  3. data/doc/jasmine/files.html +165 -11
  4. data/doc/jasmine/index.html +5 -13
  5. data/doc/jasmine/symbols/_global_.html +145 -19
  6. data/doc/jasmine/symbols/jasmine.Block.html +72 -6
  7. data/doc/jasmine/symbols/jasmine.Clock.html +678 -0
  8. data/doc/jasmine/symbols/jasmine.Env.html +632 -16
  9. data/doc/jasmine/symbols/jasmine.EnvjsReporter.html +1 -1
  10. data/doc/jasmine/symbols/jasmine.JsApiReporter.html +500 -6
  11. data/doc/jasmine/symbols/jasmine.Matchers.html +228 -9
  12. data/doc/jasmine/symbols/jasmine.MultiReporter.html +72 -6
  13. data/doc/jasmine/symbols/jasmine.NestedResults.html +5 -7
  14. data/doc/jasmine/symbols/jasmine.Reporter.html +252 -6
  15. data/doc/jasmine/symbols/jasmine.Runner.html +377 -6
  16. data/doc/jasmine/symbols/jasmine.Spec.html +972 -8
  17. data/doc/jasmine/symbols/jasmine.Spy.html +6 -8
  18. data/doc/jasmine/symbols/jasmine.Suite.html +354 -6
  19. data/doc/jasmine/symbols/jasmine.XMLReporter.html +1 -1
  20. data/doc/jasmine/symbols/jasmine.html +571 -18
  21. data/doc/jasmine/symbols/jasmine.util.html +213 -6
  22. data/doc/jasmine/symbols/src/src_Block.js.html +29 -0
  23. data/doc/jasmine/symbols/src/src_Env.js.html +232 -0
  24. data/doc/jasmine/symbols/src/src_JsApiReporter.js.html +110 -0
  25. data/doc/jasmine/symbols/src/src_Matchers.js.html +399 -0
  26. data/doc/jasmine/symbols/src/src_MultiReporter.js.html +36 -0
  27. data/doc/jasmine/symbols/src/src_NestedResults.js.html +88 -0
  28. data/doc/jasmine/symbols/src/src_PrettyPrinter.js.html +128 -0
  29. data/doc/jasmine/symbols/src/src_Queue.js.html +119 -0
  30. data/doc/jasmine/symbols/src/src_Reporter.js.html +35 -0
  31. data/doc/jasmine/symbols/src/src_Reporters.js.html +51 -0
  32. data/doc/jasmine/symbols/src/src_Runner.js.html +75 -0
  33. data/doc/jasmine/symbols/src/src_Spec.js.html +228 -0
  34. data/doc/jasmine/symbols/src/src_Suite.js.html +77 -0
  35. data/doc/jasmine/symbols/src/src_WaitsBlock.js.html +21 -0
  36. data/doc/jasmine/symbols/src/src_WaitsForBlock.js.html +45 -0
  37. data/doc/jasmine/symbols/src/src_base.js.html +557 -0
  38. data/doc/jasmine/symbols/src/src_mock-timeout.js.html +185 -0
  39. data/doc/jasmine/symbols/src/src_util.js.html +75 -0
  40. data/lib/jazrb/intro.js +32 -3
  41. data/lib/jazrb/jasmine/XMLReporter.js +36 -2
  42. data/lib/jazrb/jasmine/jasmine-0.10.0.js +73 -15
  43. data/lib/jazrb/jasmine/jasmine.js +73 -15
  44. data/lib/jazrb/options.rb +5 -0
  45. data/lib/jazrb/qintro.js +113 -0
  46. data/lib/jazrb/qoutro.js +3 -0
  47. data/lib/jazrb/qunit/qunit.css +17 -0
  48. data/lib/jazrb/qunit/qunit.js +1027 -0
  49. metadata +26 -7
  50. data/doc/jasmine/symbols/src/lib_consolex.js.html +0 -35
  51. data/doc/jasmine/symbols/src/lib_jasmine-0.10.0.js.html +0 -2302
  52. data/doc/jasmine/symbols/src/lib_jasmine-0.9.0.js.html +0 -2212
  53. data/doc/jasmine/symbols/src/lib_json2.js.html +0 -486
@@ -0,0 +1,1027 @@
1
+ /*
2
+ * QUnit - A JavaScript Unit Testing Framework
3
+ *
4
+ * http://docs.jquery.com/QUnit
5
+ *
6
+ * Copyright (c) 2009 John Resig, Jörn Zaefferer
7
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
8
+ * and GPL (GPL-LICENSE.txt) licenses.
9
+ */
10
+
11
+ (function(window) {
12
+
13
+ var QUnit = {
14
+
15
+ // Initialize the configuration options
16
+ init: function() {
17
+ config = {
18
+ stats: { all: 0, bad: 0 },
19
+ moduleStats: { all: 0, bad: 0 },
20
+ started: +new Date,
21
+ blocking: false,
22
+ autorun: false,
23
+ assertions: [],
24
+ filters: [],
25
+ queue: []
26
+ };
27
+
28
+ var tests = id("qunit-tests"),
29
+ banner = id("qunit-banner"),
30
+ result = id("qunit-testresult");
31
+
32
+ if ( tests ) {
33
+ tests.innerHTML = "";
34
+ }
35
+
36
+ if ( banner ) {
37
+ banner.className = "";
38
+ }
39
+
40
+ if ( result ) {
41
+ result.parentNode.removeChild( result );
42
+ }
43
+ },
44
+
45
+ // call on start of module test to prepend name to all tests
46
+ module: function(name, testEnvironment) {
47
+ config.currentModule = name;
48
+
49
+ synchronize(function() {
50
+ if ( config.currentModule ) {
51
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
52
+ }
53
+
54
+ config.currentModule = name;
55
+ config.moduleTestEnvironment = testEnvironment;
56
+ config.moduleStats = { all: 0, bad: 0 };
57
+
58
+ QUnit.moduleStart( name, testEnvironment );
59
+ });
60
+ },
61
+
62
+ asyncTest: function(testName, expected, callback) {
63
+ if ( arguments.length === 2 ) {
64
+ callback = expected;
65
+ expected = 0;
66
+ }
67
+
68
+ QUnit.test(testName, expected, callback, true);
69
+ },
70
+
71
+ test: function(testName, expected, callback, async) {
72
+ var name = testName, testEnvironment, testEnvironmentArg;
73
+
74
+ if ( arguments.length === 2 ) {
75
+ callback = expected;
76
+ expected = null;
77
+ }
78
+ // is 2nd argument a testEnvironment?
79
+ if ( expected && typeof expected === 'object') {
80
+ testEnvironmentArg = expected;
81
+ expected = null;
82
+ }
83
+
84
+ if ( config.currentModule ) {
85
+ name = config.currentModule + " module: " + name;
86
+ }
87
+
88
+ if ( !validTest(name) ) {
89
+ return;
90
+ }
91
+
92
+ synchronize(function() {
93
+ QUnit.testStart( testName );
94
+
95
+ testEnvironment = extend({
96
+ setup: function() {},
97
+ teardown: function() {}
98
+ }, config.moduleTestEnvironment);
99
+ if (testEnvironmentArg) {
100
+ extend(testEnvironment,testEnvironmentArg);
101
+ }
102
+
103
+ // allow utility functions to access the current test environment
104
+ QUnit.current_testEnvironment = testEnvironment;
105
+
106
+ config.assertions = [];
107
+ config.expected = null;
108
+
109
+ if ( arguments.length >= 3 ) {
110
+ config.expected = callback;
111
+ callback = arguments[2];
112
+ }
113
+
114
+ try {
115
+ if ( !config.pollution ) {
116
+ saveGlobal();
117
+ }
118
+
119
+ testEnvironment.setup.call(testEnvironment);
120
+ } catch(e) {
121
+ QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
122
+ }
123
+
124
+ if ( async ) {
125
+ QUnit.stop();
126
+ }
127
+
128
+ try {
129
+ callback.call(testEnvironment);
130
+ } catch(e) {
131
+ fail("Test " + name + " died, exception and test follows", e, callback);
132
+ QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
133
+ // else next test will carry the responsibility
134
+ saveGlobal();
135
+
136
+ // Restart the tests if they're blocking
137
+ if ( config.blocking ) {
138
+ start();
139
+ }
140
+ }
141
+ });
142
+
143
+ synchronize(function() {
144
+ try {
145
+ checkPollution();
146
+ testEnvironment.teardown.call(testEnvironment);
147
+ } catch(e) {
148
+ QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
149
+ }
150
+
151
+ try {
152
+ QUnit.reset();
153
+ } catch(e) {
154
+ fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
155
+ }
156
+
157
+ if ( config.expected && config.expected != config.assertions.length ) {
158
+ QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
159
+ }
160
+
161
+ var good = 0, bad = 0,
162
+ tests = id("qunit-tests");
163
+
164
+ config.stats.all += config.assertions.length;
165
+ config.moduleStats.all += config.assertions.length;
166
+
167
+ if ( tests ) {
168
+ var ol = document.createElement("ol");
169
+ ol.style.display = "none";
170
+
171
+ for ( var i = 0; i < config.assertions.length; i++ ) {
172
+ var assertion = config.assertions[i];
173
+
174
+ var li = document.createElement("li");
175
+ li.className = assertion.result ? "pass" : "fail";
176
+ li.innerHTML = assertion.message || "(no message)";
177
+ ol.appendChild( li );
178
+
179
+ if ( assertion.result ) {
180
+ good++;
181
+ } else {
182
+ bad++;
183
+ config.stats.bad++;
184
+ config.moduleStats.bad++;
185
+ }
186
+ }
187
+
188
+ var b = document.createElement("strong");
189
+ b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
190
+
191
+ addEvent(b, "click", function() {
192
+ var next = b.nextSibling, display = next.style.display;
193
+ next.style.display = display === "none" ? "block" : "none";
194
+ });
195
+
196
+ addEvent(b, "dblclick", function(e) {
197
+ var target = (e || window.event).target;
198
+ if ( target.nodeName.toLowerCase() === "strong" ) {
199
+ var text = "", node = target.firstChild;
200
+
201
+ while ( node.nodeType === 3 ) {
202
+ text += node.nodeValue;
203
+ node = node.nextSibling;
204
+ }
205
+
206
+ text = text.replace(/(^\s*|\s*$)/g, "");
207
+
208
+ if ( window.location ) {
209
+ window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
210
+ }
211
+ }
212
+ });
213
+
214
+ var li = document.createElement("li");
215
+ li.className = bad ? "fail" : "pass";
216
+ li.appendChild( b );
217
+ li.appendChild( ol );
218
+ tests.appendChild( li );
219
+
220
+ if ( bad ) {
221
+ var toolbar = id("qunit-testrunner-toolbar");
222
+ if ( toolbar ) {
223
+ toolbar.style.display = "block";
224
+ id("qunit-filter-pass").disabled = null;
225
+ id("qunit-filter-missing").disabled = null;
226
+ }
227
+ }
228
+
229
+ } else {
230
+ for ( var i = 0; i < config.assertions.length; i++ ) {
231
+ if ( !config.assertions[i].result ) {
232
+ bad++;
233
+ config.stats.bad++;
234
+ config.moduleStats.bad++;
235
+ }
236
+ }
237
+ }
238
+
239
+ QUnit.testDone( testName, bad, config.assertions.length );
240
+
241
+ if ( !window.setTimeout && !config.queue.length ) {
242
+ done();
243
+ }
244
+ });
245
+
246
+ if ( window.setTimeout && !config.doneTimer ) {
247
+ config.doneTimer = window.setTimeout(function(){
248
+ if ( !config.queue.length ) {
249
+ done();
250
+ } else {
251
+ synchronize( done );
252
+ }
253
+ }, 13);
254
+ }
255
+ },
256
+
257
+ /**
258
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
259
+ */
260
+ expect: function(asserts) {
261
+ config.expected = asserts;
262
+ },
263
+
264
+ /**
265
+ * Asserts true.
266
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
267
+ */
268
+ ok: function(a, msg) {
269
+ QUnit.log(a, msg);
270
+
271
+ config.assertions.push({
272
+ result: !!a,
273
+ message: msg
274
+ });
275
+ },
276
+
277
+ /**
278
+ * Checks that the first two arguments are equal, with an optional message.
279
+ * Prints out both actual and expected values.
280
+ *
281
+ * Prefered to ok( actual == expected, message )
282
+ *
283
+ * @example equals( format("Received {0} bytes.", 2), "Received 2 bytes." );
284
+ *
285
+ * @param Object actual
286
+ * @param Object expected
287
+ * @param String message (optional)
288
+ */
289
+ equals: function(actual, expected, message) {
290
+ push(expected == actual, actual, expected, message);
291
+ },
292
+
293
+ same: function(a, b, message) {
294
+ push(QUnit.equiv(a, b), a, b, message);
295
+ },
296
+
297
+ start: function() {
298
+ // A slight delay, to avoid any current callbacks
299
+ if ( window.setTimeout ) {
300
+ window.setTimeout(function() {
301
+ if ( config.timeout ) {
302
+ clearTimeout(config.timeout);
303
+ }
304
+
305
+ config.blocking = false;
306
+ process();
307
+ }, 13);
308
+ } else {
309
+ config.blocking = false;
310
+ process();
311
+ }
312
+ },
313
+
314
+ stop: function(timeout) {
315
+ config.blocking = true;
316
+
317
+ if ( timeout && window.setTimeout ) {
318
+ config.timeout = window.setTimeout(function() {
319
+ QUnit.ok( false, "Test timed out" );
320
+ QUnit.start();
321
+ }, timeout);
322
+ }
323
+ },
324
+
325
+ /**
326
+ * Resets the test setup. Useful for tests that modify the DOM.
327
+ */
328
+ reset: function() {
329
+ if ( window.jQuery ) {
330
+ jQuery("#main").html( config.fixture );
331
+ jQuery.event.global = {};
332
+ jQuery.ajaxSettings = extend({}, config.ajaxSettings);
333
+ }
334
+ },
335
+
336
+ /**
337
+ * Trigger an event on an element.
338
+ *
339
+ * @example triggerEvent( document.body, "click" );
340
+ *
341
+ * @param DOMElement elem
342
+ * @param String type
343
+ */
344
+ triggerEvent: function( elem, type, event ) {
345
+ if ( document.createEvent ) {
346
+ event = document.createEvent("MouseEvents");
347
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
348
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
349
+ elem.dispatchEvent( event );
350
+
351
+ } else if ( elem.fireEvent ) {
352
+ elem.fireEvent("on"+type);
353
+ }
354
+ },
355
+
356
+ // Safe object type checking
357
+ is: function( type, obj ) {
358
+ return Object.prototype.toString.call( obj ) === "[object "+ type +"]";
359
+ },
360
+
361
+ // Logging callbacks
362
+ done: function(failures, total) {},
363
+ log: function(result, message) {},
364
+ testStart: function(name) {},
365
+ testDone: function(name, failures, total) {},
366
+ moduleStart: function(name, testEnvironment) {},
367
+ moduleDone: function(name, failures, total) {}
368
+ };
369
+
370
+ // Maintain internal state
371
+ var config = {
372
+ // The queue of tests to run
373
+ queue: [],
374
+
375
+ // block until document ready
376
+ blocking: true
377
+ };
378
+
379
+ // Load paramaters
380
+ (function() {
381
+ var location = window.location || { search: "", protocol: "file:" },
382
+ GETParams = location.search.slice(1).split('&');
383
+
384
+ for ( var i = 0; i < GETParams.length; i++ ) {
385
+ GETParams[i] = decodeURIComponent( GETParams[i] );
386
+ if ( GETParams[i] === "noglobals" ) {
387
+ GETParams.splice( i, 1 );
388
+ i--;
389
+ config.noglobals = true;
390
+ } else if ( GETParams[i].search('=') > -1 ) {
391
+ GETParams.splice( i, 1 );
392
+ i--;
393
+ }
394
+ }
395
+
396
+ // restrict modules/tests by get parameters
397
+ config.filters = GETParams;
398
+
399
+ // Figure out if we're running the tests from a server or not
400
+ QUnit.isLocal = !!(location.protocol === 'file:');
401
+ })();
402
+
403
+ // Expose the API as global variables, unless an 'exports'
404
+ // object exists, in that case we assume we're in CommonJS
405
+ if ( typeof exports === "undefined" || typeof require === "undefined" ) {
406
+ extend(window, QUnit);
407
+ window.QUnit = QUnit;
408
+ } else {
409
+ extend(exports, QUnit);
410
+ exports.QUnit = QUnit;
411
+ }
412
+
413
+ if ( typeof document === "undefined" || document.readyState === "complete" ) {
414
+ config.autorun = true;
415
+ }
416
+
417
+ addEvent(window, "load", function() {
418
+ // Initialize the config, saving the execution queue
419
+ var oldconfig = extend({}, config);
420
+ QUnit.init();
421
+ extend(config, oldconfig);
422
+
423
+ config.blocking = false;
424
+
425
+ var userAgent = id("qunit-userAgent");
426
+ if ( userAgent ) {
427
+ userAgent.innerHTML = navigator.userAgent;
428
+ }
429
+
430
+ var toolbar = id("qunit-testrunner-toolbar");
431
+ if ( toolbar ) {
432
+ toolbar.style.display = "none";
433
+
434
+ var filter = document.createElement("input");
435
+ filter.type = "checkbox";
436
+ filter.id = "qunit-filter-pass";
437
+ filter.disabled = true;
438
+ addEvent( filter, "click", function() {
439
+ var li = document.getElementsByTagName("li");
440
+ for ( var i = 0; i < li.length; i++ ) {
441
+ if ( li[i].className.indexOf("pass") > -1 ) {
442
+ li[i].style.display = filter.checked ? "none" : "block";
443
+ }
444
+ }
445
+ });
446
+ toolbar.appendChild( filter );
447
+
448
+ var label = document.createElement("label");
449
+ label.setAttribute("for", "qunit-filter-pass");
450
+ label.innerHTML = "Hide passed tests";
451
+ toolbar.appendChild( label );
452
+
453
+ var missing = document.createElement("input");
454
+ missing.type = "checkbox";
455
+ missing.id = "qunit-filter-missing";
456
+ missing.disabled = true;
457
+ addEvent( missing, "click", function() {
458
+ var li = document.getElementsByTagName("li");
459
+ for ( var i = 0; i < li.length; i++ ) {
460
+ if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
461
+ li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
462
+ }
463
+ }
464
+ });
465
+ toolbar.appendChild( missing );
466
+
467
+ label = document.createElement("label");
468
+ label.setAttribute("for", "qunit-filter-missing");
469
+ label.innerHTML = "Hide missing tests (untested code is broken code)";
470
+ toolbar.appendChild( label );
471
+ }
472
+
473
+ var main = id('main');
474
+ if ( main ) {
475
+ config.fixture = main.innerHTML;
476
+ }
477
+
478
+ if ( window.jQuery ) {
479
+ config.ajaxSettings = window.jQuery.ajaxSettings;
480
+ }
481
+
482
+ QUnit.start();
483
+ });
484
+
485
+ function done() {
486
+ if ( config.doneTimer && window.clearTimeout ) {
487
+ window.clearTimeout( config.doneTimer );
488
+ config.doneTimer = null;
489
+ }
490
+
491
+ if ( config.queue.length ) {
492
+ config.doneTimer = window.setTimeout(function(){
493
+ if ( !config.queue.length ) {
494
+ done();
495
+ } else {
496
+ synchronize( done );
497
+ }
498
+ }, 13);
499
+
500
+ return;
501
+ }
502
+
503
+ config.autorun = true;
504
+
505
+ // Log the last module results
506
+ if ( config.currentModule ) {
507
+ QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
508
+ }
509
+
510
+ var banner = id("qunit-banner"),
511
+ tests = id("qunit-tests"),
512
+ html = ['Tests completed in ',
513
+ +new Date - config.started, ' milliseconds.<br/>',
514
+ '<span class="bad">', config.stats.all - config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> passed, ', config.stats.bad,' failed.'].join('');
515
+
516
+ if ( banner ) {
517
+ banner.className += " " + (config.stats.bad ? "fail" : "pass");
518
+ }
519
+
520
+ if ( tests ) {
521
+ var result = id("qunit-testresult");
522
+
523
+ if ( !result ) {
524
+ result = document.createElement("p");
525
+ result.id = "qunit-testresult";
526
+ result.className = "result";
527
+ tests.parentNode.insertBefore( result, tests.nextSibling );
528
+ }
529
+
530
+ result.innerHTML = html;
531
+ }
532
+
533
+ QUnit.done( config.stats.bad, config.stats.all );
534
+ }
535
+
536
+ function validTest( name ) {
537
+ var i = config.filters.length,
538
+ run = false;
539
+
540
+ if ( !i ) {
541
+ return true;
542
+ }
543
+
544
+ while ( i-- ) {
545
+ var filter = config.filters[i],
546
+ not = filter.charAt(0) == '!';
547
+
548
+ if ( not ) {
549
+ filter = filter.slice(1);
550
+ }
551
+
552
+ if ( name.indexOf(filter) !== -1 ) {
553
+ return !not;
554
+ }
555
+
556
+ if ( not ) {
557
+ run = true;
558
+ }
559
+ }
560
+
561
+ return run;
562
+ }
563
+
564
+ function push(result, actual, expected, message) {
565
+ message = message || (result ? "okay" : "failed");
566
+ QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
567
+ }
568
+
569
+ function synchronize( callback ) {
570
+ config.queue.push( callback );
571
+
572
+ if ( config.autorun && !config.blocking ) {
573
+ process();
574
+ }
575
+ }
576
+
577
+ function process() {
578
+ while ( config.queue.length && !config.blocking ) {
579
+ config.queue.shift()();
580
+ }
581
+ }
582
+
583
+ function saveGlobal() {
584
+ config.pollution = [];
585
+
586
+ if ( config.noglobals ) {
587
+ for ( var key in window ) {
588
+ config.pollution.push( key );
589
+ }
590
+ }
591
+ }
592
+
593
+ function checkPollution( name ) {
594
+ var old = config.pollution;
595
+ saveGlobal();
596
+
597
+ var newGlobals = diff( old, config.pollution );
598
+ if ( newGlobals.length > 0 ) {
599
+ ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
600
+ config.expected++;
601
+ }
602
+
603
+ var deletedGlobals = diff( config.pollution, old );
604
+ if ( deletedGlobals.length > 0 ) {
605
+ ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
606
+ config.expected++;
607
+ }
608
+ }
609
+
610
+ // returns a new Array with the elements that are in a but not in b
611
+ function diff( a, b ) {
612
+ var result = a.slice();
613
+ for ( var i = 0; i < result.length; i++ ) {
614
+ for ( var j = 0; j < b.length; j++ ) {
615
+ if ( result[i] === b[j] ) {
616
+ result.splice(i, 1);
617
+ i--;
618
+ break;
619
+ }
620
+ }
621
+ }
622
+ return result;
623
+ }
624
+
625
+ function fail(message, exception, callback) {
626
+ if ( typeof console !== "undefined" && console.error && console.warn ) {
627
+ console.error(message);
628
+ console.error(exception);
629
+ console.warn(callback.toString());
630
+
631
+ } else if ( window.opera && opera.postError ) {
632
+ opera.postError(message, exception, callback.toString);
633
+ }
634
+ }
635
+
636
+ function extend(a, b) {
637
+ for ( var prop in b ) {
638
+ a[prop] = b[prop];
639
+ }
640
+
641
+ return a;
642
+ }
643
+
644
+ function addEvent(elem, type, fn) {
645
+ if ( elem.addEventListener ) {
646
+ elem.addEventListener( type, fn, false );
647
+ } else if ( elem.attachEvent ) {
648
+ elem.attachEvent( "on" + type, fn );
649
+ } else {
650
+ fn();
651
+ }
652
+ }
653
+
654
+ function id(name) {
655
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
656
+ document.getElementById( name );
657
+ }
658
+
659
+ // Test for equality any JavaScript type.
660
+ // Discussions and reference: http://philrathe.com/articles/equiv
661
+ // Test suites: http://philrathe.com/tests/equiv
662
+ // Author: Philippe Rathé <prathe@gmail.com>
663
+ QUnit.equiv = function () {
664
+
665
+ var innerEquiv; // the real equiv function
666
+ var callers = []; // stack to decide between skip/abort functions
667
+
668
+
669
+ // Determine what is o.
670
+ function hoozit(o) {
671
+ if (QUnit.is("String", o)) {
672
+ return "string";
673
+
674
+ } else if (QUnit.is("Boolean", o)) {
675
+ return "boolean";
676
+
677
+ } else if (QUnit.is("Number", o)) {
678
+
679
+ if (isNaN(o)) {
680
+ return "nan";
681
+ } else {
682
+ return "number";
683
+ }
684
+
685
+ } else if (typeof o === "undefined") {
686
+ return "undefined";
687
+
688
+ // consider: typeof null === object
689
+ } else if (o === null) {
690
+ return "null";
691
+
692
+ // consider: typeof [] === object
693
+ } else if (QUnit.is( "Array", o)) {
694
+ return "array";
695
+
696
+ // consider: typeof new Date() === object
697
+ } else if (QUnit.is( "Date", o)) {
698
+ return "date";
699
+
700
+ // consider: /./ instanceof Object;
701
+ // /./ instanceof RegExp;
702
+ // typeof /./ === "function"; // => false in IE and Opera,
703
+ // true in FF and Safari
704
+ } else if (QUnit.is( "RegExp", o)) {
705
+ return "regexp";
706
+
707
+ } else if (typeof o === "object") {
708
+ return "object";
709
+
710
+ } else if (QUnit.is( "Function", o)) {
711
+ return "function";
712
+ } else {
713
+ return undefined;
714
+ }
715
+ }
716
+
717
+ // Call the o related callback with the given arguments.
718
+ function bindCallbacks(o, callbacks, args) {
719
+ var prop = hoozit(o);
720
+ if (prop) {
721
+ if (hoozit(callbacks[prop]) === "function") {
722
+ return callbacks[prop].apply(callbacks, args);
723
+ } else {
724
+ return callbacks[prop]; // or undefined
725
+ }
726
+ }
727
+ }
728
+
729
+ var callbacks = function () {
730
+
731
+ // for string, boolean, number and null
732
+ function useStrictEquality(b, a) {
733
+ if (b instanceof a.constructor || a instanceof b.constructor) {
734
+ // to catch short annotaion VS 'new' annotation of a declaration
735
+ // e.g. var i = 1;
736
+ // var j = new Number(1);
737
+ return a == b;
738
+ } else {
739
+ return a === b;
740
+ }
741
+ }
742
+
743
+ return {
744
+ "string": useStrictEquality,
745
+ "boolean": useStrictEquality,
746
+ "number": useStrictEquality,
747
+ "null": useStrictEquality,
748
+ "undefined": useStrictEquality,
749
+
750
+ "nan": function (b) {
751
+ return isNaN(b);
752
+ },
753
+
754
+ "date": function (b, a) {
755
+ return hoozit(b) === "date" && a.valueOf() === b.valueOf();
756
+ },
757
+
758
+ "regexp": function (b, a) {
759
+ return hoozit(b) === "regexp" &&
760
+ a.source === b.source && // the regex itself
761
+ a.global === b.global && // and its modifers (gmi) ...
762
+ a.ignoreCase === b.ignoreCase &&
763
+ a.multiline === b.multiline;
764
+ },
765
+
766
+ // - skip when the property is a method of an instance (OOP)
767
+ // - abort otherwise,
768
+ // initial === would have catch identical references anyway
769
+ "function": function () {
770
+ var caller = callers[callers.length - 1];
771
+ return caller !== Object &&
772
+ typeof caller !== "undefined";
773
+ },
774
+
775
+ "array": function (b, a) {
776
+ var i;
777
+ var len;
778
+
779
+ // b could be an object literal here
780
+ if ( ! (hoozit(b) === "array")) {
781
+ return false;
782
+ }
783
+
784
+ len = a.length;
785
+ if (len !== b.length) { // safe and faster
786
+ return false;
787
+ }
788
+ for (i = 0; i < len; i++) {
789
+ if ( ! innerEquiv(a[i], b[i])) {
790
+ return false;
791
+ }
792
+ }
793
+ return true;
794
+ },
795
+
796
+ "object": function (b, a) {
797
+ var i;
798
+ var eq = true; // unless we can proove it
799
+ var aProperties = [], bProperties = []; // collection of strings
800
+
801
+ // comparing constructors is more strict than using instanceof
802
+ if ( a.constructor !== b.constructor) {
803
+ return false;
804
+ }
805
+
806
+ // stack constructor before traversing properties
807
+ callers.push(a.constructor);
808
+
809
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
810
+
811
+ aProperties.push(i); // collect a's properties
812
+
813
+ if ( ! innerEquiv(a[i], b[i])) {
814
+ eq = false;
815
+ }
816
+ }
817
+
818
+ callers.pop(); // unstack, we are done
819
+
820
+ for (i in b) {
821
+ bProperties.push(i); // collect b's properties
822
+ }
823
+
824
+ // Ensures identical properties name
825
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
826
+ }
827
+ };
828
+ }();
829
+
830
+ innerEquiv = function () { // can take multiple arguments
831
+ var args = Array.prototype.slice.apply(arguments);
832
+ if (args.length < 2) {
833
+ return true; // end transition
834
+ }
835
+
836
+ return (function (a, b) {
837
+ if (a === b) {
838
+ return true; // catch the most you can
839
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
840
+ return false; // don't lose time with error prone cases
841
+ } else {
842
+ return bindCallbacks(a, callbacks, [b, a]);
843
+ }
844
+
845
+ // apply transition with (1..n) arguments
846
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
847
+ };
848
+
849
+ return innerEquiv;
850
+
851
+ }();
852
+
853
+ /**
854
+ * jsDump
855
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
856
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
857
+ * Date: 5/15/2008
858
+ * @projectDescription Advanced and extensible data dumping for Javascript.
859
+ * @version 1.0.0
860
+ * @author Ariel Flesler
861
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
862
+ */
863
+ QUnit.jsDump = (function() {
864
+ function quote( str ) {
865
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
866
+ };
867
+ function literal( o ) {
868
+ return o + '';
869
+ };
870
+ function join( pre, arr, post ) {
871
+ var s = jsDump.separator(),
872
+ base = jsDump.indent(),
873
+ inner = jsDump.indent(1);
874
+ if ( arr.join )
875
+ arr = arr.join( ',' + s + inner );
876
+ if ( !arr )
877
+ return pre + post;
878
+ return [ pre, inner + arr, base + post ].join(s);
879
+ };
880
+ function array( arr ) {
881
+ var i = arr.length, ret = Array(i);
882
+ this.up();
883
+ while ( i-- )
884
+ ret[i] = this.parse( arr[i] );
885
+ this.down();
886
+ return join( '[', ret, ']' );
887
+ };
888
+
889
+ var reName = /^function (\w+)/;
890
+
891
+ var jsDump = {
892
+ parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
893
+ var parser = this.parsers[ type || this.typeOf(obj) ];
894
+ type = typeof parser;
895
+
896
+ return type == 'function' ? parser.call( this, obj ) :
897
+ type == 'string' ? parser :
898
+ this.parsers.error;
899
+ },
900
+ typeOf:function( obj ) {
901
+ var type;
902
+ if ( obj === null ) {
903
+ type = "null";
904
+ } else if (typeof obj === "undefined") {
905
+ type = "undefined";
906
+ } else if (QUnit.is("RegExp", obj)) {
907
+ type = "regexp";
908
+ } else if (QUnit.is("Date", obj)) {
909
+ type = "date";
910
+ } else if (QUnit.is("Function", obj)) {
911
+ type = "function";
912
+ } else if (QUnit.is("Array", obj)) {
913
+ type = "array";
914
+ } else if (QUnit.is("Window", obj) || QUnit.is("global", obj)) {
915
+ type = "window";
916
+ } else if (QUnit.is("HTMLDocument", obj)) {
917
+ type = "document";
918
+ } else if (QUnit.is("HTMLCollection", obj) || QUnit.is("NodeList", obj)) {
919
+ type = "nodelist";
920
+ } else if (/^\[object HTML/.test(Object.prototype.toString.call( obj ))) {
921
+ type = "node";
922
+ } else {
923
+ type = typeof obj;
924
+ }
925
+ return type;
926
+ },
927
+ separator:function() {
928
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
929
+ },
930
+ indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
931
+ if ( !this.multiline )
932
+ return '';
933
+ var chr = this.indentChar;
934
+ if ( this.HTML )
935
+ chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
936
+ return Array( this._depth_ + (extra||0) ).join(chr);
937
+ },
938
+ up:function( a ) {
939
+ this._depth_ += a || 1;
940
+ },
941
+ down:function( a ) {
942
+ this._depth_ -= a || 1;
943
+ },
944
+ setParser:function( name, parser ) {
945
+ this.parsers[name] = parser;
946
+ },
947
+ // The next 3 are exposed so you can use them
948
+ quote:quote,
949
+ literal:literal,
950
+ join:join,
951
+ //
952
+ _depth_: 1,
953
+ // This is the list of parsers, to modify them, use jsDump.setParser
954
+ parsers:{
955
+ window: '[Window]',
956
+ document: '[Document]',
957
+ error:'[ERROR]', //when no parser is found, shouldn't happen
958
+ unknown: '[Unknown]',
959
+ 'null':'null',
960
+ undefined:'undefined',
961
+ 'function':function( fn ) {
962
+ var ret = 'function',
963
+ name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
964
+ if ( name )
965
+ ret += ' ' + name;
966
+ ret += '(';
967
+
968
+ ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
969
+ return join( ret, this.parse(fn,'functionCode'), '}' );
970
+ },
971
+ array: array,
972
+ nodelist: array,
973
+ arguments: array,
974
+ object:function( map ) {
975
+ var ret = [ ];
976
+ this.up();
977
+ for ( var key in map )
978
+ ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
979
+ this.down();
980
+ return join( '{', ret, '}' );
981
+ },
982
+ node:function( node ) {
983
+ var open = this.HTML ? '&lt;' : '<',
984
+ close = this.HTML ? '&gt;' : '>';
985
+
986
+ var tag = node.nodeName.toLowerCase(),
987
+ ret = open + tag;
988
+
989
+ for ( var a in this.DOMAttrs ) {
990
+ var val = node[this.DOMAttrs[a]];
991
+ if ( val )
992
+ ret += ' ' + a + '=' + this.parse( val, 'attribute' );
993
+ }
994
+ return ret + close + open + '/' + tag + close;
995
+ },
996
+ functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
997
+ var l = fn.length;
998
+ if ( !l ) return '';
999
+
1000
+ var args = Array(l);
1001
+ while ( l-- )
1002
+ args[l] = String.fromCharCode(97+l);//97 is 'a'
1003
+ return ' ' + args.join(', ') + ' ';
1004
+ },
1005
+ key:quote, //object calls it internally, the key part of an item in a map
1006
+ functionCode:'[code]', //function calls it internally, it's the content of the function
1007
+ attribute:quote, //node calls it internally, it's an html attribute value
1008
+ string:quote,
1009
+ date:quote,
1010
+ regexp:literal, //regex
1011
+ number:literal,
1012
+ 'boolean':literal
1013
+ },
1014
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
1015
+ id:'id',
1016
+ name:'name',
1017
+ 'class':'className'
1018
+ },
1019
+ HTML:true,//if true, entities are escaped ( <, >, \t, space and \n )
1020
+ indentChar:' ',//indentation unit
1021
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
1022
+ };
1023
+
1024
+ return jsDump;
1025
+ })();
1026
+
1027
+ })(this);