commit 3aaebb58025cab59e285880de483a4dd63ca70b4
parent d61fdeda4cbcfce365d348252c7e0ab3582da6dd
Author: Simon Kornblith <simon@simonster.com>
Date: Mon, 27 Feb 2012 18:50:24 -0500
Bring translator tester up to date with translator tester on the website, and add convenience methods to perform translator tests without loading testTranslators.html.
Diffstat:
3 files changed, 206 insertions(+), 36 deletions(-)
diff --git a/chrome/content/zotero/tools/testTranslators/testTranslators.css b/chrome/content/zotero/tools/testTranslators/testTranslators.css
@@ -8,6 +8,7 @@ table {
border-width: 0 0 1px 1px;
border-style: solid;
border-collapse: collapse;
+ width: 100%;
}
td, th {
@@ -18,21 +19,19 @@ td, th {
}
.th-translator {
- width: 250px;
- max-width: 250px;
}
.th-status {
width: 100px;
+ max-width: 100px;
}
.th-pending, .th-supported, .th-succeeded, .th-failed, .th-mismatch {
width: 75px;
+ max-width: 75px;
}
.th-issues {
- width: 250px;
- max-width: 500px;
}
.status-succeeded, .supported-yes {
diff --git a/chrome/content/zotero/tools/testTranslators/testTranslators.js b/chrome/content/zotero/tools/testTranslators/testTranslators.js
@@ -29,6 +29,7 @@ const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeede
var translatorTables = {},
translatorTestViews = {},
translatorTestViewsToRun = {},
+ translatorTestStats = {},
translatorBox,
outputBox,
allOutputView,
@@ -187,7 +188,17 @@ TranslatorTestView.prototype.setLabel = function(label) {
var issue = issues[i];
var div = document.createElement("div"),
a = document.createElement("a");
- a.textContent = issue.title+" (#"+issue.number+")";
+
+ var date = issue.updated_at;
+ date = new Date(Date.UTC(date.substr(0, 4), date.substr(5, 2)-1, date.substr(8, 2),
+ date.substr(11, 2), date.substr(14, 2), date.substr(17, 2)));
+ if("toLocaleFormat" in date) {
+ date = date.toLocaleFormat("%x");
+ } else {
+ date = date.getFullYear()+"-"+date.getMonth()+"-"+date.getDate();
+ }
+
+ a.textContent = issue.title+" (#"+issue.number+"; "+date+")";
a.setAttribute("href", issue.html_url);
a.setAttribute("target", "_blank");
div.appendChild(a);
@@ -200,18 +211,14 @@ TranslatorTestView.prototype.setLabel = function(label) {
* Initializes TranslatorTestView given a translator and its type
*/
TranslatorTestView.prototype.initWithTranslatorAndType = function(translator, type) {
- this._translatorID = translator.translatorID;
this.setLabel(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;
+ translatorTestViews[type].push(this);
translatorTables[this._type].appendChild(this._row);
}
@@ -222,14 +229,11 @@ TranslatorTestView.prototype.unserialize = function(serializedData) {
this._outputView.addOutput(serializedData.output);
this.setLabel(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._type = serializedData.type;
+ translatorTestViews[serializedData.type].push(this);
this.canRun = false;
this.updateStatus(serializedData);
-
- this._type = serializedData.type;
translatorTables[this._type].appendChild(this._row);
}
@@ -237,17 +241,7 @@ TranslatorTestView.prototype.unserialize = function(serializedData) {
* Initializes TranslatorTestView given a JSON-ified translatorTester
*/
TranslatorTestView.prototype.serialize = function(serializedData) {
- return {
- "translatorID":this._translatorID,
- "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
- };
+ return this._translatorTester.serialize();
}
/**
@@ -258,6 +252,9 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
this._status.removeChild(this._status.firstChild);
}
+ this._supported.textContent = obj.isSupported ? "Yes" : "No";
+ this._supported.className = obj.isSupported ? "supported-yes" : "supported-no";
+
var pending = typeof obj.pending === "object" ? obj.pending.length : obj.pending;
var succeeded = typeof obj.succeeded === "object" ? obj.succeeded.length : obj.succeeded;
var failed = typeof obj.failed === "object" ? obj.failed.length : obj.failed;
@@ -307,6 +304,8 @@ TranslatorTestView.prototype.updateStatus = function(obj, status) {
this._succeeded.textContent = succeeded;
this._failed.textContent = failed;
this._unknown.textContent = unknown;
+
+ if(this._type) translatorTestStats[this._type].update();
}
/**
@@ -332,6 +331,44 @@ TranslatorTestView.prototype.runTests = function(doneCallback) {
}
/**
+ * Gets overall stats for translators
+ */
+var TranslatorTestStats = function(translatorType) {
+ this.translatorType = translatorType
+ this.node = document.createElement("p");
+};
+
+TranslatorTestStats.prototype.update = function() {
+ var types = {
+ "Success":0,
+ "Data Mismatch":0,
+ "Partial Failure":0,
+ "Failure":0,
+ "Untested":0,
+ "Running":0,
+ "Pending":0,
+ "Not Run":0
+ };
+
+ var testViews = translatorTestViews[this.translatorType];
+ for(var i in testViews) {
+ var status = testViews[i]._status ? testViews[i]._status.textContent : "Not Run";
+ if(status in types) {
+ types[status] += 1;
+ }
+ }
+
+ var typeInfo = [];
+ for(var i in types) {
+ if(types[i]) {
+ typeInfo.push(i+": "+types[i]);
+ }
+ }
+
+ this.node.textContent = typeInfo.join(" | ");
+};
+
+/**
* Called when loaded
*/
function load(event) {
@@ -384,6 +421,8 @@ function init() {
var displayType = TRANSLATOR_TYPES[i];
var translatorType = displayType.toLowerCase();
+ translatorTestViews[translatorType] = [];
+
// create header
var h1 = document.createElement("h1");
h1.appendChild(document.createTextNode(displayType+" Translators "));
@@ -409,6 +448,9 @@ function init() {
var translatorTable = document.createElement("table");
translatorTables[translatorType] = translatorTable;
+ translatorTestStats[translatorType] = new TranslatorTestStats(translatorType);
+ translatorBox.appendChild(translatorTestStats[translatorType].node);
+
// add headings to table
var headings = document.createElement("tr");
for(var j in TABLE_COLUMNS) {
@@ -500,7 +542,6 @@ function jsonNotFound(str) {
* Called after translators are returned from main script
*/
function haveTranslators(translators, type) {
- translatorTestViews[type] = [];
translatorTestViewsToRun[type] = [];
translators = translators.sort(function(a, b) {
@@ -510,12 +551,12 @@ function haveTranslators(translators, type) {
for(var i in translators) {
var translatorTestView = new TranslatorTestView();
translatorTestView.initWithTranslatorAndType(translators[i], type);
- translatorTestViews[type].push(translatorTestView);
if(translatorTestView.canRun) {
translatorTestViewsToRun[type].push(translatorTestView);
}
}
+ translatorTestStats[type].update();
var ev = document.createEvent('HTMLEvents');
ev.initEvent('ZoteroHaveTranslators-'+type, true, true);
document.dispatchEvent(ev);
@@ -551,7 +592,7 @@ function initTests(type, callback, runCallbackIfComplete) {
* Serializes translator tests to JSON
*/
function serializeToJSON() {
- var serializedData = {"browser":Zotero.browser, "results":[]};
+ var serializedData = {"browser":Zotero.browser, "version":Zotero.version, "results":[]};
for(var i in translatorTestViews) {
var n = translatorTestViews[i].length;
for(var j=0; j<n; j++) {
diff --git a/chrome/content/zotero/tools/testTranslators/translatorTester.js b/chrome/content/zotero/tools/testTranslators/translatorTester.js
@@ -25,8 +25,110 @@
// Timeout for test to complete
const TEST_RUN_TIMEOUT = 600000;
+var EXPORTED_SYMBOLS = ["Zotero_TranslatorTesters"];
-var Zotero_TranslatorTester_IGNORE_FIELDS = ["complete", "accessDate", "checkFields"];
+try {
+ Zotero;
+} catch(e) {
+ var Zotero;
+}
+
+Zotero_TranslatorTesters = new function() {
+ const TEST_TYPES = ["web", "import", "export", "search"];
+
+ /**
+ * Runs all tests
+ */
+ this.runAllTests = function(numConcurrentTests, skipTranslators, doneCallback) {
+ if(!Zotero) {
+ Zotero = Components.classes["@zotero.org/Zotero;1"]
+ .getService(Components.interfaces.nsISupports).wrappedJSObject;
+ }
+
+ var testers = [];
+ var waitingForTranslators = TEST_TYPES.length;
+ for(var i=0; i<TEST_TYPES.length; i++) {
+ Zotero.Translators.getAllForType(TEST_TYPES[i], new function() {
+ var type = TEST_TYPES[i];
+ return function(translators) {
+ for(var i=0; i<translators.length; i++) {
+ if(skipTranslators && !skipTranslators[translators[i].translatorID]) {
+ testers.push(new Zotero_TranslatorTester(translators[i], type));
+ }
+ };
+
+ if(!(--waitingForTranslators)) {
+ runTesters(testers, numConcurrentTests, doneCallback);
+ }
+ };
+ });
+ };
+ };
+
+ /**
+ * Runs a specific set of tests
+ */
+ function runTesters(testers, numConcurrentTests, doneCallback) {
+ var testersRunning = 0;
+ var results = [];
+
+ var strcmp;
+ try {
+ var localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"]
+ .getService(Components.interfaces.nsILocaleService);
+ var collationFactory = Components.classes["@mozilla.org/intl/collation-factory;1"]
+ .getService(Components.interfaces.nsICollationFactory);
+ var collation = collationFactory.CreateCollation(localeService.getApplicationLocale());
+ strcmp = function(a, b) {
+ return collation.compareString(1, a, b);
+ };
+ } catch (e) {
+ strcmp = function (a, b) {
+ return a.localeCompare(b);
+ };
+ }
+
+ var testerDoneCallback = function(tester) {
+ if(tester.pending.length) return;
+
+ Zotero.debug("Done testing "+tester.translator.label);
+
+ // Done translating, so serialize test results
+ testersRunning--;
+ results.push(tester.serialize());
+
+ if(testers.length) {
+ // Run next tester if one is available
+ runNextTester();
+ } else if(testersRunning === 0) {
+ // Testing is done, so sort results
+ results.sort(function(a, b) {
+ if(a.type !== b.type) {
+ return TEST_TYPES.indexOf(a.type) - TEST_TYPES.indexOf(b.type);
+ }
+ return strcmp(a.label, b.label);
+ });
+
+ // Call done callback
+ doneCallback({
+ "browser":Zotero.browser,
+ "version":Zotero.version,
+ "results":results
+ });
+ }
+ };
+
+ var runNextTester = function() {
+ testersRunning++;
+ Zotero.debug("Testing "+testers[0].translator.label);
+ testers.shift().runTests(testerDoneCallback);
+ };
+
+ for(var i=0; i<numConcurrentTests; i++) {
+ runNextTester();
+ };
+ }
+}
/**
* A tool to run unit tests for a given translator
@@ -39,13 +141,14 @@ var Zotero_TranslatorTester_IGNORE_FIELDS = ["complete", "accessDate", "checkFie
* @constructor
* @param {Zotero.Translator[]} translator The translator for which to run tests
* @param {String} type The type of tests to run (web, import, export, or search)
- * @param {Function} [debug] A function to call to write debug output. If not present, Zotero.debug
- * will be used.
+ * @param {Function} [debugCallback] A function to call to write debug output. If not present,
+ * Zotero.debug will be used.
*/
-Zotero_TranslatorTester = function(translator, type, debug) {
+Zotero_TranslatorTester = function(translator, type, debugCallback) {
this.type = type;
this.translator = translator;
- this._debug = debug ? debug : function(obj, a, b) { Zotero.debug(a, b) };
+ this.output = "";
+ this.isSupported = this.translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER;
this.tests = [];
this.pending = [];
@@ -53,6 +156,16 @@ Zotero_TranslatorTester = function(translator, type, debug) {
this.failed = [];
this.unknown = [];
+ var me = this;
+ this._debug = function(obj, a, b) {
+ me.output += me.output ? "\n"+a : a;
+ if(debugCallback) {
+ debugCallback(me, a, b);
+ } else {
+ Zotero.debug(a, b);
+ }
+ };
+
var code = translator.code;
var testStart = code.indexOf("/** BEGIN TEST CASES **/");
var testEnd = code.indexOf("/** END TEST CASES **/");
@@ -106,12 +219,29 @@ Zotero_TranslatorTester._sanitizeItem = function(item, forSave) {
} catch(e) {};
// remove fields to be ignored
- for(var j=0, n=Zotero_TranslatorTester_IGNORE_FIELDS.length; j<n; j++) {
- delete item[Zotero_TranslatorTester_IGNORE_FIELDS[j]];
+ const IGNORE_FIELDS = ["complete", "accessDate", "checkFields"];
+ for(var j=0, n=IGNORE_FIELDS.length; j<n; j++) {
+ delete item[IGNORE_FIELDS[j]];
}
return item;
};
+/**
+ * Serializes translator tester results to JSON
+ */
+Zotero_TranslatorTester.prototype.serialize = function() {
+ return {
+ "translatorID":this.translator.translatorID,
+ "type":this.type,
+ "output":this.output,
+ "label":this.translator.label,
+ "isSupported":this.isSupported,
+ "pending":this.pending,
+ "failed":this.failed,
+ "succeeded":this.succeeded,
+ "unknown":this.unknown
+ };
+};
/**
* Sets tests for this translatorTester