jim 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/HISTORY +28 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +2 -1
  4. data/jim.gemspec +67 -9
  5. data/lib/jim/bundler.rb +14 -11
  6. data/lib/jim/cli.rb +51 -9
  7. data/lib/jim/index.rb +3 -7
  8. data/lib/jim/installer.rb +140 -22
  9. data/lib/jim/templates/commands +21 -6
  10. data/lib/jim/version_parser.rb +2 -3
  11. data/lib/jim.rb +19 -2
  12. data/test/fixtures/jimfile +3 -3
  13. data/test/fixtures/sammy-0.5.0/HISTORY.md +135 -0
  14. data/test/fixtures/sammy-0.5.0/LICENSE +22 -0
  15. data/test/fixtures/sammy-0.5.0/README.md +81 -0
  16. data/test/fixtures/sammy-0.5.0/Rakefile +174 -0
  17. data/test/fixtures/sammy-0.5.0/examples/backend/README.md +23 -0
  18. data/test/fixtures/sammy-0.5.0/examples/backend/Rakefile +15 -0
  19. data/test/fixtures/sammy-0.5.0/examples/backend/app.rb +17 -0
  20. data/test/fixtures/sammy-0.5.0/examples/backend/app.ru +3 -0
  21. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/app.js +106 -0
  22. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.cloudkit.js +840 -0
  23. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/jquery.js +19 -0
  24. data/test/fixtures/sammy-0.5.0/examples/backend/public/javascripts/sammy.js +1013 -0
  25. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/index.html.erb +11 -0
  26. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task.html.erb +4 -0
  27. data/test/fixtures/sammy-0.5.0/examples/backend/public/templates/task_details.html.erb +4 -0
  28. data/test/fixtures/sammy-0.5.0/examples/backend/views/app.sass +63 -0
  29. data/test/fixtures/sammy-0.5.0/examples/backend/views/index.haml +18 -0
  30. data/test/fixtures/sammy-0.5.0/examples/form_handling/files/form.html +12 -0
  31. data/test/fixtures/sammy-0.5.0/examples/form_handling/index.html +65 -0
  32. data/test/fixtures/sammy-0.5.0/examples/hello_world/index.html +50 -0
  33. data/test/fixtures/sammy-0.5.0/examples/location_override/README.md +15 -0
  34. data/test/fixtures/sammy-0.5.0/examples/location_override/data.html +110 -0
  35. data/test/fixtures/sammy-0.5.0/examples/location_override/index.html +79 -0
  36. data/test/fixtures/sammy-0.5.0/examples/location_override/test.html +121 -0
  37. data/test/fixtures/sammy-0.5.0/lib/min/sammy-0.5.0.min.js +5 -0
  38. data/test/fixtures/sammy-0.5.0/lib/min/sammy-lastest.min.js +5 -0
  39. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.cache.js +117 -0
  40. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.haml.js +539 -0
  41. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.json.js +362 -0
  42. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.mustache.js +415 -0
  43. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.nested_params.js +118 -0
  44. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.storage.js +515 -0
  45. data/test/fixtures/sammy-0.5.0/lib/plugins/sammy.template.js +117 -0
  46. data/test/fixtures/sammy-0.5.0/lib/sammy.js +1367 -0
  47. data/test/fixtures/sammy-0.5.0/test/fixtures/partial +1 -0
  48. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.html +1 -0
  49. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.noengine +1 -0
  50. data/test/fixtures/sammy-0.5.0/test/fixtures/partial.template +1 -0
  51. data/test/fixtures/sammy-0.5.0/test/index.html +84 -0
  52. data/test/fixtures/sammy-0.5.0/test/test_sammy_application.js +953 -0
  53. data/test/fixtures/sammy-0.5.0/test/test_sammy_event_context.js +252 -0
  54. data/test/fixtures/sammy-0.5.0/test/test_sammy_location_proxy.js +91 -0
  55. data/test/fixtures/sammy-0.5.0/test/test_sammy_plugins.js +296 -0
  56. data/test/fixtures/sammy-0.5.0/test/test_sammy_storage.js +175 -0
  57. data/test/fixtures/sammy-0.5.0/test/test_server +27 -0
  58. data/test/fixtures/sammy-0.5.0/vendor/jquery-1.4.1.js +6078 -0
  59. data/test/fixtures/sammy-0.5.0/vendor/jquery-1.4.1.min.js +152 -0
  60. data/test/fixtures/sammy-0.5.0/vendor/jsdoc/doc.haml +58 -0
  61. data/test/fixtures/sammy-0.5.0/vendor/jsdoc/jsdoc.rb +143 -0
  62. data/test/fixtures/sammy-0.5.0/vendor/jslitmus.js +670 -0
  63. data/test/fixtures/sammy-0.5.0/vendor/qunit/qunit.css +119 -0
  64. data/test/fixtures/sammy-0.5.0/vendor/qunit/qunit.js +1043 -0
  65. data/test/fixtures/sammy-0.5.0/vendor/qunit-spec.js +127 -0
  66. data/test/helper.rb +23 -3
  67. data/test/test_jim_bundler.rb +9 -8
  68. data/test/test_jim_cli.rb +21 -12
  69. data/test/test_jim_installer.rb +152 -35
  70. data/test/test_jim_version_parser.rb +4 -0
  71. metadata +117 -27
  72. data/.document +0 -5
@@ -0,0 +1,670 @@
1
+ // JSLitmus.js
2
+ //
3
+ // History:
4
+ // 2008-10-27: Initial release
5
+ // 2008-11-09: Account for iteration loop overhead
6
+ // 2008-11-13: Added OS detection
7
+ // 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
8
+ //
9
+ // Copyright (c) 2008-2009, Robert Kieffer
10
+ // All Rights Reserved
11
+ //
12
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ // of this software and associated documentation files (the
14
+ // Software), to deal in the Software without restriction, including
15
+ // without limitation the rights to use, copy, modify, merge, publish,
16
+ // distribute, sublicense, and/or sell copies of the Software, and to permit
17
+ // persons to whom the Software is furnished to do so, subject to the
18
+ // following conditions:
19
+ //
20
+ // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
21
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
23
+ // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
24
+ // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26
+ // USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+
28
+ (function() {
29
+ // Private methods and state
30
+
31
+ // Get platform info but don't go crazy trying to recognize everything
32
+ // that's out there. This is just for the major platforms and OSes.
33
+ var platform = 'unknown platform', ua = navigator.userAgent;
34
+
35
+ // Detect OS
36
+ var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
37
+ var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
38
+ if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
39
+
40
+ // Detect browser
41
+ var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
42
+
43
+ // Detect version
44
+ var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
45
+ var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
46
+ var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
47
+
48
+ /**
49
+ * A smattering of methods that are needed to implement the JSLitmus testbed.
50
+ */
51
+ var jsl = {
52
+ /**
53
+ * Enhanced version of escape()
54
+ */
55
+ escape: function(s) {
56
+ s = s.replace(/,/g, '\\,');
57
+ s = escape(s);
58
+ s = s.replace(/\+/g, '%2b');
59
+ s = s.replace(/ /g, '+');
60
+ return s;
61
+ },
62
+
63
+ /**
64
+ * Get an element by ID.
65
+ */
66
+ $: function(id) {
67
+ return document.getElementById(id);
68
+ },
69
+
70
+ /**
71
+ * Null function
72
+ */
73
+ F: function() {},
74
+
75
+ /**
76
+ * Set the status shown in the UI
77
+ */
78
+ status: function(msg) {
79
+ var el = jsl.$('jsl_status');
80
+ if (el) el.innerHTML = msg || '';
81
+ },
82
+
83
+ /**
84
+ * Convert a number to an abbreviated string like, "15K" or "10M"
85
+ */
86
+ toLabel: function(n) {
87
+ if (n == Infinity) {
88
+ return 'Infinity';
89
+ } else if (n > 1e9) {
90
+ n = Math.round(n/1e8);
91
+ return n/10 + 'B';
92
+ } else if (n > 1e6) {
93
+ n = Math.round(n/1e5);
94
+ return n/10 + 'M';
95
+ } else if (n > 1e3) {
96
+ n = Math.round(n/1e2);
97
+ return n/10 + 'K';
98
+ }
99
+ return n;
100
+ },
101
+
102
+ /**
103
+ * Copy properties from src to dst
104
+ */
105
+ extend: function(dst, src) {
106
+ for (var k in src) dst[k] = src[k]; return dst;
107
+ },
108
+
109
+ /**
110
+ * Like Array.join(), but for the key-value pairs in an object
111
+ */
112
+ join: function(o, delimit1, delimit2) {
113
+ if (o.join) return o.join(delimit1); // If it's an array
114
+ var pairs = [];
115
+ for (var k in o) pairs.push(k + delimit1 + o[k]);
116
+ return pairs.join(delimit2);
117
+ },
118
+
119
+ /**
120
+ * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
121
+ */
122
+ indexOf: function(arr, o) {
123
+ if (arr.indexOf) return arr.indexOf(o);
124
+ for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
125
+ return -1;
126
+ }
127
+ };
128
+
129
+ /**
130
+ * Test manages a single test (created with
131
+ * JSLitmus.test())
132
+ *
133
+ * @private
134
+ */
135
+ var Test = function (name, f) {
136
+ if (!f) throw new Error('Undefined test function');
137
+ if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) {
138
+ throw new Error('"' + name + '" test: Test is not a valid Function object');
139
+ }
140
+ this.loopArg = RegExp.$1;
141
+ this.name = name;
142
+ this.f = f;
143
+ };
144
+
145
+ jsl.extend(Test, /** @lends Test */ {
146
+ /** Calibration tests for establishing iteration loop overhead */
147
+ CALIBRATIONS: [
148
+ new Test('calibrating loop', function(count) {while (count--);}),
149
+ new Test('calibrating function', jsl.F)
150
+ ],
151
+
152
+ /**
153
+ * Run calibration tests. Returns true if calibrations are not yet
154
+ * complete (in which case calling code should run the tests yet again).
155
+ * onCalibrated - Callback to invoke when calibrations have finished
156
+ */
157
+ calibrate: function(onCalibrated) {
158
+ for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
159
+ var cal = Test.CALIBRATIONS[i];
160
+ if (cal.running) return true;
161
+ if (!cal.count) {
162
+ cal.isCalibration = true;
163
+ cal.onStop = onCalibrated;
164
+ //cal.MIN_TIME = .1; // Do calibrations quickly
165
+ cal.run(2e4);
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ }
171
+ });
172
+
173
+ jsl.extend(Test.prototype, {/** @lends Test.prototype */
174
+ /** Initial number of iterations */
175
+ INIT_COUNT: 10,
176
+ /** Max iterations allowed (i.e. used to detect bad looping functions) */
177
+ MAX_COUNT: 1e9,
178
+ /** Minimum time a test should take to get valid results (secs) */
179
+ MIN_TIME: .5,
180
+
181
+ /** Callback invoked when test state changes */
182
+ onChange: jsl.F,
183
+
184
+ /** Callback invoked when test is finished */
185
+ onStop: jsl.F,
186
+
187
+ /**
188
+ * Reset test state
189
+ */
190
+ reset: function() {
191
+ delete this.count;
192
+ delete this.time;
193
+ delete this.running;
194
+ delete this.error;
195
+ },
196
+
197
+ /**
198
+ * Run the test (in a timeout). We use a timeout to make sure the browser
199
+ * has a chance to finish rendering any UI changes we've made, like
200
+ * updating the status message.
201
+ */
202
+ run: function(count) {
203
+ count = count || this.INIT_COUNT;
204
+ jsl.status(this.name + ' x ' + count);
205
+ this.running = true;
206
+ var me = this;
207
+ setTimeout(function() {me._run(count);}, 200);
208
+ },
209
+
210
+ /**
211
+ * The nuts and bolts code that actually runs a test
212
+ */
213
+ _run: function(count) {
214
+ var me = this;
215
+
216
+ // Make sure calibration tests have run
217
+ if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
218
+ this.error = null;
219
+
220
+ try {
221
+ var start, f = this.f, now, i = count;
222
+
223
+ // Start the timer
224
+ start = new Date();
225
+
226
+ // Now for the money shot. If this is a looping function ...
227
+ if (this.loopArg) {
228
+ // ... let it do the iteration itself
229
+ f(count);
230
+ } else {
231
+ // ... otherwise do the iteration for it
232
+ while (i--) f();
233
+ }
234
+
235
+ // Get time test took (in secs)
236
+ this.time = Math.max(1,new Date() - start)/1000;
237
+
238
+ // Store iteration count and per-operation time taken
239
+ this.count = count;
240
+ this.period = this.time/count;
241
+
242
+ // Do we need to do another run?
243
+ this.running = this.time <= this.MIN_TIME;
244
+
245
+ // ... if so, compute how many times we should iterate
246
+ if (this.running) {
247
+ // Bump the count to the nearest power of 2
248
+ var x = this.MIN_TIME/this.time;
249
+ var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
250
+ count *= pow;
251
+ if (count > this.MAX_COUNT) {
252
+ throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
253
+ }
254
+ }
255
+ } catch (e) {
256
+ // Exceptions are caught and displayed in the test UI
257
+ this.reset();
258
+ this.error = e;
259
+ }
260
+
261
+ // Figure out what to do next
262
+ if (this.running) {
263
+ me.run(count);
264
+ } else {
265
+ jsl.status('');
266
+ me.onStop(me);
267
+ }
268
+
269
+ // Finish up
270
+ this.onChange(this);
271
+ },
272
+
273
+ /**
274
+ * Get the number of operations per second for this test.
275
+ *
276
+ * @param normalize if true, iteration loop overhead taken into account
277
+ */
278
+ getHz: function(/**Boolean*/ normalize) {
279
+ var p = this.period;
280
+
281
+ // Adjust period based on the calibration test time
282
+ if (normalize && !this.isCalibration) {
283
+ var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
284
+
285
+ // If the period is within 20% of the calibration time, then zero the
286
+ // it out
287
+ p = p < cal.period*1.2 ? 0 : p - cal.period;
288
+ }
289
+
290
+ return Math.round(1/p);
291
+ },
292
+
293
+ /**
294
+ * Get a friendly string describing the test
295
+ */
296
+ toString: function() {
297
+ return this.name + ' - ' + this.time/this.count + ' secs';
298
+ }
299
+ });
300
+
301
+ // CSS we need for the UI
302
+ var STYLESHEET = '<style> \
303
+ #jslitmus {font-family:sans-serif; font-size: 12px;} \
304
+ #jslitmus a {text-decoration: none;} \
305
+ #jslitmus a:hover {text-decoration: underline;} \
306
+ #jsl_status { \
307
+ margin-top: 10px; \
308
+ font-size: 10px; \
309
+ color: #888; \
310
+ } \
311
+ A IMG {border:none} \
312
+ #test_results { \
313
+ margin-top: 10px; \
314
+ font-size: 12px; \
315
+ font-family: sans-serif; \
316
+ border-collapse: collapse; \
317
+ border-spacing: 0px; \
318
+ } \
319
+ #test_results th, #test_results td { \
320
+ border: solid 1px #ccc; \
321
+ vertical-align: top; \
322
+ padding: 3px; \
323
+ } \
324
+ #test_results th { \
325
+ vertical-align: bottom; \
326
+ background-color: #ccc; \
327
+ padding: 1px; \
328
+ font-size: 10px; \
329
+ } \
330
+ #test_results #test_platform { \
331
+ color: #444; \
332
+ text-align:center; \
333
+ } \
334
+ #test_results .test_row { \
335
+ color: #006; \
336
+ cursor: pointer; \
337
+ } \
338
+ #test_results .test_nonlooping { \
339
+ border-left-style: dotted; \
340
+ border-left-width: 2px; \
341
+ } \
342
+ #test_results .test_looping { \
343
+ border-left-style: solid; \
344
+ border-left-width: 2px; \
345
+ } \
346
+ #test_results .test_name {white-space: nowrap;} \
347
+ #test_results .test_pending { \
348
+ } \
349
+ #test_results .test_running { \
350
+ font-style: italic; \
351
+ } \
352
+ #test_results .test_done {} \
353
+ #test_results .test_done { \
354
+ text-align: right; \
355
+ font-family: monospace; \
356
+ } \
357
+ #test_results .test_error {color: #600;} \
358
+ #test_results .test_error .error_head {font-weight:bold;} \
359
+ #test_results .test_error .error_body {font-size:85%;} \
360
+ #test_results .test_row:hover td { \
361
+ background-color: #ffc; \
362
+ text-decoration: underline; \
363
+ } \
364
+ #chart { \
365
+ margin: 10px 0px; \
366
+ width: 250px; \
367
+ } \
368
+ #chart img { \
369
+ border: solid 1px #ccc; \
370
+ margin-bottom: 5px; \
371
+ } \
372
+ #chart #tiny_url { \
373
+ height: 40px; \
374
+ width: 250px; \
375
+ } \
376
+ #jslitmus_credit { \
377
+ font-size: 10px; \
378
+ color: #888; \
379
+ margin-top: 8px; \
380
+ } \
381
+ </style>';
382
+
383
+ // HTML markup for the UI
384
+ var MARKUP = '<div id="jslitmus"> \
385
+ <button onclick="JSLitmus.runAll(event)">Run Tests</button> \
386
+ <button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
387
+ <br \> \
388
+ <br \> \
389
+ <input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
390
+ <table id="test_results"> \
391
+ <colgroup> \
392
+ <col /> \
393
+ <col width="100" /> \
394
+ </colgroup> \
395
+ <tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
396
+ <tr><th>Test</th><th>Ops/sec</th></tr> \
397
+ <tr id="test_row_template" class="test_row" style="display:none"> \
398
+ <td class="test_name"></td> \
399
+ <td class="test_result">Ready</td> \
400
+ </tr> \
401
+ </table> \
402
+ <div id="jsl_status"></div> \
403
+ <div id="chart" style="display:none"> \
404
+ <a id="chart_link" target="_blank"><img id="chart_image"></a> \
405
+ TinyURL (for chart): \
406
+ <iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
407
+ </div> \
408
+ <a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
409
+ </div>';
410
+
411
+ /**
412
+ * The public API for creating and running tests
413
+ */
414
+ window.JSLitmus = {
415
+ /** The list of all tests that have been registered with JSLitmus.test */
416
+ _tests: [],
417
+ /** The queue of tests that need to be run */
418
+ _queue: [],
419
+
420
+ /**
421
+ * The parsed query parameters the current page URL. This is provided as a
422
+ * convenience for test functions - it's not used by JSLitmus proper
423
+ */
424
+ params: {},
425
+
426
+ /**
427
+ * Initialize
428
+ */
429
+ _init: function() {
430
+ // Parse query params into JSLitmus.params[] hash
431
+ var match = (location + '').match(/([^?#]*)(#.*)?$/);
432
+ if (match) {
433
+ var pairs = match[1].split('&');
434
+ for (var i = 0; i < pairs.length; i++) {
435
+ var pair = pairs[i].split('=');
436
+ if (pair.length > 1) {
437
+ var key = pair.shift();
438
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
439
+ this.params[key] = value;
440
+ }
441
+ }
442
+ }
443
+
444
+ // Write out the stylesheet. We have to do this here because IE
445
+ // doesn't honor sheets written after the document has loaded.
446
+ document.write(STYLESHEET);
447
+
448
+ // Setup the rest of the UI once the document is loaded
449
+ if (window.addEventListener) {
450
+ window.addEventListener('load', this._setup, false);
451
+ } else if (document.addEventListener) {
452
+ document.addEventListener('load', this._setup, false);
453
+ } else if (window.attachEvent) {
454
+ window.attachEvent('onload', this._setup);
455
+ }
456
+
457
+ return this;
458
+ },
459
+
460
+ /**
461
+ * Set up the UI
462
+ */
463
+ _setup: function() {
464
+ var el = jsl.$('jslitmus_container');
465
+ if (!el) document.body.appendChild(el = document.createElement('div'));
466
+
467
+ el.innerHTML = MARKUP;
468
+
469
+ // Render the UI for all our tests
470
+ for (var i=0; i < JSLitmus._tests.length; i++)
471
+ JSLitmus.renderTest(JSLitmus._tests[i]);
472
+ },
473
+
474
+ /**
475
+ * (Re)render all the test results
476
+ */
477
+ renderAll: function() {
478
+ for (var i = 0; i < JSLitmus._tests.length; i++)
479
+ JSLitmus.renderTest(JSLitmus._tests[i]);
480
+ JSLitmus.renderChart();
481
+ },
482
+
483
+ /**
484
+ * (Re)render the chart graphics
485
+ */
486
+ renderChart: function() {
487
+ var url = JSLitmus.chartUrl();
488
+ jsl.$('chart_link').href = url;
489
+ jsl.$('chart_image').src = url;
490
+ jsl.$('chart').style.display = '';
491
+
492
+ // Update the tiny URL
493
+ jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
494
+ },
495
+
496
+ /**
497
+ * (Re)render the results for a specific test
498
+ */
499
+ renderTest: function(test) {
500
+ // Make a new row if needed
501
+ if (!test._row) {
502
+ var trow = jsl.$('test_row_template');
503
+ if (!trow) return;
504
+
505
+ test._row = trow.cloneNode(true);
506
+ test._row.style.display = '';
507
+ test._row.id = '';
508
+ test._row.onclick = function() {JSLitmus._queueTest(test);};
509
+ test._row.title = 'Run ' + test.name + ' test';
510
+ trow.parentNode.appendChild(test._row);
511
+ test._row.cells[0].innerHTML = test.name;
512
+ }
513
+
514
+ var cell = test._row.cells[1];
515
+ var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
516
+
517
+ if (test.error) {
518
+ cns.push('test_error');
519
+ cell.innerHTML =
520
+ '<div class="error_head">' + test.error + '</div>' +
521
+ '<ul class="error_body"><li>' +
522
+ jsl.join(test.error, ': ', '</li><li>') +
523
+ '</li></ul>';
524
+ } else {
525
+ if (test.running) {
526
+ cns.push('test_running');
527
+ cell.innerHTML = 'running';
528
+ } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
529
+ cns.push('test_pending');
530
+ cell.innerHTML = 'pending';
531
+ } else if (test.count) {
532
+ cns.push('test_done');
533
+ var hz = test.getHz(jsl.$('test_normalize').checked);
534
+ cell.innerHTML = hz != Infinity ? hz : '&infin;';
535
+ } else {
536
+ cell.innerHTML = 'ready';
537
+ }
538
+ }
539
+ cell.className = cns.join(' ');
540
+ },
541
+
542
+ /**
543
+ * Create a new test
544
+ */
545
+ test: function(name, f) {
546
+ // Create the Test object
547
+ var test = new Test(name, f);
548
+ JSLitmus._tests.push(test);
549
+
550
+ // Re-render if the test state changes
551
+ test.onChange = JSLitmus.renderTest;
552
+
553
+ // Run the next test if this one finished
554
+ test.onStop = function(test) {
555
+ if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
556
+ JSLitmus.currentTest = null;
557
+ JSLitmus._nextTest();
558
+ };
559
+
560
+ // Render the new test
561
+ this.renderTest(test);
562
+ },
563
+
564
+ /**
565
+ * Add all tests to the run queue
566
+ */
567
+ runAll: function(e) {
568
+ e = e || window.event;
569
+ var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
570
+ for (var i = 0; i < len; i++) {
571
+ JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
572
+ }
573
+ },
574
+
575
+ /**
576
+ * Remove all tests from the run queue. The current test has to finish on
577
+ * it's own though
578
+ */
579
+ stop: function() {
580
+ while (JSLitmus._queue.length) {
581
+ var test = JSLitmus._queue.shift();
582
+ JSLitmus.renderTest(test);
583
+ }
584
+ },
585
+
586
+ /**
587
+ * Run the next test in the run queue
588
+ */
589
+ _nextTest: function() {
590
+ if (!JSLitmus.currentTest) {
591
+ var test = JSLitmus._queue.shift();
592
+ if (test) {
593
+ jsl.$('stop_button').disabled = false;
594
+ JSLitmus.currentTest = test;
595
+ test.run();
596
+ JSLitmus.renderTest(test);
597
+ if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
598
+ } else {
599
+ jsl.$('stop_button').disabled = true;
600
+ JSLitmus.renderChart();
601
+ }
602
+ }
603
+ },
604
+
605
+ /**
606
+ * Add a test to the run queue
607
+ */
608
+ _queueTest: function(test) {
609
+ if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
610
+ JSLitmus._queue.push(test);
611
+ JSLitmus.renderTest(test);
612
+ JSLitmus._nextTest();
613
+ },
614
+
615
+ /**
616
+ * Generate a Google Chart URL that shows the data for all tests
617
+ */
618
+ chartUrl: function() {
619
+ var n = JSLitmus._tests.length, markers = [], data = [];
620
+ var d, min = 0, max = -1e10;
621
+ var normalize = jsl.$('test_normalize').checked;
622
+
623
+ // Gather test data
624
+ for (var i=0; i < JSLitmus._tests.length; i++) {
625
+ var test = JSLitmus._tests[i];
626
+ if (test.count) {
627
+ var hz = test.getHz(normalize);
628
+ var v = hz != Infinity ? hz : 0;
629
+ data.push(v);
630
+ markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
631
+ markers.length + ',10');
632
+ max = Math.max(v, max);
633
+ }
634
+ }
635
+ if (markers.length <= 0) return null;
636
+
637
+ // Build chart title
638
+ var title = document.getElementsByTagName('title');
639
+ title = (title && title.length) ? title[0].innerHTML : null;
640
+ var chart_title = [];
641
+ if (title) chart_title.push(title);
642
+ chart_title.push('Ops/sec (' + platform + ')');
643
+
644
+ // Build labels
645
+ var labels = [jsl.toLabel(min), jsl.toLabel(max)];
646
+
647
+ var w = 250, bw = 15;
648
+ var bs = 5;
649
+ var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
650
+
651
+ var params = {
652
+ chtt: escape(chart_title.join('|')),
653
+ chts: '000000,10',
654
+ cht: 'bhg', // chart type
655
+ chd: 't:' + data.join(','), // data set
656
+ chds: min + ',' + max, // max/min of data
657
+ chxt: 'x', // label axes
658
+ chxl: '0:|' + labels.join('|'), // labels
659
+ chsp: '0,1',
660
+ chm: markers.join('|'), // test names
661
+ chbh: [bw, 0, bs].join(','), // bar widths
662
+ // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
663
+ chs: w + 'x' + h
664
+ };
665
+ return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
666
+ }
667
+ };
668
+
669
+ JSLitmus._init();
670
+ })();