package com.door43.translationstudio.core;
import android.content.Context;
import android.test.InstrumentationTestCase;
import com.door43.tools.reporting.FileUtils;
import com.door43.translationstudio.AppContext;
import com.door43.translationstudio.spannables.USFMVerseSpan;
import com.door43.translationstudio.tasks.UploadCrashReportTask;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by blm on 4/19/16.
*/
public class ImportUsfmTest extends InstrumentationTestCase {
private JSONArray mExpectedBooks;
private TargetLanguage mTargetLanguage;
private ImportUsfm mUsfm;
private Context mTestContext;
private Context mAppContext;
private Library mLibrary;
@Override
public void setUp() throws Exception {
super.setUp();
mExpectedBooks = new JSONArray();
mLibrary = AppContext.getLibrary();
UploadCrashReportTask.archiveErrorLogs();
mTargetLanguage = mLibrary.getTargetLanguage("es");
mTestContext = getInstrumentation().getContext();
mAppContext = AppContext.context();
if(AppContext.getProfile() == null) { // make sure this is initialized
AppContext.setProfile(new Profile("testing"));
}
}
@Override
public void tearDown() throws Exception {
if(mUsfm != null) {
mUsfm.cleanup();
}
}
public void test01ValidImportMark() throws Exception {
//given
String source = "mrk.usfm";
addExpectedBook(source, "mrk", true, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test02ImportMarkMissingName() throws Exception {
//given
String source = "mrk_no_id.usfm";
addExpectedBook(source, "", false, true);
boolean expectNoEmptyChunks = true;
boolean expectSucccess = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test03ImportMarkMissingNameForce() throws Exception {
//given
String source = "mrk_no_id.usfm";
String useName = "Mrk";
addExpectedBook(source, useName, true, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
InputStream usfmStream = mTestContext.getAssets().open("usfm/" + source);
String text = IOUtils.toString(usfmStream, "UTF-8");
//when
boolean success = mUsfm.processText(text, source, false, useName);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test04ValidImportPsalms() throws Exception {
//given
String source = "19-PSA.usfm"; // psalms has a verse range
addExpectedBook(source, "psa", true, false);
boolean expectNoEmptyChunks = true;
boolean expectSucccess = true;
boolean exactVerseCount = false;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test05ImportMarkNoChapters() throws Exception {
//given
String source = "mrk_no_chapter.usfm";
addExpectedBook(source, "mrk", false, false);
boolean expectNoEmptyChunks = true;
boolean expectSucccess = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test06ImportMarkMissingChapters() throws Exception {
//given
String source = "mrk_one_chapter.usfm";
addExpectedBook(source, "mrk", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test07ImportMarkNoVerses() throws Exception {
//given
String source = "mrk_one_chapter.usfm";
addExpectedBook(source, "mrk", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test08ImportMarkMissingVerse() throws Exception {
//given
String source = "mrk_missing_verse.usfm";
addExpectedBook(source, "mrk", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = false;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test09ImportMarkEmptyChapter() throws Exception {
//given
String source = "mrk_empty_chapter.usfm";
addExpectedBook(source, "mrk", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test10ImportJudeNoVerses() throws Exception {
//given
String source = "jude.no_verses.usfm";
addExpectedBook(source, "jud", false, false);
boolean expectSucccess = false;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test11ImportJudeNoChapter() throws Exception {
//given
String source = "jude.no_chapter_or_verses.usfm";
addExpectedBook(source, "jud", false, false);
boolean expectSucccess = false;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test12ImportPhpNoChapter1() throws Exception {
//given
String source = "php_usfm_NoC1.usfm";
addExpectedBook(source, "php", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test13ImportPhpNoChapter2() throws Exception {
//given
String source = "php_usfm_NoC2.usfm";
addExpectedBook(source, "php", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test14ImportPhpChapter3OutOfOrder() throws Exception {
//given
String source = "php_usfm_C3_out_of_order.usfm";
addExpectedBook(source, "php", false, false);
boolean expectSucccess = false;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test15ImportPhpMissingLastChapter() throws Exception {
//given
String source = "php_usfm_missing_last_chapter.usfm";
addExpectedBook(source, "php", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test16ImportPhpNoChapter1Marker() throws Exception {
//given
String source = "php_usfm_NoC1_marker.usfm";
addExpectedBook(source, "php", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test17ImportPhpNoChapter2Marker() throws Exception {
//given
String source = "php_usfm_NoC2_marker.usfm";
addExpectedBook(source, "php", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test18ImportPhpMissingLastChapterMarker() throws Exception {
//given
String source = "php_usfm_missing_last_chapter_marker.usfm";
addExpectedBook(source, "php", true, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = false;
boolean exactVerseCount = true;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void test19ImportJudeOutOfOrderVerses() throws Exception {
//given
String source = "jude.out_order_verses.usfm";
addExpectedBook(source, "jud", false, false);
boolean expectSucccess = true;
boolean expectNoEmptyChunks = true;
boolean exactVerseCount = false;
mUsfm = new ImportUsfm(mAppContext, mTargetLanguage);
//when
boolean success = mUsfm.readResourceFile(mTestContext, "usfm/" + source);
//then
verifyResults( success, expectSucccess, mExpectedBooks, expectNoEmptyChunks, exactVerseCount);
}
public void addExpectedBook(String filename, String book, boolean success, boolean missingName) throws JSONException {
JSONObject expectedBook = new JSONObject();
expectedBook.put("filename", filename);
expectedBook.put("book", book);
expectedBook.put("success", success);
expectedBook.put("missingName", missingName);
mExpectedBooks.put(expectedBook);
}
public String getFileName(JSONObject object) throws JSONException {
return object.getString("filename");
}
public String getBook(JSONObject object) throws JSONException {
return object.getString("book");
}
public boolean getMissingName(JSONObject object) throws JSONException {
return object.getBoolean("missingName");
}
public boolean getSuccess(JSONObject object) throws JSONException {
return object.getBoolean("success");
}
public void verifyResults(boolean success, boolean expected, JSONArray expectedBooks, boolean noEmptyChunks, boolean exactVerseCount) throws JSONException {
String results = mUsfm.getResultsString();
assertTrue("results text should not be empty", !results.isEmpty());
assertEquals("results", expected, success);
assertEquals("results", expected, mUsfm.isProcessSuccess());
String[] resultLines = results.split("\n");
int missingNamesCount = 0;
for(int i = 0; i < expectedBooks.length(); i++) {
JSONObject object = expectedBooks.getJSONObject(i);
String fileName = getFileName(object);
String book = getBook(object);
boolean expectedsuccess = getSuccess(object);
boolean missingName = getMissingName(object);
verifyBookResults(resultLines, fileName, book, expectedsuccess, noEmptyChunks, success, exactVerseCount);
if(missingName) {
findMissingName( fileName);
missingNamesCount++;
}
}
MissingNameItem[] missingNameItems = mUsfm.getBooksMissingNames();
assertEquals("Missing name count should equal", missingNamesCount, missingNameItems.length);
}
public void findMissingName(String filename) {
MissingNameItem[] missingNameItems = mUsfm.getBooksMissingNames();
boolean found = false;
for (MissingNameItem missingNameItem : missingNameItems) {
if(missingNameItem.description.indexOf(filename) >= 0) {
found = true;
break;
}
}
assertTrue(filename + " should be missing name ", found);
}
public void verifyBookResults(String[] results, String filename, String book, boolean noErrorsExpected, boolean noEmptyChunks, boolean success, boolean exactVerseCount) {
String bookLine = filename;
if(!book.isEmpty()) {
bookLine = book.toLowerCase() + " = " + filename;
}
String foundBookMarker = "Found book: ";
String expectLine = foundBookMarker + bookLine;
boolean bookFound = false;
for(int i = 0; i < results.length; i++) {
String line = results[i];
if(line.indexOf(expectLine) >= 0) {
boolean noErrorsFound = false;
for(int j = i + 1; j < results.length; j++) {
String resultsLine = results[j];
int pos = resultsLine.indexOf(foundBookMarker); // if starting next book, then done
if(pos >= 0) {
break;
}
pos = resultsLine.indexOf("No errors Found");
if(pos >= 0) {
noErrorsFound = true;
break;
}
}
assertEquals(bookLine + " found, no errors expected " + noErrorsExpected, noErrorsExpected, noErrorsFound);
bookFound = true;
break;
}
}
assertTrue(bookLine + " not found", bookFound);
String chunk = "";
// verify chapters and verses
if(success && !book.isEmpty()) {
SourceTranslation sourceTranslation = mLibrary.getSourceTranslation(book.toLowerCase(), "en", "ulb");
File[] projects = mUsfm.getImportProjects();
if(success) {
assertTrue("Import Projects count should be greater than zero, but is " + projects.length, projects.length > 0);
}
for (File project : projects) {
Chapter[] chapters = mLibrary.getChapters(sourceTranslation);
for (Chapter chapter : chapters) {
// verify chapter
File chapterPath = new File(project, chapter.getId());
assertTrue("Chapter missing " + chapterPath.toString(), chapterPath.exists());
// verify chunks
String[] chapterFrameSlugs = mLibrary.getFrameSlugs(sourceTranslation, chapter.getId());
for (int i = 0; i < chapterFrameSlugs.length; i++) {
String chapterFrameSlug = chapterFrameSlugs[i];
int expectCount = -1;
if(i + 1 < chapterFrameSlugs.length) {
String nextSlug = chapterFrameSlugs[i+1];
int nextStart = Integer.valueOf(nextSlug);
if(nextStart > 0) {
expectCount = nextStart - Integer.valueOf(chapterFrameSlug);
}
}
File chunkPath = new File(chapterPath, chapterFrameSlug + ".txt");
assertTrue("Chunk missing " + chunkPath.toString(), chunkPath.exists());
try {
chunk = FileUtils.readFileToString(chunkPath);
int count = getVerseCount(chunk);
if(noEmptyChunks) {
boolean emptyChunk = chunk.isEmpty();
assertTrue("Chunk is empty " + chunkPath.toString(),!emptyChunk);
assertTrue("VerseCount should not be zero: " + count + " in chunk " + chunkPath.toString(), count > 0);
if((expectCount >= 0) && exactVerseCount) {
assertEquals("Verse Count" + " in chunk " + chunkPath.toString(), expectCount, count);
}
}
} catch (IOException e) {
e.printStackTrace();
fail("Could not read chunk " + chunkPath.toString());
}
}
}
}
}
}
private static final Pattern PATTERN_USFM_VERSE_SPAN = Pattern.compile(USFMVerseSpan.PATTERN);
/**
* get verse count
*/
private int getVerseCount(String text) {
int foundVerseCount = 0;
Pattern pattern = PATTERN_USFM_VERSE_SPAN;
Matcher matcher = pattern.matcher(text);
int currentVerse = 0;
int endVerseRange = 0;
while (matcher.find()) {
String verse = matcher.group(1);
int[] verseRange = getVerseRange(verse);
if (null == verseRange) {
break;
}
currentVerse = verseRange[0];
endVerseRange = verseRange[1];
if (endVerseRange > 0) {
foundVerseCount += (endVerseRange - currentVerse + 1);
} else {
foundVerseCount++;
}
}
return foundVerseCount;
}
/**
* parse verse number to get range
* @param verse
* @return
*/
private int[] getVerseRange(String verse) {
int[] verseRange;
int currentVerse;
int endVerseRange;
try {
int currentVers = Integer.valueOf(verse);
verseRange = new int[] {currentVers, 0};
} catch (NumberFormatException e) { // might be a range in format 12-13
String[] range = verse.split("-");
if (range.length < 2) {
verseRange = null;
} else {
currentVerse = Integer.valueOf(range[0]);
endVerseRange = Integer.valueOf(range[1]);
verseRange = new int[]{currentVerse, endVerseRange};
}
}
return verseRange;
}
}