NIHVIVO-3628 Create unit tests to cover the parsing and interpreting of custom list view config files.

This commit is contained in:
j2blake 2012-02-21 17:06:55 +00:00
parent 3ceff9e0a5
commit b53f26a375
26 changed files with 1282 additions and 20 deletions

View file

@ -97,6 +97,24 @@ public abstract class AbstractTestClass {
Logger.getLogger(category).setLevel(level); Logger.getLogger(category).setLevel(level);
} }
/**
* Capture the log for this class to this Writer. Choose whether or not to
* suppress it from the console.
*/
protected void captureLogOutput(Class<?> clazz, Writer writer,
boolean suppress) {
PatternLayout layout = new PatternLayout("%p %m%n");
ConsoleAppender appender = new ConsoleAppender();
appender.setWriter(writer);
appender.setLayout(layout);
Logger logger = Logger.getLogger(clazz);
logger.removeAllAppenders();
logger.setAdditivity(!suppress);
logger.addAppender(appender);
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Control standard output or error output. // Control standard output or error output.
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------

View file

@ -0,0 +1,683 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Level;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import stubs.edu.cornell.mannlib.vitro.webapp.dao.ObjectPropertyDaoStub;
import stubs.edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryStub;
import stubs.freemarker.cache.TemplateLoaderStub;
import stubs.javax.servlet.ServletContextStub;
import stubs.javax.servlet.http.HttpServletRequestStub;
import stubs.javax.servlet.http.HttpSessionStub;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel.InvalidConfigurationException;
import freemarker.template.Configuration;
public class ObjectPropertyTemplateModel_PropertyListConfigTest extends
AbstractTestClass {
private static File configDir;
private ObjectPropertyTemplateModel optm;
private ObjectProperty op;
private WebappDaoFactoryStub wadf;
private ObjectPropertyDaoStub opDao;
private ServletContextStub ctx;
private HttpSessionStub session;
private HttpServletRequestStub hreq;
private VitroRequest vreq;
private IndividualImpl subject;
private TemplateLoaderStub tl;
private StringWriter logMessages;
/**
* In general, we expect no exception, but individual tests may override,
* like this:
*
* <pre>
* thrown.expect(InvalidConfigurationException.class);
* thrown.expectMessage(&quot;Bozo&quot;);
* </pre>
*/
@Rule
public ExpectedException thrown = ExpectedException.none();
@BeforeClass
public static void createConfigFiles() throws IOException {
configDir = createTempDirectory("configDir");
createConfigFile("constructQueryMissing");
createConfigFile("constructQueryMultiple");
createConfigFile("default");
createConfigFile("notValidXml");
createConfigFile("postProcessorClassNotFound");
createConfigFile("postProcessorClassNotSuitable");
createConfigFile("postProcessorConstructorThrowsException");
createConfigFile("postProcessorNameEmpty");
createConfigFile("postProcessorOK");
createConfigFile("postProcessorWrongConstructor");
createConfigFile("selectQueryNodeBlank");
createConfigFile("selectQueryNodeNotFound");
createConfigFile("selectQuerySubNodes");
createConfigFile("selectQueryNoSubNodes");
createConfigFile("selectQueryCollatedValid");
createConfigFile("selectQueryCollatedNoSelect");
createConfigFile("selectQueryCollatedNoOrder");
createConfigFile("templateNodeIsEmpty");
createConfigFile("templateNodeNotFound");
createConfigFile("templateDoesNotExist");
}
/** Copy a file from the classpath into the temporary config directory. */
private static void createConfigFile(String shortName) throws IOException {
String fullName = "testConfig-" + shortName + ".xml";
Class<?> clazz = ObjectPropertyTemplateModel_PropertyListConfigTest.class;
String contents = readAll(clazz.getResourceAsStream(fullName));
createFile(configDir, fullName, contents);
}
@Before
public void setup() {
logMessages = new StringWriter();
opDao = new ObjectPropertyDaoStub();
wadf = new WebappDaoFactoryStub();
wadf.setObjectPropertyDao(opDao);
ctx = new ServletContextStub();
// create paths for all of the files in the temporary config directory.
ctx.setRealPaths("/config", configDir);
// add a path to match the hard-coded default path.
ctx.setRealPath("/config/listViewConfig-default.xml",
ctx.getRealPath("/config/testConfig-default.xml"));
session = new HttpSessionStub();
session.setServletContext(ctx);
hreq = new HttpServletRequestStub();
hreq.setSession(session);
vreq = new VitroRequest(hreq);
vreq.setWebappDaoFactory(wadf);
subject = new IndividualImpl();
BaseTemplateModel.setServletContext(ctx);
Configuration fmConfig = new Configuration();
vreq.setAttribute("freemarkerConfig", fmConfig);
tl = new TemplateLoaderStub();
tl.createTemplate("propStatement-default.ftl", "");
fmConfig.setTemplateLoader(tl);
}
@AfterClass
public static void cleanup() {
if (configDir != null) {
purgeDirectoryRecursively(configDir);
}
}
// TODO - don't swallow the exception if we can't create a config.
// TODO - baseTemplateModel shouldn't require the servlet context to be set
// statically!!! ServletContext shouldn't be a static field.
// ----------------------------------------------------------------------
// The tests
// ----------------------------------------------------------------------
//
// Null arguments
//
@Test(expected = NullPointerException.class)
public void operationIsNull() throws InvalidConfigurationException {
// TODO This should throw a more predictable NullPointerException
optm = new NonCollatingOPTM(null, subject, vreq, false);
}
@Test(expected = NullPointerException.class)
public void subjectIsNull() throws InvalidConfigurationException {
// TODO This should throw a more predictable NullPointerException
op = buildOperation("default");
optm = new NonCollatingOPTM(op, null, vreq, false);
}
@Test(expected = NullPointerException.class)
public void requestIsNull() throws InvalidConfigurationException {
// TODO This should throw a more predictable NullPointerException
op = buildOperation("default");
optm = new NonCollatingOPTM(op, subject, null, false);
}
//
// Locating the file.
//
@Test
public void configFileNotSpecified() throws InvalidConfigurationException {
op = buildOperation("default");
opDao.setCustomListViewConfigFileName(op, null);
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertEquals("uses default config", true, optm.hasDefaultListView());
}
// @Ignore
@Test
public void configFilePathCantBeTranslated()
throws InvalidConfigurationException {
// TODO if we can't translate the path, log the error and use the
// default.
captureLogsFromOPTM();
op = buildOperation("fileHasNoRealPath");
optm = new NonCollatingOPTM(op, subject, vreq, false);
// Throws an exception because we don't test for a null path from the
// ServletContext.
assertLogMessagesContains("no real path", "at java.io.File.<init>");
}
@Test
public void configFileNotFound() throws InvalidConfigurationException {
captureLogsFromOPTM();
op = buildOperation("configFileDoesNotExist");
// There should be a real path, but no file at that location.
String bogusFilepath = new File(configDir, "doesNotExist")
.getAbsolutePath();
String path = "/config/" + opDao.getCustomListViewConfigFileName(op);
ctx.setRealPath(path, bogusFilepath);
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("file not found", "Can't find config file");
}
@Test
public void configFileNotValidXml() throws InvalidConfigurationException {
suppressSyserr();
captureLogsFromOPTM();
op = buildOperation("notValidXml");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("not valid XML", "SAXParseException");
}
//
// Problems with the <query-select> node
//
@Test
public void selectQueryNodeIsNotFound()
throws InvalidConfigurationException {
captureLogsFromOPTM();
op = buildOperation("selectQueryNodeNotFound");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("no select query",
"Missing select query specification");
}
@Test
public void selectQueryNodeIsBlank() throws InvalidConfigurationException {
captureLogsFromOPTM();
op = buildOperation("selectQueryNodeBlank");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("blank select query",
"Missing select query specification");
}
//
// Problems with the <template> node
//
@Test
public void templateNodeNotFound() throws InvalidConfigurationException {
captureLogsFromOPTM();
op = buildOperation("templateNodeNotFound");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("no template node",
"Missing template specification");
}
@Test
public void templateNodeIsEmpty() throws InvalidConfigurationException {
// TODO fix this so it doesn't throw a NullPointerException - use
// textValue() or something
captureLogsFromOPTM();
op = buildOperation("templateNodeIsEmpty");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("empty template node",
"Missing template specification");
}
@Test
public void templateDoesNotExist() throws InvalidConfigurationException {
captureLogsFromOPTM();
op = buildOperation("templateDoesNotExist");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertLogMessagesContains("template doesn't exist",
"Specified template does not exist");
}
//
// Optional tags in the select query.
//
@Test
public void selectSubNodesCollatedCritical()
throws InvalidConfigurationException {
op = buildOperation("selectQuerySubNodes");
optm = new SimpleCollatingOPTM(op, subject, vreq, false);
assertSelectQuery("collated, critical",
"Plain collated plain critical plain collated plain.");
}
@Test
public void selectSubNodesCollatedUncritical()
throws InvalidConfigurationException {
op = buildOperation("selectQuerySubNodes");
optm = new SimpleCollatingOPTM(op, subject, vreq, true);
assertSelectQuery("collated, UNcritical",
"Plain collated plain plain collated plain.");
}
@Test
public void selectSubNodesUncollatedCritical()
throws InvalidConfigurationException {
op = buildOperation("selectQuerySubNodes");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertSelectQuery("UNcollated, critical",
"Plain plain critical plain plain.");
}
@Test
public void selectSubNodesUncollatedUncritical()
throws InvalidConfigurationException {
op = buildOperation("selectQuerySubNodes");
optm = new NonCollatingOPTM(op, subject, vreq, true);
assertSelectQuery("UNcollated, UNcritical", "Plain plain plain plain.");
}
@Test
public void selectNoSubNodesCollatedCritical()
throws InvalidConfigurationException {
op = buildOperation("selectQueryNoSubNodes");
optm = new SimpleCollatingOPTM(op, subject, vreq, false);
assertSelectQuery("simple collated, critical", "Plain.");
}
@Test
public void collatedNoSubclassSelector()
throws InvalidConfigurationException {
thrown.expect(InvalidConfigurationException.class);
thrown.expectMessage("Query does not select a subclass variable");
op = buildOperation("selectQueryCollatedNoSelect");
optm = new CheckingCollatingOPTM(op, subject, vreq, false);
}
@Test
public void collatedNoSubclassOrder() throws InvalidConfigurationException {
thrown.expect(InvalidConfigurationException.class);
thrown.expectMessage("Query does not sort first by subclass variable");
op = buildOperation("selectQueryCollatedNoOrder");
optm = new CheckingCollatingOPTM(op, subject, vreq, false);
}
@Test
public void collatedValid() throws InvalidConfigurationException {
// Throws no exception
op = buildOperation("selectQueryCollatedValid");
optm = new CheckingCollatingOPTM(op, subject, vreq, false);
}
//
// Construct query
//
@Test
public void constructQueryNodeMissing()
throws InvalidConfigurationException {
op = buildOperation("constructQueryMissing");
optm = new NonCollatingOPTM(op, subject, vreq, true);
// Not an error.
}
@Test
public void constructQueryMultipleValues()
throws InvalidConfigurationException {
op = buildOperation("constructQueryMultiple");
optm = new NonCollatingOPTM(op, subject, vreq, true);
assertConstructQueries("multiple construct queries", "ONE", "TWO",
"THREE");
}
//
// PostProcessor
//
@Test
public void postProcessorNameEmpty() throws InvalidConfigurationException {
captureLogsFromOPTM();
op = buildOperation("postProcessorNameEmpty");
optm = new NonCollatingOPTM(op, subject, vreq, false);
// TODO This should not cause an error. If it did, it should not swallow
// the exception. It should use the default PP.
assertLogMessagesContains("pp name empty", "NullPointerException");
assertPostProcessorClass("pp name empty", null);
}
@Test
public void postProcessorClassNotFound()
throws InvalidConfigurationException {
captureLogsFromOPTM();
setLoggerLevel(ObjectPropertyTemplateModel.class, Level.DEBUG);
op = buildOperation("postProcessorClassNotFound");
optm = new NonCollatingOPTM(op, subject, vreq, false);
// TODO this should log an error.
assertLogMessagesContains("pp class not found",
"Cannot find postprocessor specified");
assertPostProcessorClass("pp class not found",
DefaultObjectPropertyDataPostProcessor.class);
}
@Test
public void postProcessorClassIsNotSuitable()
throws InvalidConfigurationException {
captureLogsFromOPTM();
setLoggerLevel(ObjectPropertyTemplateModel.class, Level.DEBUG);
op = buildOperation("postProcessorClassNotSuitable");
optm = new NonCollatingOPTM(op, subject, vreq, false);
// TODO this should log an error.
assertLogMessagesContains("pp doesn't implement required interface",
"Cannot find postprocessor specified");
assertPostProcessorClass("pp doesn't implement required interface",
DefaultObjectPropertyDataPostProcessor.class);
}
@Test
public void postProcessorClassHasWrongConstructor()
throws InvalidConfigurationException {
captureLogsFromOPTM();
setLoggerLevel(ObjectPropertyTemplateModel.class, Level.DEBUG);
op = buildOperation("postProcessorWrongConstructor");
optm = new NonCollatingOPTM(op, subject, vreq, false);
// TODO this should log an error.
assertLogMessagesContains("pp has wrong constructor",
"Cannot find postprocessor specified");
assertPostProcessorClass("pp has wrong constructor",
DefaultObjectPropertyDataPostProcessor.class);
}
@Test
public void postProcessorConstructorThrowsAnException()
throws InvalidConfigurationException {
captureLogsFromOPTM();
setLoggerLevel(ObjectPropertyTemplateModel.class, Level.DEBUG);
op = buildOperation("postProcessorConstructorThrowsException");
optm = new NonCollatingOPTM(op, subject, vreq, false);
// TODO this should log an error.
assertLogMessagesContains("pp throws an exception",
"Cannot find postprocessor specified");
assertPostProcessorClass("pp throws an exception",
DefaultObjectPropertyDataPostProcessor.class);
}
@Test
public void postProcessorOK() throws InvalidConfigurationException {
op = buildOperation("postProcessorOK");
optm = new NonCollatingOPTM(op, subject, vreq, false);
assertPostProcessorClass("pp OK", PostProcessorOK.class);
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
/**
* Sets up an operation with name "foobar" and adds it to the
* ObjectPropertyDaoStub.
*
* The URI will be "http://foobar", and the ListViewConfig file will be
* "testConfig-foobar.xml". That file is assumed to exist already, and to be
* mapped in the ServletContextStub.
*/
private ObjectProperty buildOperation(String name) {
ObjectProperty property = new ObjectProperty();
property.setURI("http://" + name);
opDao.addObjectProperty(property);
opDao.setCustomListViewConfigFileName(property, "testConfig-" + name
+ ".xml");
return property;
}
/**
* Capture the log for ObjectPropertyTemplateModel and suppress it from the
* console.
*/
private void captureLogsFromOPTM() {
captureLogOutput(ObjectPropertyTemplateModel.class, logMessages, true);
}
private void assertLogMessagesContains(String message, String expected) {
if (logMessages.toString().contains(expected)) {
return;
}
fail(message + "\nLOG\n" + logMessages + "\nDOES NOT CONTAIN\n"
+ expected);
}
private void assertSelectQuery(String message, String expected) {
String actual = "BOGUS";
try {
Method m = ObjectPropertyTemplateModel.class.getDeclaredMethod(
"getSelectQuery", new Class<?>[0]);
m.setAccessible(true);
actual = (String) m.invoke(optm, new Object[0]);
} catch (Exception e) {
fail(message + " - " + e);
}
assertEquals(message, expected, actual);
}
@SuppressWarnings("unchecked")
private void assertConstructQueries(String message, String... expectedArray) {
Set<String> expected = new HashSet<String>(Arrays.asList(expectedArray));
Set<String> actual = null;
try {
Method m = ObjectPropertyTemplateModel.class.getDeclaredMethod(
"getConstructQueries", new Class<?>[0]);
m.setAccessible(true);
actual = (Set<String>) m.invoke(optm, new Object[0]);
} catch (Exception e) {
fail(message + " - " + e);
}
assertEqualSets(message, expected, actual);
}
private void assertPostProcessorClass(String message, Class<?> expected) {
try {
Field configField = ObjectPropertyTemplateModel.class
.getDeclaredField("config");
configField.setAccessible(true);
Object config = configField.get(optm);
Class<?> configClass = Class
.forName("edu.cornell.mannlib.vitro.webapp.web."
+ "templatemodels.individual."
+ "ObjectPropertyTemplateModel$PropertyListConfig");
Field ppField = configClass.getDeclaredField("postprocessor");
ppField.setAccessible(true);
Object pp = ppField.get(config);
if (pp == null) {
assertNull(message + " - postprocessor is null", expected);
} else {
assertEquals(message, expected, pp.getClass());
}
} catch (Exception e) {
e.printStackTrace();
fail(message + " - " + e);
}
}
// ----------------------------------------------------------------------
// Supporting classes
// ----------------------------------------------------------------------
private static class NonCollatingOPTM extends ObjectPropertyTemplateModel {
NonCollatingOPTM(ObjectProperty op, Individual subject,
VitroRequest vreq, boolean editing)
throws InvalidConfigurationException {
super(op, subject, vreq, editing);
}
@Override
protected boolean isEmpty() {
return true;
}
@Override
public boolean isCollatedBySubclass() {
return false;
}
}
/*
* No populated properties and we don't do syntax checking on the select
* query.
*/
private static class SimpleCollatingOPTM extends
CollatedObjectPropertyTemplateModel {
SimpleCollatingOPTM(ObjectProperty op, Individual subject,
VitroRequest vreq, boolean editing)
throws InvalidConfigurationException {
super(op, subject, vreq, editing, Collections
.<ObjectProperty> emptyList());
}
@Override
protected ConfigError checkQuery(String queryString) {
return null;
}
}
/** No populated properties but we do check the syntax of the select query. */
private static class CheckingCollatingOPTM extends
CollatedObjectPropertyTemplateModel {
CheckingCollatingOPTM(ObjectProperty op, Individual subject,
VitroRequest vreq, boolean editing)
throws InvalidConfigurationException {
super(op, subject, vreq, editing, Collections
.<ObjectProperty> emptyList());
}
}
/** Does not have a constructor with the correct arguments */
public static class PostProcessorHasWrongConstructor implements
ObjectPropertyDataPostProcessor {
@Override
public void process(List<Map<String, String>> data) {
// Do nothing.
}
}
/** Constructor throws an exception */
public static class PostProcessorThrowsException implements
ObjectPropertyDataPostProcessor {
@SuppressWarnings("unused")
public PostProcessorThrowsException(ObjectPropertyTemplateModel optm,
WebappDaoFactory wadf) {
throw new RuntimeException("Constructor throws exception");
}
@Override
public void process(List<Map<String, String>> data) {
// Do nothing.
}
}
/** Acceptable postprocessor */
public static class PostProcessorOK implements
ObjectPropertyDataPostProcessor {
@SuppressWarnings("unused")
public PostProcessorOK(ObjectPropertyTemplateModel optm,
WebappDaoFactory wadf) {
// Do nothing.
}
@Override
public void process(List<Map<String, String>> data) {
// Do nothing.
}
}
}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
No construct query. Should throw an error.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
More than one construct query.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>ONE</query-construct>
<query-construct>TWO</query-construct>
<query-construct>THREE</query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Default list view configuration for unit tests in this directory.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
This would be valid except for the XML error.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct/>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
postprocessor tag refers to a non-existent class.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel_PropertyListConfigTest$NoSuchClass</postprocessor>
</list-view-config>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
postprocessor tag refers to a class that does not implement the required interface.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel_PropertyListConfigTest$ClassNotSuitable</postprocessor>
</list-view-config>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
postprocessor tag refers to a class that does not implement the required interface.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel_PropertyListConfigTest$PostProcessorThrowsException</postprocessor>
</list-view-config>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Has a postprocessor tag with no contents. Should use the default.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
<postprocessor></postprocessor>
</list-view-config>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
postprocessor tag references an acceptable class.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel_PropertyListConfigTest$PostProcessorOK</postprocessor>
</list-view-config>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
This postprocessor is unacceptable because it doesn't have the required constructor.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
<postprocessor>edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual.ObjectPropertyTemplateModel_PropertyListConfigTest$PostProcessorWrongConstructor</postprocessor>
</list-view-config>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Config file with no subclass ordering. Should throw an error on a collated property
-->
<list-view-config>
<query-select>SELECT ?subclass O_R_D_E_R BY ?subclass</query-select>
<query-construct> Construct </query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Config file with no subclass selector. Should throw an error on a collated property
-->
<list-view-config>
<query-select>S_E_L_E_C_T ?subclass ORDER BY ?subclass</query-select>
<query-construct> Construct </query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Config file with subclass selector and subclass ordering. Should not throw an error on a collated property
-->
<list-view-config>
<query-select>SELECT ?subclass ORDER BY ?subclass</query-select>
<query-construct> Construct </query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Test this with collated and uncollated, critical and uncritical, to insure that we don't need the nested tags.
-->
<list-view-config>
<query-select>Plain.</query-select>
<query-construct> Construct </query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Invalid - <query-select> is blank.
-->
<list-view-config>
<query-select>
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Invalid - no <query-select> node.
-->
<list-view-config>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Test this with collated and uncollated, critical and non-critical,
to be sure that we include or omit the appropriate text.
-->
<list-view-config>
<query-select>Plain <collated>collated </collated>plain <critical-data-required>critical </critical-data-required>plain <collated>collated </collated>plain.</query-select>
<query-construct> Construct </query-construct>
<template>propStatement-default.ftl</template>
</list-view-config>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Template file does not exist. Should throw an exception.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template>propStatement-doesNotExist.ftl</template>
</list-view-config>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Template node is empty - should throw an exception.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
<template/>
</list-view-config>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
No template node. Should throw an exception.
-->
<list-view-config>
<query-select>
SELECT <collated> ?subclass </collated>
?object
WHERE {
?subject ?property ?object
<collated>
?object a ?subclass.
</collated>
}
</query-select>
<query-construct>
CONSTRUCT {
?subject ?property ?object .
} WHERE {
?subject ?property ?object
}
</query-construct>
</list-view-config>

View file

@ -26,18 +26,32 @@ public class ObjectPropertyDaoStub implements ObjectPropertyDao {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private final Map<String, ObjectProperty> opMap = new HashMap<String, ObjectProperty>(); private final Map<String, ObjectProperty> opMap = new HashMap<String, ObjectProperty>();
private final Map<String, String> configFilesMap = new HashMap<String, String>();
public void addObjectProperty(ObjectProperty predicate) { public void addObjectProperty(ObjectProperty property) {
if (predicate == null) { if (property == null) {
throw new NullPointerException("predicate may not be null."); throw new NullPointerException("predicate may not be null.");
} }
String uri = predicate.getURI(); String uri = property.getURI();
if (uri == null) { if (uri == null) {
throw new NullPointerException("uri may not be null."); throw new NullPointerException("uri may not be null.");
} }
opMap.put(uri, predicate); opMap.put(uri, property);
}
public void setCustomListViewConfigFileName(ObjectProperty property, String filename) {
if (property == null) {
throw new NullPointerException("property may not be null.");
}
String uri = property.getURI();
if (uri == null) {
throw new NullPointerException("uri may not be null.");
}
configFilesMap.put(uri, filename);
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -46,9 +60,24 @@ public class ObjectPropertyDaoStub implements ObjectPropertyDao {
@Override @Override
public ObjectProperty getObjectPropertyByURI(String objectPropertyURI) { public ObjectProperty getObjectPropertyByURI(String objectPropertyURI) {
if (objectPropertyURI == null) {
return null;
}
return opMap.get(objectPropertyURI); return opMap.get(objectPropertyURI);
} }
@Override
public String getCustomListViewConfigFileName(ObjectProperty objectProperty) {
if (objectProperty == null) {
return null;
}
String uri = objectProperty.getURI();
if (uri == null) {
return null;
}
return configFilesMap.get(uri);
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Un-implemented methods // Un-implemented methods
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -241,10 +270,4 @@ public class ObjectPropertyDaoStub implements ObjectPropertyDao {
"ObjectPropertyDaoStub.getObjectPropertyList() not implemented."); "ObjectPropertyDaoStub.getObjectPropertyList() not implemented.");
} }
@Override
public String getCustomListViewConfigFileName(ObjectProperty objectProperty) {
throw new RuntimeException(
"ObjectPropertyDaoStub.getCustomListViewConfigFileName() not implemented.");
}
} }

View file

@ -45,6 +45,7 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
private ObjectPropertyStatementDao objectPropertyStatementDao; private ObjectPropertyStatementDao objectPropertyStatementDao;
private OntologyDao ontologyDao; private OntologyDao ontologyDao;
private UserAccountsDao userAccountsDao; private UserAccountsDao userAccountsDao;
private VClassDao vClassDao;
public void setDefaultNamespace(String defaultNamespace) { public void setDefaultNamespace(String defaultNamespace) {
this.defaultNamespace = defaultNamespace; this.defaultNamespace = defaultNamespace;
@ -81,6 +82,10 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
public void setUserAccountsDao(UserAccountsDao userAccountsDao) { public void setUserAccountsDao(UserAccountsDao userAccountsDao) {
this.userAccountsDao = userAccountsDao; this.userAccountsDao = userAccountsDao;
} }
public void setVClassDao(VClassDao vClassDao) {
this.vClassDao = vClassDao;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Stub methods // Stub methods
@ -130,6 +135,11 @@ return this.objectPropertyStatementDao; }
return this.userAccountsDao; return this.userAccountsDao;
} }
@Override
public VClassDao getVClassDao() {
return this.vClassDao;
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Un-implemented methods // Un-implemented methods
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -194,12 +204,6 @@ return this.objectPropertyStatementDao; }
"WebappDaoFactory.getDatatypeDao() not implemented."); "WebappDaoFactory.getDatatypeDao() not implemented.");
} }
@Override
public VClassDao getVClassDao() {
throw new RuntimeException(
"WebappDaoFactory.getVClassDao() not implemented.");
}
@Override @Override
public DataPropertyStatementDao getDataPropertyStatementDao() { public DataPropertyStatementDao getDataPropertyStatementDao() {
throw new RuntimeException( throw new RuntimeException(

View file

@ -0,0 +1,58 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package stubs.freemarker.cache;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import freemarker.cache.TemplateLoader;
/**
* A simple implementation where the templates are stored a strings in a map
* instead of as files, and where the "template source" objects are just the
* template names.
*/
public class TemplateLoaderStub implements TemplateLoader {
// ----------------------------------------------------------------------
// Stub infrastructure
// ----------------------------------------------------------------------
private final Map<String, String> templateMap = new HashMap<String, String>();
public void createTemplate(String name, String contents) {
templateMap.put(name, contents);
}
// ----------------------------------------------------------------------
// Stub methods
// ----------------------------------------------------------------------
@Override
public Object findTemplateSource(String name) throws IOException {
if (templateMap.containsKey(name)) {
return name;
} else {
return null;
}
}
@Override
public void closeTemplateSource(Object templateSource) throws IOException {
// Nothing to close
}
@Override
public long getLastModified(Object templateSource) {
return -1;
}
@Override
public Reader getReader(Object templateSource, String encoding)
throws IOException {
return new StringReader(templateMap.get(templateSource));
}
}

View file

@ -3,6 +3,7 @@
package stubs.javax.servlet; package stubs.javax.servlet;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
@ -17,11 +18,14 @@ import javax.servlet.Servlet;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/** /**
* A simple stand-in for the {@link ServletContext}, for use in unit tests. * A simple stand-in for the {@link ServletContext}, for use in unit tests.
*/ */
@SuppressWarnings("deprecation")
public class ServletContextStub implements ServletContext { public class ServletContextStub implements ServletContext {
private static final Log log = LogFactory.getLog(ServletContextStub.class);
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Stub infrastructure // Stub infrastructure
@ -37,7 +41,7 @@ public class ServletContextStub implements ServletContext {
throw new NullPointerException("contextPath may not be null."); throw new NullPointerException("contextPath may not be null.");
} }
} }
public void setMockResource(String path, String contents) { public void setMockResource(String path, String contents) {
if (path == null) { if (path == null) {
throw new NullPointerException("path may not be null."); throw new NullPointerException("path may not be null.");
@ -48,18 +52,32 @@ public class ServletContextStub implements ServletContext {
mockResources.put(path, contents); mockResources.put(path, contents);
} }
} }
public void setRealPath(String path, String filepath) { public void setRealPath(String path, String filepath) {
if (path == null) { if (path == null) {
throw new NullPointerException("path may not be null."); throw new NullPointerException("path may not be null.");
} }
if (filepath == null) { if (filepath == null) {
log.debug("removing real path for '" + path + "'");
realPaths.remove(path); realPaths.remove(path);
} else { } else {
log.debug("adding real path for '" + path + "' = '" + filepath
+ "'");
realPaths.put(path, filepath); realPaths.put(path, filepath);
} }
} }
/**
* Call setRealPath for each of the files in this directory (non-recursive).
* Use the prefix, a separator, and the filename as the path.
*/
public void setRealPaths(String pathPrefix, File dir) {
for (File file : dir.listFiles()) {
setRealPath(pathPrefix + File.separatorChar + file.getName(),
file.getPath());
}
}
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// Stub methods // Stub methods
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
@ -104,7 +122,9 @@ public class ServletContextStub implements ServletContext {
@Override @Override
public String getRealPath(String path) { public String getRealPath(String path) {
return realPaths.get(path); String real = realPaths.get(path);
log.debug("Real path for '" + path + "' is '" + real + "'");
return real;
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------