VIVO-533 When loading templates, mimic the language filtering of the RDFService.

This commit is contained in:
j2blake 2013-11-18 17:13:09 -05:00
parent 19f2d14b5f
commit 818962d0a6
6 changed files with 683 additions and 363 deletions

View file

@ -1,183 +0,0 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.text.SimpleDateFormat;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
/**
* Test the methods of {@link FlatteningTemplateLoader}.
*/
public class FlatteningTemplateLoaderTest extends AbstractTestClass {
/**
* TODO test plan
*
* <pre>
* findTemplateSource
* null arg
* not found
* found in top level
* found in lower level
* with path
*
* getReader
* get it, read it, check it, close it.
*
* getLastModified
* check the create date within a range
* modify it and check again.
*
* </pre>
*/
// ----------------------------------------------------------------------
// setup and teardown
// ----------------------------------------------------------------------
private static final String SUBDIRECTORY_NAME = "sub";
private static final String TEMPLATE_NAME_UPPER = "template.ftl";
private static final String TEMPLATE_NAME_UPPER_WITH_PATH = "path/template.ftl";
private static final String TEMPLATE_UPPER_CONTENTS = "The contents of the file.";
private static final String TEMPLATE_NAME_LOWER = "another.ftl";
private static final String TEMPLATE_LOWER_CONTENTS = "Another template file.";
private static File tempDir;
private static File notADirectory;
private static File upperTemplate;
private static File lowerTemplate;
private FlatteningTemplateLoader loader;
@BeforeClass
public static void setUpFiles() throws IOException {
notADirectory = File.createTempFile(
FlatteningTemplateLoader.class.getSimpleName(), "");
tempDir = createTempDirectory(FlatteningTemplateLoader.class
.getSimpleName());
upperTemplate = createFile(tempDir, TEMPLATE_NAME_UPPER,
TEMPLATE_UPPER_CONTENTS);
File subdirectory = new File(tempDir, SUBDIRECTORY_NAME);
subdirectory.mkdir();
lowerTemplate = createFile(subdirectory, TEMPLATE_NAME_LOWER,
TEMPLATE_LOWER_CONTENTS);
}
@Before
public void initializeLoader() {
loader = new FlatteningTemplateLoader(tempDir);
}
@AfterClass
public static void cleanUpFiles() throws IOException {
purgeDirectoryRecursively(tempDir);
}
// ----------------------------------------------------------------------
// the tests
// ----------------------------------------------------------------------
@Test(expected = NullPointerException.class)
public void constructorNull() {
new FlatteningTemplateLoader(null);
}
@Test(expected = IllegalArgumentException.class)
public void constructorNonExistent() {
new FlatteningTemplateLoader(new File("bogusDirName"));
}
@Test(expected = IllegalArgumentException.class)
public void constructorNotADirectory() {
new FlatteningTemplateLoader(notADirectory);
}
@Test
public void findNull() throws IOException {
Object source = loader.findTemplateSource(null);
assertNull("find null", source);
}
@Test
public void findNotFound() throws IOException {
Object source = loader.findTemplateSource("bogus");
assertNull("not found", source);
}
@Test
public void findInTopLevel() throws IOException {
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
assertEquals("top level", upperTemplate, source);
}
@Test
public void findInLowerLevel() throws IOException {
Object source = loader.findTemplateSource(TEMPLATE_NAME_LOWER);
assertEquals("lower level", lowerTemplate, source);
}
@Test
public void findIgnoringPath() throws IOException {
Object source = loader
.findTemplateSource(TEMPLATE_NAME_UPPER_WITH_PATH);
assertEquals("top level", upperTemplate, source);
}
@Test
public void checkTheReader() throws IOException {
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
Reader reader = loader.getReader(source, "UTF-8");
String contents = readAll(reader);
assertEquals("read the contents", contents, TEMPLATE_UPPER_CONTENTS);
}
/**
* Some systems only record last-modified times to the nearest second, so we
* can't rely on them changing during the course of the test. Force the
* change, and test for it.
*/
@Test
public void teplateLastModified() throws IOException {
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
long modified = loader.getLastModified(source);
long now = System.currentTimeMillis();
assertTrue("near to now: modified=" + formatTimeStamp(modified)
+ ", now=" + formatTimeStamp(now),
2000 > Math.abs(modified - now));
upperTemplate.setLastModified(5000);
assertEquals("modified modified", 5000, loader.getLastModified(source));
}
@Test
public void closeDoesntCrash() throws IOException {
Object source = loader.findTemplateSource(TEMPLATE_NAME_UPPER);
loader.closeTemplateSource(source);
}
// ----------------------------------------------------------------------
// helper methods
// ----------------------------------------------------------------------
private String formatTimeStamp(long time) {
SimpleDateFormat formatter = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss.SSS");
return formatter.format(time);
}
}

View file

@ -0,0 +1,359 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.freemarker.loader;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.SortedSet;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;
import edu.cornell.mannlib.vitro.webapp.freemarker.loader.FreemarkerTemplateLoader.PathPieces;
import edu.cornell.mannlib.vitro.webapp.freemarker.loader.FreemarkerTemplateLoader.PathPiecesFileVisitor;
/**
* TODO
*/
public class FreemarkerTemplateLoaderTest {
private PathPiecesFileVisitor visitor;
private String[] paths;
// ----------------------------------------------------------------------
// PathPieces tests
// ----------------------------------------------------------------------
@Test
public void ppLanguageRegionExtension() {
assertPathPieces("this_en_US.ftl", "this", "_en", "_US", ".ftl");
}
@Test
public void ppLanguageRegion() {
assertPathPieces("this_en_US", "this", "_en", "_US", "");
}
@Test
public void ppLanguageExtension() {
assertPathPieces("this_en.ftl", "this", "_en", "", ".ftl");
}
@Test
public void ppLanguage() {
assertPathPieces("this_en", "this", "_en", "", "");
}
@Test
public void ppDefaultExtension() {
assertPathPieces("this.ftl", "this", "", "", ".ftl");
}
@Test
public void ppDefault() {
assertPathPieces("this", "this", "", "", "");
}
@Test
public void ppExtraUnderscoreExtension() {
assertPathPieces("woo_hoo_en_US.ftl", "woo_hoo", "_en", "_US", ".ftl");
}
@Test
public void ppExtraUnderscore() {
assertPathPieces("woo_hoo_en_US", "woo_hoo", "_en", "_US", "");
}
// ----------------------------------------------------------------------
// Specific function tests
// ----------------------------------------------------------------------
@Test
public void baseAndExtensionMatch() {
paths("match-me.ftl");
assertMatches("match-me.ftl", 1, "match-me.ftl");
}
@Test
public void baseAndExtensionDontMatch() {
paths("match-me.ftl");
assertMatches("fail.ftl", 0, null);
assertMatches("match-me", 0, null);
assertMatches("match-me.FTL", 0, null);
}
@Test
public void matchRegardlessOfDepth() {
paths("short-path.ftl", "long/long-path.ftl");
assertMatches("long/short-path.ftl", 1, "short-path.ftl");
assertMatches("long-path.ftl", 1, "long/long-path.ftl");
}
@Test
public void preferShorterPath() {
paths("shorter-is-better", "long/shorter-is-better");
assertMatches("shorter-is-better", 2, "shorter-is-better");
}
@Test
public void preferShorterPathToExactPath() {
paths("shorter-is-better", "long/shorter-is-better");
assertMatches("long/shorter-is-better", 2, "shorter-is-better");
}
@Test
public void languageAndRegionMustMatchExactly() {
paths("this_es_MX.ftl", "this_es_ES.ftl", "this_es.ftl");
assertMatches("this_es_ES.ftl", 1, "this_es_ES.ftl");
}
@Test
public void languageAndRegionNoMatch() {
paths("this_es_MX.ftl", "this_es_ES.ftl", "this_es.ftl");
assertMatches("this_es_GO.ftl", 0, null);
}
@Test
public void languagePrefersExactMatch() {
paths("this_es_MX.ftl", "this_es.ftl", "this_es_ES.ftl");
assertMatches("this_es.ftl", 3, "this_es.ftl");
}
@Test
public void languageAcceptsApproximateMatch() {
paths("this_es_MX.ftl");
assertMatches("this_es.ftl", 1, "this_es_MX.ftl");
}
@Test
public void languagePrefersApproximateAlphabetical() {
paths("this_es_MX.ftl", "this_es_ES.ftl");
assertMatches("this_es.ftl", 2, "this_es_ES.ftl");
}
@Test
public void defaultPrefersExactMatch() {
paths("this_fr.ftl", "this.ftl", "this_fr_BE.ftl");
assertMatches("this.ftl", 3, "this.ftl");
}
@Test
public void defaultPrefersDefaultRegion() {
paths("this_fr_BE.ftl", "this_fr.ftl", "this_fr_CA.ftl");
assertMatches("this.ftl", 3, "this_fr.ftl");
}
@Test
public void defaultPrefersLanguageAlphabetical() {
paths("this_es.ftl", "this_fr.ftl");
assertMatches("this.ftl", 2, "this_es.ftl");
}
@Test
public void defaultPrefersRegionAlphabetical() {
paths("this_fr_BE.ftl", "this_fr_CA.ftl");
assertMatches("this.ftl", 2, "this_fr_BE.ftl");
}
// ----------------------------------------------------------------------
// Freemarker simulation tests
// ----------------------------------------------------------------------
public static final String[] FREEMARKER_TEST_PATHS = {
"long/this_fr_BE.ftl", "language_fr.ftl", "default.ftl",
"language-approx_en_US.ftl" };
@Test
public void freemarkerLangAndRegionExact() {
paths = FREEMARKER_TEST_PATHS;
assertFM("this_fr_BE.ftl", 1, "long/this_fr_BE.ftl");
}
@Test
public void freemarkerLangAndRegionMatchLang() {
paths = FREEMARKER_TEST_PATHS;
assertFM("language_fr_CA.ftl", 2, "language_fr.ftl");
}
@Test
public void freemarkerLangAndRegionMatchDefault() {
paths = FREEMARKER_TEST_PATHS;
assertFM("default_es_ES.ftl", 3, "default.ftl");
}
@Test
public void freemarkerLangAndRegionNoMatch() {
paths = FREEMARKER_TEST_PATHS;
assertFM("bogus_en_US.ftl", 3, null);
}
@Test
public void freemarkerLangExact() {
paths = FREEMARKER_TEST_PATHS;
assertFM("language_fr.ftl", 1, "language_fr.ftl");
}
@Test
public void freemarkerLangMatchLangAndRegion() {
paths = FREEMARKER_TEST_PATHS;
assertFM("language-approx_en.ftl", 1, "language-approx_en_US.ftl");
}
@Test
public void freemarkerLangMatchDefault() {
paths = FREEMARKER_TEST_PATHS;
assertFM("default_en.ftl", 2, "default.ftl");
}
@Test
public void freemarkerLangNoMatch() {
paths = FREEMARKER_TEST_PATHS;
assertFM("bogus_it.ftl", 2, null);
}
@Test
public void freemarkerDefaultExact() {
paths = FREEMARKER_TEST_PATHS;
assertFM("default.ftl", 1, "default.ftl");
}
@Test
public void freemarkerDefaultMatchLang() {
paths = FREEMARKER_TEST_PATHS;
assertFM("language.ftl", 1, "language_fr.ftl");
}
@Test
public void freemarkerDefaultMatchLangAndRegion() {
paths = FREEMARKER_TEST_PATHS;
assertFM("this.ftl", 1, "long/this_fr_BE.ftl");
}
@Test
public void freemarkerDefaultNoMatch() {
paths = FREEMARKER_TEST_PATHS;
assertFM("bogus.ftl", 1, null);
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
private void paths(String... p) {
this.paths = p;
}
private void assertPathPieces(String path, String base, String language,
String region, String extension) {
PathPieces pp = new PathPieces(path);
String[] expected = new String[] { base, language, region, extension };
String[] actual = new String[] { pp.base, pp.language, pp.region,
pp.extension };
assertEquals("pieces", Arrays.asList(expected), Arrays.asList(actual));
}
/**
* @param searchTerm
* template we are looking for
* @param expectedHowMany
* How many matches do we expect?
* @param expectedBestFit
* What should the best match turn out to be?
* @throws IOException
*/
private void assertMatches(String searchTerm, int expectedHowMany,
String expectedBestFit) {
SortedSet<PathPieces> matches = runTheVisitor(searchTerm);
int actualHowMany = matches.size();
String actualBestFit = matches.isEmpty() ? null : matches.last().path
.toString();
if (expectedHowMany != actualHowMany) {
fail("How many results: expected " + expectedHowMany
+ ", but was " + actualHowMany + ": " + matches);
}
if (!StringUtils.equals(expectedBestFit, actualBestFit)) {
fail("Best result: expected '" + expectedBestFit + "', but was '"
+ actualBestFit + "': " + matches);
}
}
/**
* Try for exact match, then pare down if needed, just like Freemarker
* would.
*/
private void assertFM(String searchTerm, int expectedNumberOfTries,
String expectedBestFit) {
PathPieces stPp = new PathPieces(searchTerm);
int actualNumberOfTries = 0;
String actualBestFit = null;
if (StringUtils.isNotBlank(stPp.region)) {
actualNumberOfTries++;
SortedSet<PathPieces> matches = runTheVisitor(stPp.base
+ stPp.language + stPp.region + stPp.extension);
if (!matches.isEmpty()) {
actualBestFit = matches.last().path.toString();
}
}
if (actualBestFit == null && StringUtils.isNotBlank(stPp.language)) {
actualNumberOfTries++;
SortedSet<PathPieces> matches = runTheVisitor(stPp.base
+ stPp.language + stPp.extension);
if (!matches.isEmpty()) {
actualBestFit = matches.last().path.toString();
}
}
if (actualBestFit == null) {
actualNumberOfTries++;
SortedSet<PathPieces> matches = runTheVisitor(stPp.base
+ stPp.extension);
if (!matches.isEmpty()) {
actualBestFit = matches.last().path.toString();
}
}
assertEquals("How many tries", expectedNumberOfTries,
actualNumberOfTries);
assertEquals("best fit", expectedBestFit, actualBestFit);
}
private SortedSet<PathPieces> runTheVisitor(String searchTerm) {
try {
visitor = new PathPiecesFileVisitorStub(new PathPieces(searchTerm));
for (String p : this.paths) {
visitor.visitFile(Paths.get(p), null);
}
} catch (IOException e) {
fail("Failed: " + e);
}
return visitor.getMatches();
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
/**
* We want to test the PathPiecesFileVisitor, but we can't have it checking
* to see whether the files actually exist.
*/
private static class PathPiecesFileVisitorStub extends
PathPiecesFileVisitor {
public PathPiecesFileVisitorStub(PathPieces searchTerm) {
super(searchTerm);
}
@Override
public boolean fileQualifies(Path path) {
return true;
}
}
}