commit 9f218caf7512462e707c832bded4c38459b275e1
parent 59066e40b7913a1a9f6c6f7cfa55375d8611d2f2
Author: Simon Kornblith <simon@simonster.com>
Date: Mon, 18 Jul 2011 21:14:51 +0000
- Ability to serialize and reload translator tests from translator tester (addresses #1842, Translator unit test automation)
- Fix a spacing issue in preferences
Diffstat:
2 files changed, 187 insertions(+), 64 deletions(-)
diff --git a/chrome/content/zotero/tools/testTranslators/testTranslators.js b/chrome/content/zotero/tools/testTranslators/testTranslators.js
@@ -26,12 +26,14 @@
const NUM_CONCURRENT_TESTS = 6;
const TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"];
const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Unknown"];
-var translatorTables = {};
-var translatorTestViewsToRun = {};
-var translatorBox;
-var outputBox;
-var allOutputView;
-var currentOutputView;
+var translatorTables = {},
+ translatorTestViews = {},
+ translatorTestViewsToRun = {},
+ translatorBox,
+ outputBox,
+ allOutputView,
+ currentOutputView,
+ viewerMode = true;
/**
* Handles adding debug output to the output box
@@ -48,7 +50,7 @@ var OutputView = function(el) {
*/
OutputView.prototype.setDisplayed = function(isDisplayed) {
this.isDisplayed = isDisplayed;
- if(this.isDisplayed) outputBox.textContent = this._output.join("\n\n");
+ if(this.isDisplayed) outputBox.textContent = this._output.join("\n");
if(this._el) this._el.className = (isDisplayed ? "output-displayed" : "output-hidden");
currentOutputView = this;
}
@@ -58,7 +60,14 @@ OutputView.prototype.setDisplayed = function(isDisplayed) {
*/
OutputView.prototype.addOutput = function(msg, level) {
this._output.push(msg);
- if(this.isDisplayed) outputBox.textContent = this._output.join("\n\n");
+ if(this.isDisplayed) outputBox.textContent = this._output.join("\n");
+}
+
+/**
+ * Gets output to the output view
+ */
+OutputView.prototype.getOutput = function() {
+ return this._output.join("\n");
}
/**
@@ -66,21 +75,14 @@ OutputView.prototype.addOutput = function(msg, level) {
* @constructor
*/
var TranslatorTestView = function(translator, type) {
- this._translator = translator;
- this._type = type;
-
- var row = document.createElement("tr");
+ var row = this._row = document.createElement("tr");
// Translator
this._label = document.createElement("td");
- this._label.appendChild(document.createTextNode(translator.label));
row.appendChild(this._label);
// Supported
this._supported = document.createElement("td");
- var isSupported = translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
- this._supported.appendChild(document.createTextNode(isSupported ? "Yes" : "No"));
- this._supported.className = isSupported ? "supported-yes" : "supported-no";
row.appendChild(this._supported);
// Status
@@ -103,12 +105,9 @@ var TranslatorTestView = function(translator, type) {
this._unknown = document.createElement("td");
row.appendChild(this._unknown);
- // append to table
- translatorTables[type].appendChild(row);
-
// create output view and debug function
- var outputView = new OutputView(row);
- var debug = function(obj, msg, level) {
+ var outputView = this._outputView = new OutputView(row);
+ this._debug = function(obj, msg, level) {
outputView.addOutput(msg, level);
allOutputView.addOutput(msg, level);
}
@@ -123,13 +122,63 @@ var TranslatorTestView = function(translator, type) {
}, false);
// create translator tester and update status based on what it knows
- this._translatorTester = new Zotero_TranslatorTester(translator, type, debug);
- this.updateStatus(this._translatorTester);
- this.hasTests = !!this._translatorTester.tests.length;
this.isRunning = false;
}
/**
+ * Initializes TranslatorTestView given a translator and its type
+ */
+TranslatorTestView.prototype.initWithTranslatorAndType = function(translator, type) {
+ this._label.appendChild(document.createTextNode(translator.label));
+
+ this.isSupported = translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
+ this._supported.appendChild(document.createTextNode(this.isSupported ? "Yes" : "No"));
+ this._supported.className = this.isSupported ? "supported-yes" : "supported-no";
+
+ this._translatorTester = new Zotero_TranslatorTester(translator, type, this._debug);
+ this.canRun = !!this._translatorTester.tests.length;
+ this.updateStatus(this._translatorTester);
+
+ this._type = type;
+ translatorTables[this._type].appendChild(this._row);
+}
+
+/**
+ * Initializes TranslatorTestView given a JSON-ified translatorTester
+ */
+TranslatorTestView.prototype.unserialize = function(serializedData) {
+ this._outputView.addOutput(serializedData.output);
+ this._label.appendChild(document.createTextNode(serializedData.label));
+
+ this.isSupported = serializedData.isSupported;
+ this._supported.appendChild(document.createTextNode(this.isSupported ? "Yes" : "No"));
+ this._supported.className = this.isSupported ? "supported-yes" : "supported-no";
+
+ this._translatorTester = serializedData;
+ this.canRun = false;
+ this.updateStatus(this._translatorTester);
+
+ this._type = serializedData.type;
+ translatorTables[this._type].appendChild(this._row);
+}
+
+/**
+ * Initializes TranslatorTestView given a JSON-ified translatorTester
+ */
+TranslatorTestView.prototype.serialize = function(serializedData) {
+ return {
+ "type":this._type,
+ "output":this._outputView.getOutput(),
+ "label":this._label.textContent,
+ "isSupported":this.isSupported,
+ "pending":this._translatorTester.pending,
+ "failed":this._translatorTester.failed,
+ "succeeded":this._translatorTester.succeeded,
+ "unknown":this._translatorTester.unknown
+ };
+}
+
+/**
* Changes the displayed status of a translator
*/
TranslatorTestView.prototype.updateStatus = function(obj, status) {
@@ -137,7 +186,7 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
this._status.removeChild(this._status.firstChild);
}
- if(obj.tests.length) {
+ if(obj.pending.length || obj.succeeded.length || obj.failed.length || obj.unknown.length) {
if(obj.pending.length) {
if(this.isRunning) {
this._status.className = "status-running";
@@ -145,7 +194,7 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
} else if(status && status === "pending") {
this._status.className = "status-pending";
this._status.textContent = "Pending";
- } else {
+ } else if(this.canRun) {
// show link to start
var me = this;
var a = document.createElement("a");
@@ -156,6 +205,8 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
}, false);
a.textContent = "Run";
this._status.appendChild(a);
+ } else {
+ this._status.textContent = "Not Run";
}
} else if(obj.failed.length) {
this._status.className = "status-failed";
@@ -203,7 +254,11 @@ TranslatorTestView.prototype.runTests = function(doneCallback) {
/**
* Called when loaded
*/
-function load(event) {
+function load(event) {
+ try {
+ viewerMode = !Zotero;
+ } catch(e) {};
+
if(window.chrome || window.safari) {
// initialize injection
Zotero.initInject();
@@ -253,22 +308,24 @@ function init() {
var h1 = document.createElement("h1");
h1.appendChild(document.createTextNode(displayType+" Translators "));
- // create "run all"
- var runAll = document.createElement("a");
- runAll.href = "#";
- runAll.appendChild(document.createTextNode("(Run)"));
- runAll.addEventListener("click", new function() {
- var type = translatorType;
- return function(e) {
- e.preventDefault();
- for(var i in translatorTestViewsToRun[type]) {
- var testView = translatorTestViewsToRun[type][i];
- testView.updateStatus(testView._translatorTester, "pending");
+ if(!viewerMode) {
+ // create "run all"
+ var runAll = document.createElement("a");
+ runAll.href = "#";
+ runAll.appendChild(document.createTextNode("(Run)"));
+ runAll.addEventListener("click", new function() {
+ var type = translatorType;
+ return function(e) {
+ e.preventDefault();
+ for(var i in translatorTestViewsToRun[type]) {
+ var testView = translatorTestViewsToRun[type][i];
+ testView.updateStatus(testView._translatorTester, "pending");
+ }
+ runTranslatorTests(type);
}
- runTranslatorTests(type);
- }
- }, false);
- h1.appendChild(runAll);
+ }, false);
+ h1.appendChild(runAll);
+ }
translatorBox.appendChild(h1);
@@ -290,24 +347,74 @@ function init() {
translatorBox.appendChild(translatorTable);
// get translators, with code for unsupported translators
- Zotero.Translators.getAllForType(translatorType, new function() {
- var type = translatorType;
- return function(translators) {
- haveTranslators(translators, type);
+ if(!viewerMode) {
+ Zotero.Translators.getAllForType(translatorType, new function() {
+ var type = translatorType;
+ return function(translators) {
+ haveTranslators(translators, type);
+ }
+ }, true);
+ }
+ }
+
+ if(viewerMode) {
+ // if no Zotero object, try to unserialize data
+ var req = new XMLHttpRequest();
+ req.open("GET", "testResults.json", true);
+ req.overrideMimeType("text/plain");
+ req.onreadystatechange = function(e) {
+ if(req.readyState != 4) return;
+
+ if(req.responseText) { // success; unserialize
+ var data = JSON.parse(req.responseText);
+ for(var i=0, n=data.length; i<n; i++) {
+ var translatorTestView = new TranslatorTestView();
+ translatorTestView.unserialize(data[i]);
+ }
+ } else {
+ jsonNotFound("XMLHttpRequest returned "+req.status);
}
- }, true);
+ };
+
+ try {
+ req.send();
+ } catch(e) {
+ jsonNotFound(e.toString());
+ }
+ } else {
+ // create "serialize" link at bottom
+ var lastP = document.createElement("p");
+ var serialize = document.createElement("a");
+ serialize.href = "#";
+ serialize.appendChild(document.createTextNode("Serialize Results"));
+ serialize.addEventListener("click", serializeAll, false);
+ lastP.appendChild(serialize);
+ translatorBox.appendChild(lastP);
}
}
+
+/**
+ * Indicates no JSON file could be found.
+ */
+function jsonNotFound(str) {
+ var body = document.body;
+ while(body.hasChildNodes()) body.removeChild(body.firstChild);
+ body.textContent = "testResults.json could not be loaded ("+str+").";
+}
+
/**
* Called after translators are returned from main script
*/
function haveTranslators(translators, type) {
+ translatorTestViews[type] = [];
translatorTestViewsToRun[type] = [];
for(var i in translators) {
- var translatorTestView = new TranslatorTestView(translators[i], type);
- if(translatorTestView.hasTests) {
+ var translatorTestView = new TranslatorTestView();
+ translatorTestView.initWithTranslatorAndType(translators[i], type);
+ translatorTestViews[type].push(translatorTestView);
+ if(translatorTestView.canRun) {
translatorTestViewsToRun[type].push(translatorTestView);
}
}
@@ -325,4 +432,20 @@ function runTranslatorTests(type, callback) {
}
}
+/**
+ * Serializes all run translator tests
+ */
+function serializeAll(e) {
+ var serializedData = [];
+ for(var i in translatorTestViews) {
+ var n = translatorTestViews[i].length;
+ for(var j=0; j<n; j++) {
+ serializedData.push(translatorTestViews[i][j].serialize());
+ }
+ }
+
+ document.location.href = "data:application/octet-stream,"+encodeURIComponent(JSON.stringify(serializedData, null, "\t"));
+ e.preventDefault();
+}
+
window.addEventListener("load", load, false);
\ No newline at end of file
diff --git a/chrome/content/zotero/tools/testTranslators/translatorTester.js b/chrome/content/zotero/tools/testTranslators/translatorTester.js
@@ -40,8 +40,8 @@ const Zotero_TranslatorTester_IGNORE_FIELDS = ["complete", "accessDate", "checkF
* will be used.
*/
Zotero_TranslatorTester = function(translator, type, debug) {
- this._type = type;
- this._translator = translator;
+ this.type = type;
+ this.translator = translator;
this._debug = debug ? debug : function(obj, a, b) { Zotero.debug(a, b) };
this.tests = [];
@@ -122,7 +122,7 @@ Zotero_TranslatorTester.prototype.setTests = function(tests) {
Zotero_TranslatorTester.prototype.runTests = function(testDoneCallback, recursiveRun) {
if(!recursiveRun) {
var w = (this.pending.length === 1) ? " test" : " tests";
- this._debug(this, "TranslatorTester: Running "+this.pending.length+" "+w+" for "+this._translator.label);
+ this._debug(this, "TranslatorTester: Running "+this.pending.length+" "+w+" for "+this.translator.label);
}
if(!this.pending.length) {
@@ -144,13 +144,13 @@ Zotero_TranslatorTester.prototype._runTestsRecursively = function(testDoneCallba
var me = this;
var callback = function(obj, test, status, message) {
- me._debug(this, "TranslatorTester: "+me._translator.label+" Test "+testNumber+": "+status+" ("+message+")");
+ me._debug(this, "TranslatorTester: "+me.translator.label+" Test "+testNumber+": "+status+" ("+message+")");
me[status].push(test);
if(testDoneCallback) testDoneCallback(me, test, status, message);
me.runTests(testDoneCallback, true);
};
- if(this._type === "web") {
+ if(this.type === "web") {
this.fetchPageAndRunTest(test, callback);
} else {
this.runTest(test, null, callback);
@@ -190,13 +190,13 @@ Zotero_TranslatorTester.prototype.fetchPageAndRunTest = function(test, testDoneC
*/
Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback) {
var me = this;
- var translate = Zotero.Translate.newInstance(this._type);
+ var translate = Zotero.Translate.newInstance(this.type);
- if(this._type === "web") {
+ if(this.type === "web") {
translate.setDocument(doc);
- } else if(this._type === "import") {
+ } else if(this.type === "import") {
translate.setString(test.input);
- } else if(this._type === "search") {
+ } else if(this.type === "search") {
translate.setSearch(test.input);
}
@@ -233,7 +233,7 @@ Zotero_TranslatorTester.prototype.runTest = function(test, doc, testDoneCallback
translate.capitalizeTitles = false;
// internal hack to call detect on this translator
- translate._potentialTranslators = [this._translator];
+ translate._potentialTranslators = [this.translator];
translate._foundTranslators = [];
translate._currentState = "detect";
translate._detect();
@@ -246,14 +246,14 @@ Zotero_TranslatorTester.prototype._runTestTranslate = function(translate, transl
if(!translators.length) {
testDoneCallback(this, test, "failed", "Detection failed");
return;
- } else if(this._type === "web" && (translators[0].itemType !== "multiple" && test.items.length > 1 ||
+ } else if(this.type === "web" && (translators[0].itemType !== "multiple" && test.items.length > 1 ||
test.items.length === 1 && translators[0].itemType !== test.items[0].itemType)) {
// this handles "items":"multiple" too, since the string has length 8
testDoneCallback(this, test, "failed", "Detection returned wrong item type");
return;
}
- translate.setTranslator(this._translator);
+ translate.setTranslator(this.translator);
translate.translate(false);
};
@@ -305,9 +305,9 @@ Zotero_TranslatorTester.prototype.newTest = function(doc, testReadyCallback) {
var multipleMode = false;
var me = this;
- var translate = Zotero.Translate.newInstance(this._type);
+ var translate = Zotero.Translate.newInstance(this.type);
translate.setDocument(doc);
- translate.setTranslator(this._translator);
+ translate.setTranslator(this.translator);
translate.setHandler("debug", this._debug);
translate.setHandler("select", function(obj, items, callback) {
multipleMode = true;
@@ -348,7 +348,7 @@ Zotero_TranslatorTester.prototype._createTest = function(translate, multipleMode
var items = translate.newItems;
}
- testReadyCallback(this, {"type":this._type, "url":translate.document.location.href,
+ testReadyCallback(this, {"type":this.type, "url":translate.document.location.href,
"items":items});
};