/*******************************************************************************
* Copyright (c) 2012, Directors of the Tyndale STEP Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* Neither the name of the Tyndale House, Cambridge (www.TyndaleHouse.com)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package com.tyndalehouse.step.core.service.jsword.impl;
import com.tyndalehouse.step.core.models.BookName;
import com.tyndalehouse.step.core.models.InterlinearMode;
import com.tyndalehouse.step.core.models.LookupOption;
import com.tyndalehouse.step.core.models.OsisWrapper;
import com.tyndalehouse.step.core.service.VocabularyService;
import com.tyndalehouse.step.core.utils.TestUtils;
import com.tyndalehouse.step.core.xsl.impl.ColorCoderProviderImpl;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookData;
import org.crosswire.jsword.book.BookException;
import org.crosswire.jsword.book.Books;
import org.crosswire.jsword.passage.*;
import org.crosswire.jsword.versification.BibleBook;
import org.crosswire.jsword.versification.Versification;
import org.crosswire.jsword.versification.system.Versifications;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
/**
* a service providing a wrapper around JSword
*
* @author CJBurrell
*/
public class JSwordPassageServiceImplTest {
private static final Logger LOGGER = LoggerFactory.getLogger(JSwordPassageServiceImplTest.class);
private JSwordPassageServiceImpl jsi;
/**
* Sets up the object under test
*/
@Before
public void setUp() {
this.jsi = new JSwordPassageServiceImpl(TestUtils.mockVersificationService(), null, mock(VocabularyService.class),
mock(ColorCoderProviderImpl.class), TestUtils.mockVersionResolver(), null);
}
/**
* tests that verse 0 gets excluded
*
* @throws NoSuchKeyException e
*/
@Test
public void testNormalize() throws NoSuchKeyException {
final Book book = Books.installed().getBook("KJV");
Key key = book.getKey("John 4");
assertTrue(key.get(0).getOsisID().equals("John.4.0"));
key = this.jsi.normalize(key, Versifications.instance().getVersification("KJV"));
assertEquals("Joh 4", key.getName());
}
/**
* Test for bug TYNSTEP-378
*/
@Test
public void testColorCoding() {
final List<LookupOption> options = new ArrayList<LookupOption>();
options.add(LookupOption.COLOUR_CODE);
final OsisWrapper osisText = this.jsi.getOsisText("KJV", "Gen.1.1", options, null,
InterlinearMode.NONE);
assertTrue(osisText.getValue().contains("In the beginning"));
}
/**
* Baseline for bug TYNSTEP-378, checking that in interlinear colour coding still works.
*/
@Test
public void testColorCodingInterlinear() {
final List<LookupOption> options = new ArrayList<LookupOption>();
options.add(LookupOption.COLOUR_CODE);
options.add(LookupOption.INTERLINEAR);
final OsisWrapper osisText = this.jsi.getOsisText("KJV", "Gen.1.1", options, "KJV",
InterlinearMode.INTERLINEAR);
assertTrue(osisText.getValue().contains("In the beginning"));
}
@Test
public void readRev12FromNrsvEsv() {
this.jsi.getOsisText("ESV-THE", "Rev.12.17-18");
}
/**
* should expand Ruth.1.22 to Ruth.1
*/
@Test
public void testExpandNoGap() {
final Key expandToFullChapter = this.jsi.expandToFullChapter("Ruth", "1", "22", Books.installed()
.getBook("KJV"),
new Verse(Versifications.instance().getVersification(Versifications.DEFAULT_V11N),
BibleBook.RUTH, 1, 22), 0);
LOGGER.debug(expandToFullChapter.getName());
}
/**
* tests what happens when we select interlinear
*
* @throws NoSuchKeyException uncaught exceptions
* @throws BookException uncaught exception
* @throws IOException uncaught exception
* @throws JDOMException uncaught exception
*/
@Test
public void testInterlinearTransformation() throws NoSuchKeyException, BookException, JDOMException,
IOException {
final Book currentBook = Books.installed().getBook("OSMHB");
final BookData bookData = new BookData(currentBook, currentBook.getKey("Ps.51"));
final Element osisFragment = bookData.getOsisFragment();
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
LOGGER.trace(xmlOutputter.outputString(osisFragment));
// do the test
final List<LookupOption> options = new ArrayList<LookupOption>();
// options.add(INTERLINEAR);
final String osisText = this.jsi.getOsisText("OSMHB", "Ps.51", options, "ESV-THE",
InterlinearMode.INTERLINEAR).getValue();
final SAXBuilder sb = new SAXBuilder();
final Document d = sb.build(new StringReader(osisText));
LOGGER.trace("\n {}", xmlOutputter.outputString(d));
Assert.assertTrue(osisText.contains("span class='interlinear'"));
}
/**
* tests that the XSLT transformation is handled correctly
*
* @throws BookException uncaught exception
* @throws NoSuchKeyException uncaught exception
* @throws IOException uncaught exception
* @throws JDOMException uncaught exception
*/
@Test
public void testXslTransformation() throws BookException, NoSuchKeyException, JDOMException, IOException {
final Book currentBook = Books.installed().getBook("KJV");
final BookData bookData = new BookData(currentBook, currentBook.getKey("Romans 1:4"));
final Element osisFragment = bookData.getOsisFragment();
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
LOGGER.trace(xmlOutputter.outputString(osisFragment));
// do the test
final List<LookupOption> options = new ArrayList<LookupOption>();
final String osisText = this.jsi.getOsisText("KJV", "Romans 1:4", options, "", InterlinearMode.NONE)
.getValue();
final SAXBuilder sb = new SAXBuilder();
final Document d = sb.build(new StringReader(osisText));
LOGGER.trace("\n {}", xmlOutputter.outputString(d));
Assert.assertTrue(osisText.contains("span"));
}
/**
* tests that the XSLT transformation is handled correctly
*
* @throws BookException uncaught exception
* @throws NoSuchKeyException uncaught exception
* @throws IOException uncaught exception
* @throws JDOMException uncaught exception
*/
@Test
public void testComparing() throws BookException, NoSuchKeyException, JDOMException, IOException {
final Book currentBook = Books.installed().getBook("ESV-THE");
final Book secondaryBook = Books.installed().getBook("KJV");
final String reference = "Psalm.3";
final BookData bookData = new BookData(new Book[]{currentBook, secondaryBook},
currentBook.getKey(reference), true);
final Element osisFragment = bookData.getOsisFragment();
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
LOGGER.info(xmlOutputter.outputString(osisFragment));
// do the test
final List<LookupOption> options = new ArrayList<LookupOption>();
final String osisText = this.jsi.getInterleavedVersions(
new String[]{currentBook.getInitials(), secondaryBook.getInitials()}, reference, options,
InterlinearMode.INTERLEAVED_COMPARE).getValue();
final SAXBuilder sb = new SAXBuilder();
final Document d = sb.build(new StringReader(osisText));
LOGGER.info("\n {}", xmlOutputter.outputString(d));
Assert.assertTrue(osisText.contains("span"));
}
/**
* Tests the resolving of passage references
*/
@Test
public void testSingleReference() {
final String allRefs = this.jsi.getAllReferences("Gen.1", "ESV-THE");
assertTrue(allRefs.contains("Gen.1.1"));
assertTrue(allRefs.contains("Gen.1.2"));
}
/**
* Tests that getting a bible book returns the correct set of names
*/
@Test
public void testGetBibleBooks() {
final JSwordMetadataServiceImpl jsi = new JSwordMetadataServiceImpl(
TestUtils.mockVersificationService(), null);
final List<BookName> bibleBookNames = jsi.getBibleBookNames("Ma", "ESV-THE", null);
final String[] containedAbbrevations = new String[]{"Mal", "Mat", "Mar"};
for (final String s : containedAbbrevations) {
boolean found = false;
for (final BookName b : bibleBookNames) {
if (s.equalsIgnoreCase(b.getShortName())) {
found = true;
break;
}
}
if (!found) {
fail(s + " was not found");
}
}
}
/**
* Testing that reference gets bumped up and down
*/
@Test
public void testGetSiblingChapter() {
org.crosswire.jsword.versification.BookName.setFullBookName(false);
// previous chapter tests
assertEquals("Gen 1", this.jsi.getSiblingChapter("Genesis 2", "ESV-THE", true).getName());
assertEquals("Gen 1", this.jsi.getSiblingChapter("Genesis 2:5", "ESV-THE", true).getName());
assertEquals("Gen 1", this.jsi.getSiblingChapter("Genesis 2-3:17", "ESV-THE", true).getName());
assertEquals("Gen 1", this.jsi.getSiblingChapter("Genesis 2:3-3:17", "ESV-THE", true).getName());
// next chapter tests
assertEquals("Gen 4", this.jsi.getSiblingChapter("Genesis 2-3:17", "ESV-THE", false).getName());
assertEquals("Gen 4", this.jsi.getSiblingChapter("Genesis 2-3:24", "ESV-THE", false).getName());
assertEquals("Gen 4", this.jsi.getSiblingChapter("Genesis 3:17", "ESV-THE", false).getName());
assertEquals("Gen 4", this.jsi.getSiblingChapter("Genesis 3:24", "ESV-THE", false).getName());
assertEquals("Gen 3", this.jsi.getSiblingChapter("Genesis 2", "ESV-THE", false).getName());
assertEquals("Mal 4", this.jsi.getSiblingChapter("Mat 1", "ESV-THE", true).getName());
assertEquals("Mat 1", this.jsi.getSiblingChapter("Mal 4", "ESV-THE", false).getName());
assertEquals("Mar 16", this.jsi.getSiblingChapter("Luke 1", "ESV-THE", true).getName());
assertEquals("Luk 1", this.jsi.getSiblingChapter("Mark 16", "ESV-THE", false).getName());
assertEquals("Gen 1", this.jsi.getSiblingChapter("Genesis 1:2", "ESV-THE", true).getName());
assertEquals("Rev 22", this.jsi.getSiblingChapter("Revelation 22:5", "ESV-THE", false).getName());
}
/**
* testing variations of getting the previous reference
*
* @throws NoSuchKeyException uncaught exception
*/
@Test
public void testGetPreviousRef() throws NoSuchKeyException {
final Book book = Books.installed().getBook("KJV");
final Key key = book.getKey("Genesis 3:17");
assertEquals("Gen.3", this.jsi.getPreviousRef(new String[]{"Gen", "3", "17"}, key, book)
.getOsisRef());
assertEquals("Gen.2", this.jsi.getPreviousRef(new String[]{"Gen", "3", "1"}, key, book)
.getOsisRef());
assertEquals("Gen.2", this.jsi.getPreviousRef(new String[]{"Gen", "3"}, key, book).getOsisRef());
}
/**
* testing variations of getting the previous reference
*
* @throws NoSuchKeyException uncaught exception
*/
@Test
public void testGetNextRef() throws NoSuchKeyException {
final Book book = Books.installed().getBook("KJV");
final Key key = book.getKey("Genesis 3:24");
assertEquals("Gen.4", this.jsi.getNextRef(new String[]{"Gen", "3", "24"}, key, book).getOsisRef());
assertEquals("Gen.4", this.jsi.getNextRef(new String[]{"Gen", "3"}, key, book).getOsisRef());
}
/**
* Justs shows XML on the stdout
*
* @throws BookException an exceptioon
* @throws NoSuchKeyException an exception
* @throws IOException an exception
* @throws JDOMException an exception
*/
@Test
public void testInterleave() throws BookException, NoSuchKeyException, JDOMException, IOException {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
final String ref = "John 4:1";
// do the test
final String[] versions = new String[]{"Byz", "Tisch"};
final BookData data = new BookData(new Book[]{Books.installed().getBook(versions[0]),
Books.installed().getBook(versions[1])}, Books.installed().getBook(versions[0]).getKey(ref),
true);
LOGGER.debug("Original is:\n {}", xmlOutputter.outputString(data.getOsisFragment()));
final OsisWrapper interleavedVersions = this.jsi.getInterleavedVersions(versions, ref,
new ArrayList<LookupOption>(), InterlinearMode.COLUMN_COMPARE);
final SAXBuilder sb = new SAXBuilder();
final Document d = sb.build(new StringReader(interleavedVersions.getValue()));
LOGGER.debug("\n {}", xmlOutputter.outputString(d));
}
/**
* Justs shows XML on the stdout
*
* @throws BookException an exceptioon
* @throws NoSuchKeyException an exception
* @throws IOException an exception
* @throws JDOMException an exception
*/
@Test
public void testSegVariants() throws BookException, NoSuchKeyException, JDOMException, IOException {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
final String ref = "Mat.9.4";
final String version = "WHNU";
final Book book = Books.installed().getBook(version);
// do the test
final BookData data = new BookData(book, book.getKey(ref));
LOGGER.info("Original is:\n {}", xmlOutputter.outputString(data.getOsisFragment()));
final OsisWrapper interleavedVersions = this.jsi.getOsisText(version, ref);
final SAXBuilder sb = new SAXBuilder();
final Document d = sb.build(new StringReader(interleavedVersions.getValue()));
final String outputString = xmlOutputter.outputString(d);
LOGGER.info(outputString);
assertTrue(outputString.contains("ειδως"));
assertTrue(outputString.contains("title=\"ιδων"));
}
/**
* Justs shows XML on the stdout
*
* @throws BookException an exceptioon
* @throws NoSuchKeyException an exception
* @throws IOException an exception
* @throws JDOMException an exception
*/
@Test
public void testLongHeaders() throws BookException, NoSuchKeyException, JDOMException, IOException {
final String version = "ESV-THE";
final String ref = "Luk 4:27";
// set up the static JSword field
org.crosswire.jsword.versification.BookName.setFullBookName(false);
// do the test
final String osisText = this.jsi.getOsisText(version, ref, new ArrayList<LookupOption>(), null,
InterlinearMode.NONE).getValue();
if (LOGGER.isDebugEnabled()) {
final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
final SAXBuilder sb = new SAXBuilder();
final Document d = sb.build(new StringReader(osisText));
LOGGER.debug("\n {}", xmlOutputter.outputString(d));
}
Assert.assertTrue(osisText.contains("Luke 4:27"));
}
/**
* Tests a lookup by number
*/
@Test
public void testNumberLookup() {
assertTrue(this.jsi
.getOsisTextByVerseNumbers("ASV", "ESV-THE", 4, 4, new ArrayList<LookupOption>(), null, null,
false).getValue().contains("In the beginning"));
assertTrue(this.jsi
.getOsisTextByVerseNumbers("ASV", "ESV-THE", 60000, 60000, new ArrayList<LookupOption>(), null,
null, false).getValue().contains("The grace of the Lord Jesus"));
assertTrue(this.jsi
.getOsisTextByVerseNumbers("FreSegond", "ESV-THE", 60000, 60000, new ArrayList<LookupOption>(),
null, null, false).getValue()
.contains("Que la gr\u00e2ce du Seigneur J\u00e9sus soit avec tous!"));
}
/**
* tries to replicate the issue with bookdata not being able to be read in a concurrent fashion
*
* @throws NoSuchKeyException a no such key exception
* @throws BookException a book exception
* @throws InterruptedException when the thread is interrupted
*/
@Test
public void testConcurrencyIssueOnBookData() throws NoSuchKeyException, BookException,
InterruptedException {
final String[] names = {"KJV", "ESV-THE"};
final String ref = "Rom.1.1";
final Runnable r1 = new Runnable() {
@Override
public void run() {
final Book b0 = Books.installed().getBook(names[0]);
BookData bd1;
try {
bd1 = new BookData(b0, b0.getKey(ref));
bd1.getSAXEventProvider();
} catch (final NoSuchKeyException e) {
LOGGER.error("A jsword error during test", e);
Assert.fail("JSword bug has occured");
} catch (final BookException e) {
LOGGER.error("A jsword error during test", e);
Assert.fail("JSword bug has occured");
}
}
};
final Runnable r2 = new Runnable() {
@Override
public void run() {
final Book b0 = Books.installed().getBook(names[1]);
BookData bd1;
try {
bd1 = new BookData(b0, b0.getKey(ref));
bd1.getSAXEventProvider();
} catch (final NoSuchKeyException e) {
LOGGER.error("A jsword error during test", e);
Assert.fail("JSword bug has occured");
} catch (final BookException e) {
LOGGER.error("A jsword error during test", e);
Assert.fail("JSword bug has occured");
}
}
};
int ii = 0;
while (ii++ < 20) {
final Thread t1 = new Thread(r1);
final Thread t2 = new Thread(r2);
t1.start();
t2.start();
t1.join();
t2.join();
}
}
/**
* Tests that we don't allow large passages to be returned...
*/
@Test
public void testPassageShrinking() {
assertEquals("Gen.1", this.jsi.getBookData("ESV-THE", "Gen 1").getKey().getOsisRef());
assertEquals("Gen.1", this.jsi.getBookData("ESV-THE", "Gen").getKey().getOsisRef());
assertEquals("Gen.1", this.jsi.getBookData("ESV-THE", "Gen 1-50").getKey().getOsisRef());
assertEquals("Gen.1", this.jsi.getBookData("ESV-THE", "Gen 1-12").getKey().getOsisRef());
assertEquals("Gen.1", this.jsi.getBookData("ESV-THE", " Gen").getKey().getOsisRef());
assertEquals("Gen.1", this.jsi.getBookData("ESV-THE", "Gen ").getKey().getOsisRef());
}
/**
* Gets the gets the interlinear versions.
*/
@Test
public void testGetInterlinearVersions() {
assertEquals("ESV-THE", this.jsi.getInterlinearVersion("ESV-THE"));
assertEquals("ESV-THE,KJV", this.jsi.getInterlinearVersion("ESV-THE,KJV"));
assertEquals("ESV-THE,KJV", this.jsi.getInterlinearVersion("ESV-THE,,KJV"));
assertEquals("ESV-THE,KJV", this.jsi.getInterlinearVersion("ESV-THE,,,KJV"));
assertEquals("ESV-THE,KJV", this.jsi.getInterlinearVersion("ESV-THE,,,,KJV"));
assertEquals("ESV-THE,KJV", this.jsi.getInterlinearVersion("ESV-THE,KJV,"));
assertEquals("ESV-THE,KJV", this.jsi.getInterlinearVersion(",ESV-THE,KJV"));
assertEquals("ESV-THE", this.jsi.getInterlinearVersion(",ESV-THE,"));
assertEquals("ESV-THE", this.jsi.getInterlinearVersion(",,ESV-THE,,"));
assertEquals("ESV-THE,KJV,AV", this.jsi.getInterlinearVersion(",,ESV-THE,,KJV,,,AV"));
}
/**
* Reducing the key size to something appropriate for the UI and acceptable for copyright holders.
*
* @throws NoSuchKeyException the no such key exception
*/
@Test
public void testReduceKeySize() throws NoSuchKeyException {
final Versification v = Versifications.instance().getVersification("KJV");
final Book b = Books.installed().getBook("ESV-THE");
assertEquals("Gen.2", reduceKeySize(v, b, "Gen.2-Rev.1").getOsisRef());
assertEquals("Gen.2", reduceKeySize(v, b, "Gen.2").getOsisRef());
assertEquals("Gen.0", reduceKeySize(v, b, "Gen.0").getOsisRef());
assertEquals("Gen.0", reduceKeySize(v, b, "Gen.0").getOsisRef());
assertEquals("Gen.1.1", reduceKeySize(v, b, "Gen.1.1").getOsisRef());
assertEquals("Judg.1", reduceKeySize(v, b, "Judg").getOsisRef());
assertEquals("Jude", reduceKeySize(v, b, "Jude").getOsisRef());
assertEquals("Ruth.1", reduceKeySize(v, b, "Rut").getOsisRef());
}
/**
* Reduce key size.
*
* @param v the versification
* @param b the book
* @param keyString the key string
* @return the key
* @throws NoSuchKeyException the no such key exception
*/
private Key reduceKeySize(final Versification v, final Book b, final String keyString)
throws NoSuchKeyException {
return this.jsi.reduceKeySize(b.getKey(keyString), v);
}
}