Bring translator tester up to date with translator tester on the website, and add convenience methods to perform translator tests without loading testTranslators.html.
This commit is contained in:
parent
d61fdeda4c
commit
3aaebb5802
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,6 +330,44 @@ TranslatorTestView.prototype.runTests = function(doneCallback) {
|
|||
this._translatorTester.runTests(newCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -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++) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user