Repository: incubator-freemarker
Updated Branches:
  refs/heads/3 7486e23b3 -> d373a34d3


Changed FileTestCase again... now it works even if the resources/classes of the 
same package are loaded from multiple directories.


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/6a2b2ad5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/6a2b2ad5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/6a2b2ad5

Branch: refs/heads/3
Commit: 6a2b2ad57633cf1f142bb45a65149c786cae986b
Parents: 7486e23
Author: ddekany <[email protected]>
Authored: Sun May 7 17:52:05 2017 +0200
Committer: ddekany <[email protected]>
Committed: Sun May 7 17:52:05 2017 +0200

----------------------------------------------------------------------
 .../apache/freemarker/core/Configuration.java   |   8 +-
 .../freemarker/core/util/_StringUtil.java       |  13 ++
 .../org/apache/freemarker/core/ASTTest.java     |   7 +-
 .../freemarker/core/util/StringUtilTest.java    |  11 ++
 .../test/servlet/Model2TesterServlet.java       |   3 +
 .../test/templatesuite/TemplateTestCase.java    |  76 ++++----
 .../freemarker/test/util/FileTestCase.java      | 176 ++++++++++++-------
 7 files changed, 177 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/main/java/org/apache/freemarker/core/Configuration.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/Configuration.java 
b/src/main/java/org/apache/freemarker/core/Configuration.java
index df15c0f..e97014f 100644
--- a/src/main/java/org/apache/freemarker/core/Configuration.java
+++ b/src/main/java/org/apache/freemarker/core/Configuration.java
@@ -98,12 +98,8 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  *
  * <p>This class is meant to be used in a singleton pattern. That is, you 
create an instance of this at the beginning of
  * the application life-cycle with {@link Configuration.Builder}, set its 
settings
- * (either
- * with
- * the
- * setter methods like {@link 
Configuration.Builder#setTemplateLoader(TemplateLoader)} or by loading a
- * {@code .properties} file and use that with {@link 
Configuration.Builder#setSettings(Properties)}}), and
- * then
+ * (either with the setter methods like {@link 
Configuration.Builder#setTemplateLoader(TemplateLoader)} or by loading a
+ * {@code .properties} file and use that with {@link 
Configuration.Builder#setSettings(Properties)}}), and then
  * use that single instance everywhere in your application. Frequently 
re-creating {@link Configuration} is a typical
  * and grave mistake from performance standpoint, as the {@link Configuration} 
holds the template cache, and often also
  * the class introspection cache, which then will be lost. (Note that, 
naturally, having multiple long-lived instances,

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/main/java/org/apache/freemarker/core/util/_StringUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/freemarker/core/util/_StringUtil.java 
b/src/main/java/org/apache/freemarker/core/util/_StringUtil.java
index 50c1874..b53aae8 100644
--- a/src/main/java/org/apache/freemarker/core/util/_StringUtil.java
+++ b/src/main/java/org/apache/freemarker/core/util/_StringUtil.java
@@ -1658,5 +1658,18 @@ public class _StringUtil {
     public static boolean isUpperUSASCII(char c) {
         return c >= 'A' && c <= 'Z';
     }
+
+    private static final Pattern NORMALIZE_EOLS_REGEXP = 
Pattern.compile("\\r\\n?+");
+
+    /**
+     * Converts all non UN*X End-Of-Line character sequences (CR and CRLF) to 
UN*X format (LF).
+     * Returns {@code null} for {@code null} input.
+     */
+    public static String normalizeEOLs(String s) {
+        if (s == null) {
+            return null;
+        }
+        return NORMALIZE_EOLS_REGEXP.matcher(s).replaceAll("\n");
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/test/java/org/apache/freemarker/core/ASTTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/ASTTest.java 
b/src/test/java/org/apache/freemarker/core/ASTTest.java
index ff67cfb..5a6526e 100644
--- a/src/test/java/org/apache/freemarker/core/ASTTest.java
+++ b/src/test/java/org/apache/freemarker/core/ASTTest.java
@@ -21,7 +21,6 @@ package org.apache.freemarker.core;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.net.URL;
 
 import org.apache.freemarker.core.ASTPrinter.Options;
 import org.apache.freemarker.core.util._StringUtil;
@@ -91,8 +90,10 @@ public class ASTTest extends FileTestCase {
                 ASTPrinter.getASTAsString(templateName,
                         TestUtil.removeFTLCopyrightComment(
                                 normalizeLineBreaks(
-                                        loadTestTextResource(new 
URL(getTestClassDirectory(), templateName))
-                        )), ops));
+                                        loadTestTextResource(
+                                                getTestFileURL(
+                                                        
getExpectedContentFileDirectoryResourcePath(), templateName)))
+                        ), ops));
     }
     
     private String normalizeLineBreaks(final String s) throws 
FileNotFoundException, IOException {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java 
b/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
index 0df8394..2a0ae9d 100644
--- a/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
+++ b/src/test/java/org/apache/freemarker/core/util/StringUtilTest.java
@@ -388,5 +388,16 @@ public class StringUtilTest {
         _StringUtil.RTFEnc(in, sw);
         assertEquals(expected, sw.toString());
     }
+
+    @Test
+    public void testNormalizeEOLs() {
+        assertNull(_StringUtil.normalizeEOLs(null));
+        assertEquals("", _StringUtil.normalizeEOLs(""));
+        assertEquals("x", _StringUtil.normalizeEOLs("x"));
+        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\ny"));
+        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\r\ny"));
+        assertEquals("x\ny", _StringUtil.normalizeEOLs("x\ry"));
+        assertEquals("\n\n\n\n\n\n", 
_StringUtil.normalizeEOLs("\n\r\r\r\n\r\n\r"));
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/test/java/org/apache/freemarker/test/servlet/Model2TesterServlet.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/test/servlet/Model2TesterServlet.java 
b/src/test/java/org/apache/freemarker/test/servlet/Model2TesterServlet.java
index 9a39705..b69a33c 100644
--- a/src/test/java/org/apache/freemarker/test/servlet/Model2TesterServlet.java
+++ b/src/test/java/org/apache/freemarker/test/servlet/Model2TesterServlet.java
@@ -22,6 +22,7 @@ package org.apache.freemarker.test.servlet;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 
+import javax.el.ExpressionFactory;
 import javax.servlet.RequestDispatcher;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -104,6 +105,8 @@ public class Model2TesterServlet extends HttpServlet {
         
         final String paramViewServlet = 
req.getParameter(VIEW_SERVLET_PARAM_NAME);
         if (paramViewServlet == null) {
+            LOG.info("Found ExpressionFactory at: {}", 
ExpressionFactory.class.getResource("ExpressionFactory"
+                    + ".class")); //!!T
             req.getRequestDispatcher(viewPath).forward(req, resp);
         } else {
             final RequestDispatcher requestDispatcher = 
getServletContext().getNamedDispatcher(paramViewServlet);

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java 
b/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
index 2a24b5b..07bf0ca 100644
--- 
a/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
+++ 
b/src/test/java/org/apache/freemarker/test/templatesuite/TemplateTestCase.java
@@ -24,7 +24,6 @@ import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.net.URL;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -413,7 +412,7 @@ public class TemplateTestCase extends FileTestCase {
         }
         
         if (out != null) {
-            assertExpectedFileEqualsString(getName(), out.toString());
+            assertExpectedFileEqualsString(expectedFileName, out.toString());
         }
     }
 
@@ -424,19 +423,14 @@ public class TemplateTestCase extends FileTestCase {
     }
 
     @Override
-    protected URL getExpectedFileDirectory() throws IOException {
-        return new URL(super.getExpectedFileDirectory(), "expected/");
+    protected String getExpectedContentFileDirectoryResourcePath() throws 
IOException {
+        return 
joinResourcePaths(super.getExpectedContentFileDirectoryResourcePath(), 
"expected");
     }
 
     @Override
-    protected Charset getTestResourceCharset() {
+    protected Charset getTestResourceDefaultCharset() {
         return confB.getOutputEncoding() != null ? confB.getOutputEncoding() : 
StandardCharsets.UTF_8;
     }
-    
-    @Override
-    protected URL getExpectedFileFor(String testCaseFileName) throws 
IOException {
-        return new URL(getExpectedFileDirectory(), expectedFileName);
-    }
 
     static class TestBoolean implements TemplateBooleanModel, 
TemplateScalarModel {
         @Override
@@ -449,40 +443,40 @@ public class TemplateTestCase extends FileTestCase {
             return "de";
         }
     }
-    
+
     static class TestMethod implements TemplateMethodModel {
-      @Override
-    public Object exec(List arguments) {
-          return "x";
-      }
+        @Override
+        public Object exec(List arguments) {
+            return "x";
+        }
     }
-    
+
     static class TestNode implements TemplateNodeModel {
-      
-      @Override
-    public String getNodeName() {
-          return "name";
-      }
-                    
-      @Override
-    public TemplateNodeModel getParentNode() {
-          return null;
-      }
-    
-      @Override
-    public String getNodeType() {
-          return "element";
-      }
-    
-      @Override
-    public TemplateSequenceModel getChildNodes() {
-          return null;
-      }
-      
-      @Override
-    public String getNodeNamespace() {
-          return null;
-      }
+
+        @Override
+        public String getNodeName() {
+            return "name";
+        }
+
+        @Override
+        public TemplateNodeModel getParentNode() {
+            return null;
+        }
+
+        @Override
+        public String getNodeType() {
+            return "element";
+        }
+
+        @Override
+        public TemplateSequenceModel getChildNodes() {
+            return null;
+        }
+
+        @Override
+        public String getNodeNamespace() {
+            return null;
+        }
     }
 
    public Object getTestMapBean() {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/6a2b2ad5/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/freemarker/test/util/FileTestCase.java 
b/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
index 144592a..ba13558 100644
--- a/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
+++ b/src/test/java/org/apache/freemarker/test/util/FileTestCase.java
@@ -20,22 +20,19 @@
 package org.apache.freemarker.test.util;
 
 import java.io.File;
-import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Writer;
 import java.net.URL;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
+import org.apache.freemarker.core.util._NullArgumentException;
 import org.apache.freemarker.core.util._StringUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
@@ -44,20 +41,22 @@ import junit.framework.TestCase;
  */
 public abstract class FileTestCase extends TestCase {
 
+    public static final Logger LOG = 
LoggerFactory.getLogger(FileTestCase.class);
+
     public FileTestCase(String name) {
         super(name);
     }
 
     protected void assertExpectedFileEqualsString(String expectedFileName, 
String actualContent) {
         try {
-            final URL expectedFile = getExpectedFileFor(expectedFileName);
+            final URL expectedFile = 
getExpectedContentFileURL(expectedFileName);
             
             try {
                 multilineAssertEquals(loadTestTextResource(expectedFile), 
actualContent);
-            } catch (AssertionFailedError e) {
-                File actualFile = getActualFileFor(expectedFileName);
-                if (actualFile == null) {
-                    saveString(actualFile, actualContent);
+            } catch (AssertionFailedError | FileNotFoundException e) {
+                File actualFile = getActualContentFileFor(expectedFile);
+                if (actualFile != null) {
+                    FileUtils.write(actualFile, actualContent);
                     reportActualFileSaved(actualFile);
                 }
 
@@ -69,8 +68,8 @@ public abstract class FileTestCase extends TestCase {
     }
 
     private void multilineAssertEquals(String expected, String actual) {
-        String normExpected = normalizeNewLines(expected);
-        final String normActual = normalizeNewLines(actual);
+        String normExpected = _StringUtil.normalizeEOLs(expected);
+        final String normActual = _StringUtil.normalizeEOLs(actual);
         
         // Ignore final line-break difference:
         if (normActual.endsWith("\n") && !normExpected.endsWith("\n")) {
@@ -82,65 +81,127 @@ public abstract class FileTestCase extends TestCase {
         assertEquals(normExpected, normActual);
     }
 
-    private String normalizeNewLines(String s) {
-        return _StringUtil.replace(s, "\r\n", "\n").replace('\r', '\n');
+    protected void reportActualFileSaved(File actualContentFile) {
+        LOG.info("Saved actual output of the failed test to here: {}", 
actualContentFile.getAbsolutePath());
     }
 
-    private void saveString(File actualFile, String actualContents) throws 
IOException {
-        Writer w = new OutputStreamWriter(new FileOutputStream(actualFile), 
StandardCharsets.UTF_8);
-        try {
-            w.write(actualContents);
-        } finally {
-            w.close();
+    /**
+     * Convenience method for calling {@link #getTestFileURL(String, String)} 
with {@link
+     * #getExpectedContentFileDirectoryResourcePath()} as the first argument.
+     */
+    protected final URL getExpectedContentFileURL(String 
expectedContentFileName) throws IOException {
+        return getTestFileURL(getExpectedContentFileDirectoryResourcePath(), 
expectedContentFileName);
+    }
+
+    /**
+     * Gets the URL of the test file that contains the expected result.
+     *
+     * @param directoryResourcePath
+     *         The class-loader resource path of the containing directory; if 
relative, it's interpreted relatively to
+     *         the package of {@link #getTestResourcesBaseClass()}.
+     *
+     * @return Not {@code null}; if the file isn't found, throw {@link 
FileNotFoundException}
+     *
+     * @throws FileNotFoundException
+     *         If the requested file wasn't found.
+     */
+    protected final URL getTestFileURL(String directoryResourcePath, String 
fileName) throws IOException {
+        _NullArgumentException.check("directoryResourcePath", 
directoryResourcePath);
+        _NullArgumentException.check("testCaseFileName", fileName);
+
+        Class baseClass = getTestResourcesBaseClass();
+        String resourcePath = joinResourcePaths(directoryResourcePath, 
fileName);
+        // It's important that we only query an URL for the file (not for the 
parent package directory), because the
+        // parent URL can depend on the file name if the class loader uses 
multiple directories/jars.
+        URL resource = baseClass.getResource(resourcePath);
+        if (resource == null) {
+            throw new FileNotFoundException("Class-loader resource not found 
for: "
+                    + "baseClass: " + baseClass.getName() + "; "
+                    + "resourcePath (shown quoted): " + 
_StringUtil.jQuote(resourcePath));
         }
+        return resource;
     }
 
-    protected URL getExpectedFileFor(String testCaseFileName) throws 
IOException {
-        return new URL(getExpectedFileDirectory(), testCaseFileName);
+    /**
+     * Concatenates two resource paths, taking care of the edge cases due to 
leading and trailing "/"
+     * characters in them.
+     */
+    protected final String joinResourcePaths(String dirPath, String tailPath) {
+        if (tailPath.startsWith("/") || dirPath.isEmpty()) {
+            return tailPath;
+        }
+        return dirPath.endsWith("/") ? dirPath + tailPath : dirPath + "/" + 
tailPath;
     }
 
     /**
-     * @return {@code null} if there's no place to write the actual files to
+     * Gets the actual content file to create which belongs to an expected 
content file. Actual content files are
+     * created when the expected and the actual content differs.
+     *
+     * @return {@code null} if there's no place to write the files that 
contain the actual content
      */
-    protected File getActualFileFor(String testCaseFileName) throws 
IOException {
-        File actualFileDirectory = getActualFileDirectory();
-        if (actualFileDirectory == null) {
+    protected File getActualContentFileFor(URL expectedContentFile) throws 
IOException {
+        _NullArgumentException.check("expectedContentFile", 
expectedContentFile);
+
+        File actualContentFileDir = 
getActualContentFileDirectory(expectedContentFile);
+        if (actualContentFileDir == null) {
             return null;
         }
-        return new File(actualFileDirectory, 
deduceActualFileName(testCaseFileName));
+
+        String expectedContentFileName = expectedContentFile.getPath();
+        int lastSlashIdx = expectedContentFileName.lastIndexOf('/');
+        if (lastSlashIdx != -1) {
+            expectedContentFileName = 
expectedContentFileName.substring(lastSlashIdx + 1);
+        }
+
+        return new File(actualContentFileDir, 
deduceActualContentFileName(expectedContentFileName));
     }
-    
-    private String deduceActualFileName(String testCaseFileName) {
-        int lastDotIdx = testCaseFileName.lastIndexOf('.');
+
+    /**
+     * Deduces the actual content file name from the expected content file 
name.
+     *
+     * @return Not {@code null}
+     */
+    protected String deduceActualContentFileName(String 
expectedContentFileName) {
+        _NullArgumentException.check("expectedContentFileName", 
expectedContentFileName);
+
+        int lastDotIdx = expectedContentFileName.lastIndexOf('.');
         return lastDotIdx == -1
-                ? testCaseFileName + ".actual" 
-                : testCaseFileName.substring(0, lastDotIdx) + "-actual" + 
testCaseFileName.substring(lastDotIdx);
+                ? expectedContentFileName + ".actual"
+                : expectedContentFileName.substring(0, lastDotIdx) + "-actual" 
+ expectedContentFileName.substring(lastDotIdx);
     }
 
     /**
-     * The URL of the directory that contains the expected files; must end 
with "/" or "/." or else relative paths won't
-     * be resolved correctly.
+     * The class loader resource path of the directory that contains the 
expected files; must start and end with "/"!
      */
-    protected URL getExpectedFileDirectory() throws IOException {
-        return getTestClassDirectory();
+    protected String getExpectedContentFileDirectoryResourcePath() throws 
IOException {
+        return getTestClassDirectoryResourcePath();
     }
 
     /**
      * @return {@code null} if there's no directory to write the actual files 
to
      */
-    protected File getActualFileDirectory() throws IOException {
-        return FileUtils.toFile(getExpectedFileDirectory());
+    protected File getActualContentFileDirectory(URL expectedFile) throws 
IOException {
+        return FileUtils.toFile(expectedFile).getParentFile();
     }
 
-    @SuppressFBWarnings(value="UI_INHERITANCE_UNSAFE_GETRESOURCE", 
justification="By design relative to subclass")
-    protected final URL getTestClassDirectory() throws IOException {
-        URL url = getClass().getResource(".");
-        if (url == null) throw new IOException("Couldn't get resource URL for 
\".\"");
-        return url;
+    /**
+     * The class loader resource path of the directory that contains the test 
files; must not end with "/"!
+     */
+    protected String getTestClassDirectoryResourcePath() throws IOException {
+        return "";
+    }
+
+    /**
+     * Resource paths are loaded using this class's {@link 
Class#getResourceAsStream(String)} method; thus, if
+     * {@link #getTestClassDirectoryResourcePath()} and such return a relative 
paths, they will be relative to the
+     * package of this class.
+     */
+    protected Class getTestResourcesBaseClass() {
+        return getClass();
     }
 
     protected String loadTestTextResource(URL resource) throws IOException {
-        return loadTestTextResource(resource, getTestResourceCharset());
+        return loadTestTextResource(resource, getTestResourceDefaultCharset());
     }
     
     protected String loadTestTextResource(URL resource, Charset charset) 
throws IOException {
@@ -148,27 +209,8 @@ public abstract class FileTestCase extends TestCase {
                 IOUtils.toString(resource, charset.name()));
     }
     
-    protected Charset getTestResourceCharset() {
+    protected Charset getTestResourceDefaultCharset() {
         return StandardCharsets.UTF_8;
     }
-    
-    protected void reportActualFileSaved(File f) {
-        System.out.println("Note: Saved actual output of the failed test to 
here: " + f.getAbsolutePath());
-    }
-   
-    private static String loadString(InputStream in, Charset charset) throws 
IOException {
-        Reader r = new InputStreamReader(in, charset);
-        StringBuilder sb = new StringBuilder(1024);
-        try {
-            char[] buf = new char[4096];
-            int ln;
-            while ((ln = r.read(buf)) != -1) {
-                sb.append(buf, 0, ln);
-            }
-        } finally {
-            r.close();
-        }
-        return sb.toString();
-    }
-    
+
 }

Reply via email to