Rewrite local testdriver processing. Using a listener framework to report test result...
[dygraphs.git] / auto_tests / misc / fake-jstestdriver.js
index 4397741..404d165 100644 (file)
  * @author konigsberg@google.com (Robert Konigsberg)
  */
 var jstestdriver = {
-  jQuery : jQuery
+  jQuery : jQuery,
+  listeners_ : [],
+  announce_ : function(name, args) {
+    for (var idx = 0; idx < jstestdriver.listeners_.length; idx++) {
+      var listener = jstestdriver.listeners_[idx];
+      if (listener[name]) {
+        listener[name].apply(null, args);
+      }
+    }
+  },
+  attachListener: function(listener) {
+    jstestdriver.listeners_.push(listener);
+  }
 };
 
+if (!console) {
+  var console = {
+    log: function(x) {
+      // ...
+    }
+  };
+}
+
 var jstd = {
   include : function(name) {
     this.sucker("Not including " + name);
@@ -36,42 +56,129 @@ var jstd = {
   }
 };
 
+var testCaseList = [];
+
 function TestCase(name) {
-  jstd.sucker("Not really creating TestCase(" + name + ")");
-  this.name = name;
-  this.toString = function() {
+  var testCase = function() { return this; };
+  testCase.name = name;
+  testCase.toString = function() {
     return "Fake test case " + name;
   };
 
-  var testCase = function() { return this; };
   testCase.prototype.setUp = function() { };
   testCase.prototype.tearDown = function() { };
-  testCase.prototype.runTest = function(name) {
+  testCase.prototype.name = name;
+  /**
+   * name can be a string, which is looked up in this object, or it can be a
+   * function, in which case it's run.
+   *
+   * Examples:
+   * var tc = new MyTestCase();
+   * tc.runTest("testThis");
+   * tc.runTest(tc.testThis);
+   *
+   * The duplication tc in runTest is irritating, but it plays well with
+   * Chrome's console completion.
+   */
+  testCase.prototype.runTest = function(func) {
+    var result = false;
+    var ex = null;
+    var name = typeof(func) == "string" ? func : "(anonymous function)";
+    jstestdriver.announce_("start", [this, name]);
     try {
-      this.setUp();
-      var fn = this[name];
-      fn.apply(this, []);
-      this.tearDown();
-      return true;
+      result = this.runTest_(func);
     } catch (e) {
-      console.log(e);
-      if (e.stack) {
-        console.log(e.stack);
-      }
-      return false;
+      ex = e;
+    }
+    jstestdriver.announce_("finish", [this, name, result, ex]);
+  }
+
+  testCase.prototype.runTest_ = function(func) {
+    this.setUp();
+
+    var fn = null;
+    var parameterType = typeof(func);
+    if (typeof(func) == "function") {
+      fn = func;
+    } else if (typeof(func) == "string") {
+      fn = this[func];
+    } else {
+      fail("can't supply " + typeof(func) + " to runTest");
     }
+
+    fn.apply(this, []);
+    this.tearDown();
+    return true;
   };
+
   testCase.prototype.runAllTests = function() {
+    var results = {};
+    var names = this.getTestNames();
+    for (var idx in names) {
+      var name = names[idx];
+      console.log("Running " + name);
+      var result = this.runTest(name);
+      results[name] = result;
+    }
+    console.log(prettyPrintEntity_(results));
+    return results;
+  };
+
+  testCase.prototype.getTestNames = function() {
     // what's better than for ... in for non-array objects?
-    var tests = {};
+    var tests = [];
     for (var name in this) {
       if (name.indexOf('test') == 0 && typeof(this[name]) == 'function') {
-        console.log("Running " + name);
-        var result = this.runTest(name);
-        tests[name] = result;
+        tests.push(name);
       }
     }
-    console.log(prettyPrintEntity_(tests));
-  };
+    return tests;
+  }
+
+  testCaseList.push({name : name, testCase : testCase});
   return testCase;
 };
+
+// Note: this creates a bunch of global variables intentionally.
+function addGlobalTestSymbols() {
+  globalTestDb = {};  // maps test name -> test function wrapper
+
+  var num_tests = 0;
+  for (var i = 0; i < testCaseList.length; i++) {
+    var tc_class = testCaseList[i].testCase;
+    for (var name in tc_class.prototype) {
+      if (name.indexOf('test') == 0 && typeof(tc_class.prototype[name]) == 'function') {
+        if (globalTestDb.hasOwnProperty(name)) {
+          console.log('Duplicated test name: ' + name);
+        } else {
+          globalTestDb[name] = function(name, tc_class) {
+            return function() {
+              var tc = new tc_class;
+              return tc.runTest(name);
+            };
+          }(name, tc_class);
+          eval(name + " = globalTestDb['" + name + "'];");
+          num_tests += 1;
+        }
+      }
+    }
+  }
+  console.log('Loaded ' + num_tests + ' tests in ' +
+              testCaseList.length + ' test cases');
+}
+
+function getAllTestCases() {
+  return testCaseList;
+}
+
+jstestdriver.attachListener({
+  finish : function(tc, name, result, e) {
+    if (e) {
+      console.log(e);
+      if (e.stack) {
+        console.log(e.stack);
+      }
+    }
+  }
+});
+