mirror of
https://github.com/kiwix/kiwix-js.git
synced 2025-09-22 12:01:15 -04:00
Some more work on the "Articles nearby feature", including adding a few functions in geometry.js (with corresponding unit tests)
This commit is contained in:
parent
46257816cf
commit
20f213abd5
@ -137,7 +137,7 @@ define(function(require) {
|
||||
var filerequest = storage.get(directory + 'coordinates_' + prefixedFileNumber
|
||||
+ '.idx');
|
||||
filerequest.onsuccess = function() {
|
||||
currentLocalArchiveInstance.coordinateFiles[index] = filerequest.result;
|
||||
currentLocalArchiveInstance.coordinateFiles[index - 1] = filerequest.result;
|
||||
currentLocalArchiveInstance.readCoordinateFilesFromStorage(storage, directory,
|
||||
index + 1);
|
||||
};
|
||||
@ -218,7 +218,7 @@ define(function(require) {
|
||||
var coordinateFileNr = coordinateFileRegex.exec(file.name);
|
||||
if (coordinateFileNr && coordinateFileNr.length > 0) {
|
||||
var intFileNr = 1 * coordinateFileNr[1];
|
||||
this.coordinateFiles[intFileNr] = file;
|
||||
this.coordinateFiles[intFileNr - 1] = file;
|
||||
}
|
||||
else {
|
||||
var dataFileNr = dataFileRegex.exec(file.name);
|
||||
@ -725,69 +725,110 @@ define(function(require) {
|
||||
LocalArchive.prototype.getTitlesInCoords = function(rect, maxTitles, callbackFunction) {
|
||||
var normalizedRectangle = rect.normalized();
|
||||
var i = 0;
|
||||
LocalArchive.getTitlesInCoordsInt(this, i, 0, normalizedRectangle, GLOBE_RECTANGLE, maxTitles, new Array(), callbackFunction, this.callbackGetTitlesInCoordsInt);
|
||||
LocalArchive.getTitlesInCoordsInt(this, i, 0, normalizedRectangle, GLOBE_RECTANGLE, maxTitles, new Array(), callbackFunction, LocalArchive.callbackGetTitlesInCoordsInt);
|
||||
};
|
||||
|
||||
LocalArchive.callbackGetTitlesInCoordsInt = function(localArchive, titlesFound, i, maxTitles, normalizedRectangle, callbackFunction) {
|
||||
i++;
|
||||
if (titlesFound.length < maxTitles && i < localArchive.coordinateFiles.length) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, i, 0, normalizedRectangle, GLOBE_RECTANGLE, maxTitles, titlesFound, callbackFunction, this.callbackGetTitlesInCoordsInt);
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, i, 0, normalizedRectangle, GLOBE_RECTANGLE, maxTitles, titlesFound, callbackFunction, LocalArchive.callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
else {
|
||||
callbackFunction(titlesFound);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Reads 4 bytes in given byteArray, starting at startIndex, and convert
|
||||
* these 4 bytes into latitude and longitude (each uses 2 bytes, little endian)
|
||||
* @param {type} byteArray
|
||||
* @param {type} startIndex
|
||||
* @returns {_L23.geometry.point}
|
||||
*/
|
||||
readCoordinates = function(byteArray, startIndex) {
|
||||
var lat = byteArray[startIndex] + 256 * byteArray[startIndex + 1];
|
||||
var long = byteArray[startIndex + 2] + 256 * byteArray[startIndex + 3];
|
||||
var point = new geometry.point(long, lat);
|
||||
return point;
|
||||
};
|
||||
|
||||
LocalArchive.getTitlesInCoordsInt = function(localArchive, coordinateFileIndex, coordFilePos, targetRect, thisRect, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt) {
|
||||
// TODO : as reading a file is asynchronous, this function needs to be split
|
||||
// into several callback functions
|
||||
|
||||
// read this.coordinateFiles[coordinateFileIndex] at coordFilePos
|
||||
// retrieve selector
|
||||
var selector;
|
||||
// 0xFFFF = 65535 in decimal
|
||||
if (selector === 65535) {
|
||||
// not enough articles, further subdivision needed
|
||||
// read coordinates in coordinateFile
|
||||
// compute the 4 rectangles and 4 positions
|
||||
var rectSW;
|
||||
var pos0;
|
||||
var rectSE;
|
||||
var pos1;
|
||||
var rectNW;
|
||||
var pos2;
|
||||
var rectNE;
|
||||
var pos3;
|
||||
if (targetRect.intersects(rectSW)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos0, targetRect, rectSW, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
if (targetRect.intersects(rectSE)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos1, targetRect, rectSE, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
if (targetRect.intersects(rectNW)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos2, targetRect, rectNW, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
if (targetRect.intersects(rectNE)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos3, targetRect, rectNE, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < selector; i ++) {
|
||||
// Read position (in title file) in coordinateFile
|
||||
var title_pos;
|
||||
if (!targetRect.contains(c)) {
|
||||
continue;
|
||||
var reader = new FileReader();
|
||||
reader.onerror = errorHandler;
|
||||
reader.onabort = function(e) {
|
||||
alert('Coordinate file read cancelled');
|
||||
};
|
||||
|
||||
reader.onload = function(e) {
|
||||
var binaryTitleFile = e.target.result;
|
||||
var byteArray = new Uint8Array(binaryTitleFile);
|
||||
// Compute selector
|
||||
var selector = byteArray[0] + 256 * byteArray[1];
|
||||
|
||||
// 0xFFFF = 65535 in decimal
|
||||
if (selector === 65535) {
|
||||
// not enough articles, further subdivision needed
|
||||
var center = readCoordinates(byteArray, 2);
|
||||
var lensw = byteArray[10] + 256 * byteArray[11] + 256 * 256 * byteArray[12] + 256 * 256 * 256 * byteArray[13];
|
||||
var lense = byteArray[14] + 256 * byteArray[15] + 256 * 256 * byteArray[16] + 256 * 256 * 256 * byteArray[17];
|
||||
var lennw = byteArray[18] + 256 * byteArray[19] + 256 * 256 * byteArray[20] + 256 * 256 * 256 * byteArray[21];
|
||||
// compute the 4 positions
|
||||
var pos0 = coordFilePos + 22;
|
||||
var pos1 = pos0 + lensw;
|
||||
var pos2 = pos1 + lense;
|
||||
var pos3 = pos2 + lennw;
|
||||
// compute the 4 rectangles
|
||||
var rectSW = new geometry.rect(thisRect.origin(), center);
|
||||
var rectSE = (new geometry.rect(thisRect.topRight(), center)).normalized();
|
||||
var rectNW = (new geometry.rect(thisRect.bottomLeft(), center)).normalized();
|
||||
var rectNE = (new geometry.rect(thisRect.corner(), center)).normalized();
|
||||
if (targetRect.intersect(rectSW)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos0, targetRect, rectSW, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
// read title at title_pos in title file
|
||||
var title;
|
||||
titlesFound.push(title);
|
||||
if (maxTitles >= 0 && titlesFound.length >= maxTitles) {
|
||||
LocalArchive.callbackGetTitlesInCoordsInt(localArchive, titlesFound, coordinateFileIndex, maxTitles, targetRect, callbackFunction);
|
||||
return;
|
||||
if (targetRect.intersect(rectSE)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos1, targetRect, rectSE, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
if (targetRect.intersect(rectNW)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos2, targetRect, rectNW, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
if (targetRect.intersect(rectNE)) {
|
||||
LocalArchive.getTitlesInCoordsInt(localArchive, coordinateFileIndex, pos3, targetRect, rectNE, maxTitles, titlesFound, callbackFunction, callbackGetTitlesInCoordsInt);
|
||||
}
|
||||
}
|
||||
LocalArchive.callbackGetTitlesInCoordsInt(localArchive, titlesFound, coordinateFileIndex, maxTitles, targetRect, callbackFunction);
|
||||
}
|
||||
else {
|
||||
// TODO this part needs to be reworked and does not work as is
|
||||
// I can not push titles found in the list with a simple for loop because of the asynchronous read
|
||||
// Maybe I should split that in 2 parts : first gather all the title positions with the loop
|
||||
// and then read all the titles
|
||||
for (var i = 0; i < selector; i ++) {
|
||||
var indexInByteArray = 2 + i * 8;
|
||||
// Read position (in title file) in coordinateFile
|
||||
var c = readCoordinates(byteArray, indexInByteArray);
|
||||
var title_pos = byteArray[indexInByteArray + 2] + 256 * byteArray[indexInByteArray + 3] + 256 * 256 * byteArray[indexInByteArray + 4] + 256 * 256 * 256 * byteArray[indexInByteArray + 5];
|
||||
if (!targetRect.containsPoint(c)) {
|
||||
continue;
|
||||
}
|
||||
// read title at title_pos in title file
|
||||
localArchive.getTitlesStartingAtOffset(title_pos, 1, function(titles) {
|
||||
titlesFound.push(titles[0]);
|
||||
if (maxTitles >= 0 && titlesFound.length >= maxTitles) {
|
||||
LocalArchive.callbackGetTitlesInCoordsInt(localArchive, titlesFound, coordinateFileIndex, maxTitles, targetRect, callbackFunction);
|
||||
// TODO : this "return" does not exit from the right function
|
||||
// I need to find a way to make it return from the onLoad above
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
LocalArchive.callbackGetTitlesInCoordsInt(localArchive, titlesFound, coordinateFileIndex, maxTitles, targetRect, callbackFunction);
|
||||
}
|
||||
|
||||
};
|
||||
// Read 22 bytes in the coordinate files, at coordFilePos index, in order to read the selector and the coordinates
|
||||
// 2 + 4 + 4 + 3 * 4 = 22
|
||||
var blob = localArchive.coordinateFiles[coordinateFileIndex].slice(coordFilePos, coordFilePos + 22);
|
||||
// Read in the file as a binary string
|
||||
reader.readAsArrayBuffer(blob);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -861,4 +902,4 @@ define(function(require) {
|
||||
return {
|
||||
LocalArchive: LocalArchive
|
||||
};
|
||||
});
|
||||
});
|
||||
|
@ -259,11 +259,22 @@ define(function(require) {
|
||||
h = x.height;
|
||||
x = x.x;
|
||||
}
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = w;
|
||||
this.height = h;
|
||||
}
|
||||
if (w === undefined && h === undefined) {
|
||||
// The rectangle is built from topLeft and bottomRight points
|
||||
var topLeft = x;
|
||||
var bottomRight = y;
|
||||
this.x = topLeft.x;
|
||||
this.y = topLeft.y;
|
||||
this.width = bottomRight.x - topLeft.x;
|
||||
this.height = bottomRight.y - topLeft.y;
|
||||
}
|
||||
else {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = w;
|
||||
this.height = h;
|
||||
}
|
||||
}
|
||||
|
||||
rect.prototype = {
|
||||
toString: function() {
|
||||
@ -331,6 +342,49 @@ define(function(require) {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// Algorithm copied from java.awt.Rectangle from OpenJDK
|
||||
// @return {bool} true if rectangle r is inside me
|
||||
contains: function(r) {
|
||||
var nr = r.normalized();
|
||||
var W = nr.width;
|
||||
var H = nr.height;
|
||||
var X = nr.x;
|
||||
var Y = nr.y;
|
||||
var w = this.width;
|
||||
var h = this.height;
|
||||
if ((w | h | W | H) < 0) {
|
||||
// At least one of the dimensions is negative...
|
||||
return false;
|
||||
}
|
||||
// Note: if any dimension is zero, tests below must return false...
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
if (X < x || Y < y) {
|
||||
return false;
|
||||
}
|
||||
w += x;
|
||||
W += X;
|
||||
if (W <= X) {
|
||||
// X+W overflowed or W was zero, return false if...
|
||||
// either original w or W was zero or
|
||||
// x+w did not overflow or
|
||||
// the overflowed x+w is smaller than the overflowed X+W
|
||||
if (w >= x || W > w) return false;
|
||||
} else {
|
||||
// X+W did not overflow and W was not zero, return false if...
|
||||
// original w was zero or
|
||||
// x+w did not overflow and x+w is smaller than X+W
|
||||
if (w >= x && W > w) return false;
|
||||
}
|
||||
h += y;
|
||||
H += Y;
|
||||
if (H <= Y) {
|
||||
if (h >= y || H > h) return false;
|
||||
} else {
|
||||
if (h >= y && H > h) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// @return {point} a point on my boundary nearest to p
|
||||
// @see Squeak Smalltalk, Rectangle>>pointNearestTo:
|
||||
pointNearestToPoint: function(p) {
|
||||
|
564
tests/tests.js
564
tests/tests.js
@ -1,269 +1,295 @@
|
||||
/**
|
||||
* tests.js : Unit tests implemented with qunit
|
||||
*
|
||||
* Copyright 2013 Mossroy
|
||||
* License GPL v3:
|
||||
*
|
||||
* This file is part of Evopedia.
|
||||
*
|
||||
* Evopedia is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Evopedia is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Evopedia (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var $ = require('jquery');
|
||||
var evopediaTitle = require('title');
|
||||
var evopediaArchive = require('archive');
|
||||
var geometry = require('geometry');
|
||||
|
||||
// Due to security restrictions in the browsers,
|
||||
// we can not read directly the files and run the unit tests
|
||||
// The user has to select them manually, then launch the tests
|
||||
$('#runTests').on('click', function(e) {
|
||||
runTests();
|
||||
});
|
||||
|
||||
var runTests = function() {
|
||||
|
||||
module("environment");
|
||||
test("qunit test", function() {
|
||||
equal("test", "test", "QUnit is properly configured");
|
||||
});
|
||||
|
||||
test("check archive files are selected", function() {
|
||||
var archiveFiles = document.getElementById('archiveFiles').files;
|
||||
ok(archiveFiles && archiveFiles[0] && archiveFiles[0].size > 0, "First archive file set and not empty");
|
||||
ok(archiveFiles.length >= 5, "At least 5 files are selected");
|
||||
});
|
||||
|
||||
// Create a localArchive from selected files, in order to run the following tests
|
||||
var localArchive = new evopediaArchive.LocalArchive();
|
||||
localArchive.initializeFromArchiveFiles(document.getElementById('archiveFiles').files);
|
||||
|
||||
module("evopedia");
|
||||
asyncTest("check getTitlesStartingAtOffset 0", function() {
|
||||
var callbackFunction = function(titleList) {
|
||||
equal(titleList.length, 4, "4 titles found, as requested");
|
||||
var indexAbraham = -1;
|
||||
for (var i = 0; i < titleList.length; i++) {
|
||||
if (titleList[i] && titleList[i].name === "Abraham") {
|
||||
indexAbraham = i;
|
||||
}
|
||||
}
|
||||
ok(indexAbraham > -1, "Title 'Abraham' found");
|
||||
var firstTitleName = "not found";
|
||||
var secondTitleName = "not found";
|
||||
if (titleList.length >= 1 && titleList[0]) {
|
||||
firstTitleName = titleList[0].name;
|
||||
}
|
||||
if (titleList.length >= 2 && titleList[1]) {
|
||||
secondTitleName = titleList[1].name;
|
||||
}
|
||||
equal(firstTitleName, "Abbasid_Caliphate", "First article name is 'Abbasid_Caliphate'");
|
||||
equal(secondTitleName, "Abortion", "Second article name is 'Abortion'");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitlesStartingAtOffset(0, 4, callbackFunction);
|
||||
});
|
||||
|
||||
asyncTest("check findTitlesWithPrefix Am", function() {
|
||||
var callbackFunction = function(titleList) {
|
||||
ok(titleList && titleList.length > 0, "At least one title is found");
|
||||
var firstTitleName = "not found";
|
||||
var secondTitleName = "not found";
|
||||
if (titleList.length >= 1 && titleList[0]) {
|
||||
firstTitleName = titleList[0].name;
|
||||
}
|
||||
if (titleList.length >= 2 && titleList[1]) {
|
||||
secondTitleName = titleList[1].name;
|
||||
}
|
||||
equal(firstTitleName, "Amazon_River", "First article name is 'Amazon_River'");
|
||||
equal(secondTitleName, "American_Civil_War", "Second article name is 'American_Civil_War'");
|
||||
equal(titleList.length, 4, "4 titles should be found");
|
||||
start();
|
||||
};
|
||||
localArchive.findTitlesWithPrefix("Am", 10, callbackFunction);
|
||||
});
|
||||
|
||||
// Create a title instance for the Article 'Abraham'
|
||||
var titleAbraham = new evopediaTitle.Title();
|
||||
titleAbraham.archive = localArchive;
|
||||
titleAbraham.articleLength = 10071;
|
||||
titleAbraham.blockOffset = 127640;
|
||||
titleAbraham.blockStart = 2364940;
|
||||
titleAbraham.fileNr = 0;
|
||||
titleAbraham.name = "Abraham";
|
||||
titleAbraham.titleOffset = 57;
|
||||
|
||||
asyncTest("check getTitleByName with accents : Diego Velázquez", function() {
|
||||
var callbackFunction = function(title) {
|
||||
ok(title !== null, "Title found");
|
||||
equal(title.name, "Diego_Velázquez", "Name of the title is correct");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitleByName("Diego_Velázquez", callbackFunction);
|
||||
});
|
||||
asyncTest("check getTitleByName with quote : Hundred Years' War", function() {
|
||||
var callbackFunction = function(title) {
|
||||
ok(title !== null, "Title found");
|
||||
equal(title.name, "Hundred_Years'_War", "Name of the title is correct");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitleByName("Hundred_Years'_War", callbackFunction);
|
||||
});
|
||||
|
||||
test("check parseTitleFromId", function() {
|
||||
var titleId = "small|2010-08-14|0|57|Abraham|2364940|127640|10071";
|
||||
var title = evopediaTitle.Title.parseTitleId(localArchive, titleId);
|
||||
ok(title, "Title instance created");
|
||||
deepEqual(title, titleAbraham, "Parsing from titleId gives Abraham title");
|
||||
});
|
||||
|
||||
asyncTest("check readArticle", function() {
|
||||
var callbackFunction = function(title, htmlArticle) {
|
||||
ok(htmlArticle && htmlArticle.length > 0, "Article not empty");
|
||||
// Remove new lines
|
||||
htmlArticle = htmlArticle.replace(/[\r\n]/g, " ");
|
||||
ok(htmlArticle.match("^[ \t]*<h1[^>]*>Abraham</h1>"), "'Abraham' title at the beginning");
|
||||
ok(htmlArticle.match("</div>[ \t]$"), "</div> at the end");
|
||||
start();
|
||||
};
|
||||
localArchive.readArticle(titleAbraham, callbackFunction);
|
||||
});
|
||||
|
||||
asyncTest("check getTitleByName and readArticle with escape bytes", function() {
|
||||
var callbackArticleRead = function(title, htmlArticle) {
|
||||
ok(htmlArticle && htmlArticle.length > 0, "Article not empty");
|
||||
// Remove new lines
|
||||
htmlArticle = htmlArticle.replace(/[\r\n]/g, " ");
|
||||
ok(htmlArticle.match("^[ \t]*<h1[^>]*>AIDS</h1>"), "'AIDS' title at the beginning");
|
||||
ok(htmlArticle.match("</div>[ \t]$"), "</div> at the end");
|
||||
start();
|
||||
};
|
||||
var callbackTitleFound = function(title) {
|
||||
ok(title !== null, "Title found");
|
||||
equal(title.name, "AIDS", "Name of the title is correct");
|
||||
localArchive.readArticle(title, callbackArticleRead);
|
||||
};
|
||||
localArchive.getTitleByName("AIDS", callbackTitleFound);
|
||||
});
|
||||
|
||||
asyncTest("check getTitleByName with a title name that does not exist in the archive", function() {
|
||||
var callbackTitleFound = function(title) {
|
||||
ok(title === null, "No title found because it does not exist in the archive");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitleByName("abcdef", callbackTitleFound);
|
||||
});
|
||||
|
||||
asyncTest("check loading a math image", function() {
|
||||
var callbackFunction = function(data) {
|
||||
ok(data && data.length > 0, "Image not empty");
|
||||
// edb3069b82c68d270f6642c171cc6293.png should give a "1 1/2" formula (can be found in "Rational_number" article)
|
||||
equal(data,
|
||||
"iVBORw0KGgoAAAANSUhEUgAAABUAAAApBAMAAAAogX9zAAAAMFBMVEX///8AAADm5uZAQEDMzMwWFhYiIiIwMDBQUFCenp62trZiYmIMDAwEBASKiop0dHRvDVFEAAAAb0lEQVQY02NggAAmAwY4cE2AM9VNEWwG9oFhcxgKN9HJhYyCQCBApgs5jYMVYCKrGdgOwNgGDCzSMLYwA4MYjH2cgeEawjgWCQSbQwjBdpyAYMch2f4Awd7HwAVj8n1g4Iaxl+7e3Q1jXxQUlGMAAJkfGS29Qu04AAAAAElFTkSuQmCC",
|
||||
"Math image corresponds to '1 1/2' png");
|
||||
start();
|
||||
};
|
||||
|
||||
localArchive.loadMathImage("edb3069b82c68d270f6642c171cc6293", callbackFunction);
|
||||
});
|
||||
|
||||
module("geometry");
|
||||
test("check rectangle intersection", function() {
|
||||
var rect1 = new geometry.rect(0,0,2,2);
|
||||
var rect2 = new geometry.rect(1,1,2,2);
|
||||
var rect3 = new geometry.rect(2,2,2,2);
|
||||
var rect4 = new geometry.rect(1,1,1,1);
|
||||
var rect5 = new geometry.rect(3,3,2,2);
|
||||
var rect6 = new geometry.rect(2,0,1,10);
|
||||
ok(rect1.intersect(rect2), "rect1 intersects rect2");
|
||||
ok(rect2.intersect(rect1), "rect2 intersects rect1");
|
||||
ok(rect2.intersect(rect3), "rect1 intersects rect3");
|
||||
ok(!rect1.intersect(rect3), "rect1 does not intersect rect3");
|
||||
ok(!rect4.intersect(rect3), "rect4 does not intersect rect3");
|
||||
ok(rect4.intersect(rect2), "rect4 intersects rect2");
|
||||
ok(!rect5.intersect(rect1), "rect5 does not intersect rect1");
|
||||
ok(!rect1.intersect(rect5), "rect1 does not intersect rect5");
|
||||
ok(rect6.intersect(rect2), "rect6 intersects rect2");
|
||||
ok(rect6.intersect(rect3), "rect6 intersects rect3");
|
||||
ok(!rect6.intersect(rect5), "rect6 intersects rect5");
|
||||
});
|
||||
test("check rectangle contains a point", function() {
|
||||
var rect1 = new geometry.rect(2,3,4,5);
|
||||
var point1 = new geometry.point(1,1);
|
||||
var point2 = new geometry.point(2,3);
|
||||
var point3 = new geometry.point(4,4);
|
||||
var point4 = new geometry.point(7,9);
|
||||
var point5 = new geometry.point(4,6);
|
||||
ok(!rect1.containsPoint(point1), "rect1 does not contain point1");
|
||||
ok(!rect1.containsPoint(point2), "rect1 does not contain point2");
|
||||
ok(rect1.containsPoint(point3), "rect1 contains point3");
|
||||
ok(!rect1.containsPoint(point4), "rect1 does not contain point4");
|
||||
ok(rect1.containsPoint(point5), "rect1 contains point5");
|
||||
});
|
||||
test("check normalization of a rectangle", function() {
|
||||
var rect1 = new geometry.rect(2,3,4,5);
|
||||
var normalizedRect1 = rect1.normalized();
|
||||
ok(rect1.x===normalizedRect1.x
|
||||
&& rect1.y===normalizedRect1.y
|
||||
&& rect1.width===normalizedRect1.width
|
||||
&& rect1.height===normalizedRect1.height, "rect1 is the same after normalization");
|
||||
var rect2 = new geometry.rect(6,3,-4,5);
|
||||
var normalizedRect2 = rect2.normalized();
|
||||
//alert("normalizedRect2 = " + normalizedRect2);
|
||||
ok(normalizedRect2.x===2
|
||||
&& normalizedRect2.y===3
|
||||
&& normalizedRect2.width===4
|
||||
&& normalizedRect2.height===5, "rect2 successfully normalized by switching top left and top right corners");
|
||||
var rect3 = new geometry.rect(2,8,4,-5);
|
||||
var normalizedRect3 = rect3.normalized();
|
||||
ok(normalizedRect3.x===2
|
||||
&& normalizedRect3.y===3
|
||||
&& normalizedRect3.width===4
|
||||
&& normalizedRect3.height===5, "rect3 successfully normalized by switching top left and botton left corners");
|
||||
var rect4 = new geometry.rect(6,8,-4,-5);
|
||||
var normalizedRect4 = rect4.normalized();
|
||||
ok(normalizedRect4.x===2
|
||||
&& normalizedRect4.y===3
|
||||
&& normalizedRect4.width===4
|
||||
&& normalizedRect4.height===5, "rect4 successfully normalized by switching bottom right and top left corners");
|
||||
var rect5 = new geometry.rect(12,2,-4,-1);
|
||||
var normalizedRect5 = rect5.normalized();
|
||||
ok(normalizedRect5.x===8
|
||||
&& normalizedRect5.y===1
|
||||
&& normalizedRect5.width===4
|
||||
&& normalizedRect5.height===1, "rect5 successfully normalized by switching bottom right and top left corners");
|
||||
});
|
||||
|
||||
module("articles_nearby");
|
||||
asyncTest("check articles found nearby France and Germany", function() {
|
||||
var callbackTitlesNearbyFound = function(titles) {
|
||||
ok(titles !== null, "Some titles should be found");
|
||||
equal(titles.length, 3, "3 titles should be found");
|
||||
var titleAlps;
|
||||
for (var i=0; i<titles.length; i++) {
|
||||
var title = titles[i];
|
||||
if (title.name === "Alps") {
|
||||
titleAlps = title[i];
|
||||
}
|
||||
}
|
||||
ok(titleAlps !== null, "The title 'Alps' should be found");
|
||||
// TODO : check the coordinates of title Alps?
|
||||
start();
|
||||
};
|
||||
var rectFranceGermany = new geometry.rect(40,50,-10,10);
|
||||
localArchive.getTitlesInCoords(rectFranceGermany, 10, callbackTitlesNearbyFound);
|
||||
});
|
||||
};
|
||||
});
|
||||
/**
|
||||
* tests.js : Unit tests implemented with qunit
|
||||
*
|
||||
* Copyright 2013 Mossroy
|
||||
* License GPL v3:
|
||||
*
|
||||
* This file is part of Evopedia.
|
||||
*
|
||||
* Evopedia is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Evopedia is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Evopedia (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var $ = require('jquery');
|
||||
var evopediaTitle = require('title');
|
||||
var evopediaArchive = require('archive');
|
||||
var geometry = require('geometry');
|
||||
|
||||
// Due to security restrictions in the browsers,
|
||||
// we can not read directly the files and run the unit tests
|
||||
// The user has to select them manually, then launch the tests
|
||||
$('#runTests').on('click', function(e) {
|
||||
runTests();
|
||||
});
|
||||
|
||||
var runTests = function() {
|
||||
|
||||
module("environment");
|
||||
test("qunit test", function() {
|
||||
equal("test", "test", "QUnit is properly configured");
|
||||
});
|
||||
|
||||
test("check archive files are selected", function() {
|
||||
var archiveFiles = document.getElementById('archiveFiles').files;
|
||||
ok(archiveFiles && archiveFiles[0] && archiveFiles[0].size > 0, "First archive file set and not empty");
|
||||
ok(archiveFiles.length >= 5, "At least 5 files are selected");
|
||||
});
|
||||
|
||||
// Create a localArchive from selected files, in order to run the following tests
|
||||
var localArchive = new evopediaArchive.LocalArchive();
|
||||
localArchive.initializeFromArchiveFiles(document.getElementById('archiveFiles').files);
|
||||
|
||||
module("evopedia");
|
||||
asyncTest("check getTitlesStartingAtOffset 0", function() {
|
||||
var callbackFunction = function(titleList) {
|
||||
equal(titleList.length, 4, "4 titles found, as requested");
|
||||
var indexAbraham = -1;
|
||||
for (var i = 0; i < titleList.length; i++) {
|
||||
if (titleList[i] && titleList[i].name === "Abraham") {
|
||||
indexAbraham = i;
|
||||
}
|
||||
}
|
||||
ok(indexAbraham > -1, "Title 'Abraham' found");
|
||||
var firstTitleName = "not found";
|
||||
var secondTitleName = "not found";
|
||||
if (titleList.length >= 1 && titleList[0]) {
|
||||
firstTitleName = titleList[0].name;
|
||||
}
|
||||
if (titleList.length >= 2 && titleList[1]) {
|
||||
secondTitleName = titleList[1].name;
|
||||
}
|
||||
equal(firstTitleName, "Abbasid_Caliphate", "First article name is 'Abbasid_Caliphate'");
|
||||
equal(secondTitleName, "Abortion", "Second article name is 'Abortion'");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitlesStartingAtOffset(0, 4, callbackFunction);
|
||||
});
|
||||
|
||||
asyncTest("check findTitlesWithPrefix Am", function() {
|
||||
var callbackFunction = function(titleList) {
|
||||
ok(titleList && titleList.length > 0, "At least one title is found");
|
||||
var firstTitleName = "not found";
|
||||
var secondTitleName = "not found";
|
||||
if (titleList.length >= 1 && titleList[0]) {
|
||||
firstTitleName = titleList[0].name;
|
||||
}
|
||||
if (titleList.length >= 2 && titleList[1]) {
|
||||
secondTitleName = titleList[1].name;
|
||||
}
|
||||
equal(firstTitleName, "Amazon_River", "First article name is 'Amazon_River'");
|
||||
equal(secondTitleName, "American_Civil_War", "Second article name is 'American_Civil_War'");
|
||||
equal(titleList.length, 4, "4 titles should be found");
|
||||
start();
|
||||
};
|
||||
localArchive.findTitlesWithPrefix("Am", 10, callbackFunction);
|
||||
});
|
||||
|
||||
// Create a title instance for the Article 'Abraham'
|
||||
var titleAbraham = new evopediaTitle.Title();
|
||||
titleAbraham.archive = localArchive;
|
||||
titleAbraham.articleLength = 10071;
|
||||
titleAbraham.blockOffset = 127640;
|
||||
titleAbraham.blockStart = 2364940;
|
||||
titleAbraham.fileNr = 0;
|
||||
titleAbraham.name = "Abraham";
|
||||
titleAbraham.titleOffset = 57;
|
||||
|
||||
asyncTest("check getTitleByName with accents : Diego Velázquez", function() {
|
||||
var callbackFunction = function(title) {
|
||||
ok(title !== null, "Title found");
|
||||
equal(title.name, "Diego_Velázquez", "Name of the title is correct");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitleByName("Diego_Velázquez", callbackFunction);
|
||||
});
|
||||
asyncTest("check getTitleByName with quote : Hundred Years' War", function() {
|
||||
var callbackFunction = function(title) {
|
||||
ok(title !== null, "Title found");
|
||||
equal(title.name, "Hundred_Years'_War", "Name of the title is correct");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitleByName("Hundred_Years'_War", callbackFunction);
|
||||
});
|
||||
|
||||
test("check parseTitleFromId", function() {
|
||||
var titleId = "small|2010-08-14|0|57|Abraham|2364940|127640|10071";
|
||||
var title = evopediaTitle.Title.parseTitleId(localArchive, titleId);
|
||||
ok(title, "Title instance created");
|
||||
deepEqual(title, titleAbraham, "Parsing from titleId gives Abraham title");
|
||||
});
|
||||
|
||||
asyncTest("check readArticle", function() {
|
||||
var callbackFunction = function(title, htmlArticle) {
|
||||
ok(htmlArticle && htmlArticle.length > 0, "Article not empty");
|
||||
// Remove new lines
|
||||
htmlArticle = htmlArticle.replace(/[\r\n]/g, " ");
|
||||
ok(htmlArticle.match("^[ \t]*<h1[^>]*>Abraham</h1>"), "'Abraham' title at the beginning");
|
||||
ok(htmlArticle.match("</div>[ \t]$"), "</div> at the end");
|
||||
start();
|
||||
};
|
||||
localArchive.readArticle(titleAbraham, callbackFunction);
|
||||
});
|
||||
|
||||
asyncTest("check getTitleByName and readArticle with escape bytes", function() {
|
||||
var callbackArticleRead = function(title, htmlArticle) {
|
||||
ok(htmlArticle && htmlArticle.length > 0, "Article not empty");
|
||||
// Remove new lines
|
||||
htmlArticle = htmlArticle.replace(/[\r\n]/g, " ");
|
||||
ok(htmlArticle.match("^[ \t]*<h1[^>]*>AIDS</h1>"), "'AIDS' title at the beginning");
|
||||
ok(htmlArticle.match("</div>[ \t]$"), "</div> at the end");
|
||||
start();
|
||||
};
|
||||
var callbackTitleFound = function(title) {
|
||||
ok(title !== null, "Title found");
|
||||
equal(title.name, "AIDS", "Name of the title is correct");
|
||||
localArchive.readArticle(title, callbackArticleRead);
|
||||
};
|
||||
localArchive.getTitleByName("AIDS", callbackTitleFound);
|
||||
});
|
||||
|
||||
asyncTest("check getTitleByName with a title name that does not exist in the archive", function() {
|
||||
var callbackTitleFound = function(title) {
|
||||
ok(title === null, "No title found because it does not exist in the archive");
|
||||
start();
|
||||
};
|
||||
localArchive.getTitleByName("abcdef", callbackTitleFound);
|
||||
});
|
||||
|
||||
asyncTest("check loading a math image", function() {
|
||||
var callbackFunction = function(data) {
|
||||
ok(data && data.length > 0, "Image not empty");
|
||||
// edb3069b82c68d270f6642c171cc6293.png should give a "1 1/2" formula (can be found in "Rational_number" article)
|
||||
equal(data,
|
||||
"iVBORw0KGgoAAAANSUhEUgAAABUAAAApBAMAAAAogX9zAAAAMFBMVEX///8AAADm5uZAQEDMzMwWFhYiIiIwMDBQUFCenp62trZiYmIMDAwEBASKiop0dHRvDVFEAAAAb0lEQVQY02NggAAmAwY4cE2AM9VNEWwG9oFhcxgKN9HJhYyCQCBApgs5jYMVYCKrGdgOwNgGDCzSMLYwA4MYjH2cgeEawjgWCQSbQwjBdpyAYMch2f4Awd7HwAVj8n1g4Iaxl+7e3Q1jXxQUlGMAAJkfGS29Qu04AAAAAElFTkSuQmCC",
|
||||
"Math image corresponds to '1 1/2' png");
|
||||
start();
|
||||
};
|
||||
|
||||
localArchive.loadMathImage("edb3069b82c68d270f6642c171cc6293", callbackFunction);
|
||||
});
|
||||
|
||||
module("geometry");
|
||||
test("check rectangle intersection", function() {
|
||||
var rect1 = new geometry.rect(0,0,2,2);
|
||||
var rect2 = new geometry.rect(1,1,2,2);
|
||||
var rect3 = new geometry.rect(2,2,2,2);
|
||||
var rect4 = new geometry.rect(1,1,1,1);
|
||||
var rect5 = new geometry.rect(3,3,2,2);
|
||||
var rect6 = new geometry.rect(2,0,1,10);
|
||||
ok(rect1.intersect(rect2), "rect1 intersects rect2");
|
||||
ok(rect2.intersect(rect1), "rect2 intersects rect1");
|
||||
ok(rect2.intersect(rect3), "rect1 intersects rect3");
|
||||
ok(!rect1.intersect(rect3), "rect1 does not intersect rect3");
|
||||
ok(!rect4.intersect(rect3), "rect4 does not intersect rect3");
|
||||
ok(rect4.intersect(rect2), "rect4 intersects rect2");
|
||||
ok(!rect5.intersect(rect1), "rect5 does not intersect rect1");
|
||||
ok(!rect1.intersect(rect5), "rect1 does not intersect rect5");
|
||||
ok(rect6.intersect(rect2), "rect6 intersects rect2");
|
||||
ok(rect6.intersect(rect3), "rect6 intersects rect3");
|
||||
ok(!rect6.intersect(rect5), "rect6 intersects rect5");
|
||||
});
|
||||
test("check rectangle contains a point", function() {
|
||||
var rect1 = new geometry.rect(2,3,4,5);
|
||||
var point1 = new geometry.point(1,1);
|
||||
var point2 = new geometry.point(2,3);
|
||||
var point3 = new geometry.point(4,4);
|
||||
var point4 = new geometry.point(7,9);
|
||||
var point5 = new geometry.point(4,6);
|
||||
ok(!rect1.containsPoint(point1), "rect1 does not contain point1");
|
||||
ok(!rect1.containsPoint(point2), "rect1 does not contain point2");
|
||||
ok(rect1.containsPoint(point3), "rect1 contains point3");
|
||||
ok(!rect1.containsPoint(point4), "rect1 does not contain point4");
|
||||
ok(rect1.containsPoint(point5), "rect1 contains point5");
|
||||
});
|
||||
test("check normalization of a rectangle", function() {
|
||||
var rect1 = new geometry.rect(2,3,4,5);
|
||||
var normalizedRect1 = rect1.normalized();
|
||||
ok(rect1.x===normalizedRect1.x
|
||||
&& rect1.y===normalizedRect1.y
|
||||
&& rect1.width===normalizedRect1.width
|
||||
&& rect1.height===normalizedRect1.height, "rect1 is the same after normalization");
|
||||
var rect2 = new geometry.rect(6,3,-4,5);
|
||||
var normalizedRect2 = rect2.normalized();
|
||||
//alert("normalizedRect2 = " + normalizedRect2);
|
||||
ok(normalizedRect2.x===2
|
||||
&& normalizedRect2.y===3
|
||||
&& normalizedRect2.width===4
|
||||
&& normalizedRect2.height===5, "rect2 successfully normalized by switching top left and top right corners");
|
||||
var rect3 = new geometry.rect(2,8,4,-5);
|
||||
var normalizedRect3 = rect3.normalized();
|
||||
ok(normalizedRect3.x===2
|
||||
&& normalizedRect3.y===3
|
||||
&& normalizedRect3.width===4
|
||||
&& normalizedRect3.height===5, "rect3 successfully normalized by switching top left and botton left corners");
|
||||
var rect4 = new geometry.rect(6,8,-4,-5);
|
||||
var normalizedRect4 = rect4.normalized();
|
||||
ok(normalizedRect4.x===2
|
||||
&& normalizedRect4.y===3
|
||||
&& normalizedRect4.width===4
|
||||
&& normalizedRect4.height===5, "rect4 successfully normalized by switching bottom right and top left corners");
|
||||
var rect5 = new geometry.rect(12,2,-4,-1);
|
||||
var normalizedRect5 = rect5.normalized();
|
||||
ok(normalizedRect5.x===8
|
||||
&& normalizedRect5.y===1
|
||||
&& normalizedRect5.width===4
|
||||
&& normalizedRect5.height===1, "rect5 successfully normalized by switching bottom right and top left corners");
|
||||
});
|
||||
test("check rectangle constructor from top-left and bottom-right points", function() {
|
||||
var topLeft = new geometry.point(2,3);
|
||||
var bottomRight = new geometry.point(5,5);
|
||||
var rect = new geometry.rect(topLeft, bottomRight);
|
||||
equal(rect.x, 2 , "rect.x should be 2");
|
||||
equal(rect.y, 3 , "rect.y should be 3");
|
||||
equal(rect.width, 3 , "rect.width should be 3");
|
||||
equal(rect.height, 2 , "rect.height should be 2");
|
||||
});
|
||||
test("check rectangle contains another rectangle", function() {
|
||||
var rect1 = new geometry.rect(2,3,4,4);
|
||||
var rect2 = new geometry.rect(3,4,1,1);
|
||||
var rect3 = new geometry.rect(1,1,1,1);
|
||||
var rect4 = new geometry.rect(3,1,2,4);
|
||||
var rect5 = new geometry.rect(3,1,6,4);
|
||||
var rect6 = new geometry.rect(2,3,3,2);
|
||||
var rect7 = new geometry.rect(5,6,-3,-2); // same as rect7 but not normalized
|
||||
ok(rect1.contains(rect2), "rect1 should contain rect2");
|
||||
ok(!rect2.contains(rect1), "rect2 should not contain rect1");
|
||||
ok(!rect1.contains(rect3), "rect1 should not contain rect3");
|
||||
ok(!rect1.contains(rect4), "rect1 should not contain rect4");
|
||||
ok(!rect1.contains(rect5), "rect1 should not contain rect5");
|
||||
ok(rect1.contains(rect1), "rect1 should contain rect1");
|
||||
ok(rect1.contains(rect6), "rect1 should contain rect6");
|
||||
ok(rect1.contains(rect7), "rect1 should contain rect7");
|
||||
});
|
||||
|
||||
module("articles_nearby");
|
||||
asyncTest("check articles found nearby France and Germany", function() {
|
||||
var callbackTitlesNearbyFound = function(titles) {
|
||||
ok(titles !== null, "Some titles should be found");
|
||||
equal(titles.length, 3, "3 titles should be found");
|
||||
var titleAlps = null;
|
||||
for (var i=0; i<titles.length; i++) {
|
||||
var title = titles[i];
|
||||
if (title && title.name === "Alps") {
|
||||
titleAlps = title;
|
||||
}
|
||||
}
|
||||
ok(titleAlps !== null, "The title 'Alps' should be found");
|
||||
// TODO : check the coordinates of title Alps?
|
||||
start();
|
||||
};
|
||||
var rectFranceGermany = new geometry.rect(40,50,-10,10);
|
||||
localArchive.getTitlesInCoords(rectFranceGermany, 10, callbackTitlesNearbyFound);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user