[Pkg-javascript-commits] [backbone] 12/34: Adding the beginnings of a speed suite to the Test page.

Jonas Smedegaard js at moszumanska.debian.org
Sat May 3 16:58:44 UTC 2014


This is an automated email from the git hooks/post-receive script.

js pushed a commit to tag 0.1.2
in repository backbone.

commit e7ce57cc1dbb2b5d3048428333153453baf3817a
Author: Jeremy Ashkenas <jashkenas at gmail.com>
Date:   Thu Oct 14 14:46:53 2010 -0400

    Adding the beginnings of a speed suite to the Test page.
---
 backbone.js                     |   2 +-
 test/collection.js              |  22 +-
 test/{bindable.js => events.js} |   8 +-
 test/model.js                   |  22 +-
 test/speed.js                   |  25 ++
 test/test.html                  |   7 +-
 test/vendor/jslitmus.js         | 649 ++++++++++++++++++++++++++++++++++++++++
 test/view.js                    |  15 +-
 8 files changed, 715 insertions(+), 35 deletions(-)

diff --git a/backbone.js b/backbone.js
index 58b6bdd..d0a1acc 100644
--- a/backbone.js
+++ b/backbone.js
@@ -82,7 +82,7 @@
       if (!(calls = this._callbacks)) return this;
       if (list = calls[ev]) {
         for (i = 0, l = list.length; i < l; i++) {
-          list[i].apply(this, _.rest(arguments));
+          list[i].apply(this, Array.prototype.slice.call(arguments, 1));
         }
       }
       if (list = calls['all']) {
diff --git a/test/collection.js b/test/collection.js
index fb9cec8..de5c974 100644
--- a/test/collection.js
+++ b/test/collection.js
@@ -1,6 +1,6 @@
 $(document).ready(function() {
 
-  module("Backbone collections");
+  module("Backbone.Collection");
 
   window.lastRequest = null;
 
@@ -15,7 +15,7 @@ $(document).ready(function() {
   var e = null;
   var col = window.col = new Backbone.Collection([a,b,c,d]);
 
-  test("collections: new and sort", function() {
+  test("Collection: new and sort", function() {
     equals(col.first(), a, "a should be first");
     equals(col.last(), d, "d should be last");
     col.comparator = function(model) { return model.id; };
@@ -25,21 +25,21 @@ $(document).ready(function() {
     equals(col.length, 4);
   });
 
-  test("collections: get, getByCid", function() {
+  test("Collection: get, getByCid", function() {
     equals(col.get(1), d);
     equals(col.get(3), b);
     equals(col.getByCid(col.first().cid), col.first());
   });
 
-  test("collections: at", function() {
+  test("Collection: at", function() {
     equals(col.at(2), b);
   });
 
-  test("collections: pluck", function() {
+  test("Collection: pluck", function() {
     equals(col.pluck('label').join(' '), 'd c b a');
   });
 
-  test("collections: add", function() {
+  test("Collection: add", function() {
     var added = null;
     col.bind('add', function(model){ added = model.get('label'); });
     e = new Backbone.Model({id: 0, label : 'e'});
@@ -49,7 +49,7 @@ $(document).ready(function() {
     equals(col.first(), e);
   });
 
-  test("collections: remove", function() {
+  test("Collection: remove", function() {
     var removed = null;
     col.bind('remove', function(model){ removed = model.get('label'); });
     col.remove(e);
@@ -58,13 +58,13 @@ $(document).ready(function() {
     equals(col.first(), d);
   });
 
-  test("collections: fetch", function() {
+  test("Collection: fetch", function() {
     col.fetch();
     equals(lastRequest[0], 'read');
     equals(lastRequest[1], col);
   });
 
-  test("collections: create", function() {
+  test("Collection: create", function() {
     var model = col.create({label: 'f'});
     equals(lastRequest[0], 'create');
     equals(lastRequest[1], model);
@@ -82,7 +82,7 @@ $(document).ready(function() {
     equals(coll.one, 1);
   });
 
-  test("collections: Underscore methods", function() {
+  test("Collection: Underscore methods", function() {
     equals(col.map(function(model){ return model.get('label'); }).join(' '), 'd c b a');
     equals(col.any(function(model){ return model.id === 100; }), false);
     equals(col.any(function(model){ return model.id === 1; }), true);
@@ -97,7 +97,7 @@ $(document).ready(function() {
     equals(col.min(function(model){ return model.id; }).id, 1);
   });
 
-  test("collections: refresh", function() {
+  test("Collection: refresh", function() {
     var refreshed = 0;
     var models = col.models;
     col.bind('refresh', function() { refreshed += 1; });
diff --git a/test/bindable.js b/test/events.js
similarity index 84%
rename from test/bindable.js
rename to test/events.js
index 1d92bfa..8380842 100644
--- a/test/bindable.js
+++ b/test/events.js
@@ -1,8 +1,8 @@
 $(document).ready(function() {
 
-  module("Backbone bindable");
+  module("Backbone.Events");
 
-  test("bindable: bind and trigger", function() {
+  test("Events: bind and trigger", function() {
     var obj = { counter: 0 };
     _.extend(obj,Backbone.Events);
     obj.bind('event', function() { obj.counter += 1; });
@@ -15,7 +15,7 @@ $(document).ready(function() {
     equals(obj.counter, 5, 'counter should be incremented five times.');
   });
 
-  test("bindable: bind, then unbind all functions", function() {
+  test("Events: bind, then unbind all functions", function() {
     var obj = { counter: 0 };
     _.extend(obj,Backbone.Events);
     var callback = function() { obj.counter += 1; };
@@ -26,7 +26,7 @@ $(document).ready(function() {
     equals(obj.counter, 1, 'counter should have only been incremented once.');
   });
 
-  test("bindable: bind two callbacks, unbind only one", function() {
+  test("Events: bind two callbacks, unbind only one", function() {
     var obj = { counterA: 0, counterB: 0 };
     _.extend(obj,Backbone.Events);
     var callback = function() { obj.counterA += 1; };
diff --git a/test/model.js b/test/model.js
index f10e914..cedb005 100644
--- a/test/model.js
+++ b/test/model.js
@@ -1,6 +1,6 @@
 $(document).ready(function() {
 
-  module("Backbone model");
+  module("Backbone.Model");
 
   // Variable to catch the last request.
   window.lastRequest = null;
@@ -26,7 +26,7 @@ $(document).ready(function() {
   var collection = new klass();
   collection.add(doc);
 
-  test("model: initialize", function() {
+  test("Model: initialize", function() {
     var Model = Backbone.Model.extend({
       initialize: function() {
         this.one = 1;
@@ -36,11 +36,11 @@ $(document).ready(function() {
     equals(model.one, 1);
   });
 
-  test("model: url", function() {
+  test("Model: url", function() {
     equals(doc.url(), '/collection/1-the-tempest');
   });
 
-  test("model: clone", function() {
+  test("Model: clone", function() {
     attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
     a = new Backbone.Model(attrs);
     b = a.clone();
@@ -55,7 +55,7 @@ $(document).ready(function() {
     equals(b.get('foo'), 1, "Changing a parent attribute does not change the clone.");
   });
 
-  test("model: isNew", function() {
+  test("Model: isNew", function() {
     attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
     a = new Backbone.Model(attrs);
     ok(a.isNew(), "it should be new");
@@ -63,12 +63,12 @@ $(document).ready(function() {
     ok(a.isNew(), "any defined ID is legal, negative or positive");
   });
 
-  test("model: get", function() {
+  test("Model: get", function() {
     equals(doc.get('title'), 'The Tempest');
     equals(doc.get('author'), 'Bill Shakespeare');
   });
 
-  test("model: set and unset", function() {
+  test("Model: set and unset", function() {
     attrs = { 'foo': 1, 'bar': 2, 'baz': 3};
     a = new Backbone.Model(attrs);
     var changeCount = 0;
@@ -85,7 +85,7 @@ $(document).ready(function() {
     ok(changeCount == 2, "Change count should have incremented for unset.");
   });
 
-  test("model: changed, hasChanged, changedAttributes, previous, previousAttributes", function() {
+  test("Model: changed, hasChanged, changedAttributes, previous, previousAttributes", function() {
     var model = new Backbone.Model({name : "Tim", age : 10});
     model.bind('change', function() {
       ok(model.hasChanged('name'), 'name changed');
@@ -99,19 +99,19 @@ $(document).ready(function() {
     equals(model.get('name'), 'Rob');
   });
 
-  test("model: save", function() {
+  test("Model: save", function() {
     doc.save({title : "Henry V"});
     equals(lastRequest[0], 'update');
     ok(_.isEqual(lastRequest[1], doc));
   });
 
-  test("model: destroy", function() {
+  test("Model: destroy", function() {
     doc.destroy();
     equals(lastRequest[0], 'delete');
     ok(_.isEqual(lastRequest[1], doc));
   });
 
-  test("model: validate", function() {
+  test("Model: validate", function() {
     var lastError;
     var model = new Backbone.Model();
     model.validate = function(attrs) {
diff --git a/test/speed.js b/test/speed.js
new file mode 100644
index 0000000..0f29d47
--- /dev/null
+++ b/test/speed.js
@@ -0,0 +1,25 @@
+(function(){
+
+  var object = {};
+  _.extend(object, Backbone.Events);
+  var fn = function(){};
+
+  JSLitmus.test('Events: bind + unbind', function() {
+    object.bind("event", fn);
+    object.unbind("event", fn);
+  });
+
+  object.bind('test:trigger', fn);
+
+  JSLitmus.test('Events: trigger', function() {
+    object.trigger('test:trigger');
+  });
+
+  object.bind('test:trigger2', fn);
+  object.bind('test:trigger2', fn);
+
+  JSLitmus.test('Events: trigger 2 functions, passing 5 arguments', function() {
+    object.trigger('test:trigger2', 1, 2, 3, 4, 5);
+  });
+
+})();
\ No newline at end of file
diff --git a/test/test.html b/test/test.html
index 4ecd386..22d16f0 100644
--- a/test/test.html
+++ b/test/test.html
@@ -5,18 +5,23 @@
   <link rel="stylesheet" href="vendor/qunit.css" type="text/css" media="screen" />
   <script type="text/javascript" src="vendor/jquery-1.4.2.js"></script>
   <script type="text/javascript" src="vendor/qunit.js"></script>
+  <script type="text/javascript" src="vendor/jslitmus.js"></script>
   <script type="text/javascript" src="vendor/underscore-1.1.0.js"></script>
   <script type="text/javascript" src="../backbone.js"></script>
 
-  <script type="text/javascript" src="bindable.js"></script>
+  <script type="text/javascript" src="events.js"></script>
   <script type="text/javascript" src="model.js"></script>
   <script type="text/javascript" src="collection.js"></script>
   <script type="text/javascript" src="view.js"></script>
+  <script type="text/javascript" src="speed.js"></script>
 </head>
 <body>
   <h1 id="qunit-header">Backbone Test Suite</h1>
   <h2 id="qunit-banner"></h2>
   <h2 id="qunit-userAgent"></h2>
   <ol id="qunit-tests"></ol>
+  <br /><br />
+  <h1 id="qunit-header">Backbone Speed Suite</h1>
+  <div id="jslitmus_container" style="margin: 20px 10px;"></div>
 </body>
 </html>
diff --git a/test/vendor/jslitmus.js b/test/vendor/jslitmus.js
new file mode 100644
index 0000000..a411179
--- /dev/null
+++ b/test/vendor/jslitmus.js
@@ -0,0 +1,649 @@
+// JSLitmus.js
+//
+// Copyright (c) 2010, Robert Kieffer, http://broofa.com
+// Available under MIT license (http://en.wikipedia.org/wiki/MIT_License)
+
+(function() {
+  // Private methods and state
+
+  // Get platform info but don't go crazy trying to recognize everything
+  // that's out there.  This is just for the major platforms and OSes.
+  var platform = 'unknown platform', ua = navigator.userAgent;
+
+  // Detect OS
+  var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
+  var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
+  if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
+
+  // Detect browser
+  var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
+
+  // Detect version
+  var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
+  var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
+  var platform = (pOS && pName && pVersion) ? pName + ' '  + pVersion + ' on ' + pOS : 'unknown platform';
+
+  /**
+  * A smattering of methods that are needed to implement the JSLitmus testbed.
+  */
+  var jsl = {
+    /**
+    * Enhanced version of escape()
+    */
+    escape: function(s) {
+      s = s.replace(/,/g, '\\,');
+      s = escape(s);
+      s = s.replace(/\+/g, '%2b');
+      s = s.replace(/ /g, '+');
+      return s;
+    },
+
+    /**
+    * Get an element by ID.
+    */
+    $: function(id) {
+      return document.getElementById(id);
+    },
+
+    /**
+    * Null function
+    */
+    F: function() {},
+
+    /**
+    * Set the status shown in the UI
+    */
+    status: function(msg) {
+      var el = jsl.$('jsl_status');
+      if (el) el.innerHTML = msg || '';
+    },
+
+    /**
+    * Convert a number to an abbreviated string like, "15K" or "10M"
+    */
+    toLabel: function(n) {
+      if (n == Infinity) {
+        return 'Infinity';
+      } else if (n > 1e9) {
+        n = Math.round(n/1e8);
+        return n/10 + 'B';
+      } else if (n > 1e6) {
+        n = Math.round(n/1e5);
+        return n/10 + 'M';
+      } else if (n > 1e3) {
+        n = Math.round(n/1e2);
+        return n/10 + 'K';
+      }
+      return n;
+    },
+
+    /**
+    * Copy properties from src to dst
+    */
+    extend: function(dst, src) {
+      for (var k in src) dst[k] = src[k]; return dst;
+    },
+
+    /**
+    * Like Array.join(), but for the key-value pairs in an object
+    */
+    join: function(o, delimit1, delimit2) {
+      if (o.join) return o.join(delimit1);  // If it's an array
+      var pairs = [];
+      for (var k in o) pairs.push(k + delimit1 + o[k]);
+      return pairs.join(delimit2);
+    },
+
+    /**
+    * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
+    */
+    indexOf: function(arr, o) {
+      if (arr.indexOf) return arr.indexOf(o);
+      for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
+      return -1;
+    }
+  };
+
+  /**
+  * Test manages a single test (created with
+  * JSLitmus.test())
+  *
+  * @private
+  */
+  var Test = function (name, f) {
+    if (!f) throw new Error('Undefined test function');
+    if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) {
+      throw new Error('"' + name + '" test: Test is not a valid Function object');
+    }
+    this.loopArg = RegExp.$1;
+    this.name = name;
+    this.f = f;
+  };
+
+  jsl.extend(Test, /** @lends Test */ {
+    /** Calibration tests for establishing iteration loop overhead */
+    CALIBRATIONS: [
+      new Test('calibrating loop', function(count) {while (count--);}),
+      new Test('calibrating function', jsl.F)
+    ],
+
+    /**
+    * Run calibration tests.  Returns true if calibrations are not yet
+    * complete (in which case calling code should run the tests yet again).
+    * onCalibrated - Callback to invoke when calibrations have finished
+    */
+    calibrate: function(onCalibrated) {
+      for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
+        var cal = Test.CALIBRATIONS[i];
+        if (cal.running) return true;
+        if (!cal.count) {
+          cal.isCalibration = true;
+          cal.onStop = onCalibrated;
+          //cal.MIN_TIME = .1; // Do calibrations quickly
+          cal.run(2e4);
+          return true;
+        }
+      }
+      return false;
+    }
+  });
+
+  jsl.extend(Test.prototype, {/** @lends Test.prototype */
+    /** Initial number of iterations */
+    INIT_COUNT: 10,
+    /** Max iterations allowed (i.e. used to detect bad looping functions) */
+    MAX_COUNT: 1e9,
+    /** Minimum time a test should take to get valid results (secs) */
+    MIN_TIME: .5,
+
+    /** Callback invoked when test state changes */
+    onChange: jsl.F,
+
+    /** Callback invoked when test is finished */
+    onStop: jsl.F,
+
+    /**
+     * Reset test state
+     */
+    reset: function() {
+      delete this.count;
+      delete this.time;
+      delete this.running;
+      delete this.error;
+    },
+
+    /**
+    * Run the test (in a timeout). We use a timeout to make sure the browser
+    * has a chance to finish rendering any UI changes we've made, like
+    * updating the status message.
+    */
+    run: function(count) {
+      count = count || this.INIT_COUNT;
+      jsl.status(this.name + ' x ' + count);
+      this.running = true;
+      var me = this;
+      setTimeout(function() {me._run(count);}, 200);
+    },
+
+    /**
+     * The nuts and bolts code that actually runs a test
+     */
+    _run: function(count) {
+      var me = this;
+
+      // Make sure calibration tests have run
+      if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
+      this.error = null;
+
+      try {
+        var start, f = this.f, now, i = count;
+
+        // Start the timer
+        start = new Date();
+
+        // Now for the money shot.  If this is a looping function ...
+        if (this.loopArg) {
+          // ... let it do the iteration itself
+          f(count);
+        } else {
+          // ... otherwise do the iteration for it
+          while (i--) f();
+        }
+
+        // Get time test took (in secs)
+        this.time = Math.max(1,new Date() - start)/1000;
+
+        // Store iteration count and per-operation time taken
+        this.count = count;
+        this.period = this.time/count;
+
+        // Do we need to do another run?
+        this.running = this.time <= this.MIN_TIME;
+
+        // ... if so, compute how many times we should iterate
+        if (this.running) {
+          // Bump the count to the nearest power of 2
+          var x = this.MIN_TIME/this.time;
+          var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
+          count *= pow;
+          if (count > this.MAX_COUNT) {
+            throw new Error('Max count exceeded.  If this test uses a looping function, make sure the iteration loop is working properly.');
+          }
+        }
+      } catch (e) {
+        // Exceptions are caught and displayed in the test UI
+        this.reset();
+        this.error = e;
+      }
+
+      // Figure out what to do next
+      if (this.running) {
+        me.run(count);
+      } else {
+        jsl.status('');
+        me.onStop(me);
+      }
+
+      // Finish up
+      this.onChange(this);
+    },
+
+    /**
+    * Get the number of operations per second for this test.
+    *
+    * @param normalize if true, iteration loop overhead taken into account
+    */
+    getHz: function(/**Boolean*/ normalize) {
+      var p = this.period;
+
+      // Adjust period based on the calibration test time
+      if (normalize && !this.isCalibration) {
+        var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
+
+        // If the period is within 20% of the calibration time, then zero the
+        // it out
+        p = p < cal.period*1.2 ? 0 : p - cal.period;
+      }
+
+      return Math.round(1/p);
+    },
+
+    /**
+    * Get a friendly string describing the test
+    */
+    toString: function() {
+      return this.name + ' - '  + this.time/this.count + ' secs';
+    }
+  });
+
+  // CSS we need for the UI
+  var STYLESHEET = '<style> \
+    #jslitmus {font-family:sans-serif; font-size: 12px;} \
+    #jslitmus a {text-decoration: none;} \
+    #jslitmus a:hover {text-decoration: underline;} \
+    #jsl_status { \
+      margin-top: 10px; \
+      font-size: 10px; \
+      color: #888; \
+    } \
+    A IMG  {border:none} \
+    #test_results { \
+      margin-top: 10px; \
+      font-size: 12px; \
+      font-family: sans-serif; \
+      border-collapse: collapse; \
+      border-spacing: 0px; \
+    } \
+    #test_results th, #test_results td { \
+      border: solid 1px #ccc; \
+      vertical-align: top; \
+      padding: 3px; \
+    } \
+    #test_results th { \
+      vertical-align: bottom; \
+      background-color: #ccc; \
+      padding: 1px; \
+      font-size: 10px; \
+    } \
+    #test_results #test_platform { \
+      color: #444; \
+      text-align:center; \
+    } \
+    #test_results .test_row { \
+      color: #006; \
+      cursor: pointer; \
+    } \
+    #test_results .test_nonlooping { \
+      border-left-style: dotted; \
+      border-left-width: 2px; \
+    } \
+    #test_results .test_looping { \
+      border-left-style: solid; \
+      border-left-width: 2px; \
+    } \
+    #test_results .test_name {white-space: nowrap;} \
+    #test_results .test_pending { \
+    } \
+    #test_results .test_running { \
+      font-style: italic; \
+    } \
+    #test_results .test_done {} \
+    #test_results .test_done { \
+      text-align: right; \
+      font-family: monospace; \
+    } \
+    #test_results .test_error {color: #600;} \
+    #test_results .test_error .error_head {font-weight:bold;} \
+    #test_results .test_error .error_body {font-size:85%;} \
+    #test_results .test_row:hover td { \
+      background-color: #ffc; \
+      text-decoration: underline; \
+    } \
+    #chart { \
+      margin: 10px 0px; \
+      width: 250px; \
+    } \
+    #chart img { \
+      border: solid 1px #ccc; \
+      margin-bottom: 5px; \
+    } \
+    #chart #tiny_url { \
+      height: 40px; \
+      width: 250px; \
+    } \
+    #jslitmus_credit { \
+      font-size: 10px; \
+      color: #888; \
+      margin-top: 8px; \
+    } \
+    </style>';
+
+  // HTML markup for the UI
+  var MARKUP = '<div id="jslitmus"> \
+      <button onclick="JSLitmus.runAll(event)">Run Tests</button> \
+      <button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
+      <br \> \
+      <br \> \
+      <input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
+      <table id="test_results"> \
+        <colgroup> \
+          <col /> \
+          <col width="100" /> \
+        </colgroup> \
+        <tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
+        <tr><th>Test</th><th>Ops/sec</th></tr> \
+        <tr id="test_row_template" class="test_row" style="display:none"> \
+          <td class="test_name"></td> \
+          <td class="test_result">Ready</td> \
+        </tr> \
+      </table> \
+      <div id="jsl_status"></div> \
+      <div id="chart" style="display:none"> \
+      <a id="chart_link" target="_blank"><img id="chart_image"></a> \
+      TinyURL (for chart): \
+      <iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
+      </div> \
+      <a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
+    </div>';
+
+  /**
+   * The public API for creating and running tests
+   */
+  window.JSLitmus = {
+    /** The list of all tests that have been registered with JSLitmus.test */
+    _tests: [],
+    /** The queue of tests that need to be run */
+    _queue: [],
+
+    /**
+    * The parsed query parameters the current page URL.  This is provided as a
+    * convenience for test functions - it's not used by JSLitmus proper
+    */
+    params: {},
+
+    /**
+     * Initialize
+     */
+    _init: function() {
+      // Parse query params into JSLitmus.params[] hash
+      var match = (location + '').match(/([^?#]*)(#.*)?$/);
+      if (match) {
+        var pairs = match[1].split('&');
+        for (var i = 0; i < pairs.length; i++) {
+          var pair = pairs[i].split('=');
+          if (pair.length > 1) {
+            var key = pair.shift();
+            var value = pair.length > 1 ? pair.join('=') : pair[0];
+            this.params[key] = value;
+          }
+        }
+      }
+
+      // Write out the stylesheet.  We have to do this here because IE
+      // doesn't honor sheets written after the document has loaded.
+      document.write(STYLESHEET);
+
+      // Setup the rest of the UI once the document is loaded
+      if (window.addEventListener) {
+        window.addEventListener('load', this._setup, false);
+      } else if (document.addEventListener) {
+        document.addEventListener('load', this._setup, false);
+      } else if (window.attachEvent) {
+        window.attachEvent('onload', this._setup);
+      }
+
+      return this;
+    },
+
+    /**
+     * Set up the UI
+     */
+    _setup: function() {
+      var el = jsl.$('jslitmus_container');
+      if (!el) document.body.appendChild(el = document.createElement('div'));
+
+      el.innerHTML = MARKUP;
+
+      // Render the UI for all our tests
+      for (var i=0; i < JSLitmus._tests.length; i++)
+        JSLitmus.renderTest(JSLitmus._tests[i]);
+    },
+
+    /**
+     * (Re)render all the test results
+     */
+    renderAll: function() {
+      for (var i = 0; i < JSLitmus._tests.length; i++)
+        JSLitmus.renderTest(JSLitmus._tests[i]);
+      JSLitmus.renderChart();
+    },
+
+    /**
+     * (Re)render the chart graphics
+     */
+    renderChart: function() {
+      var url = JSLitmus.chartUrl();
+      jsl.$('chart_link').href = url;
+      jsl.$('chart_image').src = url;
+      jsl.$('chart').style.display = '';
+
+      // Update the tiny URL
+      jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
+    },
+
+    /**
+     * (Re)render the results for a specific test
+     */
+    renderTest: function(test) {
+      // Make a new row if needed
+      if (!test._row) {
+        var trow = jsl.$('test_row_template');
+        if (!trow) return;
+
+        test._row = trow.cloneNode(true);
+        test._row.style.display = '';
+        test._row.id = '';
+        test._row.onclick = function() {JSLitmus._queueTest(test);};
+        test._row.title = 'Run ' + test.name + ' test';
+        trow.parentNode.appendChild(test._row);
+        test._row.cells[0].innerHTML = test.name;
+      }
+
+      var cell = test._row.cells[1];
+      var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
+
+      if (test.error) {
+        cns.push('test_error');
+        cell.innerHTML =
+        '<div class="error_head">' + test.error + '</div>' +
+        '<ul class="error_body"><li>' +
+          jsl.join(test.error, ': ', '</li><li>') +
+          '</li></ul>';
+      } else {
+        if (test.running) {
+          cns.push('test_running');
+          cell.innerHTML = 'running';
+        } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
+          cns.push('test_pending');
+          cell.innerHTML = 'pending';
+        } else if (test.count) {
+          cns.push('test_done');
+          var hz = test.getHz(jsl.$('test_normalize').checked);
+          cell.innerHTML = hz != Infinity ? hz : '∞';
+          cell.title = 'Looped ' + test.count + ' times in ' + test.time + ' seconds';
+        } else {
+          cell.innerHTML = 'ready';
+        }
+      }
+      cell.className = cns.join(' ');
+    },
+
+    /**
+     * Create a new test
+     */
+    test: function(name, f) {
+      // Create the Test object
+      var test = new Test(name, f);
+      JSLitmus._tests.push(test);
+
+      // Re-render if the test state changes
+      test.onChange = JSLitmus.renderTest;
+
+      // Run the next test if this one finished
+      test.onStop = function(test) {
+        if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
+        JSLitmus.currentTest = null;
+        JSLitmus._nextTest();
+      };
+
+      // Render the new test
+      this.renderTest(test);
+    },
+
+    /**
+     * Add all tests to the run queue
+     */
+    runAll: function(e) {
+      e = e || window.event;
+      var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
+      for (var i = 0; i < len; i++) {
+        JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
+      }
+    },
+
+    /**
+     * Remove all tests from the run queue.  The current test has to finish on
+     * it's own though
+     */
+    stop: function() {
+      while (JSLitmus._queue.length) {
+        var test = JSLitmus._queue.shift();
+        JSLitmus.renderTest(test);
+      }
+    },
+
+    /**
+     * Run the next test in the run queue
+     */
+    _nextTest: function() {
+      if (!JSLitmus.currentTest) {
+        var test = JSLitmus._queue.shift();
+        if (test) {
+          jsl.$('stop_button').disabled = false;
+          JSLitmus.currentTest = test;
+          test.run();
+          JSLitmus.renderTest(test);
+          if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
+        } else {
+          jsl.$('stop_button').disabled = true;
+          JSLitmus.renderChart();
+        }
+      }
+    },
+
+    /**
+     * Add a test to the run queue
+     */
+    _queueTest: function(test) {
+      if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
+      JSLitmus._queue.push(test);
+      JSLitmus.renderTest(test);
+      JSLitmus._nextTest();
+    },
+
+    /**
+     * Generate a Google Chart URL that shows the data for all tests
+     */
+    chartUrl: function() {
+      var n = JSLitmus._tests.length, markers = [], data = [];
+      var d, min = 0, max = -1e10;
+      var normalize = jsl.$('test_normalize').checked;
+
+      // Gather test data
+      for (var i=0; i < JSLitmus._tests.length; i++) {
+        var test = JSLitmus._tests[i];
+        if (test.count) {
+          var hz = test.getHz(normalize);
+          var v = hz != Infinity ? hz : 0;
+          data.push(v);
+          markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
+            markers.length + ',10');
+          max = Math.max(v, max);
+        }
+      }
+      if (markers.length <= 0) return null;
+
+      // Build chart title
+      var title = document.getElementsByTagName('title');
+      title = (title && title.length) ? title[0].innerHTML : null;
+      var chart_title = [];
+      if (title) chart_title.push(title);
+      chart_title.push('Ops/sec (' + platform + ')');
+
+      // Build labels
+      var labels = [jsl.toLabel(min), jsl.toLabel(max)];
+
+      var w = 250, bw = 15;
+      var bs = 5;
+      var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
+
+      var params = {
+        chtt: escape(chart_title.join('|')),
+        chts: '000000,10',
+        cht: 'bhg',                     // chart type
+        chd: 't:' + data.join(','),     // data set
+        chds: min + ',' + max,          // max/min of data
+        chxt: 'x',                      // label axes
+        chxl: '0:|' + labels.join('|'), // labels
+        chsp: '0,1',
+        chm: markers.join('|'),         // test names
+        chbh: [bw, 0, bs].join(','),    // bar widths
+        // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
+        chs: w + 'x' + h
+      };
+      return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
+    }
+  };
+
+  JSLitmus._init();
+})();
\ No newline at end of file
diff --git a/test/view.js b/test/view.js
index e05b2bd..bf7302c 100644
--- a/test/view.js
+++ b/test/view.js
@@ -1,32 +1,33 @@
 $(document).ready(function() {
 
-  module("Backbone View");
+  module("Backbone.View");
 
   var view = new Backbone.View({
     id        : 'test-view',
     className : 'test-view'
   });
 
-  test("view: constructor", function() {
+  test("View: constructor", function() {
     equals(view.el.id, 'test-view');
     equals(view.el.className, 'test-view');
     equals(view.options.id, 'test-view');
     equals(view.options.className, 'test-view');
   });
 
-  test("view: jQuery", function() {
+  test("View: jQuery", function() {
     view.el = document.body;
-    equals(view.$('#qunit-header').text(), 'Backbone Test Suite');
+    equals(view.$('#qunit-header')[0].innerHTML, 'Backbone Test Suite');
+    equals(view.$('#qunit-header')[1].innerHTML, 'Backbone Speed Suite');
   });
 
-  test("view: make", function() {
+  test("View: make", function() {
     var div = view.make('div', {id: 'test-div'}, "one two three");
     equals(div.tagName.toLowerCase(), 'div');
     equals(div.id, 'test-div');
     equals($(div).text(), 'one two three');
   });
 
-  test("view: initialize", function() {
+  test("View: initialize", function() {
     var View = Backbone.View.extend({
       initialize: function() {
         this.one = 1;
@@ -36,7 +37,7 @@ $(document).ready(function() {
     equals(view.one, 1);
   });
 
-  test("view: handleEvents", function() {
+  test("View: handleEvents", function() {
     var counter = 0;
     view.el = document.body;
     view.increment = function() {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/backbone.git



More information about the Pkg-javascript-commits mailing list