/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.topicmaps.xml;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import org.xml.sax.SAXParseException;
import net.ontopia.utils.OntopiaRuntimeException;
import net.ontopia.infoset.core.LocatorIF;
import net.ontopia.infoset.impl.basic.URILocator;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.core.TopicMapImporterIF;
import net.ontopia.topicmaps.core.TopicNameIF;
import net.ontopia.topicmaps.core.VariantNameIF;
import net.ontopia.topicmaps.impl.basic.InMemoryTopicMapStore;
import net.ontopia.topicmaps.utils.PSI;
import net.ontopia.utils.TestFileUtils;
import net.ontopia.utils.URIUtils;
import org.junit.Assert;
import org.junit.Test;
public class XTMReaderTest extends AbstractXMLTestCase {
private final static String testdataDirectory = "canonical";
public void setUp() {
}
// --- Utilities
protected TopicMapIF readTopicMap(String filename) throws IOException {
filename = TestFileUtils.getTestInputFile(testdataDirectory, "in", filename);
XTMTopicMapReader reader = new XTMTopicMapReader(URIUtils.getURI(filename));
reader.setValidation(false);
TopicMapIF tm = reader.read();
Assert.assertTrue(
"attempting to read second (non-existent) topic map did not give null",
reader.read() == null);
return tm;
}
// NOTE: this one validates!
protected TopicMapIF readTopicMap(String dir, String filename)
throws IOException {
filename = TestFileUtils.getTestInputFile(dir, filename);
return new XTMTopicMapReader(URIUtils.getURI(filename)).read();
}
protected TopicMapIF readTopicMap(String dir, String subdir, String filename)
throws IOException {
filename = TestFileUtils.getTestInputFile(dir, subdir, filename);
return new XTMTopicMapReader(URIUtils.getURI(filename)).read();
}
protected Collection readTopicMaps(String filename) throws IOException {
filename = TestFileUtils.getTestInputFile(testdataDirectory, "in", filename);
XTMTopicMapReader reader = new XTMTopicMapReader(URIUtils.getURI(filename));
reader.setValidation(false);
return reader.readAll();
}
protected URILocator makeLocator(String uri) {
try {
return new URILocator(uri);
} catch (java.net.MalformedURLException e) {
System.err.println("(INTERNAL) " + e);
return null;
}
}
// --- Test cases
@Test
public void testNothing() throws IOException {
try {
readTopicMap("various", "nothing.xtm");
Assert.fail("reading XML document with no topic map did not throw exception");
} catch (InvalidTopicMapException e) {
} catch (net.ontopia.utils.OntopiaRuntimeException e) {
if (!(e.getCause() instanceof org.xml.sax.SAXParseException))
throw e;
}
}
@Test
public void testEmptyTopicMap() throws IOException {
TopicMapIF tm = readTopicMap("empty.xtm");
Assert.assertTrue("empty topic map not empty after import",
tm.getTopics().size() == 0 && tm.getAssociations().size() == 0);
Assert.assertTrue("topic map has no base address",
tm.getStore().getBaseAddress() != null);
}
@Test
public void testMultipleTopicMaps() throws IOException {
Collection tms = readTopicMaps("multiple-tms-read.xtm");
Assert.assertTrue("reader doesn't recognize correct number of topic maps", tms
.size() == 2);
Iterator iter = tms.iterator();
while (iter.hasNext()) {
TopicMapIF tm = (TopicMapIF) iter.next();
Assert.assertTrue("topic map has't got exactly two topics"
+ tm.getItemIdentifiers(), tm.getTopics().size() == 2);
}
}
@Test
public void testImportTopicMaps() throws IOException {
// Create empty store
InMemoryTopicMapStore store = new InMemoryTopicMapStore();
TopicMapIF tm = store.getTopicMap();
// Import first XTM file
String file1 = TestFileUtils.getTestInputFile(testdataDirectory, "in",
"latin1.xtm");
TopicMapImporterIF importer1 = new XTMTopicMapReader(URIUtils.getURI(file1));
importer1.importInto(tm);
// Import second XTM file
String file2 = TestFileUtils.getTestInputFile(testdataDirectory, "in",
"mergeloop.xtm");
TopicMapImporterIF importer2 = new XTMTopicMapReader(URIUtils.getURI(file2));
importer2.importInto(tm);
// Check the result
Assert.assertTrue("topic map has't got exactly four topics: "
+ tm.getTopics().size(), tm.getTopics().size() == 4);
}
@Test
public void testTopicName() throws IOException {
TopicMapIF tm = readTopicMap("basename.xtm");
Assert.assertTrue("wrong number of topics after import",
tm.getTopics().size() == 6);
Assert.assertTrue("spurious topic map constructs found", tm.getAssociations()
.size() == 0);
TopicIF topic = getTopicById(tm, "country");
verifySingleTopicName(topic, "Country");
}
@Test
public void testVariants() throws IOException {
TopicMapIF tm = readTopicMap("variants.xtm");
Assert.assertTrue("wrong number of topics after import",
tm.getTopics().size() == 3);
Assert.assertTrue("spurious topic map constructs found", tm.getAssociations()
.size() == 0);
TopicIF country = getTopicById(tm, "country");
TopicIF norwegian = getTopicById(tm, "norwegian");
Assert.assertTrue("topic has spurious children", country.getTypes().size() == 0
&& country.getRoles().size() == 0
&& country.getOccurrences().size() == 0);
Assert.assertTrue("topic has wrong number of base names", country.getTopicNames()
.size() == 1);
TopicNameIF basename = (TopicNameIF) country.getTopicNames().iterator()
.next();
Assert.assertTrue("wrong basename value: '" + basename.getValue() + "'", basename
.getValue().equals("Country"));
Assert.assertTrue("wrong number of variant children", basename.getVariants()
.size() == 1);
VariantNameIF variant = (VariantNameIF) basename.getVariants().iterator()
.next();
Assert.assertTrue("wrong variant value: '" + variant.getValue() + "'", variant
.getValue().equals("Land"));
Assert.assertTrue("wrong scope of variant", variant.getScope().size() == 1
&& variant.getScope().iterator().next().equals(norwegian));
}
@Test
public void testOccurrences() throws IOException {
TopicMapIF tm = readTopicMap("occurrences.xtm");
Assert.assertTrue("wrong number of topics after import",
tm.getTopics().size() == 5);
Assert.assertTrue("spurious topic map constructs found", tm.getAssociations()
.size() == 0);
TopicIF norway = getTopicById(tm, "norway");
TopicIF homepage = getTopicById(tm, "homepage");
verifySingleTopicName(homepage, "Home page");
TopicIF tourism = getTopicById(tm, "tourism");
verifySingleTopicName(tourism, "Tourism");
Assert.assertTrue("topic has spurious children", norway.getTypes().size() == 0
&& norway.getRoles().size() == 0 && norway.getTopicNames().size() == 1);
Assert.assertTrue("topic has wrong number of occurrences", norway.getOccurrences()
.size() == 4);
Iterator it = norway.getOccurrences().iterator();
LocatorIF norge = makeLocator("http://www.norge.no");
LocatorIF norwaycom = makeLocator("http://www.norway.com");
LocatorIF visit = makeLocator("http://www.visitnorway.com");
while (it.hasNext()) {
OccurrenceIF occ = (OccurrenceIF) it.next();
if (occ.getLocator() == null) {
Assert.assertTrue("occurrence " + occ + " has spurious themes", occ.getScope()
.size() == 0);
Assert.assertTrue("occurrence has invalid resource data", occ.getValue()
.equals("Norway is a nice country."));
} else if (occ.getLocator().equals(norge)) {
Assert.assertTrue("occurrence " + occ + " has spurious themes", occ.getScope()
.size() == 0);
Assert.assertTrue("occurrence " + occ + " has wrong type", occ.getType()
.equals(homepage));
} else if (occ.getLocator().equals(norwaycom)) {
Assert.assertTrue("occurrence " + occ + " has spurious themes", occ.getScope()
.size() == 0);
Assert.assertTrue("occurrence " + occ + " has spurious type", occ.getType()
.getSubjectIdentifiers().contains(PSI.getXTMOccurrence()));
} else if (occ.getLocator().equals(visit)) {
Assert.assertTrue("occurrence " + occ + " has wrong number of themes", occ
.getScope().size() == 1);
Assert.assertTrue("occurrence " + occ + " has wrong theme", occ.getScope()
.iterator().next().equals(tourism));
Assert.assertTrue("occurrence " + occ + " has spurious type", occ.getType()
.getSubjectIdentifiers().contains(PSI.getXTMOccurrence()));
} else
Assert.fail("spurious occurrence: " + occ);
}
}
@Test
public void testTopicNameScope() throws IOException {
TopicMapIF tm = readTopicMap("basename-scope.xtm");
Assert.assertTrue("wrong number of topics after import",
tm.getTopics().size() == 4);
Assert.assertTrue("spurious topic map constructs found", tm.getAssociations()
.size() == 0);
TopicIF norway = getTopicById(tm, "norway");
TopicIF foo = getTopicById(tm, "foo");
TopicIF bar = getTopicById(tm, "bar");
verifySingleTopicName(foo, "Foo");
verifySingleTopicName(bar, "Bar");
Assert.assertTrue("topic has spurious children", norway.getTypes().size() == 0
&& norway.getRoles().size() == 0 && norway.getOccurrences().size() == 0);
TopicNameIF basename = (TopicNameIF) norway.getTopicNames().iterator()
.next();
Assert.assertTrue("wrong basename value: '" + basename.getValue() + "'", basename
.getValue().equals("Norway"));
Assert.assertTrue("wrong scope on basename", basename.getScope().size() == 2
&& basename.getScope().contains(foo)
&& basename.getScope().contains(bar));
}
// this is a regression test for bug #457
// see http://www.y12.doe.gov/sgml/sc34/document/0299.htm#merge-prop-srclocs
@Test
public void testTopicMapReification() throws IOException {
TopicMapIF tm = readTopicMap(testdataDirectory, "extra",
"master-of-reified-tm.xtm");
Assert.assertTrue("topic map has been incorrectly merged with child topic map", tm
.getReifier() == null);
}
@Test
public void testXMLBaseAndBaseLocator() throws IOException {
TopicMapIF tm = readTopicMap(testdataDirectory, "extra",
"tm-xmlbase.xtm");
LocatorIF base = tm.getStore().getBaseAddress();
Assert.assertTrue("topicmap.getBaseLocator() should not be set to xml:base", base
.getAddress().startsWith("file:"));
}
// tests for bug #523
@Test
public void testEntity() throws IOException {
TopicMapIF tm = readTopicMap(testdataDirectory, "extra",
"entities.xtm");
Collection<TopicIF> topics = tm.getTopics();
for (TopicIF topic : topics) {
Collection<TopicNameIF> names = topic.getTopicNames();
if (names != null && names.size() > 0) {
LocatorIF subjind = (LocatorIF) topic.getSubjectIdentifiers()
.iterator().next();
Assert.assertTrue("base URI not updated for entities (" + subjind + ")",
subjind.getAddress().endsWith(".ent"));
}
}
}
// --- Validation tests
@Test
public void testValidTM() throws IOException {
readTopicMap("various", "jill.xtm");
}
@Test
public void testInvalidTM() throws IOException {
try {
readTopicMap(testdataDirectory, "errors", "badxtm.xtm");
Assert.fail("Invalid topic map was allowed to load");
} catch (OntopiaRuntimeException e) {
Assert.assertTrue("Error not from XTM validation: " + e.getCause(),
e.getCause() instanceof SAXParseException);
}
}
@Test
public void testXTMValidIfDTDRead() throws IOException {
// motivated by bug #864
readTopicMap("various", "valid-if-dtd-read.xtm");
}
@Test
public void testXTMValidIfDTDReadButDTDRefBad() throws IOException {
// motivated by bug #864
try {
readTopicMap("various", "valid-but-bad-dtdref.xtm");
Assert.fail("Invalid topic map was allowed to load"); // well, ok, it *is* valid,
// but
// we can't know that
} catch (OntopiaRuntimeException e) {
Assert.assertTrue("Error not from XTM validation: " + e.getCause(),
e.getCause() instanceof SAXParseException);
}
}
@Test
public void testErrorLocationReporting1() throws IOException {
// verifies that the XTM 1.0 reader actually reports where in the file
// invalidity errors occur
try {
readTopicMap("various", "invalid1.xtm");
Assert.fail("No error detected in invalid file!");
} catch (OntopiaRuntimeException e) {
if (e.getCause() instanceof SAXParseException) {
SAXParseException ex = (SAXParseException) e.getCause();
Assert.assertTrue("wrong error file: " + ex.getSystemId(), ex.getSystemId()
.endsWith("invalid1.xtm"));
Assert.assertTrue("wrong error line: " + ex.getLineNumber(), ex
.getLineNumber() == 7);
} else
Assert.fail("Unknown cause of error: " + e);
}
}
@Test
public void testErrorLocationReporting2() throws IOException {
// verifies that the XTM 2.0 reader actually reports where in the file
// invalidity errors occur
try {
readTopicMap("various", "invalid2.xtm");
Assert.fail("No error detected in invalid file!");
} catch (OntopiaRuntimeException e) {
if (e.getCause() instanceof SAXParseException) {
SAXParseException ex = (SAXParseException) e.getCause();
Assert.assertTrue("wrong error file: " + ex.getSystemId(), ex.getSystemId()
.endsWith("invalid2.xtm"));
Assert.assertTrue("wrong error line: " + ex.getLineNumber(), ex
.getLineNumber() == 2);
} else
Assert.fail("Unknown cause of error: " + e);
}
}
@Test
public void testReificationMergeBug() throws IOException {
// tests a tricky case where topics are merged because of reification,
// and this causes the current topic to become a merged-away stub, thus
// leading to failures down the line.
// first read one topic map
TopicMapIF tm = readTopicMap("various", "reification-bug-1.xtm");
// then import the second one into it
String file = TestFileUtils.getTestInputFile("various", "reification-bug-2.xtm");
XTMTopicMapReader reader = new XTMTopicMapReader(URIUtils.getURI(file));
reader.importInto(tm); // this should not crash!
// do some testing verifying that the XTM was interpreted correctly
Assert.assertTrue("wrong number of topics", tm.getTopics().size() == 2);
Assert.assertTrue("topic map is reified", tm.getReifier() != null);
TopicIF reifier = getTopicById(tm, "reifier");
Assert.assertTrue("topic has no name", !reifier.getTopicNames().isEmpty());
}
// --- Supporting methods
private void verifySingleTopicName(TopicIF topic, String name) {
Assert.assertTrue("topic has spurious children", topic.getTypes().size() == 0
&& topic.getRoles().size() == 0 && topic.getOccurrences().size() == 0);
Assert.assertTrue("topic has wrong number of base names", topic.getTopicNames()
.size() == 1);
TopicNameIF basename = (TopicNameIF) topic.getTopicNames().iterator()
.next();
Assert.assertTrue("wrong basename value: '" + basename.getValue() + "'", basename
.getValue().equals(name));
Assert.assertTrue("basename has spurious children",
basename.getVariants().size() == 0);
Assert.assertTrue("basename has spurious themes", basename.getScope().size() == 0);
}
}