entityjs 0.3.1 → 0.3.2

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 (148) hide show
  1. data/README.md +18 -14
  2. data/entityjs.gemspec +1 -0
  3. data/lib/entityjs/assets.rb +13 -163
  4. data/lib/entityjs/command.rb +5 -2
  5. data/lib/entityjs/commands/build.rb +63 -23
  6. data/lib/entityjs/commands/eunit.rb +44 -0
  7. data/lib/entityjs/commands/release.rb +1 -1
  8. data/lib/entityjs/commands/server.rb +19 -4
  9. data/lib/entityjs/compile.rb +152 -0
  10. data/lib/entityjs/config.rb +8 -0
  11. data/lib/entityjs/dirc.rb +70 -17
  12. data/lib/entityjs/page.rb +106 -0
  13. data/lib/entityjs/parsers/parse_coffee.rb +12 -0
  14. data/lib/entityjs/version.rb +1 -1
  15. data/lib/entityjs.rb +18 -4
  16. data/public/qunit/qunit.css +9 -3
  17. data/public/qunit/qunit.entity.js +113 -31
  18. data/public/qunit/qunit.js +296 -235
  19. data/public/qunit/qunit.mock.js +54 -2
  20. data/public/tests.html +0 -15
  21. data/spec/javascripts/src/cycle/tween_spec.js +59 -0
  22. data/spec/javascripts/src/display/screen_spec.js +0 -15
  23. data/spec/javascripts/src/display/text_spec.js +4 -0
  24. data/spec/javascripts/src/input/mouse_spec.js +18 -18
  25. data/spec/javascripts/src/input/preventdefault_spec.js +14 -0
  26. data/spec/javascripts/src/math/drag_spec.js +2 -2
  27. data/spec/javascripts/src/math/hit_spec.js +24 -0
  28. data/spec/javascripts/src/math/point_spec.js +3 -3
  29. data/spec/javascripts/src/math/tile_spec.js +1 -1
  30. data/spec/javascripts/src/media/sound_spec.js +1 -1
  31. data/spec/javascripts/src/pattern/automap_spec.js +3 -3
  32. data/spec/javascripts/src/pattern/flicker_spec.js +2 -1
  33. data/spec/javascripts/src/util/random_spec.js +17 -0
  34. data/spec/javascripts/src/util/scene_spec.js +15 -0
  35. data/spec/lib/entityjs/assets_spec.rb +2 -201
  36. data/spec/lib/entityjs/commands/build_spec.rb +18 -5
  37. data/spec/lib/entityjs/commands/eunit_spec.rb +18 -0
  38. data/spec/lib/entityjs/commands/release_spec.rb +2 -0
  39. data/spec/lib/entityjs/compile_spec.rb +204 -0
  40. data/spec/lib/entityjs/dirc_spec.rb +8 -4
  41. data/spec/lib/entityjs/page_spec.rb +59 -0
  42. data/spec/support/factories.rb +0 -2
  43. data/src/core/entity.js +4 -18
  44. data/src/core/query.js +1 -1
  45. data/src/core/re.js +6 -6
  46. data/src/core/system.js +17 -12
  47. data/src/cycle/tween.js +93 -31
  48. data/src/display/align.js +11 -6
  49. data/src/display/circle.js +5 -4
  50. data/src/display/imgtext.js +33 -22
  51. data/src/display/screen.js +0 -8
  52. data/src/display/text.js +37 -4
  53. data/src/input/keyboard.js +15 -5
  54. data/src/input/mouse.js +15 -25
  55. data/src/input/preventdefault.js +11 -0
  56. data/src/math/body.js +35 -16
  57. data/src/math/drag.js +2 -2
  58. data/src/math/force.js +2 -2
  59. data/src/math/hit.js +15 -6
  60. data/src/math/hitmap.js +6 -6
  61. data/src/math/point.js +1 -1
  62. data/src/math/tile.js +22 -17
  63. data/src/media/sound.js +1 -1
  64. data/src/pattern/automap.js +16 -27
  65. data/src/pattern/flicker.js +9 -5
  66. data/src/util/random.js +4 -0
  67. data/src/util/scene.js +2 -6
  68. data/templates/arrow_keys/scripts/{display → displays}/arrow.js +0 -0
  69. data/templates/arrow_keys/scripts/{input → inputs}/controls.js +0 -0
  70. data/templates/arrow_keys/tests/{display → displays}/arrow_test.js +1 -1
  71. data/templates/arrow_keys/tests/{input → inputs}/controls_test.js +0 -0
  72. data/templates/arrow_keys/tests/scenes/load_test.js +2 -0
  73. data/templates/{blank → circle}/config.yml +0 -0
  74. data/templates/{blank → circle}/readme.txt +0 -0
  75. data/templates/circle/scripts/init.js +7 -0
  76. data/templates/circle/scripts/scenes/home.js +62 -0
  77. data/templates/circle/scripts/scenes/load.js +11 -0
  78. data/templates/circle/tests/scenes/home_test.js +29 -0
  79. data/templates/circle/tests/scenes/load_test.js +15 -0
  80. data/templates/platform/config.yml +2 -1
  81. data/templates/platform/readme.txt +15 -16
  82. data/templates/platform/scripts/{display → displays}/bit.js +0 -0
  83. data/templates/platform/scripts/{display → displays}/hero.js +0 -0
  84. data/templates/platform/scripts/{display → displays}/tile.js +0 -0
  85. data/templates/platform/scripts/{display → displays}/tsprite.js +0 -0
  86. data/templates/platform/{assets → scripts}/levels/level1.tmx +0 -0
  87. data/templates/platform/scripts/{util → utils}/counter.js +0 -0
  88. data/templates/platform/scripts/{util → utils}/level.js +0 -0
  89. data/templates/platform/tests/{display → displays}/bit_test.js +1 -1
  90. data/templates/platform/tests/displays/hero_test.js +73 -0
  91. data/templates/platform/tests/{display → displays}/tile_test.js +1 -1
  92. data/templates/platform/tests/displays/tsprite_test.js +8 -0
  93. data/templates/platform/tests/items/coin_test.js +10 -10
  94. data/templates/platform/tests/items/item_test.js +9 -9
  95. data/templates/platform/tests/items/spring_test.js +3 -3
  96. data/templates/platform/tests/scenes/load_test.js +2 -1
  97. data/templates/platform/tests/{util → utils}/counter_test.js +2 -2
  98. data/templates/platform/tests/{util → utils}/level_test.js +3 -0
  99. data/templates/pong/config.yml +22 -0
  100. data/templates/pong/readme.txt +3 -0
  101. data/templates/pong/scripts/controls/ai.js +30 -0
  102. data/templates/pong/scripts/controls/arena.js +33 -0
  103. data/templates/pong/scripts/controls/hitmap.js +54 -0
  104. data/templates/pong/scripts/controls/player.js +24 -0
  105. data/templates/pong/scripts/controls/twoarena.js +14 -0
  106. data/templates/pong/scripts/displays/ball.js +29 -0
  107. data/templates/pong/scripts/displays/counter.js +22 -0
  108. data/templates/pong/scripts/displays/paddle.js +22 -0
  109. data/templates/pong/scripts/init.js +9 -0
  110. data/templates/pong/scripts/scenes/game.js +61 -0
  111. data/templates/pong/scripts/scenes/home.js +55 -0
  112. data/templates/pong/scripts/scenes/over.js +29 -0
  113. data/templates/pong/tests/controls/ai_test.js +34 -0
  114. data/templates/pong/tests/controls/arena_test.js +20 -0
  115. data/templates/pong/tests/controls/hitmap_test.js +89 -0
  116. data/templates/pong/tests/controls/player_test.js +25 -0
  117. data/templates/pong/tests/controls/twoarena_test.js +7 -0
  118. data/templates/pong/tests/displays/ball_test.js +10 -0
  119. data/templates/pong/tests/displays/counter_test.js +13 -0
  120. data/templates/pong/tests/displays/paddle_test.js +17 -0
  121. data/templates/pong/tests/scenes/game_test.js +16 -0
  122. data/templates/pong/tests/scenes/home_test.js +30 -0
  123. data/templates/pong/tests/scenes/over_test.js +16 -0
  124. data/templates/tiltmaze/config.yml +25 -0
  125. data/templates/tiltmaze/readme.txt +79 -0
  126. data/templates/tiltmaze/scripts/displays/ball.js +78 -0
  127. data/templates/tiltmaze/scripts/displays/target.js +13 -0
  128. data/templates/tiltmaze/scripts/displays/tile.js +2 -0
  129. data/templates/tiltmaze/scripts/init.js +7 -0
  130. data/templates/tiltmaze/scripts/levels/level1.json +14 -0
  131. data/templates/tiltmaze/scripts/levels/level2.json +14 -0
  132. data/templates/tiltmaze/scripts/levels/level3.json +14 -0
  133. data/templates/tiltmaze/scripts/levels/level4.json +15 -0
  134. data/templates/tiltmaze/scripts/levels/level5.json +18 -0
  135. data/templates/tiltmaze/scripts/scenes/game.js +56 -0
  136. data/templates/tiltmaze/scripts/scenes/home.js +24 -0
  137. data/templates/tiltmaze/scripts/structs/level.js +82 -0
  138. data/templates/tiltmaze/scripts/tiles/walltile.js +147 -0
  139. data/templates/tiltmaze/tests/displays/ball_test.js +67 -0
  140. data/templates/tiltmaze/tests/displays/target_test.js +8 -0
  141. data/templates/tiltmaze/tests/factories.js +38 -0
  142. data/templates/tiltmaze/tests/scenes/game_test.js +59 -0
  143. data/templates/tiltmaze/tests/scenes/home_test.js +7 -0
  144. data/templates/tiltmaze/tests/structs/level_test.js +44 -0
  145. data/templates/tiltmaze/tests/tiles/walltile_test.js +36 -0
  146. metadata +106 -33
  147. data/templates/platform/tests/display/hero_test.js +0 -73
  148. data/templates/platform/tests/display/tsprite_test.js +0 -8
@@ -1,9 +1,9 @@
1
1
  /**
2
- * QUnit v1.3.0pre - A JavaScript Unit Testing Framework
2
+ * QUnit v1.5.0pre - A JavaScript Unit Testing Framework
3
3
  *
4
4
  * http://docs.jquery.com/QUnit
5
5
  *
6
- * Copyright (c) 2011 John Resig, Jörn Zaefferer
6
+ * Copyright (c) 2012 John Resig, Jörn Zaefferer
7
7
  * Dual licensed under the MIT (MIT-LICENSE.txt)
8
8
  * or GPL (GPL-LICENSE.txt) licenses.
9
9
  */
@@ -13,23 +13,25 @@
13
13
  var defined = {
14
14
  setTimeout: typeof window.setTimeout !== "undefined",
15
15
  sessionStorage: (function() {
16
+ var x = "qunit-test-string";
16
17
  try {
17
- return !!sessionStorage.getItem;
18
+ sessionStorage.setItem(x, x);
19
+ sessionStorage.removeItem(x);
20
+ return true;
18
21
  } catch(e) {
19
22
  return false;
20
23
  }
21
- })()
24
+ }())
22
25
  };
23
26
 
24
27
  var testId = 0,
25
28
  toString = Object.prototype.toString,
26
29
  hasOwn = Object.prototype.hasOwnProperty;
27
30
 
28
- var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
31
+ var Test = function(name, testName, expected, async, callback) {
29
32
  this.name = name;
30
33
  this.testName = testName;
31
34
  this.expected = expected;
32
- this.testEnvironmentArg = testEnvironmentArg;
33
35
  this.async = async;
34
36
  this.callback = callback;
35
37
  this.assertions = [];
@@ -62,6 +64,10 @@ Test.prototype = {
62
64
  runLoggingCallbacks( 'moduleStart', QUnit, {
63
65
  name: this.module
64
66
  } );
67
+ } else if (config.autorun) {
68
+ runLoggingCallbacks( 'moduleStart', QUnit, {
69
+ name: this.module
70
+ } );
65
71
  }
66
72
 
67
73
  config.current = this;
@@ -69,9 +75,6 @@ Test.prototype = {
69
75
  setup: function() {},
70
76
  teardown: function() {}
71
77
  }, this.moduleTestEnvironment);
72
- if (this.testEnvironmentArg) {
73
- extend(this.testEnvironment, this.testEnvironmentArg);
74
- }
75
78
 
76
79
  runLoggingCallbacks( 'testStart', QUnit, {
77
80
  name: this.testName,
@@ -82,14 +85,17 @@ Test.prototype = {
82
85
  // TODO why??
83
86
  QUnit.current_testEnvironment = this.testEnvironment;
84
87
 
88
+ if ( !config.pollution ) {
89
+ saveGlobal();
90
+ }
91
+ if ( config.notrycatch ) {
92
+ this.testEnvironment.setup.call(this.testEnvironment);
93
+ return;
94
+ }
85
95
  try {
86
- if ( !config.pollution ) {
87
- saveGlobal();
88
- }
89
-
90
96
  this.testEnvironment.setup.call(this.testEnvironment);
91
97
  } catch(e) {
92
- QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
98
+ QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
93
99
  }
94
100
  },
95
101
  run: function() {
@@ -105,8 +111,7 @@ Test.prototype = {
105
111
  try {
106
112
  this.callback.call(this.testEnvironment);
107
113
  } catch(e) {
108
- fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
109
- QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
114
+ QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + ": " + e.message, extractStacktrace( e, 1 ) );
110
115
  // else next test will carry the responsibility
111
116
  saveGlobal();
112
117
 
@@ -118,20 +123,28 @@ Test.prototype = {
118
123
  },
119
124
  teardown: function() {
120
125
  config.current = this;
121
- try {
126
+ if ( config.notrycatch ) {
122
127
  this.testEnvironment.teardown.call(this.testEnvironment);
123
- checkPollution();
124
- } catch(e) {
125
- QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
128
+ return;
129
+ } else {
130
+ try {
131
+ this.testEnvironment.teardown.call(this.testEnvironment);
132
+ } catch(e) {
133
+ QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) );
134
+ }
126
135
  }
136
+ checkPollution();
127
137
  },
128
138
  finish: function() {
129
139
  config.current = this;
130
140
  if ( this.expected != null && this.expected != this.assertions.length ) {
131
- QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
141
+ QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
142
+ } else if ( this.expected == null && !this.assertions.length ) {
143
+ QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions." );
132
144
  }
133
145
 
134
146
  var good = 0, bad = 0,
147
+ li, i,
135
148
  tests = id("qunit-tests");
136
149
 
137
150
  config.stats.all += this.assertions.length;
@@ -140,10 +153,10 @@ Test.prototype = {
140
153
  if ( tests ) {
141
154
  var ol = document.createElement("ol");
142
155
 
143
- for ( var i = 0; i < this.assertions.length; i++ ) {
156
+ for ( i = 0; i < this.assertions.length; i++ ) {
144
157
  var assertion = this.assertions[i];
145
158
 
146
- var li = document.createElement("li");
159
+ li = document.createElement("li");
147
160
  li.className = assertion.result ? "pass" : "fail";
148
161
  li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
149
162
  ol.appendChild( li );
@@ -160,13 +173,13 @@ Test.prototype = {
160
173
  // store result when possible
161
174
  if ( QUnit.config.reorder && defined.sessionStorage ) {
162
175
  if (bad) {
163
- sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
176
+ sessionStorage.setItem("qunit-test-" + this.module + "-" + this.testName, bad);
164
177
  } else {
165
- sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
178
+ sessionStorage.removeItem("qunit-test-" + this.module + "-" + this.testName);
166
179
  }
167
180
  }
168
181
 
169
- if (bad == 0) {
182
+ if (bad === 0) {
170
183
  ol.style.display = "none";
171
184
  }
172
185
 
@@ -193,7 +206,7 @@ Test.prototype = {
193
206
  }
194
207
  });
195
208
 
196
- var li = id(this.id);
209
+ li = id(this.id);
197
210
  li.className = bad ? "fail" : "pass";
198
211
  li.removeChild( li.firstChild );
199
212
  li.appendChild( b );
@@ -201,7 +214,7 @@ Test.prototype = {
201
214
  li.appendChild( ol );
202
215
 
203
216
  } else {
204
- for ( var i = 0; i < this.assertions.length; i++ ) {
217
+ for ( i = 0; i < this.assertions.length; i++ ) {
205
218
  if ( !this.assertions[i].result ) {
206
219
  bad++;
207
220
  config.stats.bad++;
@@ -210,11 +223,7 @@ Test.prototype = {
210
223
  }
211
224
  }
212
225
 
213
- try {
214
- QUnit.reset();
215
- } catch(e) {
216
- fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
217
- }
226
+ QUnit.reset();
218
227
 
219
228
  runLoggingCallbacks( 'testDone', QUnit, {
220
229
  name: this.testName,
@@ -246,12 +255,12 @@ Test.prototype = {
246
255
  });
247
256
  }
248
257
  // defer when previous test run passed, if storage is available
249
- var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
258
+ var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-test-" + this.module + "-" + this.testName);
250
259
  if (bad) {
251
260
  run();
252
261
  } else {
253
262
  synchronize(run, true);
254
- };
263
+ }
255
264
  }
256
265
 
257
266
  };
@@ -274,17 +283,12 @@ var QUnit = {
274
283
  },
275
284
 
276
285
  test: function(testName, expected, callback, async) {
277
- var name = '<span class="test-name">' + escapeInnerText(testName) + '</span>', testEnvironmentArg;
286
+ var name = '<span class="test-name">' + escapeInnerText(testName) + '</span>';
278
287
 
279
288
  if ( arguments.length === 2 ) {
280
289
  callback = expected;
281
290
  expected = null;
282
291
  }
283
- // is 2nd argument a testEnvironment?
284
- if ( expected && typeof expected === 'object') {
285
- testEnvironmentArg = expected;
286
- expected = null;
287
- }
288
292
 
289
293
  if ( config.currentModule ) {
290
294
  name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
@@ -294,49 +298,45 @@ var QUnit = {
294
298
  return;
295
299
  }
296
300
 
297
- var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
301
+ var test = new Test(name, testName, expected, async, callback);
298
302
  test.module = config.currentModule;
299
303
  test.moduleTestEnvironment = config.currentModuleTestEnviroment;
300
304
  test.queue();
301
305
  },
302
306
 
303
- /**
304
- * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
305
- */
307
+ // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
306
308
  expect: function(asserts) {
307
309
  config.current.expected = asserts;
308
310
  },
309
311
 
310
- /**
311
- * Asserts true.
312
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
313
- */
314
- ok: function(a, msg) {
315
- a = !!a;
312
+ // Asserts true.
313
+ // @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
314
+ ok: function(result, msg) {
315
+ if (!config.current) {
316
+ throw new Error("ok() assertion outside test context, was " + sourceFromStacktrace(2));
317
+ }
318
+ result = !!result;
316
319
  var details = {
317
- result: a,
320
+ result: result,
318
321
  message: msg
319
322
  };
320
- msg = escapeInnerText(msg);
323
+ msg = escapeInnerText(msg || (result ? "okay" : "failed"));
324
+ if ( !result ) {
325
+ var source = sourceFromStacktrace(2);
326
+ if (source) {
327
+ details.source = source;
328
+ msg += '<table><tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr></table>';
329
+ }
330
+ }
321
331
  runLoggingCallbacks( 'log', QUnit, details );
322
332
  config.current.assertions.push({
323
- result: a,
333
+ result: result,
324
334
  message: msg
325
335
  });
326
336
  },
327
337
 
328
- /**
329
- * Checks that the first two arguments are equal, with an optional message.
330
- * Prints out both actual and expected values.
331
- *
332
- * Prefered to ok( actual == expected, message )
333
- *
334
- * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
335
- *
336
- * @param Object actual
337
- * @param Object expected
338
- * @param String message (optional)
339
- */
338
+ // Checks that the first two arguments are equal, with an optional message. Prints out both actual and expected values.
339
+ // @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
340
340
  equal: function(actual, expected, message) {
341
341
  QUnit.push(expected == actual, actual, expected, message);
342
342
  },
@@ -440,16 +440,21 @@ var QUnit = {
440
440
 
441
441
  //We want access to the constructor's prototype
442
442
  (function() {
443
- function F(){};
443
+ function F(){}
444
444
  F.prototype = QUnit;
445
445
  QUnit = new F();
446
446
  //Make F QUnit's constructor so that we can add to the prototype later
447
447
  QUnit.constructor = F;
448
- })();
448
+ }());
449
449
 
450
- // Backwards compatibility, deprecated
451
- QUnit.equals = QUnit.equal;
452
- QUnit.same = QUnit.deepEqual;
450
+ // deprecated; still export them to window to provide clear error messages
451
+ // next step: remove entirely
452
+ QUnit.equals = function() {
453
+ QUnit.push(false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead");
454
+ };
455
+ QUnit.same = function() {
456
+ QUnit.push(false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead");
457
+ };
453
458
 
454
459
  // Maintain internal state
455
460
  var config = {
@@ -504,17 +509,14 @@ var config = {
504
509
  config.filter = urlParams.filter;
505
510
 
506
511
  // Figure out if we're running the tests from a server or not
507
- QUnit.isLocal = !!(location.protocol === 'file:');
508
- })();
512
+ QUnit.isLocal = location.protocol === 'file:';
513
+ }());
509
514
 
510
515
  // Expose the API as global variables, unless an 'exports'
511
- // object exists, in that case we assume we're in CommonJS
516
+ // object exists, in that case we assume we're in CommonJS - export everything at the end
512
517
  if ( typeof exports === "undefined" || typeof require === "undefined" ) {
513
518
  extend(window, QUnit);
514
519
  window.QUnit = QUnit;
515
- } else {
516
- extend(exports, QUnit);
517
- exports.QUnit = QUnit;
518
520
  }
519
521
 
520
522
  // define these after exposing globals to keep them in these QUnit namespace only
@@ -526,7 +528,7 @@ extend(QUnit, {
526
528
  extend(config, {
527
529
  stats: { all: 0, bad: 0 },
528
530
  moduleStats: { all: 0, bad: 0 },
529
- started: +new Date,
531
+ started: +new Date(),
530
532
  updateRate: 1000,
531
533
  blocking: false,
532
534
  autostart: true,
@@ -536,6 +538,16 @@ extend(QUnit, {
536
538
  semaphore: 0
537
539
  });
538
540
 
541
+ var qunit = id( "qunit" );
542
+ if ( qunit ) {
543
+ qunit.innerHTML =
544
+ '<h1 id="qunit-header">' + escapeInnerText( document.title ) + '</h1>' +
545
+ '<h2 id="qunit-banner"></h2>' +
546
+ '<div id="qunit-testrunner-toolbar"></div>' +
547
+ '<h2 id="qunit-userAgent"></h2>' +
548
+ '<ol id="qunit-tests"></ol>';
549
+ }
550
+
539
551
  var tests = id( "qunit-tests" ),
540
552
  banner = id( "qunit-banner" ),
541
553
  result = id( "qunit-testresult" );
@@ -561,11 +573,8 @@ extend(QUnit, {
561
573
  }
562
574
  },
563
575
 
564
- /**
565
- * Resets the test setup. Useful for tests that modify the DOM.
566
- *
567
- * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
568
- */
576
+ // Resets the test setup. Useful for tests that modify the DOM.
577
+ // If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
569
578
  reset: function() {
570
579
  if ( window.jQuery ) {
571
580
  jQuery( "#qunit-fixture" ).html( config.fixture );
@@ -577,14 +586,8 @@ extend(QUnit, {
577
586
  }
578
587
  },
579
588
 
580
- /**
581
- * Trigger an event on an element.
582
- *
583
- * @example triggerEvent( document.body, "click" );
584
- *
585
- * @param DOMElement elem
586
- * @param String type
587
- */
589
+ // Trigger an event on an element.
590
+ // @example triggerEvent( document.body, "click" );
588
591
  triggerEvent: function( elem, type, event ) {
589
592
  if ( document.createEvent ) {
590
593
  event = document.createEvent("MouseEvents");
@@ -615,19 +618,18 @@ extend(QUnit, {
615
618
  var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || '';
616
619
 
617
620
  switch (type) {
618
- case 'Number':
619
- if (isNaN(obj)) {
620
- return "nan";
621
- } else {
622
- return "number";
623
- }
624
- case 'String':
625
- case 'Boolean':
626
- case 'Array':
627
- case 'Date':
628
- case 'RegExp':
629
- case 'Function':
630
- return type.toLowerCase();
621
+ case 'Number':
622
+ if (isNaN(obj)) {
623
+ return "nan";
624
+ }
625
+ return "number";
626
+ case 'String':
627
+ case 'Boolean':
628
+ case 'Array':
629
+ case 'Date':
630
+ case 'RegExp':
631
+ case 'Function':
632
+ return type.toLowerCase();
631
633
  }
632
634
  if (typeof obj === "object") {
633
635
  return "object";
@@ -636,6 +638,9 @@ extend(QUnit, {
636
638
  },
637
639
 
638
640
  push: function(result, actual, expected, message) {
641
+ if (!config.current) {
642
+ throw new Error("assertion outside test context, was " + sourceFromStacktrace());
643
+ }
639
644
  var details = {
640
645
  result: result,
641
646
  message: message,
@@ -645,21 +650,22 @@ extend(QUnit, {
645
650
 
646
651
  message = escapeInnerText(message) || (result ? "okay" : "failed");
647
652
  message = '<span class="test-message">' + message + "</span>";
648
- expected = escapeInnerText(QUnit.jsDump.parse(expected));
649
- actual = escapeInnerText(QUnit.jsDump.parse(actual));
650
- var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
651
- if (actual != expected) {
652
- output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
653
- output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
654
- }
653
+ var output = message;
655
654
  if (!result) {
655
+ expected = escapeInnerText(QUnit.jsDump.parse(expected));
656
+ actual = escapeInnerText(QUnit.jsDump.parse(actual));
657
+ output += '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
658
+ if (actual != expected) {
659
+ output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
660
+ output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
661
+ }
656
662
  var source = sourceFromStacktrace();
657
663
  if (source) {
658
664
  details.source = source;
659
665
  output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr>';
660
666
  }
667
+ output += "</table>";
661
668
  }
662
- output += "</table>";
663
669
 
664
670
  runLoggingCallbacks( 'log', QUnit, details );
665
671
 
@@ -669,6 +675,23 @@ extend(QUnit, {
669
675
  });
670
676
  },
671
677
 
678
+ pushFailure: function(message, source) {
679
+ var details = {
680
+ result: false,
681
+ message: message
682
+ };
683
+ var output = escapeInnerText(message);
684
+ if (source) {
685
+ details.source = source;
686
+ output += '<table><tr class="test-source"><th>Source: </th><td><pre>' + escapeInnerText(source) + '</pre></td></tr></table>';
687
+ }
688
+ runLoggingCallbacks( 'log', QUnit, details );
689
+ config.current.assertions.push({
690
+ result: false,
691
+ message: output
692
+ });
693
+ },
694
+
672
695
  url: function( params ) {
673
696
  params = extend( extend( {}, QUnit.urlParams ), params );
674
697
  var querystring = "?",
@@ -724,7 +747,8 @@ QUnit.load = function() {
724
747
  config.blocking = false;
725
748
 
726
749
  var urlConfigHtml = '', len = config.urlConfig.length;
727
- for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) {
750
+ for ( var i = 0, val; i < len; i++ ) {
751
+ val = config.urlConfig[i];
728
752
  config[val] = QUnit.urlParams[val];
729
753
  urlConfigHtml += '<label><input name="' + val + '" type="checkbox"' + ( config[val] ? ' checked="checked"' : '' ) + '>' + val + '</label>';
730
754
  }
@@ -792,10 +816,10 @@ addEvent(window, "load", QUnit.load);
792
816
  // addEvent(window, "error") gives us a useless event object
793
817
  window.onerror = function( message, file, line ) {
794
818
  if ( QUnit.config.current ) {
795
- ok( false, message + ", " + file + ":" + line );
819
+ QUnit.pushFailure( message, file + ":" + line );
796
820
  } else {
797
- test( "global failure", function() {
798
- ok( false, message + ", " + file + ":" + line );
821
+ QUnit.test( "global failure", function() {
822
+ QUnit.pushFailure( message, file + ":" + line );
799
823
  });
800
824
  }
801
825
  };
@@ -815,7 +839,7 @@ function done() {
815
839
 
816
840
  var banner = id("qunit-banner"),
817
841
  tests = id("qunit-tests"),
818
- runtime = +new Date - config.started,
842
+ runtime = +new Date() - config.started,
819
843
  passed = config.stats.all - config.stats.bad,
820
844
  html = [
821
845
  'Tests completed in ',
@@ -847,6 +871,15 @@ function done() {
847
871
  ].join(" ");
848
872
  }
849
873
 
874
+ // clear own sessionStorage items if all tests passed
875
+ if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
876
+ for (var key in sessionStorage) {
877
+ if (sessionStorage.hasOwnProperty(key) && key.indexOf("qunit-test-") === 0 ) {
878
+ sessionStorage.removeItem(key);
879
+ }
880
+ }
881
+ }
882
+
850
883
  runLoggingCallbacks( 'done', QUnit, {
851
884
  failed: config.stats.bad,
852
885
  passed: passed,
@@ -881,21 +914,34 @@ function validTest( name ) {
881
914
 
882
915
  // so far supports only Firefox, Chrome and Opera (buggy)
883
916
  // could be extended in the future to use something like https://github.com/csnover/TraceKit
884
- function sourceFromStacktrace() {
917
+ function extractStacktrace( e, offset ) {
918
+ offset = offset || 3;
919
+ if (e.stacktrace) {
920
+ // Opera
921
+ return e.stacktrace.split("\n")[offset + 3];
922
+ } else if (e.stack) {
923
+ // Firefox, Chrome
924
+ var stack = e.stack.split("\n");
925
+ if (/^error$/i.test(stack[0])) {
926
+ stack.shift();
927
+ }
928
+ return stack[offset];
929
+ } else if (e.sourceURL) {
930
+ // Safari, PhantomJS
931
+ // hopefully one day Safari provides actual stacktraces
932
+ // exclude useless self-reference for generated Error objects
933
+ if ( /qunit.js$/.test( e.sourceURL ) ) {
934
+ return;
935
+ }
936
+ // for actual exceptions, this is useful
937
+ return e.sourceURL + ":" + e.line;
938
+ }
939
+ }
940
+ function sourceFromStacktrace(offset) {
885
941
  try {
886
942
  throw new Error();
887
943
  } catch ( e ) {
888
- if (e.stacktrace) {
889
- // Opera
890
- return e.stacktrace.split("\n")[6];
891
- } else if (e.stack) {
892
- // Firefox, Chrome
893
- return e.stack.split("\n")[4];
894
- } else if (e.sourceURL) {
895
- // Safari, PhantomJS
896
- // TODO sourceURL points at the 'throw new Error' line above, useless
897
- //return e.sourceURL + ":" + e.line;
898
- }
944
+ return extractStacktrace( e, offset );
899
945
  }
900
946
  }
901
947
 
@@ -923,6 +969,9 @@ function synchronize( callback, last ) {
923
969
  }
924
970
 
925
971
  function process( last ) {
972
+ function next() {
973
+ process( last );
974
+ }
926
975
  var start = new Date().getTime();
927
976
  config.depth = config.depth ? config.depth + 1 : 1;
928
977
 
@@ -930,9 +979,7 @@ function process( last ) {
930
979
  if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
931
980
  config.queue.shift()();
932
981
  } else {
933
- window.setTimeout( function(){
934
- process( last );
935
- }, 13 );
982
+ window.setTimeout( next, 13 );
936
983
  break;
937
984
  }
938
985
  }
@@ -961,12 +1008,12 @@ function checkPollution( name ) {
961
1008
 
962
1009
  var newGlobals = diff( config.pollution, old );
963
1010
  if ( newGlobals.length > 0 ) {
964
- ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
1011
+ QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
965
1012
  }
966
1013
 
967
1014
  var deletedGlobals = diff( old, config.pollution );
968
1015
  if ( deletedGlobals.length > 0 ) {
969
- ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
1016
+ QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
970
1017
  }
971
1018
  }
972
1019
 
@@ -985,18 +1032,6 @@ function diff( a, b ) {
985
1032
  return result;
986
1033
  }
987
1034
 
988
- function fail(message, exception, callback) {
989
- if ( typeof console !== "undefined" && console.error && console.warn ) {
990
- console.error(message);
991
- console.error(exception);
992
- console.error(exception.stack);
993
- console.warn(callback.toString());
994
-
995
- } else if ( window.opera && opera.postError ) {
996
- opera.postError(message, exception, callback.toString);
997
- }
998
- }
999
-
1000
1035
  function extend(a, b) {
1001
1036
  for ( var prop in b ) {
1002
1037
  if ( b[prop] === undefined ) {
@@ -1048,7 +1083,7 @@ function runLoggingCallbacks(key, scope, args) {
1048
1083
 
1049
1084
  // Test for equality any JavaScript type.
1050
1085
  // Author: Philippe Rathé <prathe@gmail.com>
1051
- QUnit.equiv = function () {
1086
+ QUnit.equiv = (function() {
1052
1087
 
1053
1088
  var innerEquiv; // the real equiv function
1054
1089
  var callers = []; // stack to decide between skip/abort functions
@@ -1070,7 +1105,7 @@ QUnit.equiv = function () {
1070
1105
  return obj.__proto__;
1071
1106
  };
1072
1107
 
1073
- var callbacks = function () {
1108
+ var callbacks = (function () {
1074
1109
 
1075
1110
  // for string, boolean, number and null
1076
1111
  function useStrictEquality(b, a) {
@@ -1097,17 +1132,18 @@ QUnit.equiv = function () {
1097
1132
  },
1098
1133
 
1099
1134
  "date" : function(b, a) {
1100
- return QUnit.objectType(b) === "date"
1101
- && a.valueOf() === b.valueOf();
1135
+ return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
1102
1136
  },
1103
1137
 
1104
1138
  "regexp" : function(b, a) {
1105
- return QUnit.objectType(b) === "regexp"
1106
- && a.source === b.source && // the regex itself
1107
- a.global === b.global && // and its modifers
1108
- // (gmi) ...
1109
- a.ignoreCase === b.ignoreCase
1110
- && a.multiline === b.multiline;
1139
+ return QUnit.objectType(b) === "regexp" &&
1140
+ // the regex itself
1141
+ a.source === b.source &&
1142
+ // and its modifers
1143
+ a.global === b.global &&
1144
+ // (gmi) ...
1145
+ a.ignoreCase === b.ignoreCase &&
1146
+ a.multiline === b.multiline;
1111
1147
  },
1112
1148
 
1113
1149
  // - skip when the property is a method of an instance (OOP)
@@ -1123,7 +1159,7 @@ QUnit.equiv = function () {
1123
1159
  var len;
1124
1160
 
1125
1161
  // b could be an object literal here
1126
- if (!(QUnit.objectType(b) === "array")) {
1162
+ if (QUnit.objectType(b) !== "array") {
1127
1163
  return false;
1128
1164
  }
1129
1165
 
@@ -1162,7 +1198,7 @@ QUnit.equiv = function () {
1162
1198
  // Allow objects with no prototype to be equivalent to
1163
1199
  // objects with Object as their constructor.
1164
1200
  if (!((getProto(a) === null && getProto(b) === Object.prototype) ||
1165
- (getProto(b) === null && getProto(a) === Object.prototype)))
1201
+ (getProto(b) === null && getProto(a) === Object.prototype)))
1166
1202
  {
1167
1203
  return false;
1168
1204
  }
@@ -1177,9 +1213,10 @@ QUnit.equiv = function () {
1177
1213
  // and go deep
1178
1214
  loop = false;
1179
1215
  for (j = 0; j < parents.length; j++) {
1180
- if (parents[j] === a[i])
1181
- loop = true; // don't go down the same path
1182
- // twice
1216
+ if (parents[j] === a[i]) {
1217
+ // don't go down the same path twice
1218
+ loop = true;
1219
+ }
1183
1220
  }
1184
1221
  aProperties.push(i); // collect a's properties
1185
1222
 
@@ -1197,12 +1234,10 @@ QUnit.equiv = function () {
1197
1234
  }
1198
1235
 
1199
1236
  // Ensures identical properties name
1200
- return eq
1201
- && innerEquiv(aProperties.sort(), bProperties
1202
- .sort());
1237
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
1203
1238
  }
1204
1239
  };
1205
- }();
1240
+ }());
1206
1241
 
1207
1242
  innerEquiv = function() { // can take multiple arguments
1208
1243
  var args = Array.prototype.slice.apply(arguments);
@@ -1213,23 +1248,21 @@ QUnit.equiv = function () {
1213
1248
  return (function(a, b) {
1214
1249
  if (a === b) {
1215
1250
  return true; // catch the most you can
1216
- } else if (a === null || b === null || typeof a === "undefined"
1217
- || typeof b === "undefined"
1218
- || QUnit.objectType(a) !== QUnit.objectType(b)) {
1251
+ } else if (a === null || b === null || typeof a === "undefined" ||
1252
+ typeof b === "undefined" ||
1253
+ QUnit.objectType(a) !== QUnit.objectType(b)) {
1219
1254
  return false; // don't lose time with error prone cases
1220
1255
  } else {
1221
1256
  return bindCallbacks(a, callbacks, [ b, a ]);
1222
1257
  }
1223
1258
 
1224
1259
  // apply transition with (1..n) arguments
1225
- })(args[0], args[1])
1226
- && arguments.callee.apply(this, args.splice(1,
1227
- args.length - 1));
1260
+ }(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length - 1)));
1228
1261
  };
1229
1262
 
1230
1263
  return innerEquiv;
1231
1264
 
1232
- }();
1265
+ }());
1233
1266
 
1234
1267
  /**
1235
1268
  * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
@@ -1244,33 +1277,36 @@ QUnit.equiv = function () {
1244
1277
  QUnit.jsDump = (function() {
1245
1278
  function quote( str ) {
1246
1279
  return '"' + str.toString().replace(/"/g, '\\"') + '"';
1247
- };
1280
+ }
1248
1281
  function literal( o ) {
1249
1282
  return o + '';
1250
- };
1283
+ }
1251
1284
  function join( pre, arr, post ) {
1252
1285
  var s = jsDump.separator(),
1253
1286
  base = jsDump.indent(),
1254
1287
  inner = jsDump.indent(1);
1255
- if ( arr.join )
1288
+ if ( arr.join ) {
1256
1289
  arr = arr.join( ',' + s + inner );
1257
- if ( !arr )
1290
+ }
1291
+ if ( !arr ) {
1258
1292
  return pre + post;
1293
+ }
1259
1294
  return [ pre, inner + arr, base + post ].join(s);
1260
- };
1295
+ }
1261
1296
  function array( arr, stack ) {
1262
- var i = arr.length, ret = Array(i);
1297
+ var i = arr.length, ret = new Array(i);
1263
1298
  this.up();
1264
- while ( i-- )
1299
+ while ( i-- ) {
1265
1300
  ret[i] = this.parse( arr[i] , undefined , stack);
1301
+ }
1266
1302
  this.down();
1267
1303
  return join( '[', ret, ']' );
1268
- };
1304
+ }
1269
1305
 
1270
1306
  var reName = /^function (\w+)/;
1271
1307
 
1272
1308
  var jsDump = {
1273
- parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
1309
+ parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance
1274
1310
  stack = stack || [ ];
1275
1311
  var parser = this.parsers[ type || this.typeOf(obj) ];
1276
1312
  type = typeof parser;
@@ -1288,7 +1324,7 @@ QUnit.jsDump = (function() {
1288
1324
  // else
1289
1325
  return (type == 'string') ? parser : this.parsers.error;
1290
1326
  },
1291
- typeOf:function( obj ) {
1327
+ typeOf: function( obj ) {
1292
1328
  var type;
1293
1329
  if ( obj === null ) {
1294
1330
  type = "null";
@@ -1318,45 +1354,48 @@ QUnit.jsDump = (function() {
1318
1354
  }
1319
1355
  return type;
1320
1356
  },
1321
- separator:function() {
1357
+ separator: function() {
1322
1358
  return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
1323
1359
  },
1324
- indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
1325
- if ( !this.multiline )
1360
+ indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
1361
+ if ( !this.multiline ) {
1326
1362
  return '';
1363
+ }
1327
1364
  var chr = this.indentChar;
1328
- if ( this.HTML )
1365
+ if ( this.HTML ) {
1329
1366
  chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
1330
- return Array( this._depth_ + (extra||0) ).join(chr);
1367
+ }
1368
+ return new Array( this._depth_ + (extra||0) ).join(chr);
1331
1369
  },
1332
- up:function( a ) {
1370
+ up: function( a ) {
1333
1371
  this._depth_ += a || 1;
1334
1372
  },
1335
- down:function( a ) {
1373
+ down: function( a ) {
1336
1374
  this._depth_ -= a || 1;
1337
1375
  },
1338
- setParser:function( name, parser ) {
1376
+ setParser: function( name, parser ) {
1339
1377
  this.parsers[name] = parser;
1340
1378
  },
1341
1379
  // The next 3 are exposed so you can use them
1342
- quote:quote,
1343
- literal:literal,
1344
- join:join,
1380
+ quote: quote,
1381
+ literal: literal,
1382
+ join: join,
1345
1383
  //
1346
1384
  _depth_: 1,
1347
1385
  // This is the list of parsers, to modify them, use jsDump.setParser
1348
- parsers:{
1386
+ parsers: {
1349
1387
  window: '[Window]',
1350
1388
  document: '[Document]',
1351
- error:'[ERROR]', //when no parser is found, shouldn't happen
1389
+ error: '[ERROR]', //when no parser is found, shouldn't happen
1352
1390
  unknown: '[Unknown]',
1353
- 'null':'null',
1354
- 'undefined':'undefined',
1355
- 'function':function( fn ) {
1391
+ 'null': 'null',
1392
+ 'undefined': 'undefined',
1393
+ 'function': function( fn ) {
1356
1394
  var ret = 'function',
1357
1395
  name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
1358
- if ( name )
1396
+ if ( name ) {
1359
1397
  ret += ' ' + name;
1398
+ }
1360
1399
  ret += '(';
1361
1400
 
1362
1401
  ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
@@ -1364,18 +1403,26 @@ QUnit.jsDump = (function() {
1364
1403
  },
1365
1404
  array: array,
1366
1405
  nodelist: array,
1367
- arguments: array,
1368
- object:function( map, stack ) {
1369
- var ret = [ ];
1406
+ 'arguments': array,
1407
+ object: function( map, stack ) {
1408
+ var ret = [ ], keys, key, val, i;
1370
1409
  QUnit.jsDump.up();
1371
- for ( var key in map ) {
1372
- var val = map[key];
1373
- ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack));
1374
- }
1410
+ if (Object.keys) {
1411
+ keys = Object.keys( map );
1412
+ } else {
1413
+ keys = [];
1414
+ for (key in map) { keys.push( key ); }
1415
+ }
1416
+ keys.sort();
1417
+ for (i = 0; i < keys.length; i++) {
1418
+ key = keys[ i ];
1419
+ val = map[ key ];
1420
+ ret.push( QUnit.jsDump.parse( key, 'key' ) + ': ' + QUnit.jsDump.parse( val, undefined, stack ) );
1421
+ }
1375
1422
  QUnit.jsDump.down();
1376
1423
  return join( '{', ret, '}' );
1377
1424
  },
1378
- node:function( node ) {
1425
+ node: function( node ) {
1379
1426
  var open = QUnit.jsDump.HTML ? '&lt;' : '<',
1380
1427
  close = QUnit.jsDump.HTML ? '&gt;' : '>';
1381
1428
 
@@ -1384,28 +1431,32 @@ QUnit.jsDump = (function() {
1384
1431
 
1385
1432
  for ( var a in QUnit.jsDump.DOMAttrs ) {
1386
1433
  var val = node[QUnit.jsDump.DOMAttrs[a]];
1387
- if ( val )
1434
+ if ( val ) {
1388
1435
  ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
1436
+ }
1389
1437
  }
1390
1438
  return ret + close + open + '/' + tag + close;
1391
1439
  },
1392
- functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
1440
+ functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function
1393
1441
  var l = fn.length;
1394
- if ( !l ) return '';
1442
+ if ( !l ) {
1443
+ return '';
1444
+ }
1395
1445
 
1396
- var args = Array(l);
1397
- while ( l-- )
1446
+ var args = new Array(l);
1447
+ while ( l-- ) {
1398
1448
  args[l] = String.fromCharCode(97+l);//97 is 'a'
1449
+ }
1399
1450
  return ' ' + args.join(', ') + ' ';
1400
1451
  },
1401
- key:quote, //object calls it internally, the key part of an item in a map
1402
- functionCode:'[code]', //function calls it internally, it's the content of the function
1403
- attribute:quote, //node calls it internally, it's an html attribute value
1404
- string:quote,
1405
- date:quote,
1406
- regexp:literal, //regex
1407
- number:literal,
1408
- 'boolean':literal
1452
+ key: quote, //object calls it internally, the key part of an item in a map
1453
+ functionCode: '[code]', //function calls it internally, it's the content of the function
1454
+ attribute: quote, //node calls it internally, it's an html attribute value
1455
+ string: quote,
1456
+ date: quote,
1457
+ regexp: literal, //regex
1458
+ number: literal,
1459
+ 'boolean': literal
1409
1460
  },
1410
1461
  DOMAttrs:{//attributes to dump from nodes, name=>realName
1411
1462
  id:'id',
@@ -1418,7 +1469,7 @@ QUnit.jsDump = (function() {
1418
1469
  };
1419
1470
 
1420
1471
  return jsDump;
1421
- })();
1472
+ }());
1422
1473
 
1423
1474
  // from Sizzle.js
1424
1475
  function getText( elems ) {
@@ -1438,7 +1489,7 @@ function getText( elems ) {
1438
1489
  }
1439
1490
 
1440
1491
  return ret;
1441
- };
1492
+ }
1442
1493
 
1443
1494
  //from jquery.js
1444
1495
  function inArray( elem, array ) {
@@ -1473,26 +1524,29 @@ QUnit.diff = (function() {
1473
1524
  function diff(o, n) {
1474
1525
  var ns = {};
1475
1526
  var os = {};
1527
+ var i;
1476
1528
 
1477
- for (var i = 0; i < n.length; i++) {
1478
- if (ns[n[i]] == null)
1529
+ for (i = 0; i < n.length; i++) {
1530
+ if (ns[n[i]] == null) {
1479
1531
  ns[n[i]] = {
1480
1532
  rows: [],
1481
1533
  o: null
1482
1534
  };
1535
+ }
1483
1536
  ns[n[i]].rows.push(i);
1484
1537
  }
1485
1538
 
1486
- for (var i = 0; i < o.length; i++) {
1487
- if (os[o[i]] == null)
1539
+ for (i = 0; i < o.length; i++) {
1540
+ if (os[o[i]] == null) {
1488
1541
  os[o[i]] = {
1489
1542
  rows: [],
1490
1543
  n: null
1491
1544
  };
1545
+ }
1492
1546
  os[o[i]].rows.push(i);
1493
1547
  }
1494
1548
 
1495
- for (var i in ns) {
1549
+ for (i in ns) {
1496
1550
  if ( !hasOwn.call( ns, i ) ) {
1497
1551
  continue;
1498
1552
  }
@@ -1508,7 +1562,7 @@ QUnit.diff = (function() {
1508
1562
  }
1509
1563
  }
1510
1564
 
1511
- for (var i = 0; i < n.length - 1; i++) {
1565
+ for (i = 0; i < n.length - 1; i++) {
1512
1566
  if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
1513
1567
  n[i + 1] == o[n[i].row + 1]) {
1514
1568
  n[i + 1] = {
@@ -1522,7 +1576,7 @@ QUnit.diff = (function() {
1522
1576
  }
1523
1577
  }
1524
1578
 
1525
- for (var i = n.length - 1; i > 0; i--) {
1579
+ for (i = n.length - 1; i > 0; i--) {
1526
1580
  if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
1527
1581
  n[i - 1] == o[n[i].row - 1]) {
1528
1582
  n[i - 1] = {
@@ -1545,9 +1599,10 @@ QUnit.diff = (function() {
1545
1599
  return function(o, n) {
1546
1600
  o = o.replace(/\s+$/, '');
1547
1601
  n = n.replace(/\s+$/, '');
1548
- var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
1602
+ var out = diff(o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/));
1549
1603
 
1550
1604
  var str = "";
1605
+ var i;
1551
1606
 
1552
1607
  var oSpace = o.match(/\s+/g);
1553
1608
  if (oSpace == null) {
@@ -1564,8 +1619,8 @@ QUnit.diff = (function() {
1564
1619
  nSpace.push(" ");
1565
1620
  }
1566
1621
 
1567
- if (out.n.length == 0) {
1568
- for (var i = 0; i < out.o.length; i++) {
1622
+ if (out.n.length === 0) {
1623
+ for (i = 0; i < out.o.length; i++) {
1569
1624
  str += '<del>' + out.o[i] + oSpace[i] + "</del>";
1570
1625
  }
1571
1626
  }
@@ -1576,7 +1631,7 @@ QUnit.diff = (function() {
1576
1631
  }
1577
1632
  }
1578
1633
 
1579
- for (var i = 0; i < out.n.length; i++) {
1634
+ for (i = 0; i < out.n.length; i++) {
1580
1635
  if (out.n[i].text == null) {
1581
1636
  str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
1582
1637
  }
@@ -1593,6 +1648,12 @@ QUnit.diff = (function() {
1593
1648
 
1594
1649
  return str;
1595
1650
  };
1596
- })();
1651
+ }());
1652
+
1653
+ // for CommonJS enviroments, export everything
1654
+ if ( typeof exports !== "undefined" || typeof require !== "undefined" ) {
1655
+ extend(exports, QUnit);
1656
+ }
1597
1657
 
1598
- })(this);
1658
+ // get at whatever the global object is, like window in browsers
1659
+ }( (function() {return this;}.call()) ));