* @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);
}
};
+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 emptyFunction = function() { return this; };
- emptyFunction.prototype.setUp = function() { };
- emptyFunction.prototype.tearDown = function() { };
- emptyFunction.prototype.runTest = function(name) {
+ testCase.prototype.setUp = function() { };
+ testCase.prototype.tearDown = function() { };
+ 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 {
+ result = this.runTest_(func);
+ } catch (e) {
+ ex = e;
+ }
+ jstestdriver.announce_("finish", [this, name, result, ex]);
+ }
+
+ testCase.prototype.runTest_ = function(func) {
this.setUp();
- var fn = this[name];
+
+ 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;
};
- return emptyFunction;
+
+ testCase.prototype.getTestNames = function() {
+ // what's better than for ... in for non-array objects?
+ var tests = [];
+ for (var name in this) {
+ if (name.indexOf('test') == 0 && typeof(this[name]) == 'function') {
+ tests.push(name);
+ }
+ }
+ 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);
+ }
+ }
+ }
+});
+