diff options
Diffstat (limited to 'velocity-engine-core/src/test/java/org/apache/velocity')
163 files changed, 20848 insertions, 0 deletions
diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/io/UnicodeInputStreamTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/io/UnicodeInputStreamTestCase.java new file mode 100644 index 00000000..68c10842 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/io/UnicodeInputStreamTestCase.java @@ -0,0 +1,239 @@ +package org.apache.velocity.io; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.commons.lang3.ArrayUtils; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; + + +/** + * Test the UnicodeInputStream. + * + * @author $author$ + * @version $Revision$, $Date$ + */ +public class UnicodeInputStreamTestCase + extends TestCase +{ + + public UnicodeInputStreamTestCase(final String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(UnicodeInputStreamTestCase.class); + } + + public void testSimpleStream() + throws Exception + { + testRun(null, "Ich bin zwei Oeltanks", "US-ASCII", true); + testRun(null, "Ich bin zwei Oeltanks", "US-ASCII", false); + } + + public void testSimpleUTF8() + throws Exception + { + testRun(null, "Ich bin zwei Oeltanks", "UTF-8", true); + testRun(null, "Ich bin zwei Oeltanks", "UTF-8", false); + } + + public void testRealUTF8() + throws Exception + { + testRun(null, "Ich bin zwei \u00d6ltanks", "UTF-8", true); + testRun(null, "Ich bin zwei \u00d6ltanks", "UTF-8", false); + } + + public void testRealUTF8WithBOM() + throws Exception + { + testRun(UnicodeInputStream.UTF8_BOM, "Ich bin ein Test", + "UTF-8", true); + testRun(UnicodeInputStream.UTF8_BOM, "Ich bin ein Test", + "UTF-8", false); + } + + public void testRealUTF16BEWithBOM() + throws Exception + { + testRun(UnicodeInputStream.UTF16BE_BOM, "Ich bin ein Test", + "UTF-16BE", true); + testRun(UnicodeInputStream.UTF16BE_BOM, "Ich bin ein Test", + "UTF-16BE", false); + } + + public void testRealUTF16LEWithBOM() + throws Exception + { + testRun(UnicodeInputStream.UTF16LE_BOM, "Ich bin ein Test", + "UTF-16LE", true); + testRun(UnicodeInputStream.UTF16LE_BOM, "Ich bin ein Test", + "UTF-16LE", false); + } + + public void testRealUTF32BEWithBOM() + throws Exception + { + testRun(UnicodeInputStream.UTF32BE_BOM, null, + "UTF-32BE", true); + testRun(UnicodeInputStream.UTF32BE_BOM, null, + "UTF-32BE", false); + } + + public void testRealUTF32LEWithBOM() + throws Exception + { + testRun(UnicodeInputStream.UTF32LE_BOM, null, + "UTF-32LE", true); + testRun(UnicodeInputStream.UTF32LE_BOM, null, + "UTF-32LE", false); + } + + + protected void testRun(final UnicodeInputStream.UnicodeBOM bom, final String str, final String testEncoding, final boolean skipBOM) + throws Exception + { + + byte [] testString = buildTestString(bom, str, testEncoding, skipBOM); + + InputStream is = null; + UnicodeInputStream uis = null; + + try + { + is = createInputStream(bom, str, testEncoding); + uis = new UnicodeInputStream(is, skipBOM); + + assertEquals("BOM Skipping problem", skipBOM, uis.isSkipBOM()); + + if (bom != null) + { + assertEquals("Wrong Encoding detected", testEncoding, uis.getEncodingFromStream()); + } + + byte [] result = readAllBytes(uis, testEncoding); + + assertNotNull(testString); + assertNotNull(result); + assertEquals("Wrong result length", testString.length, result.length); + + for (int i = 0; i < result.length; i++) + { + assertEquals("Wrong Byte at " + i, testString[i], result[i]); + } + } + finally + { + + if (uis != null) + { + uis.close(); + } + + if (is != null) + { + is.close(); + } + } + } + + protected InputStream createInputStream(final UnicodeInputStream.UnicodeBOM bom, final String str, final String enc) + throws Exception + { + + if (bom == null) + { + if (str != null) + { + return new ByteArrayInputStream(str.getBytes(enc)); + } + else + { + return new ByteArrayInputStream(new byte[0]); + } + } + else + { + if (str != null) + { + return new ByteArrayInputStream(ArrayUtils.addAll(bom.getBytes(), str.getBytes(enc))); + } + else + { + return new ByteArrayInputStream(ArrayUtils.addAll(bom.getBytes(), new byte[0])); + } + } + } + + protected byte [] buildTestString(final UnicodeInputStream.UnicodeBOM bom, final String str, final String enc, final boolean skipBOM) + throws Exception + { + + byte [] strBytes = (str != null) ? str.getBytes(enc) : new byte[0]; + + if ((bom == null) || skipBOM) + { + return strBytes; + } + else + { + return ArrayUtils.addAll(bom.getBytes(), strBytes); + } + } + + protected byte [] readAllBytes(final InputStream inputStream, final String enc) + throws Exception + { + InputStreamReader isr = null; + + byte [] res = new byte[0]; + + try + { + byte[] buf = new byte[1024]; + int read = 0; + + while ((read = inputStream.read(buf)) >= 0) + { + res = ArrayUtils.addAll(res, ArrayUtils.subarray(buf, 0, read)); + } + } + finally + { + + if (isr != null) + { + isr.close(); + } + } + + return res; + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/runtime/RuntimeInstanceTest.java b/velocity-engine-core/src/test/java/org/apache/velocity/runtime/RuntimeInstanceTest.java new file mode 100644 index 00000000..9b88e209 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/runtime/RuntimeInstanceTest.java @@ -0,0 +1,49 @@ +package org.apache.velocity.runtime; + +import static org.junit.Assert.assertEquals; + +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.resource.Resource; +import org.apache.velocity.runtime.resource.ResourceManager; +import org.junit.Test; + +public class RuntimeInstanceTest { + + @Test + public void givenOverridenInputEncoding_whenInitializing_defaultEncodingIsOverridden() { + RuntimeInstance instance = new RuntimeInstance(); + MockResourceManager manager = new MockResourceManager(); + String value = "testDummyEncoding"; + instance.addProperty(RuntimeConstants.INPUT_ENCODING, value); + instance.addProperty(RuntimeConstants.RESOURCE_MANAGER_INSTANCE, manager); + instance.init(); + + instance.getTemplate("some template"); + + assertEquals(value, manager.encoding); + + } + + class MockResourceManager implements ResourceManager { + + String encoding = null; + + @Override + public String getLoaderNameForResource(String resourceName) { + return null; + } + + @Override + public Resource getResource(String resourceName, int resourceType, String encoding) + throws ResourceNotFoundException, ParseErrorException { + this.encoding = encoding; + return null; + } + + @Override + public void initialize(RuntimeServices rs) { + + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/AbsoluteFileResourceLoaderTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/AbsoluteFileResourceLoaderTestCase.java new file mode 100644 index 00000000..abfe75cc --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/AbsoluteFileResourceLoaderTestCase.java @@ -0,0 +1,150 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Test use of an absolute path with the FileResourceLoader + * + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class AbsoluteFileResourceLoaderTestCase extends BaseTestCase +{ + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path to template file. This will get combined with the + * application directory to form an absolute path + */ + private final static String TEMPLATE_PATH = TEST_COMPARE_DIR + "/absolute/absolute"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/absolute/results"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/absolute/compare"; + + /** + * Default constructor. + */ + AbsoluteFileResourceLoaderTestCase() + { + super("AbsoluteFileResourceLoaderTest"); + } + + public static Test suite () + { + return new AbsoluteFileResourceLoaderTestCase(); + } + + /** + * Runs the test. + */ + @Override + public void runTest () + { + + try + { + assureResultsDirectoryExists(RESULTS_DIR); + + Velocity.reset(); + + // signify we want to use an absolute path + Velocity.addProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, ""); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + catch (Exception e) + { + String msg = "Cannot setup AbsoluteFileResourceLoaderTest!"; + info(msg, e); + fail(msg); + } + try + { + + String curdir = System.getProperty("user.dir"); + String f = getFileName(curdir, TEMPLATE_PATH, TMPL_FILE_EXT); + + System.out.println("Retrieving template at absolute path: " + f); + + Template template1 = RuntimeSingleton.getTemplate(f); + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "absolute", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + + /* + * put the Vector into the context, and merge both + */ + VelocityContext context = new VelocityContext(); + + template1.merge(context, writer1); + writer1.flush(); + writer1.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "absolute", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + } + catch (Exception e) + { + fail(e.getMessage()); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/AlternateValuesTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/AlternateValuesTestCase.java new file mode 100644 index 00000000..a141c065 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/AlternateValuesTestCase.java @@ -0,0 +1,61 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Base test case that provides utility methods for + * the rest of the tests. + * + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> + * @author Nathan Bubna + * @version $Id$ + */ +public class AlternateValuesTestCase extends BaseTestCase +{ + public AlternateValuesTestCase(String name) + { + super(name); + } + + public void testDefault() + { + assertEvalEquals("<foo>", "<${foo|'foo'}>"); + assertEvalEquals("bar", "#set($bar='bar')${foo|$bar}"); + assertEvalEquals("bar", "#set($bar='bar')${bar|'foo'}"); + assertEvalEquals("bar", "#set($bar='bar')${foo|${bar}}"); + assertEvalEquals("baz", "${foo|${baz|'baz'}}"); + assertEvalEquals("hop", "${foo.bar.baz()[5]|'hop'}"); + assertEvalEquals("{foo}", "{${foo|'foo'}}"); + assertEvalEquals("<1>", "<${foo|1}>"); + assertEvalEquals("<1.1>", "<${foo|1.1}>"); + } + + public void testComplexEval() + { + assertEvalEquals("<no date tool>", "<${date.format('medium', $date.date)|'no date tool'}>"); + assertEvalEquals("true", "#set($val=false)${val.toString().replace(\"false\", \"true\")|'so what'}"); + assertEvalEquals("so what", "#set($foo='foo')${foo.contains('bar')|'so what'}"); + assertEvalEquals("so what", "#set($val=false)${val.toString().contains('bar')|'so what'}"); + assertEvalEquals("true", "#set($val=false)${val.toString().contains('false')|'so what'}"); + assertEvalEquals("", "$!{null|$null}"); + assertEvalEquals("null", "$!{null|'null'}"); + assertEvalEquals("so what", "#set($spaces=' ')${spaces.trim()|'so what'}"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ArithmeticTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ArithmeticTestCase.java new file mode 100644 index 00000000..3bde4a88 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ArithmeticTestCase.java @@ -0,0 +1,244 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.velocity.runtime.parser.node.MathUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * Test arithmetic operations. Introduced after extending from Integer-only + * to Number-handling. + * + * @author <a href="mailto:pero@antaramusic.de">Peter Romianowski</a> + */ +public class ArithmeticTestCase extends TestCase +{ + + public ArithmeticTestCase(String testName) + { + super(testName); + } + + public static Test suite() + { + return new TestSuite(ArithmeticTestCase.class); + } + + public void testAdd() + { + addHelper (10, (short) 20, 30, Integer.class); + addHelper ((byte) 10, (short) 20, 30, Short.class); + addHelper (10f, (short) 20, 30, Float.class); + addHelper ((byte) 10, 20d, 30, Double.class); + addHelper (BigInteger.valueOf(10), 20, 30, BigInteger.class); + addHelper (20, BigDecimal.valueOf(10), 30, BigDecimal.class); + + // Test overflow + addHelper (Integer.MAX_VALUE, (short) 20, (double)Integer.MAX_VALUE+20, Long.class); + addHelper (20, Long.MAX_VALUE, (double)Long.MAX_VALUE+20, BigInteger.class); + addHelper (-20, Long.MIN_VALUE, (double)Long.MIN_VALUE-20, BigInteger.class); + } + + private void addHelper (Number n1, Number n2, double expectedResult, Class expectedResultType) + { + Number result = MathUtils.add( n1, n2); + assertEquals("The arithmetic operation produced an unexpected result.", expectedResult, result.doubleValue(), 0.01); + assertEquals("ResultType does not match.", expectedResultType, result.getClass()); + } + + public void testSubtract() + { + subtractHelper (100, (short) 20, 80, Integer.class); + subtractHelper ((byte) 100, (short) 20, 80, Short.class); + subtractHelper (100f, (short) 20, 80, Float.class); + subtractHelper ((byte) 100, 20d, 80, Double.class); + subtractHelper (BigInteger.valueOf(100), 20, 80, BigInteger.class); + subtractHelper (100, BigDecimal.valueOf(20), 80, BigDecimal.class); + + // Test overflow + subtractHelper (Integer.MIN_VALUE, (short) 20, (double)Integer.MIN_VALUE-20, Long.class); + subtractHelper(-20, Long.MAX_VALUE, -20d - (double) Long.MAX_VALUE, BigInteger.class); + subtractHelper(Integer.MAX_VALUE, Long.MIN_VALUE, (double) Long.MAX_VALUE + (double) Integer.MAX_VALUE, BigInteger.class); + } + + private void subtractHelper (Number n1, Number n2, double expectedResult, Class expectedResultType) + { + Number result = MathUtils.subtract( n1, n2); + assertEquals("The arithmetic operation produced an unexpected result.", expectedResult, result.doubleValue(), 0.01); + assertEquals("ResultType does not match.", expectedResultType, result.getClass()); + } + + public void testMultiply() + { + multiplyHelper (10, (short) 20, 200, Integer.class); + multiplyHelper ((byte) 100, (short) 20, 2000, Short.class); + multiplyHelper ((byte) 100, (short) 2000, 200000, Integer.class); + multiplyHelper (100f, (short) 20, 2000, Float.class); + multiplyHelper ((byte) 100, 20d, 2000, Double.class); + multiplyHelper (BigInteger.valueOf(100), 20, 2000, BigInteger.class); + multiplyHelper (100, BigDecimal.valueOf(20), 2000, BigDecimal.class); + + // Test overflow + multiplyHelper (Integer.MAX_VALUE, (short) 10, (double)Integer.MAX_VALUE*10d, Long.class); + multiplyHelper(Integer.MAX_VALUE, (short) -10, (double) Integer.MAX_VALUE * -10d, Long.class); + multiplyHelper(20, Long.MAX_VALUE, 20d * (double) Long.MAX_VALUE, BigInteger.class); + } + + private void multiplyHelper (Number n1, Number n2, double expectedResult, Class expectedResultType) + { + Number result = MathUtils.multiply( n1, n2); + assertEquals("The arithmetic operation produced an unexpected result.", expectedResult, result.doubleValue(), 0.01); + assertEquals("ResultType does not match.", expectedResultType, result.getClass()); + } + + public void testDivide() + { + divideHelper (10, (short) 2, 5, Integer.class); + divideHelper ((byte) 10, (short) 2, 5, Short.class); + divideHelper (BigInteger.valueOf(10), (short) 2, 5, BigInteger.class); + divideHelper (10, (short) 4, 2, Integer.class); + divideHelper (10, 2.5f, 4, Float.class); + divideHelper(10, 2.5, 4, Double.class); + divideHelper(10, new BigDecimal(2.5), 4, BigDecimal.class); + } + + private void divideHelper (Number n1, Number n2, double expectedResult, Class expectedResultType) + { + Number result = MathUtils.divide( n1, n2); + assertEquals("The arithmetic operation produced an unexpected result.", expectedResult, result.doubleValue(), 0.01); + assertEquals("ResultType does not match.", expectedResultType, result.getClass()); + } + + public void testModulo() + { + moduloHelper (10, (short) 2, 0, Integer.class); + moduloHelper ((byte) 10, (short) 3, 1, Short.class); + moduloHelper(BigInteger.valueOf(10), (short) 4, 2, BigInteger.class); + moduloHelper(10, 5.5f, 4.5, Float.class); + + try + { + moduloHelper (10, new BigDecimal( 2.5), 4, BigDecimal.class); + fail ("Modulo with BigDecimal is not allowed! Should have thrown an ArithmeticException."); + } + catch( ArithmeticException e) + { + // do nothing + } + } + + private void moduloHelper (Number n1, Number n2, double expectedResult, Class expectedResultType) + { + Number result = MathUtils.modulo( n1, n2); + assertEquals("The arithmetic operation produced an unexpected result.", expectedResult, result.doubleValue(), 0.01); + assertEquals("ResultType does not match.", expectedResultType, result.getClass()); + } + + public void testCompare() + { + compareHelper (10, (short) 10, 0); + compareHelper (10, (short) 11, -1); + compareHelper (BigInteger.valueOf(10), (short) 11, -1); + compareHelper ((byte) 10, (short) 3, 1); + compareHelper(10f, (short) 11, -1); + compareHelper(10d, (short) 11, -1); + } + + private void compareHelper (Number n1, Number n2, int expectedResult) + { + int result = MathUtils.compare( n1, n2 ); + assertEquals("The arithmetic operation produced an unexpected result.", expectedResult, result); + } + + public void testNegate() + { + negateHelper((byte) 1, -1, Byte.class); + negateHelper((short) 1, -1, Short.class); + negateHelper(1, -1, Integer.class); + negateHelper(1L, -1, Long.class); + negateHelper(BigInteger.valueOf(1), -1, BigInteger.class); + negateHelper(BigDecimal.valueOf(1), -1, BigDecimal.class); + negateHelper(Long.MIN_VALUE, BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1)).doubleValue(), BigInteger.class); + } + + private void negateHelper(Number n, double expectedResult, Class expectedResultType) + { + Number result = MathUtils.negate(n); + assertEquals ("The arithmetic operation produced an unexpected result.", expectedResult, result.doubleValue(), 0.01); + assertEquals ("ResultType does not match.", expectedResultType, result.getClass()); + } + +/* + * + * COMMENT OUT FOR PERFORMANCE-MEASSUREMENTS + * + * public void testProfile() + * { + * + * long start = System.currentTimeMillis(); + * + * Number v1 = new Long (1000); + * Number v2 = new Double (10.23); + * Number result = null; + * for (int a = 0; a < 10000; a++) + * { + * + * result = MathUtils.typeConvert ( + * new BigDecimal (v1.doubleValue()).add ( + * new BigDecimal (v2.doubleValue())), v1, v2, false); + * + * } + * + * System.out.println ("took: "+(System.currentTimeMillis()-start)); + * + * start = System.currentTimeMillis(); + * for (int a = 0; a < 10000; a++) + * { + * + * result = MathUtils.divide( v1, v2); + * } + * + * Number result2 = result; + * System.out.println ("took: "+(System.currentTimeMillis()-start)); + * } + * + */ + + /** + * Test additional functions + */ + public void testIsZero() + { + assertTrue (MathUtils.isZero (0)); + assertTrue (!MathUtils.isZero (1)); + assertTrue (!MathUtils.isZero (-1)); + + assertTrue (MathUtils.isZero (0f)); + assertTrue (!MathUtils.isZero (0.00001f)); + assertTrue (!MathUtils.isZero (-0.00001f)); + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ArrayMethodsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ArrayMethodsTestCase.java new file mode 100644 index 00000000..ceb82e80 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ArrayMethodsTestCase.java @@ -0,0 +1,211 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Used to check that method calls on Array references work properly + * and that they produce the same results as the same methods would on + * a fixed-size {@link List}. + */ +public class ArrayMethodsTestCase extends BaseTestCase +{ + public ArrayMethodsTestCase(final String name) + { + super(name); + } + + /** + * Runs the test. + */ + public void testArrayMethods() throws Exception + { + // test an array of string objects + Object array = new String[] { "foo", "bar", "baz" }; + checkResults(array, "woogie", true); + + // test an array of primitive ints + array = new int[] { 1, 3, 7 }; + checkResults(array, 11, false); + + // test an array of mixed objects, including null + array = new Object[] { 2.2, null }; + checkResults(array, "whatever", true); + // then set all the values to null + checkResults(array, null, true); + + // then try an empty array + array = new Object[] {}; + checkResults(array, null, true); + + // while we have an empty array and list in the context, + // make sure $array.get(0) and $list.get(0) throw + // the same type of exception (MethodInvocationException) + Throwable lt = null; + Throwable at = null; + try + { + evaluate("$list.get(0)"); + } + catch (Throwable t) + { + lt = t; + } + try + { + evaluate("$array.get(0)"); + } + catch (Throwable t) + { + at = t; + } + assertEquals(lt.getClass(), at.getClass()); + } + + private void checkResults(Object array, Object setme, + boolean compareToList) throws Exception + { + context.put("array", array); + if (compareToList) + { + // create a list to match... + context.put("list", new ArrayList(Arrays.asList((Object[])array))); + } + + // if the object to be set is null, then remove instead of put + if (setme != null) + { + context.put("setme", setme); + } + else + { + context.remove("setme"); + } + + info("Changing to an array of: " + array.getClass().getComponentType()); + info("Changing setme to: " + setme); + + int size = Array.getLength(array); + checkResult("size()", String.valueOf(size), compareToList); + + boolean isEmpty = (size == 0); + checkResult("isEmpty()", String.valueOf(isEmpty), compareToList); + + checkPropertyResult("empty", String.valueOf(isEmpty), compareToList); + + // Since 2.1, arrays are rendered the same way as lists + String renderArray = evaluate("$array"); + String renderList = evaluate("$list"); + System.err.println("<<< " + renderArray); + System.err.println(">>> " + renderList); + if (compareToList) assertTrue(renderArray.equals(renderList)); + else assertFalse(renderArray.equals(renderList)); + + for (int i=0; i < size; i++) + { + // put the index in the context, so we can try + // both an explicit index and a reference index + context.put("index", i); + + Object value = Array.get(array, i); + String get = "get($index)"; + String set = "set("+i+", $setme)"; + if (value == null) + { + checkEmptyResult(get, compareToList); + // set should return null + checkEmptyResult(set, compareToList); + } + else + { + checkResult(get, value.toString(), compareToList); + // set should return the old get value + checkResult(set, value.toString(), compareToList); + } + + // check that set() actually changed the value + assertEquals(setme, Array.get(array, i)); + + // and check that get() now returns setme + if (setme == null) + { + checkEmptyResult(get, compareToList); + } + else + { + checkResult(get, setme.toString(), compareToList); + + // now check that contains() properly finds the new value + checkResult("contains($setme)", "true", compareToList); + } + } + } + + private void checkEmptyResult(String method, boolean compareToList) + throws Exception + { + checkResult(method, "", compareToList); + } + + private void checkResult(String method, String expected, + boolean compareToList) throws Exception + { + String result = evaluate("$!array."+method); + assertEquals(expected, result); + + String listResult = null; + if (compareToList) + { + listResult = evaluate("$!list."+method); + assertEquals(result, listResult); + } + + info(" <$!array." + method + "> resolved to <" + result + ">"); + if (compareToList) + { + info(" <$!list."+method+"> resolved to "+listResult+">"); + } + } + + private void checkPropertyResult(String property, String expected, + boolean compareToList) throws Exception + { + String result = evaluate("$!array."+property); + assertEquals(expected, result); + + String listResult = null; + if (compareToList) + { + listResult = evaluate("$!list."+property); + assertEquals(result, listResult); + } + + info(" <$!array."+property+"> resolved to <"+result+">"); + if (compareToList) + { + info(" <$!list."+property+"> resolved to "+listResult+">"); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/BaseTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/BaseTestCase.java new file mode 100644 index 00000000..c6456dff --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/BaseTestCase.java @@ -0,0 +1,515 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestCase; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.runtime.resource.util.StringResourceRepository; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Locale; + +/** + * Base test case that provides utility methods for + * the rest of the tests. + * + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> + * @author Nathan Bubna + * @version $Id$ + */ +public abstract class BaseTestCase extends TestCase implements TemplateTestBase +{ + protected VelocityEngine engine; + protected VelocityContext context; + protected boolean DEBUG = Boolean.getBoolean("test.debug"); + protected TestLogger log; + protected String stringRepoName = "string.repo"; + + public BaseTestCase(String name) + { + super(name); + + // if we're just running one case, then have DEBUG + // automatically set to true + String test = System.getProperty("test"); + if (test != null) + { + DEBUG = test.equals(getClass().getSimpleName()); + } + } + + protected VelocityEngine createEngine() + { + VelocityEngine ret = new VelocityEngine(); + ret.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, log); + + // use string resource loader by default, instead of file + ret.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file,string"); + ret.addProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + ret.addProperty("string.resource.loader.repository.name", stringRepoName); + ret.addProperty("string.resource.loader.repository.static", "false"); + + setUpEngine(ret); + return ret; + } + + @Override + protected void setUp() throws Exception + { + //by default, make the engine's log output go to the test-report + log = new TestLogger(false, false); + engine = createEngine(); + context = new VelocityContext(); + setUpContext(context); + } + + protected void setUpEngine(VelocityEngine engine) + { + // extension hook + } + + protected void setUpContext(VelocityContext context) + { + // extension hook + } + + protected StringResourceRepository getStringRepository() + { + StringResourceRepository repo = + (StringResourceRepository)engine.getApplicationAttribute(stringRepoName); + if (repo == null) + { + engine.init(); + repo = + (StringResourceRepository)engine.getApplicationAttribute(stringRepoName); + } + return repo; + } + + protected void addTemplate(String name, String template) + { + info("Template '"+name+"': "+template); + getStringRepository().putStringResource(name, template); + } + + protected void removeTemplate(String name) + { + info("Removed: '"+name+"'"); + getStringRepository().removeStringResource(name); + } + + @Override + public void tearDown() + { + engine = null; + context = null; + } + + protected void info(String msg) + { + info(msg, null); + } + + protected void info(String msg, Throwable t) + { + if (DEBUG) + { + try + { + if (engine == null) + { + Velocity.getLog().info(msg, t); + } + else + { + engine.getLog().info(msg, t); + } + } + catch (Throwable t2) + { + System.out.println("Failed to log: "+msg+(t!=null?" - "+t: "")); + System.out.println("Cause: "+t2); + t2.printStackTrace(); + } + } + } + + /** + * Compare an expected string with the given loaded template + */ + protected void assertTmplEquals(String expected, String template) + { + info("Expected: " + expected + " from '" + template + "'"); + + StringWriter writer = new StringWriter(); + try + { + engine.mergeTemplate(template, "utf-8", context, writer); + } + catch (RuntimeException re) + { + info("RuntimeException!", re); + throw re; + } + catch (Exception e) + { + info("Exception!", e); + throw new RuntimeException(e); + } + + info("Result: " + writer.toString()); + assertEquals(expected, writer.toString()); + } + + /** + * Ensure that a context value is as expected. + */ + protected void assertContextValue(String key, Object expected) + { + info("Expected value of '"+key+"': "+expected); + Object value = context.get(key); + info("Result: "+value); + assertEquals(expected, value); + } + + /** + * Ensure that a template renders as expected. + */ + protected void assertEvalEquals(String expected, String template) + { + info("Expectation: "+expected); + assertEquals(expected, evaluate(template)); + } + + /** + * Ensure that the given string renders as itself when evaluated. + */ + protected void assertSchmoo(String templateIsExpected) + { + assertEvalEquals(templateIsExpected, templateIsExpected); + } + + /** + * Ensure that an exception occurs when the string is evaluated. + */ + protected Exception assertEvalException(String evil) + { + return assertEvalException(evil, null); + } + + /** + * Ensure that a specified type of exception occurs when evaluating the string. + */ + protected Exception assertEvalException(String evil, Class<?> exceptionType) + { + try + { + if (!DEBUG) + { + log.off(); + } + if (exceptionType != null) + { + info("Expectation: "+exceptionType.getName()); + } + else + { + info("Expectation: "+Exception.class.getName()); + } + evaluate(evil); + String msg = "Template '"+evil+"' should have thrown an exception."; + info("Fail: "+msg); + fail(msg); + } + catch (Exception e) + { + if (exceptionType != null && !exceptionType.isAssignableFrom(e.getClass())) + { + String msg = "Was expecting template '"+evil+"' to throw "+exceptionType+" not "+e; + info("Fail: "+msg); + fail(msg); + } + return e; + } + finally + { + if (!DEBUG) + { + log.on(); + } + } + return null; + } + + /** + * Ensure that the error message of the expected exception has the proper location info. + */ + protected Exception assertEvalExceptionAt(String evil, String template, + int line, int col) + { + String loc = template+"[line "+line+", column "+col+"]"; + info("Expectation: Exception at "+loc); + Exception e = assertEvalException(evil); + + info("Result: "+e.getClass().getName()+" - "+e.getMessage()); + if (e.getMessage().indexOf(loc) < 1) + { + fail("Was expecting exception at "+loc+" instead of "+e.getMessage()); + } + return e; + } + + /** + * Only ensure that the error message of the expected exception + * has the proper line and column info. + */ + protected Exception assertEvalExceptionAt(String evil, int line, int col) + { + return assertEvalExceptionAt(evil, "", line, col); + } + + /** + * Evaluate the specified String as a template and return the result as a String. + */ + protected String evaluate(String template) + { + StringWriter writer = new StringWriter(); + try + { + info("Template: "+template); + + // use template as its own name, since our templates are short + // unless it's not that short, then shorten it... + String name = (template.length() <= 15) ? template : template.substring(0,15); + engine.evaluate(context, writer, name, template); + + String result = writer.toString(); + info("Result: "+result); + return result; + } + catch (RuntimeException re) + { + info("RuntimeException!", re); + throw re; + } + catch (Exception e) + { + info("Exception!", e); + throw new RuntimeException(e); + } + } + + /** + * Concatenates the file name parts together appropriately. + * + * @return The full path to the file. + */ + protected String getFileName(final String dir, final String base, final String ext) + { + return getFileName(dir, base, ext, false); + } + + protected String getFileName(final String dir, final String base, final String ext, final boolean mustExist) + { + StringBuilder buf = new StringBuilder(); + try + { + File baseFile = new File(base); + if (dir != null) + { + if (!baseFile.isAbsolute()) + { + baseFile = new File(dir, base); + } + + buf.append(baseFile.getCanonicalPath()); + } + else + { + buf.append(baseFile.getPath()); + } + + if (org.apache.commons.lang3.StringUtils.isNotEmpty(ext)) + { + buf.append('.').append(ext); + } + + if (mustExist) + { + File testFile = new File(buf.toString()); + + if (!testFile.exists()) + { + String msg = "getFileName() result " + testFile.getPath() + " does not exist!"; + info(msg); + fail(msg); + } + + if (!testFile.isFile()) + { + String msg = "getFileName() result " + testFile.getPath() + " is not a file!"; + info(msg); + fail(msg); + } + } + } + catch (IOException e) + { + fail("IO Exception while running getFileName(" + dir + ", " + base + ", "+ ext + ", " + mustExist + "): " + e.getMessage()); + } + + return buf.toString(); + } + + /** + * Assures that the results directory exists. If the results directory + * cannot be created, fails the test. + */ + protected void assureResultsDirectoryExists(String resultsDirectory) + { + File dir = new File(resultsDirectory); + if (!dir.exists()) + { + info("Template results directory ("+resultsDirectory+") does not exist"); + if (dir.mkdirs()) + { + info("Created template results directory"); + if (DEBUG) + { + info("Created template results directory: "+resultsDirectory); + } + } + else + { + String errMsg = "Unable to create '"+resultsDirectory+"'"; + info(errMsg); + fail(errMsg); + } + } + } + + + /** + * Normalizes lines to account for platform differences. Macs use + * a single \r, DOS derived operating systems use \r\n, and Unix + * uses \n. Replace each with a single \n. + * + * @return source with all line terminations changed to Unix style + */ + protected String normalizeNewlines (String source) + { + return source.replaceAll("\r\n?", "\n"); + } + + /** + * Returns whether the processed template matches the + * content of the provided comparison file. + * + * @return Whether the output matches the contents + * of the comparison file. + * + * @exception Exception Test failure condition. + */ + protected boolean isMatch (String resultsDir, + String compareDir, + String baseFileName, + String resultExt, + String compareExt) throws Exception + { + if (DEBUG) + { + info("Result: "+resultsDir+'/'+baseFileName+'.'+resultExt); + } + String result = getFileContents(resultsDir, baseFileName, resultExt); + return isMatch(result,compareDir,baseFileName,compareExt); + } + + + protected String getFileContents(String dir, String baseFileName, String ext) + { + String fileName = getFileName(dir, baseFileName, ext, true); + return getFileContents(fileName); + } + + protected String getFileContents(String file) + { + String contents = null; + + try + { + contents = new String(Files.readAllBytes(Paths.get(file)), StandardCharsets.UTF_8); + } + catch (Exception e) + { + e.printStackTrace(); + } + return contents; + } + + /** + * Returns whether the processed template matches the + * content of the provided comparison file. + * + * @return Whether the output matches the contents + * of the comparison file. + * + * @exception Exception Test failure condition. + */ + protected boolean isMatch (String result, + String compareDir, + String baseFileName, + String compareExt) throws Exception + { + String compare = getFileContents(compareDir, baseFileName, compareExt); + + // normalize each wrt newline + result = normalizeNewlines(result); + compare = normalizeNewlines(compare); + if (DEBUG) + { + info("Expection: "+compareDir+'/'+baseFileName+'.'+compareExt); + } + return result.equals(compare); + } + + /** + * Turns a base file name into a test case name. + * + * @param s The base file name. + * @return The test case name. + */ + protected static String getTestCaseName(String s) + { + StringBuilder name = new StringBuilder(); + name.append(Character.toTitleCase(s.charAt(0))); + name.append(s.substring(1, s.length()).toLowerCase(Locale.ROOT)); + return name.toString(); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/BlockMacroTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/BlockMacroTestCase.java new file mode 100644 index 00000000..8eb3f7b5 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/BlockMacroTestCase.java @@ -0,0 +1,141 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * This class tests the BlockMacro functionality. + */ +public class BlockMacroTestCase extends BaseTestCase +{ + public BlockMacroTestCase(String name) + { + super(name); + } + + public void testMultipleBodyContentIncludes() throws Exception + { + String template = "#macro(foo $txt) Yeah, $txt! $bodyContent $bodyContent#end #@foo(\"woohoo\")jee#end"; + String result = " Yeah, woohoo! jee jee"; + + assertEvalEquals(result, template); + } + + public void testNestedVelocityLogic() throws Exception + { + String template = "#macro(foo $txt) Yeah, $txt! $bodyContent#end #@foo(\"woohoo\")#foreach($i in [1..3])$i:#{end}#end"; + String result = " Yeah, woohoo! 1:2:3:"; + + assertEvalEquals(result, template); + } + + public void testEmptyBody() throws Exception + { + String template = "#macro(foo $txt) Yeah, $txt! $bodyContent#end #@foo(\"woohoo\")#end"; + String result = " Yeah, woohoo! "; + + assertEvalEquals(result, template); + } + + public void testNoArgumentsEmptyBodyCall() throws Exception + { + String template = "#macro(foo) Yeah! $bodyContent#end #@foo()#end"; + String result = " Yeah! "; + + assertEvalEquals(result, template); + } + + public void testCustomBodyReference() throws Exception + { + engine.setProperty(RuntimeConstants.VM_BODY_REFERENCE, "myBody"); + String template = "#macro(foo) Yeah! $myBody#end #@foo()#end"; + String result = " Yeah! "; + + assertEvalEquals(result, template); + } + + public void testVelocity671() throws Exception + { + engine.setProperty(RuntimeConstants.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + String template = "#macro(echo)$bodyContent#end #@echo()Yeah!#end"; + String result = " Yeah!"; + assertEvalEquals(result, template); + } + + public void testStrict() + { + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, true); + assertEvalException("#@foo#end"); + assertEvalException("#@foo()#end"); + } + + public void testVelocity690() + { + assertEvalEquals(" output ", "#macro(foo) output #end#@foo #end"); + assertEvalEquals("#[ output )", "#macro(foo2)#[$bodyContent)#end#@foo2 output #end"); + assertEvalEquals("#[output)", "#macro(foo2)#[$bodyContent)#end#{@foo2}output#end"); + assertEvalException("#macro(foo) output #end#@foo"); + } + + public void testVelocity675() throws Exception + { + assertEvalEquals("#@foo#end", "#@foo#end"); + } + + public void testVelocity685() throws Exception + { + engine.setProperty(RuntimeConstants.VM_ARGUMENTS_STRICT, Boolean.TRUE); + assertEvalEquals(" ", "#macro(foo)#end #@foo() junk #end"); + } + + public void testVelocity686() throws Exception + { + String template = "#macro(foo)#set( $x = $bodyContent )#end"+ + "#@foo()b#end a $x "; + assertEvalEquals(" a b ", template); + } + + public void testNestedBlockMacro() + { + String template = "#macro(foo)foo:$bodyContent#end"+ + "#macro(bar)bar:$bodyContent#end"+ + "#@foo()foo,#@bar()bar#end#end"; + assertEvalEquals("foo:foo,bar:bar", template); + } + + public void testRecursiveBlockMacro() + { + engine.setProperty(RuntimeConstants.VM_MAX_DEPTH, 3); + String template = "#macro(foo)start:$bodyContent#end"+ + "#@foo()call:$bodyContent#end"; + assertEvalEquals("start:call:call:call:$bodyContent", template); + } + + public void testBlueJoesProblem() + { + engine.setProperty("macro."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, Boolean.TRUE); + addTemplate("a", "#macro(wrap $layout)$!macro.put($layout,$bodyContent)#parse($layout)#end"+ + "#@wrap('b')a#end"); + addTemplate("b", "#@wrap('c')b$!macro.get('b')b#end"); + addTemplate("c", "c$!macro.get('c')c"); + assertTmplEquals("cbabc", "a"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/BreakDirectiveTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/BreakDirectiveTestCase.java new file mode 100644 index 00000000..0f0cb616 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/BreakDirectiveTestCase.java @@ -0,0 +1,117 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; + +/** + * This class tests the break directive. + */ +public class BreakDirectiveTestCase extends BaseTestCase +{ + public BreakDirectiveTestCase(String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty("a.provide.scope.control", "true"); + engine.setProperty("define.provide.scope.control", "true"); + engine.setProperty("evaluate.provide.scope.control", "true"); + engine.setProperty("macro.provide.scope.control", "true"); + engine.setProperty("template.provide.scope.control", "true"); + } + + public void testBadArgs() + { + context.put("foo","foo"); + assertEvalException("#break($null)"); + assertEvalException("#break($foo)"); + assertEvalException("#break(true)"); + assertEvalException("#break(1.2)"); + assertEvalException("#break([0..1])"); + assertEvalException("#break( $too $many )"); + } + + public void testStopForeach() + { + String template = "#foreach($i in [1..5])$i#if($i>2)#break($foreach)#end#end test"; + assertEvalEquals("123 test", template); + + // only inner should be stopped, not outer + String t2 = "#foreach($j in [1..2])"+template+"#end"; + assertEvalEquals("123 test123 test", t2); + + // stop outer using #break($foreach.parent) + String t3 = "#foreach($i in [1..2])#foreach($j in [2..3])$i$j#if($i+$j==5)#break($foreach.parent)#end#end test#end"; + assertEvalEquals("1213 test2223", t3); + + // without specifying scope... + assertEvalEquals("1, 2, 3, 4, 5", + "#foreach($i in [1..10])$i#if($i > 4)#break#end, #end"); + assertEvalEquals("1", "#foreach($i in [1..5])$i#break #end"); + assertEvalEquals("~~~, ~~, ~, ", + "#foreach($i in [1..3])#foreach($j in [2..4])#if($i*$j >= 8)#break#end~#end, #end"); + } + + public void testStopTemplate() + { + addTemplate("a", "a#break($template)b"); + assertTmplEquals("a", "a"); + assertEvalEquals("ac", "#parse('a')c"); + + addTemplate("b", "b#{break}a"); + assertTmplEquals("b", "b"); + } + + public void testStopEvaluate() + { + assertEvalEquals("a", "a#break($evaluate)b"); + assertEvalEquals("a", "#evaluate('a#break($evaluate)b')"); + assertEvalEquals("a", "a#evaluate('#break($evaluate.topmost)')b"); + assertEvalEquals("a", "a#{break}b"); + } + + public void testStopDefineBlock() + { + assertEvalEquals("a", "#define($a)a#break($define)b#end$a"); + assertEvalEquals("aa", "#define($a)a#break($define.parent)b#end#define($b)a${a}b#end$b"); + assertEvalEquals("a", "#define($a)a#{break}b#end$a"); + } + + public void testStopMacro() + { + assertEvalEquals("a ", "#macro(a)a #break($macro) b#end#a"); + assertEvalEquals("b c ", "#macro(c)c #break($macro.parent) d#end"+ + "#macro(b)b #c c#end"+ + "#b"); + assertEvalEquals("d", "#macro(d)d#{break}e#end#d"); + } + + public void testStopMacroBodyBlock() + { + assertEvalEquals(" a ", "#macro(a) $bodyContent #end"+ + "#@a()a#break($a)b#end"); + assertEvalEquals(" b ", "#macro(b) $bodyContent #end"+ + "#@b()b#{break}c#end"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java new file mode 100644 index 00000000..c415e476 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/BuiltInEventHandlerTestCase.java @@ -0,0 +1,592 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.app.event.EventCartridge; +import org.apache.velocity.app.event.implement.EscapeHtmlReference; +import org.apache.velocity.app.event.implement.EscapeJavaScriptReference; +import org.apache.velocity.app.event.implement.EscapeReference; +import org.apache.velocity.app.event.implement.EscapeSqlReference; +import org.apache.velocity.app.event.implement.EscapeXmlReference; +import org.apache.velocity.app.event.implement.InvalidReferenceInfo; +import org.apache.velocity.app.event.implement.ReportInvalidReferences; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +/** + * Tests the operation of the built in event handlers. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class BuiltInEventHandlerTestCase extends BaseTestCase { + + protected boolean DEBUG = false; + + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/includeevent"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/includeevent"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/includeevent/compare"; + + /** + * Default constructor. + */ + public BuiltInEventHandlerTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + super.setUp(); + } + + public static Test suite() + { + return new TestSuite(BuiltInEventHandlerTestCase.class); + } + + protected void log(String out) + { + if (DEBUG) + { + System.out.println (out); + } + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportInvalidReferences1() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(2,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + public void testReportInvalidReferences2() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.exception","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 no problem"); + + try { + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar()"); + fail ("Expected exception."); + } catch (RuntimeException E) {} + + + log("Caught invalid references (global configuration)."); + + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportQuietInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.quiet","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(3,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportNullInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.null","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(3,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$n1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportNullQuietInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.quiet","true"); + ve.setProperty("event_handler.invalid_references.null","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(5,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + assertEquals("$n1",((InvalidReferenceInfo) errors.get(3)).getInvalidReference()); + assertEquals("$n1",((InvalidReferenceInfo) errors.get(4)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test reporting of invalid syntax + * @throws Exception + */ + public void testReportTestedInvalidReferences() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty("event_handler.invalid_references.tested","true"); + ReportInvalidReferences reporter = new ReportInvalidReferences(); + ve.init(); + + VelocityContext context = new VelocityContext(); + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(reporter); + ec.attachToContext(context); + + context.put("a1","test"); + context.put("b1","test"); + context.put("n1", null); + Writer writer = new StringWriter(); + + ve.evaluate(context,writer,"test","$a1 $c1 $a1.length() $a1.foobar() $!c1 $n1 $!n1 #if($c1) nop #end"); + + List errors = reporter.getInvalidReferences(); + assertEquals(3,errors.size()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(0)).getInvalidReference()); + assertEquals("$a1.foobar()",((InvalidReferenceInfo) errors.get(1)).getInvalidReference()); + assertEquals("$c1",((InvalidReferenceInfo) errors.get(2)).getInvalidReference()); + + log("Caught invalid references (local configuration)."); + } + + /** + * Test escaping + * @throws Exception + */ + public void testEscapeHtml() throws Exception + { + EscapeReference esc = new EscapeHtmlReference(); + assertEquals("test string&another<b>bold</b>test",esc.referenceInsert(null,"","test string&another<b>bold</b>test")); + assertEquals("<">",esc.referenceInsert(null,"","<\">")); + assertEquals("test string",esc.referenceInsert(null,"","test string")); + + log("Correctly escaped HTML"); + + } + + /** + * Test escaping + * @throws Exception + */ + public void testEscapeXml() throws Exception + { + EscapeReference esc = new EscapeXmlReference(); + assertEquals("test string&another<b>bold</b>test",esc.referenceInsert(null,"","test string&another<b>bold</b>test")); + assertEquals("<">",esc.referenceInsert(null,"","<\">")); + assertEquals("'",esc.referenceInsert(null,"","'")); + assertEquals("test string",esc.referenceInsert(null,"","test string")); + + log("Correctly escaped XML"); + + } + + /** + * Test escaping + * @throws Exception + */ + public void testEscapeSql() throws Exception + { + EscapeReference esc = new EscapeSqlReference(); + assertEquals("Jimmy''s Pizza",esc.referenceInsert(null,"","Jimmy's Pizza")); + assertEquals("test string",esc.referenceInsert(null,"","test string")); + + log("Correctly escaped SQL"); + + } + + /** + * Test escaping + * @throws Exception + */ + public void testEscapeJavaScript() throws Exception + { + EscapeReference esc = new EscapeJavaScriptReference(); + assertEquals("Jimmy\\'s Pizza",esc.referenceInsert(null,"","Jimmy's Pizza")); + assertEquals("test string",esc.referenceInsert(null,"","test string")); + + + log("Correctly escaped Javascript"); + } + + /** + * test that escape reference handler works with no match restrictions + * @throws Exception + */ + public void testEscapeReferenceMatchAll() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.EscapeHtmlReference"); + ve.init(); + + Context context; + Writer writer; + + // test normal reference + context = new VelocityContext(); + writer = new StringWriter(); + context.put("bold","<b>"); + ve.evaluate(context,writer,"test","$bold test & test"); + assertEquals("<b> test & test",writer.toString()); + + // test method reference + context = new VelocityContext(); + writer = new StringWriter(); + context.put("bold","<b>"); + ve.evaluate(context,writer,"test","$bold.substring(0,1)"); + assertEquals("<",writer.toString()); + + log("Escape matched all references (global configuration)"); + + } + + /** + * test that escape reference handler works with match restrictions + * @throws Exception + */ + public void testEscapeReferenceMatch() throws Exception + { + // set up HTML match on everything, JavaScript match on _js* + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, "org.apache.velocity.app.event.implement.EscapeHtmlReference,org.apache.velocity.app.event.implement.EscapeJavaScriptReference"); + ve.setProperty("eventhandler.escape.javascript.match", "/.*_js.*/"); + ve.init(); + + Writer writer; + + // Html no JavaScript + writer = new StringWriter(); + ve.evaluate(newEscapeContext(),writer,"test","$test1"); + assertEquals("Jimmy's <b>pizza</b>",writer.toString()); + + // comment out bad test -- requires latest commons-lang + /* + + // JavaScript and HTML + writer = new StringWriter(); + ve.evaluate(newEscapeContext(),writer,"test","$test1_js"); + assertEquals("Jimmy\\'s <b>pizza</b>",writer.toString()); + + // JavaScript and HTML + writer = new StringWriter(); + ve.evaluate(newEscapeContext(),writer,"test","$test1_js_test"); + assertEquals("Jimmy\\'s <b>pizza</b>",writer.toString()); + + // JavaScript and HTML (method call) + writer = new StringWriter(); + ve.evaluate(newEscapeContext(),writer,"test","$test1_js.substring(0,7)"); + assertEquals("Jimmy\\'s",writer.toString()); + + **/ + + log("Escape selected references (global configuration)"); + + + + } + + private Context newEscapeContext() + { + Context context = new VelocityContext(); + context.put("test1","Jimmy's <b>pizza</b>"); + context.put("test1_js","Jimmy's <b>pizza</b>"); + context.put("test1_js_test","Jimmy's <b>pizza</b>"); + return context; + } + + public void testPrintExceptionHandler() throws Exception + { + VelocityEngine ve1 = new VelocityEngine(); + ve1.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions"); + ve1.init(); + + VelocityEngine ve2 = new VelocityEngine(); + ve2.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions"); + ve2.setProperty("eventhandler.methodexception.templateinfo","true"); + ve2.init(); + + VelocityEngine ve3 = new VelocityEngine(); + ve3.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, "org.apache.velocity.app.event.implement.PrintExceptions"); + ve3.setProperty("eventhandler.methodexception.stacktrace","true"); + ve3.init(); + + Context context; + StringWriter writer; + + context = new VelocityContext(); + context.put("list",new ArrayList()); + + // exception and message only + writer = new StringWriter(); + ve1.evaluate(context, writer, "test", "$list.get(0)"); + String result = writer.toString(); + assertTrue(result.contains("IndexOutOfBoundsException")); + assertTrue( + result.contains("Index: 0, Size: 0") // JDK8 + || result.contains("Index 0 out of bounds for length 0") // JDK 11 / JDK 15 + ); + assertTrue(!result.contains("at test (line 1, column 7)")); + assertFalse( + result.contains("rangeCheck") // JDK 8 + || result.contains("Preconditions.outOfBounds") // JDK 11 / JDK 15 + ); + + // exception, message and template info + writer = new StringWriter(); + ve2.evaluate(context,writer,"test","$list.get(0)"); + result = writer.toString(); + assertTrue(result.contains("IndexOutOfBoundsException")); + assertTrue( + result.contains("Index: 0, Size: 0") // JDK8 + || result.contains("Index 0 out of bounds for length 0") // JDK 11 / JDK 15 + ); + assertTrue(result.contains("at test (line 1, column 7)")); + assertFalse( + result.contains("rangeCheck") // JDK 8 + || result.contains("Preconditions.outOfBounds") // JDK 11 / JDK 15 + ); + + // exception, message and stack trace + writer = new StringWriter(); + ve3.evaluate(context,writer,"test","$list.get(0)"); + result = writer.toString(); + assertTrue(result.contains("IndexOutOfBoundsException")); + assertTrue( + result.contains("Index: 0, Size: 0") // JDK8 + || result.contains("Index 0 out of bounds for length 0") // JDK 11 / JDK 15 + ); + assertTrue(!result.contains("at test (line 1, column 7)")); + assertTrue( + result.contains("rangeCheck") // JDK 8 + || result.contains("Preconditions.outOfBounds") // JDK 11 / JDK 15 + ); + + log("PrintException handler successful."); + + } + + public void testIncludeNotFound() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeNotFound"); + ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + ve.init(); + + Template template; + FileOutputStream fos; + Writer fwriter; + Context context; + + template = ve.getTemplate( getFileName(null, "test6", TMPL_FILE_EXT) ); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, "test6", RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + context = new VelocityContext(); + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test6", RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + + log("IncludeNotFound handler successful."); + + } + + public void testIncludeNotFoundMissingResourceName() throws Exception + { + // uses base test support + engine.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeNotFound"); + addTemplate("notfound.vm", "$missingResource"); + assertEvalEquals("foo", "#parse('foo')"); + } + + public void testIncludeRelativePath() throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, "org.apache.velocity.app.event.implement.IncludeRelativePath"); + ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + ve.init(); + + Template template; + FileOutputStream fos; + Writer fwriter; + Context context; + + template = ve.getTemplate( getFileName(null, "subdir/test2", TMPL_FILE_EXT) ); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + context = new VelocityContext(); + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test2", RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + + log("IncludeRelativePath handler successful."); + + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ClassloaderChangeTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ClassloaderChangeTestCase.java new file mode 100644 index 00000000..096dbe7b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ClassloaderChangeTestCase.java @@ -0,0 +1,169 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.commons.io.IOUtils; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.IntrospectorCache; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.StringWriter; + +/** + * Tests if we can hand Velocity an arbitrary class for logging. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class ClassloaderChangeTestCase extends TestCase +{ + private VelocityEngine ve = null; + private TestLogger logger = null; + + private static String OUTPUT = "Hello From Foo"; + + /** + * Default constructor. + */ + public ClassloaderChangeTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + ve = new VelocityEngine(); + logger = new TestLogger(false, true); + logger.setEnabledLevel(TestLogger.LOG_LEVEL_DEBUG); + ve.setProperty(VelocityEngine.RUNTIME_LOG_INSTANCE, logger); + ve.init(); + } + + public static Test suite () + { + return new TestSuite(ClassloaderChangeTestCase.class); + } + + /** + * Runs the test. + */ + public void testClassloaderChange() + throws Exception + { + logger.on(); + + VelocityContext vc = new VelocityContext(); + Object foo = null; + + /* + * first, we need a classloader to make our foo object + */ + + TestClassloader cl = new TestClassloader(); + Class<?> fooclass = cl.loadClass("Foo"); + foo = fooclass.newInstance(); + + /* + * put it into the context + */ + vc.put("foo", foo); + + /* + * and render something that would use it + * that will get it into the introspector cache + */ + StringWriter writer = new StringWriter(); + ve.evaluate( vc, writer, "test", "$foo.doIt()"); + + /* + * Check to make sure ok. note the obvious + * dependency on the Foo class... + */ + + if ( !writer.toString().equals( OUTPUT )) + { + fail("Output from doIt() incorrect"); + } + + /* + * and do it again :) + */ + cl = new TestClassloader(); + fooclass = cl.loadClass("Foo"); + foo = fooclass.newInstance(); + + vc.put("foo", foo); + + writer = new StringWriter(); + ve.evaluate( vc, writer, "test", "$foo.doIt()"); + + if ( !writer.toString().equals( OUTPUT )) + { + fail("Output from doIt() incorrect"); + } + + if (!logger.getLog().contains(IntrospectorCache.CACHEDUMP_MSG)) + { + fail("Didn't see introspector cache dump."); + } + } + + /** + * Simple (real simple...) classloader that depends + * on a Foo.class being located in the classloader + * directory under test + */ + public static class TestClassloader extends ClassLoader + { + private final static String testclass = + "classloader/Foo.class"; + + private Class<?> fooClass = null; + + public TestClassloader() + throws Exception + { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + InputStream fis = getClass().getResourceAsStream("/" + testclass); + IOUtils.copy(fis, os); + fis.close(); + os.close(); + + byte[] barr = os.toByteArray(); + + fooClass = defineClass("classloader.Foo", barr, 0, barr.length); + } + + + @Override + public Class<?> findClass(String name) + { + return fooClass; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ClasspathResourceTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ClasspathResourceTestCase.java new file mode 100644 index 00000000..41285fab --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ClasspathResourceTestCase.java @@ -0,0 +1,166 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Load templates from the Classpath. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @author <a href="mailto:daveb@miceda-data.com">Dave Bryson</a> + * @version $Id$ + */ +public class ClasspathResourceTestCase extends BaseTestCase +{ + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/cpload"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/cpload/compare"; + + /** + * Default constructor. + */ + public ClasspathResourceTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + Velocity.reset(); + Velocity.setProperty(Velocity.RESOURCE_LOADERS, "classpath"); + + /* + * I don't think I should have to do this, these should + * be in the default config file. + */ + + Velocity.addProperty( + "classpath." + Velocity.RESOURCE_LOADER + ".class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + + Velocity.setProperty( + "classpath." + Velocity.RESOURCE_LOADER + ".cache", "false"); + + Velocity.setProperty( + "classpath." + Velocity.RESOURCE_LOADER + ".modificationCheckInterval", + "2"); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public static Test suite () + { + return new TestSuite(ClasspathResourceTestCase.class); + } + + /** + * Runs the test. + */ + public void testClasspathResource () + throws Exception + { + /* + * lets ensure the results directory exists + */ + assureResultsDirectoryExists(RESULTS_DIR); + + Template template1 = RuntimeSingleton.getTemplate("/includeevent/test1-cp." + TMPL_FILE_EXT); + + // Uncomment when http://jira.codehaus.org/browse/MPTEST-57 has been resolved + // Template template2 = RuntimeSingleton.getTemplate( + // getFileName(null, "template/test2", TMPL_FILE_EXT)); + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "test1", RESULT_FILE_EXT)); + + // Uncomment when http://jira.codehaus.org/browse/MPTEST-57 has been resolved + // FileOutputStream fos2 = + // new FileOutputStream ( + // getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + // Uncomment when http://jira.codehaus.org/browse/MPTEST-57 has been resolved + // Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2)); + + /* + * put the Vector into the context, and merge both + */ + + VelocityContext context = new VelocityContext(); + + template1.merge(context, writer1); + writer1.flush(); + writer1.close(); + + // Uncomment when http://jira.codehaus.org/browse/MPTEST-57 has been resolved + // template2.merge(context, writer2); + // writer2.flush(); + // writer2.close(); + + if (!isMatch(RESULTS_DIR,COMPARE_DIR,"test1",RESULT_FILE_EXT,CMP_FILE_EXT) + // Uncomment when http://jira.codehaus.org/browse/MPTEST-57 has been resolved + // || !isMatch(RESULTS_DIR,COMPARE_DIR,"test2",RESULT_FILE_EXT,CMP_FILE_EXT) + ) + { + fail("Output is incorrect!"); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/CommentsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/CommentsTestCase.java new file mode 100644 index 00000000..39724a64 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/CommentsTestCase.java @@ -0,0 +1,108 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; + +import java.io.StringWriter; + +/** + * Test comments + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class CommentsTestCase extends BaseTestCase +{ + + public static Test suite() + { + return new TestSuite(CommentsTestCase.class); + } + + /** + * Default constructor. + * @param name + */ + public CommentsTestCase(String name) + { + super(name); + } + + + /** + * Test multiline comments + * @throws Exception + */ + public void testMultiLine() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.init(); + + Context context = new VelocityContext(); + StringWriter writer = new StringWriter(); + ve.evaluate(context, writer, "test","abc #* test\r\ntest2*#\r\ndef"); + assertEquals("abc \r\ndef", writer.toString()); + } + + /** + * Test single line comments + * @throws Exception + */ + public void testSingleLine() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.init(); + + Context context = new VelocityContext(); + StringWriter writer = new StringWriter(); + ve.evaluate(context, writer, "test","123 ## test test\r\nabc"); + assertEquals("123 abc", writer.toString()); + + context = new VelocityContext(); + writer = new StringWriter(); + ve.evaluate(context, writer, "test","123 \r\n## test test\r\nabc"); + assertEquals("123 \r\nabc", writer.toString()); + + } + + /** + * Test combined comments + * @throws Exception + */ + public void testCombined() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.init(); + + Context context = new VelocityContext(); + StringWriter writer = new StringWriter(); + ve.evaluate(context, writer, "test","test\r\n## #* *# ${user \r\nabc"); + assertEquals("test\r\nabc", writer.toString()); + + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/CommonsExtPropTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/CommonsExtPropTestCase.java new file mode 100644 index 00000000..200150f6 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/CommonsExtPropTestCase.java @@ -0,0 +1,178 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestSuite; +import org.apache.velocity.util.ExtProperties; + +import java.io.FileWriter; +import java.util.Iterator; +import java.util.Vector; + + +/** + * Tests for the ExtProperties class. This is an identical + * copy of the ConfigurationTestCase, which will disappear when + * the Configuration class does + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class CommonsExtPropTestCase extends BaseTestCase +{ + /** + * Comparison directory. + */ + private static final String COMPARE_DIR = + TEST_COMPARE_DIR + "/configuration/compare"; + + /** + * Results directory. + */ + private static final String RESULTS_DIR = + TEST_RESULT_DIR + "/configuration"; + + /** + * Test configuration + */ + private static final String TEST_CONFIG = + TEST_COMPARE_DIR + "/configuration/test-config.properties"; + + /** + * Creates a new instance. + * + */ + public CommonsExtPropTestCase(String name) + { + super(name); + } + + public static junit.framework.Test suite() + { + return new TestSuite(CommonsExtPropTestCase.class); + } + + /** + * Runs the test. + */ + public void testExtendedProperties () + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + ExtProperties c = new ExtProperties(TEST_CONFIG); + + FileWriter result = new FileWriter( + getFileName(RESULTS_DIR, "output", "res")); + + message(result, "Testing order of keys ..."); + showIterator(result, c.getKeys()); + + message(result, "Testing retrieval of CSV values ..."); + showVector(result, c.getVector("resource.loaders")); + + message(result, "Testing subset(prefix).getKeys() ..."); + ExtProperties subset = c.subset("resource.loader.file"); + showIterator(result, subset.getKeys()); + + message(result, "Testing getVector(prefix) ..."); + showVector(result, subset.getVector("path")); + + message(result, "Testing getString(key) ..."); + result.write(c.getString("config.string.value")); + result.write("\n\n"); + + message(result, "Testing getBoolean(key) ..."); + result.write(Boolean.valueOf(c.getBoolean("config.boolean.value")).toString()); + result.write("\n\n"); + + message(result, "Testing getByte(key) ..."); + result.write(new Byte(c.getByte("config.byte.value")).toString()); + result.write("\n\n"); + + message(result, "Testing getShort(key) ..."); + result.write(new Short(c.getShort("config.short.value")).toString()); + result.write("\n\n"); + + message(result, "Testing getInt(key) ..."); + result.write(new Integer(c.getInt("config.int.value")).toString()); + result.write("\n\n"); + + message(result, "Testing getLong(key) ..."); + result.write(new Long(c.getLong("config.long.value")).toString()); + result.write("\n\n"); + + message(result, "Testing getFloat(key) ..."); + result.write(new Float(c.getFloat("config.float.value")).toString()); + result.write("\n\n"); + + message(result, "Testing getDouble(key) ..."); + result.write(new Double(c.getDouble("config.double.value")).toString()); + result.write("\n\n"); + + message(result, "Testing escaped-comma scalar..."); + result.write( c.getString("escape.comma1")); + result.write("\n\n"); + + message(result, "Testing escaped-comma vector..."); + showVector(result, c.getVector("escape.comma2")); + result.write("\n\n"); + + result.flush(); + result.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "output","res","cmp")) + { + fail("Output incorrect."); + } + } + + private void showIterator(FileWriter result, Iterator i) + throws Exception + { + while(i.hasNext()) + { + result.write((String) i.next()); + result.write("\n"); + } + result.write("\n"); + } + + private void showVector(FileWriter result, Vector v) + throws Exception + { + for (Object aV : v) + { + result.write((String) aV); + result.write("\n"); + } + result.write("\n"); + } + + private void message(FileWriter result, String message) + throws Exception + { + result.write("--------------------------------------------------\n"); + result.write(message + "\n"); + result.write("--------------------------------------------------\n"); + result.write("\n"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ContextAutoreferenceKeyTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ContextAutoreferenceKeyTestCase.java new file mode 100644 index 00000000..f427f4f7 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ContextAutoreferenceKeyTestCase.java @@ -0,0 +1,58 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +/** + * This class tests passing expressions as method arguments + */ + +public class ContextAutoreferenceKeyTestCase extends BaseTestCase +{ + public ContextAutoreferenceKeyTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty(VelocityEngine.CONTEXT_AUTOREFERENCE_KEY, "self"); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("foo", "bar"); + } + + public void testAutoreference() + { + assertEvalEquals("bar", "$foo"); + assertEvalEquals("bar", "$self.foo"); + assertEvalEquals("bar", "$self.self.foo"); + assertEvalEquals("true", "$self.containsKey('foo')"); + assertEvalEquals("false", "$self.containsKey('bar')"); + assertEvalEquals("bar", "$self.put('foo', 'baz')"); + assertEvalEquals("baz", "$foo"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ContextSafetyTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ContextSafetyTestCase.java new file mode 100644 index 00000000..a30c2940 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ContextSafetyTestCase.java @@ -0,0 +1,145 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.Vector; + +/** + * Tests if we are context safe : can we switch objects in the context + * and re-merge the template safely. + * + * NOTE: + * This class should not extend RuntimeTestCase because this test + * is run from the VelocityTestSuite which in effect a runtime + * test suite and the test suite initializes the Runtime. Extending + * RuntimeTestCase causes the Runtime to be initialized twice. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class ContextSafetyTestCase extends BaseTestCase implements TemplateTestBase +{ + public ContextSafetyTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + Velocity.reset(); + Velocity.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public static Test suite() + { + return new TestSuite(ContextSafetyTestCase.class); + } + + /** + * Runs the test. + */ + public void testContextSafety () + throws Exception + { + /* + * make a Vector and String array because + * they are treated differently in Foreach() + */ + Vector<String> v = new Vector(); + + v.addElement("vector hello 1"); + v.addElement( "vector hello 2"); + v.addElement( "vector hello 3"); + + String strArray[] = new String[3]; + + strArray[0] = "array hello 1"; + strArray[1] = "array hello 2"; + strArray[2] = "array hello 3"; + + VelocityContext context = new VelocityContext(); + + assureResultsDirectoryExists(RESULT_DIR); + + /* + * get the template and the output + */ + + Template template = RuntimeSingleton.getTemplate( + getFileName(null, "context_safety", TMPL_FILE_EXT)); + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULT_DIR, "context_safety1", RESULT_FILE_EXT)); + + FileOutputStream fos2 = + new FileOutputStream ( + getFileName(RESULT_DIR, "context_safety2", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2)); + + /* + * put the Vector into the context, and merge + */ + + context.put("vector", v); + template.merge(context, writer1); + writer1.flush(); + writer1.close(); + + /* + * now put the string array into the context, and merge + */ + + context.put("vector", strArray); + template.merge(context, writer2); + writer2.flush(); + writer2.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,"context_safety1", + RESULT_FILE_EXT,CMP_FILE_EXT) || + !isMatch(RESULT_DIR,COMPARE_DIR,"context_safety2", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/DefineTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/DefineTestCase.java new file mode 100755 index 00000000..1c66ced8 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/DefineTestCase.java @@ -0,0 +1,120 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + + +/** + * This class tests the #define directive + */ +public class DefineTestCase extends BaseTestCase +{ + public DefineTestCase(String name) + { + super(name); + } + + protected String defAndEval(String block) + { + return defAndEval("def", block); + } + + protected String defAndEval(String key, String block) + { + return evaluate("#define( $"+key+" )"+block+"#end$"+key); + } + + public void testSimple() + { + assertEquals("abc", defAndEval("abc")); + assertEvalEquals("abc abc abc", "#define( $a )abc#end$a $a $a"); + } + + public void testNotSimple() + { + assertEquals("true", defAndEval("#if( $def )true#end")); + assertEquals("123", defAndEval("#foreach( $i in [1..3] )$i#end")); + assertEquals("hello world", defAndEval("#macro( test )hello world#end#test()")); + } + + public void testOverridingDefinitionInternally() + { + assertEvalEquals("truefalse", "#define( $or )true#set( $or = false )#end$or$or"); + } + + public void testLateBinding() + { + context.put("baz", "foo"); + assertEvalEquals("foobar", "#define( $lb )$baz#end${lb}#set( $baz = 'bar' )${lb}"); + } + + public void testRerendering() + { + context.put("inc", new Inc()); + assertEvalEquals("1 2 3", "#define( $i )$inc#end$i $i $i"); + } + + public void testAssignation() + { + assertEvalEquals("[][hello]","#define( $orig )hello#end[#set( $assig = $orig )][$assig]"); + } + + public void testNonRenderingUsage() + { + String template = "#define($foo)\n" + + " foo_contents\n" + + "#end\n" + + "#if ($foo)\n" + + " found foo\n" + + "#end"; + assertEvalEquals(" found foo\n", template); + } + + public void testRecursionLimit() + { + try + { + assertEvalEquals("$r", "#define( $r )$r#end$r"); + } + catch (Exception t) + { + fail("Recursion should not have thrown an exception"); + } + catch (Error e) + { + fail("Infinite recursion should not be possible."); + } + } + + public void testThingsOfQuestionableMorality() + { + // redefining $foo within $foo + assertEquals("foobar", defAndEval("foo", "foo#define( $foo )bar#end$foo")); + } + + + public static class Inc + { + int foo = 1; + public String toString() + { + return String.valueOf(foo++); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/EncodingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/EncodingTestCase.java new file mode 100644 index 00000000..bc056222 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/EncodingTestCase.java @@ -0,0 +1,208 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; + +/** + * Tests input encoding handling. The input target is UTF-8, having + * chinese and and a spanish enyay (n-twiddle) + * + * Thanks to Kent Johnson for the example input file. + * + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class EncodingTestCase extends BaseTestCase implements TemplateTestBase +{ + public EncodingTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + Velocity.reset(); + + Velocity.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + Velocity.setProperty( Velocity.INPUT_ENCODING, "UTF-8" ); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public static Test suite() + { + return new TestSuite(EncodingTestCase.class); + } + + /** + * Runs the test. + */ + public void testChineseEncoding () + throws Exception + { + VelocityContext context = new VelocityContext(); + + assureResultsDirectoryExists(RESULT_DIR); + + /* + * get the template and the output + */ + + /* + * Chinese and spanish + */ + + Template template = Velocity.getTemplate( + getFileName(null, "encodingtest", TMPL_FILE_EXT), "UTF-8"); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULT_DIR, "encodingtest", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8)); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,"encodingtest", + RESULT_FILE_EXT,CMP_FILE_EXT) ) + { + fail("Output 1 incorrect."); + } + } + + public void testHighByteChinese() + throws Exception + { + VelocityContext context = new VelocityContext(); + + assureResultsDirectoryExists(RESULT_DIR); + + /* + * a 'high-byte' chinese example from Michael Zhou + */ + + Template template = Velocity.getTemplate( + getFileName( null, "encodingtest2", TMPL_FILE_EXT), "UTF-8"); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULT_DIR, "encodingtest2", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos, StandardCharsets.UTF_8)); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,"encodingtest2", + RESULT_FILE_EXT,CMP_FILE_EXT) ) + { + fail("Output 2 incorrect."); + } + + } + + public void testHighByteChinese2() + throws Exception + { + VelocityContext context = new VelocityContext(); + + assureResultsDirectoryExists(RESULT_DIR); + + /* + * a 'high-byte' chinese from Ilkka + */ + + Template template = Velocity.getTemplate( + getFileName( null, "encodingtest3", TMPL_FILE_EXT), "GBK"); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULT_DIR, "encodingtest3", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos, "GBK")); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,"encodingtest3", + RESULT_FILE_EXT,CMP_FILE_EXT) ) + { + fail("Output 3 incorrect."); + } + } + + public void testRussian() + throws Exception + { + VelocityContext context = new VelocityContext(); + + assureResultsDirectoryExists(RESULT_DIR); + + /* + * Russian example from Vitaly Repetenko + */ + + Template template = Velocity.getTemplate( + getFileName( null, "encodingtest_KOI8-R", TMPL_FILE_EXT), "KOI8-R"); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULT_DIR, "encodingtest_KOI8-R", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos, "KOI8-R")); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,"encodingtest_KOI8-R", + RESULT_FILE_EXT,CMP_FILE_EXT) ) + { + fail("Output 4 incorrect."); + } + } +} + + + diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/EvaluateTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/EvaluateTestCase.java new file mode 100644 index 00000000..fc5c1d1b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/EvaluateTestCase.java @@ -0,0 +1,299 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.app.event.implement.EscapeHtmlReference; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; + +/** + * Test #evaluate directive. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class EvaluateTestCase extends BaseTestCase +{ + + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/evaluate"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/evaluate"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/evaluate/compare"; + + /** + * Default constructor. + * @param name + */ + public EvaluateTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + assureResultsDirectoryExists(RESULTS_DIR); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + // extension hook + } + + + /** + * Test basic functionality. + * @throws Exception + */ + public void testEvaluate() + throws Exception + { + Map props = new HashMap(); + testFile("eval1", props); + } + + /** + * Test evaluate directive preserves macros (VELOCITY-591) + * @throws Exception + */ + public void testEvaluateMacroPreserve() + throws Exception + { + Map properties = new HashMap(); + testFile("eval2", properties); + + properties.put(RuntimeConstants.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL,"false"); + testFile("eval2", properties); + } + + /** + * Test in a macro context. + * @throws Exception + */ + public void testEvaluateVMContext() + throws Exception + { + testFile("evalvmcontext", new HashMap()); + } + + /** + * Test #stop and #break + * @throws Exception + */ + public void testStopAndBreak() + { + engine.setProperty("evaluate.provide.scope.control", "true"); + assertEvalEquals("t ", "t #stop t2 #evaluate('t3')"); + assertEvalEquals("t ", "t #break t2 #evaluate('t3')"); + assertEvalEquals("t t2 t3 ", "t t2 #evaluate('t3 #stop t4') t5"); + assertEvalEquals("t t2 t3 t5", "t t2 #evaluate('t3 #break t4') t5"); + assertEvalEquals("t t2 t3 ", "t t2 #evaluate('t3 #break($evaluate.topmost) t4') t5"); + } + + /** + * Test that the event handlers work in #evaluate (since they are + * attached to the context). Only need to check one - they all + * work the same. + * @throws Exception + */ + public void testEventHandler() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, EscapeHtmlReference.class.getName()); + ve.init(); + + Context context = new VelocityContext(); + context.put("lt","<"); + context.put("gt",">"); + StringWriter writer = new StringWriter(); + ve.evaluate(context, writer, "test","${lt}test${gt} #evaluate('${lt}test2${gt}')"); + assertEquals("<test> <test2>", writer.toString()); + + } + + + /** + * Test errors are thrown + * @throws Exception + */ + public void testErrors() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.init(); + + Context context = new VelocityContext(); + + // no arguments + StringWriter writer = new StringWriter(); + try + { + ve.evaluate(context, writer, "test", + "#evaluate()"); + fail("Expected exception"); + } + catch (ParseErrorException e) + { + assertEquals("test",e.getTemplateName()); + assertEquals(1,e.getLineNumber()); + assertEquals(1,e.getColumnNumber()); + } + + // too many arguments + writer = new StringWriter(); + try + { + ve.evaluate(context, writer, "test", + "#evaluate('aaa' 'bbb')"); + fail("Expected exception"); + } + catch (ParseErrorException e) + { + assertEquals("test",e.getTemplateName()); + assertEquals(1,e.getLineNumber()); + assertEquals(17,e.getColumnNumber()); + } + + // argument not a string or reference + writer = new StringWriter(); + try + { + ve.evaluate(context, writer, "test", + "#evaluate(10)"); + fail("Expected exception"); + } + catch (ParseErrorException e) + { + assertEquals("test",e.getTemplateName()); + assertEquals(1,e.getLineNumber()); + assertEquals(11,e.getColumnNumber()); + } + + // checking line/col for parse error + writer = new StringWriter(); + try + { + String eval = "this is a multiline\n\n\n\n\n test #foreach() with an error"; + context.put("eval",eval); + ve.evaluate(context, writer, "test", + "first line\n second line: #evaluate($eval)"); + fail("Expected exception"); + } + catch (ParseErrorException e) + { + // should be start of #evaluate + assertEquals("test",e.getTemplateName()); + assertEquals(2,e.getLineNumber()); + assertEquals(15,e.getColumnNumber()); + } + } + + /** + * Test a file parses with no errors and compare to existing file. + * @param basefilename + * @throws Exception + */ + private void testFile(String basefilename, Map<String, Object> properties) + throws Exception + { + info("Test file: "+basefilename); + VelocityEngine ve = engine; + ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + for (String key : properties.keySet()) + { + String value = (String) properties.get(key); + ve.addProperty(key, value); + info("Add property: " + key + " = " + value); + } + + ve.init(); + + Template template; + FileOutputStream fos; + Writer fwriter; + + template = ve.getTemplate( getFileName(null, basefilename, TMPL_FILE_EXT) ); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, basefilename, RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, basefilename, RESULT_FILE_EXT, CMP_FILE_EXT)) + { + String result = getFileContents(RESULTS_DIR, basefilename, RESULT_FILE_EXT); + String compare = getFileContents(COMPARE_DIR, basefilename, CMP_FILE_EXT); + + String msg = "Output was incorrect\n"+ + "-----Result-----\n"+ result + + "----Expected----\n"+ compare + + "----------------"; + + fail(msg); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/EventHandlingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/EventHandlingTestCase.java new file mode 100644 index 00000000..ef3bfcdf --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/EventHandlingTestCase.java @@ -0,0 +1,271 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.event.EventCartridge; +import org.apache.velocity.app.event.MethodExceptionEventHandler; +import org.apache.velocity.app.event.ReferenceInsertionEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.util.ContextAware; +import org.apache.velocity.util.RuntimeServicesAware; +import org.apache.velocity.util.introspection.Info; + +/** + * Tests event handling for all event handlers except IncludeEventHandler. This is tested + * separately due to its complexity. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class EventHandlingTestCase extends BaseTestCase +{ + private static String NO_REFERENCE_VALUE = "<no reference value>"; + private static String REFERENCE_VALUE = "<reference value>"; + + public EventHandlingTestCase(String name) + { + super(name); + } + + public void testManualEventHandlers() + throws Exception + { + TestEventCartridge te = new TestEventCartridge(); + /* + * Test attaching the event cartridge to the context. + * Make an event cartridge, register all the + * event handlers (at once) and attach it to the + * Context + */ + + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(te); + ec.attachToContext(context); + + /* + * now wrap the event cartridge - we want to make sure that + * we can do this w/o harm + */ + doTestReferenceInsertionEventHandler1(); + doTestReferenceInsertionEventHandler2(); + doTestMethodExceptionEventHandler1(); + doTestMethodExceptionEventHandler2(); + } + + /** + * Test assigning the event handlers via properties + */ + public void testConfigurationEventHandlers() + throws Exception + { + engine.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, TestEventCartridge.class.getName()); + engine.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, TestEventCartridge.class.getName()); + + doTestReferenceInsertionEventHandler1(); + doTestReferenceInsertionEventHandler2(); + doTestMethodExceptionEventHandler1(); + doTestMethodExceptionEventHandler2(); + } + + /** + * Test all the event handlers using the given engine. + */ + private void doTestReferenceInsertionEventHandler1() + throws Exception + { + VelocityContext outer = context; + context = new VelocityContext(context); + context.put("name", "Velocity"); + + /* + * First, the reference insertion handler + */ + String expected = REFERENCE_VALUE + REFERENCE_VALUE + REFERENCE_VALUE; + assertEvalEquals(expected, "$name$name$name"); + + context = outer; + } + + private void doTestReferenceInsertionEventHandler2() + throws Exception + { + VelocityContext outer = context; + context = new VelocityContext(context); + context.put("name", "Velocity"); + + /* + * using the same handler, we can deal with + * null references as well + */ + assertEvalEquals(NO_REFERENCE_VALUE, "$floobie"); + + context = outer; + } + + private void doTestMethodExceptionEventHandler1() + throws Exception + { + VelocityContext outer = context; + context = new VelocityContext(context); + + /* + * finally, we test a method exception event - we do this + * by putting this class in the context, and calling + * a method that does nothing but throw an exception. + * we use flag in the context to turn the event handling + * on and off + * + * Note also how the reference insertion process + * happens as well + */ + context.put("allow_exception",Boolean.TRUE); + context.put("this", this ); + + evaluate(" $this.throwException()"); + + context = outer; + } + + private void doTestMethodExceptionEventHandler2() + throws Exception + { + VelocityContext outer = context; + context = new VelocityContext(context); + context.put("this", this ); + + /* + * now, we remove the exception flag, and we can see that the + * exception will propgate all the way up here, and + * wil be caught by the catch() block below + */ + assertEvalException("$this.throwException()", MethodInvocationException.class); + + context = outer; + } + + /** + * silly method to throw an exception to test + * the method invocation exception event handling + */ + public void throwException() + throws Exception + { + throw new Exception("Hello from throwException()"); + } + + + + public static class TestEventCartridge + implements ReferenceInsertionEventHandler, + MethodExceptionEventHandler, + RuntimeServicesAware,ContextAware + { + private RuntimeServices rs; + + /** + * Required by EventHandler + */ + @Override + public void setRuntimeServices(RuntimeServices rs ) + { + // make sure this is only called once + if (this.rs == null) + this.rs = rs; + + else + fail("initialize called more than once."); + } + + /** + * Event handler for when a reference is inserted into the output stream. + */ + @Override + public Object referenceInsert(Context context, String reference, Object value ) + { + // as a test, make sure this EventHandler is initialized + if (rs == null) + fail ("Event handler not initialized!"); + + + /* + * if we have a value + * return a known value + */ + String s = null; + + if( value != null ) + { + s = REFERENCE_VALUE; + } + else + { + /* + * we only want to deal with $floobie - anything + * else we let go + */ + if ( reference.equals("$floobie") ) + { + s = NO_REFERENCE_VALUE; + } + } + return s; + } + + /** + * Handles exceptions thrown during in-template method access + */ + @Override + public Object methodException(Context context, Class claz, String method, Exception e, Info info ) + { + // as a test, make sure this EventHandler is initialized + if (rs == null) + fail ("Event handler not initialized!"); + + // only do processing if the switch is on + if (context != null) + { + boolean exceptionSwitch = context.containsKey("allow_exception"); + + if( exceptionSwitch && method.equals("throwException")) + { + return "handler"; + } + else + throw new RuntimeException(e); + + } else + + throw new RuntimeException(e); + } + + Context context; + + + @Override + public void setContext(Context context) + { + this.context = context; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ExceptionTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ExceptionTestCase.java new file mode 100644 index 00000000..b555e1bc --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ExceptionTestCase.java @@ -0,0 +1,171 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.ExceptionGeneratingDirective; +import org.apache.velocity.test.misc.ExceptionGeneratingEventHandler; +import org.apache.velocity.test.misc.ExceptionGeneratingResourceLoader; +import org.apache.velocity.test.provider.TestProvider; + +import java.io.StringWriter; + +/** + * Test case for miscellaneous Exception related issues. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class ExceptionTestCase extends BaseTestCase implements TemplateTestBase +{ + VelocityEngine ve; + + /** + * Default constructor. + */ + public ExceptionTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(ExceptionTestCase.class); + } + + + public void testReferenceInsertionEventHandlerException() + throws Exception + { + ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION,ExceptionGeneratingEventHandler.class.getName()); + ve.init(); + assertException(ve); + } + + /** + * Note - this is the one case where RuntimeExceptions *are not* passed through + * verbatim. + * @throws Exception + */ + public void testMethodExceptionEventHandlerException() + throws Exception + { + ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION,ExceptionGeneratingEventHandler.class.getName()); + ve.init(); + Context context = new VelocityContext(); + context.put ("test",new TestProvider()); + assertMethodInvocationException(ve,context,"$test.getThrow()"); + assertMethodInvocationException(ve,context,"$test.throw"); + } + + public void testIncludeEventHandlerException() + throws Exception + { + ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE,ExceptionGeneratingEventHandler.class.getName()); + ve.init(); + assertException(ve,"#include('dummy')"); + } + + public void testResourceLoaderException() + throws Exception + { + ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.RESOURCE_LOADERS,"except"); + ve.setProperty("except.resource.loader.class",ExceptionGeneratingResourceLoader.class.getName()); + try + { + ve.init(); // tries to get the macro file + ve.getTemplate("test.txt"); + fail("Should have thrown RuntimeException"); + } + catch (RuntimeException E) + { + // do nothing + } + } + + + public void testDirectiveException() + throws Exception + { + ve = new VelocityEngine(); + ve.setProperty("userdirective",ExceptionGeneratingDirective.class.getName()); + ve.init(); + assertException(ve,"#Exception() test #end"); + } + + + + public void assertException(VelocityEngine ve) + throws Exception + { + Context context = new VelocityContext(); + context.put ("test","test"); + assertException(ve,context,"this is a $test"); + } + + public void assertException(VelocityEngine ve, String input) + throws Exception + { + Context context = new VelocityContext(); + context.put ("test","test"); + assertException(ve,context,input); + } + + public void assertException(VelocityEngine ve, Context context, String input) + throws Exception + { + try + { + StringWriter writer = new StringWriter(); + ve.evaluate(context,writer,"test",input); + fail("Expected RuntimeException"); + } + catch (RuntimeException E) + { + // do nothing + } + } + public void assertMethodInvocationException(VelocityEngine ve, Context context, String input) + throws Exception + { + try + { + StringWriter writer = new StringWriter(); + ve.evaluate(context,writer,"test",input); + fail("Expected MethodInvocationException"); + } + catch (MethodInvocationException E) + { + // do nothing + } + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ExpressionAsMethodArgumentTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ExpressionAsMethodArgumentTestCase.java new file mode 100644 index 00000000..2816799a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ExpressionAsMethodArgumentTestCase.java @@ -0,0 +1,56 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; + +/** + * This class tests passing expressions as method arguments + */ + +public class ExpressionAsMethodArgumentTestCase extends BaseTestCase +{ + public ExpressionAsMethodArgumentTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("tool",new MyAbsTool()); + context.put("foo",2); + context.put("bar",-3); + } + + public void testExpressionAsMethod() + { + assertEvalEquals("6","$tool.abs( $foo * $bar )"); + assertEvalEquals("12","$tool.abs( $foo * $tool.abs( $foo * $bar ) )"); + } + + public static class MyAbsTool + { + public int abs(int num) + { + return Math.abs(num); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/FilteredEventHandlingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/FilteredEventHandlingTestCase.java new file mode 100644 index 00000000..e56fa733 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/FilteredEventHandlingTestCase.java @@ -0,0 +1,238 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; + +/** + * Tests event handling for all event handlers when multiple event handlers are + * assigned for each type. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class FilteredEventHandlingTestCase extends BaseTestCase +{ + + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/includeevent"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/includeevent"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/includeevent/compare"; + + + private TestLogger logger = new TestLogger(false, false); + + /** + * Default constructor. + */ + public FilteredEventHandlingTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(FilteredEventHandlingTestCase.class); + } + + public void testFilteredEventHandling() throws Exception + { + String handler1 = "org.apache.velocity.test.eventhandler.Handler1"; + String handler2 = "org.apache.velocity.test.eventhandler.Handler2"; + String sequence1 = handler1 + "," + handler2; + String sequence2 = handler2 + "," + handler1; + + assureResultsDirectoryExists(RESULTS_DIR); + + /* + * Set up two VelocityEngines that will apply the handlers in both orders + */ + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + ve.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, sequence1); + ve.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, sequence1); + ve.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, sequence1); + ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + ve.init(); + + VelocityEngine ve2 = new VelocityEngine(); + ve2.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + ve2.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, sequence2); + ve2.setProperty(RuntimeConstants.EVENTHANDLER_REFERENCEINSERTION, sequence2); + ve2.setProperty(RuntimeConstants.EVENTHANDLER_INCLUDE, sequence2); + ve2.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + ve2.init(); + + VelocityContext context; + StringWriter w; + + + // check reference insertion with both sequences + context = new VelocityContext(); + w = new StringWriter(); + context.put("test","abc"); + ve.evaluate( context, w, "test", "$test" ); + if ( !w.toString().equals( "ABCABC" )) + { + fail( "Reference insertion test 1"); + } + + context = new VelocityContext(); + w = new StringWriter(); + context.put("test","abc"); + ve2.evaluate( context, w, "test", "$test" ); + if ( !w.toString().equals( "ABCabc" )) + { + fail( "Reference insertion test 2"); + } + + // check method exception with both sequences + + // sequence 1 + context = new VelocityContext(); + w = new StringWriter(); + context.put("test",new ArrayList()); + + try + { + ve.evaluate( context, w, "test", "$test.get(0)"); + fail ( "Method exception event test 1" ); + } + catch( MethodInvocationException mee ) + { + // do nothing + } + + // sequence2 + context = new VelocityContext(); + w = new StringWriter(); + context.put("test",new ArrayList()); + + ve2.evaluate( context, w, "test", "$test.get(0)"); + + // check log on null set with both sequences + // sequence 1 + context = new VelocityContext(); + w = new StringWriter(); + logger.startCapture(); + ve.evaluate( context, w, "test", "#set($test1 = $test2)" ); + String log = logger.getLog(); + if ( log != null && log.length() > 0) + { + fail( "log null set test 1"); + } + + // sequence 2 + context = new VelocityContext(); + w = new StringWriter(); + logger.startCapture(); + ve2.evaluate( context, w, "test", "#set($test1 = $test2)" ); + log = logger.getLog(); + if ( log != null && log.length() > 0) + { + fail( "log null set test 2"); + } + + logger.stopCapture(); + + // check include event handler with both sequences + + // sequence 1 + Template template; + FileOutputStream fos; + Writer fwriter; + + template = ve.getTemplate( getFileName(null, "test4", TMPL_FILE_EXT) ); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, "test4", RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + context = new VelocityContext(); + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test4", RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + + // sequence 2 + template = ve2.getTemplate( getFileName(null, "test5", TMPL_FILE_EXT) ); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, "test5", RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + context = new VelocityContext(); + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test5", RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ForeachTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ForeachTestCase.java new file mode 100644 index 00000000..2e495843 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ForeachTestCase.java @@ -0,0 +1,147 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.provider.ForeachMethodCallHelper; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * This class tests the Foreach loop. + * + * @author Daniel Rall + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + */ +public class ForeachTestCase extends BaseTestCase +{ + public ForeachTestCase(String name) + { + super(name); + } + + /** + * Tests limiting of the number of loop iterations. + */ + public void testMaxNbrLoopsConstraint() + throws Exception + { + // Limit the loop to three iterations. + engine.setProperty(RuntimeConstants.MAX_NUMBER_LOOPS, + 3); + + assertEvalEquals("1 2 3 ", "#foreach ($item in [1..10])$item #end"); + } + + /** + * Tests proper method execution during a Foreach loop over a Collection + * with items of varying classes. + */ + public void testCollectionAndMethodCall() + throws Exception + { + List col = new ArrayList(); + col.add(100); + col.add("STRVALUE"); + context.put("helper", new ForeachMethodCallHelper()); + context.put("col", col); + + assertEvalEquals("int 100 str STRVALUE ", "#foreach ( $item in $col )$helper.getFoo($item) #end"); + } + + /** + * Tests that #foreach will be able to retrieve an iterator from + * an arbitrary object that happens to have an iterator() method. + * (With the side effect of supporting the new Java 5 Iterable interface) + */ + public void testObjectWithIteratorMethod() + throws Exception + { + context.put("iterable", new MyIterable()); + + assertEvalEquals("1 2 3 ", "#foreach ($i in $iterable)$i #end"); + } + + public void testNotReallyIterableIteratorMethod() + throws Exception + { + context.put("nri", new NotReallyIterable()); + + assertEvalEquals("", "#foreach ($i in $nri)$i #end"); + } + + public void testVelocityHasNextProperty() + throws Exception + { + List list = new ArrayList(); + list.add("test1"); + list.add("test2"); + list.add("test3"); + context.put("list", list); + assertEvalEquals("test1 SEPARATOR test2 SEPARATOR test3 ", "#foreach ($value in $list)$value #if( $foreach.hasNext )SEPARATOR #end#end"); + } + + public void testNestedVelocityHasNextProperty() + throws Exception + { + List list = new ArrayList(); + list.add("test1"); + list.add("test2"); + list.add("test3"); + list.add("test4"); + context.put("list", list); + List list2 = new ArrayList(); + list2.add("a1"); + list2.add("a2"); + list2.add("a3"); + context.put("list2", list2); + + assertEvalEquals("test1 (a1;a2;a3)-test2 (a1;a2;a3)-test3 (a1;a2;a3)-test4 (a1;a2;a3)", "#foreach ($value in $list)$value (#foreach ($val in $list2)$val#if( $foreach.hasNext );#end#end)#if( $foreach.hasNext )-#end#end"); + } + + public static class MyIterable + { + private List foo; + + public MyIterable() + { + foo = new ArrayList(); + foo.add(1); + foo.add(2L); + foo.add("3"); + } + + public Iterator iterator() + { + return foo.iterator(); + } + } + + public static class NotReallyIterable + { + public Object iterator() + { + return new Object(); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java new file mode 100644 index 00000000..776f0b43 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/GetAsTestCase.java @@ -0,0 +1,145 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.util.TemplateBoolean; +import org.apache.velocity.util.TemplateNumber; +import org.apache.velocity.util.TemplateString; + +/** + * Test objects with getAs<Type>() methods. + */ +public class GetAsTestCase extends BaseTestCase +{ + public GetAsTestCase(final String name) + { + super(name); + } + + public void testCustomString() + { + // render + context.put("foo", new CustomString("getAsString")); + assertEvalEquals("getAsString", "$foo"); + // aborted value + context.put("bar", new CustomString(null)); + assertEvalEquals("", "$!bar"); + // concatenation + context.put("half", new CustomString("half")); + assertEvalEquals("1half", "#set( $out = 1 + $half )$out"); + } + + public void testCustomBoolean() + { + context.put("foo", new CustomBoolean(false)); + assertEvalEquals("right", "#if( !$foo )right#end"); + } + + public void testCustomNumber() + { + context.put("foo", new CustomNumber(7)); + assertEvalEquals("14", "#set( $bar = $foo * 2 )$bar"); + } + + + public void testTemplateString() + { + context.put("foo", new CustomTemplateString("getAsString")); + assertEvalEquals("getAsString", "$foo"); + } + + public void testTemplateBoolean() + { + context.put("foo", new CustomTemplateBoolean(false)); + assertEvalEquals("right", "#if( !$foo )right#end"); + } + + public void testTemplateNumber() + { + context.put("foo", new CustomTemplateNumber(5)); + assertEvalEquals("25", "#set( $foo = $foo * $foo )$foo"); + } + + + + public static class CustomString + { + String string; + public CustomString(String string) + { + this.string = string; + } + public String getAsString() + { + return string; + } + } + + public static class CustomBoolean + { + boolean bool; + public CustomBoolean(boolean bool) + { + this.bool = bool; + } + public boolean getAsBoolean() + { + return bool; + } + } + + public static class CustomNumber + { + Number num; + public CustomNumber(Number num) + { + this.num = num; + } + public Number getAsNumber() + { + return num; + } + } + + public static class CustomTemplateString extends CustomString implements TemplateString + { + public CustomTemplateString(String string) + { + super(string); + } + } + + public static class CustomTemplateBoolean extends CustomBoolean implements TemplateBoolean + { + public CustomTemplateBoolean(Boolean bool) + { + super(bool); + } + } + + public static class CustomTemplateNumber extends CustomNumber implements TemplateNumber + { + public CustomTemplateNumber(Number num) + { + super(num); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/HyphenInIdentifiersTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/HyphenInIdentifiersTestCase.java new file mode 100644 index 00000000..e4ccc7f9 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/HyphenInIdentifiersTestCase.java @@ -0,0 +1,50 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; + +/** + * This class tests passing expressions as method arguments + */ + +public class HyphenInIdentifiersTestCase extends BaseTestCase +{ + public HyphenInIdentifiersTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.addProperty("parser.allow_hyphen_in_identifiers", true); + } + + public void testHyphen() + { + assertEvalEquals("6","#set($var-1 = 7)#set($var-2 = $var-1 - 1)$var-2"); + } + + public void testHyphenInCollection() + { + assertEvalEquals("foofoofoo","#set($map = {'name-with-hyphen':'foo'})$map.name-with-hyphen${map.name-with-hyphen}${map.get('name-with-hyphen')}"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyNoEmptyCheckTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyNoEmptyCheckTestCase.java new file mode 100644 index 00000000..2935100c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyNoEmptyCheckTestCase.java @@ -0,0 +1,120 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.util.Collections; + +/** + * Used to check that empty values are properly handled in #if statements + */ +public class IfEmptyNoEmptyCheckTestCase extends BaseTestCase +{ + public IfEmptyNoEmptyCheckTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty(RuntimeConstants.CHECK_EMPTY_OBJECTS, "false"); + } + + protected void assertEmpty(Object obj) + { + context.put("obj", obj); + assertEvalEquals("", "#if( $obj )fail#end"); + } + + protected void assertNotEmpty(Object obj) + { + context.put("obj", obj); + assertEvalEquals("", "#if( !$obj )fail#end"); + } + + public void testNull() + { + assertEmpty(null); + assertNotEmpty(new NullAsString()); + assertNotEmpty(new NullAsNumber()); + } + + public void testDataStructures() + { + assertNotEmpty(Collections.emptyMap()); + assertNotEmpty(Collections.emptyList()); + assertNotEmpty(new Object[]{}); + } + + public void testString() + { + assertNotEmpty(""); + assertNotEmpty(new EmptyAsString()); + } + + public void testNumber() + { + assertNotEmpty(0); + } + + public void testStringBuilder() + { + StringBuilder builder = new StringBuilder(); + assertNotEmpty(builder); + } + + public void testLiterals() + { + assertEvalEquals("", "#if( !0 )fail#end"); + assertEvalEquals("", "#if( !0.0 )fail#end"); + assertEvalEquals("", "#if( !'' )fail#end"); + assertEvalEquals("", "#if( !\"\" )fail#end"); + assertEvalEquals("", "#if( ![] )fail#end"); + assertEvalEquals("", "#if( !{} )fail#end"); + } + + public static class NullAsString + { + public String getAsString() + { + return null; + } + } + + public static class EmptyAsString + { + public String getAsString() + { + return ""; + } + } + + public static class NullAsNumber + { + public String getAsNumber() + { + return null; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java new file mode 100644 index 00000000..52631a19 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IfEmptyTestCase.java @@ -0,0 +1,144 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collections; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Used to check that empty values are properly handled in #if statements + */ +public class IfEmptyTestCase extends BaseTestCase +{ + public IfEmptyTestCase(final String name) + { + super(name); + } + + protected void assertEmpty(Object obj) + { + context.put("obj", obj); + assertEvalEquals("", "#if( $obj )fail#end"); + } + + protected void assertNotEmpty(Object obj) + { + context.put("obj", obj); + assertEvalEquals("", "#if( !$obj )fail#end"); + } + + public void testNull() + { + assertEmpty(null); + assertEmpty(new NullAsString()); + assertEmpty(new NullAsNumber()); + } + + public void testDataStructures() + { + assertEmpty(Collections.emptyMap()); + assertEmpty(Collections.emptyList()); + assertEmpty(new Object[]{}); + List list = new ArrayList(); + list.add(1); + assertNotEmpty(list); + Map map = new TreeMap(); + map.put("foo", 1); + assertNotEmpty(map); + } + + public void testString() + { + assertEmpty(""); + assertEmpty(new EmptyAsString()); + assertNotEmpty("hello"); + } + + public void testNumber() + { + assertEmpty(0); + assertEmpty(0L); + assertEmpty(0.0f); + assertEmpty(0.0); + assertEmpty(BigInteger.ZERO); + assertEmpty(BigDecimal.ZERO); + assertNotEmpty(1); + assertNotEmpty(1L); + assertNotEmpty(1.0f); + assertNotEmpty(1.0); + assertNotEmpty(BigInteger.ONE); + assertNotEmpty(BigDecimal.ONE); + } + + public void testStringBuilder() + { + StringBuilder builder = new StringBuilder(); + assertEmpty(builder); + builder.append("yo"); + assertNotEmpty(builder); + } + + public void testLiterals() + { + assertEvalEquals("", "#if( 0 )fail#end"); + assertEvalEquals("", "#if( 0.0 )fail#end"); + assertEvalEquals("", "#if( '' )fail#end"); + assertEvalEquals("", "#if( \"\" )fail#end"); + assertEvalEquals("", "#if( [] )fail#end"); + assertEvalEquals("", "#if( {} )fail#end"); + + assertEvalEquals("", "#if( !1 )fail#end"); + assertEvalEquals("", "#if( !1.0 )fail#end"); + assertEvalEquals("", "#if( !'foo' )fail#end"); + assertEvalEquals("", "#if( !\"foo\" )fail#end"); + assertEvalEquals("", "#if( ![ 'foo' ] )fail#end"); + assertEvalEquals("", "#if( !{ 'foo':'bar' } )fail#end"); + } + + public static class NullAsString + { + public String getAsString() + { + return null; + } + } + + public static class EmptyAsString + { + public String getAsString() + { + return ""; + } + } + + public static class NullAsNumber + { + public String getAsNumber() + { + return null; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java new file mode 100755 index 00000000..f1ce938d --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IfNullTestCase.java @@ -0,0 +1,101 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; + +/** + * Used to check that nulls are properly handled in #if statements + */ +public class IfNullTestCase extends BaseTestCase +{ + public IfNullTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("nullToString", new NullToString()); + context.put("notnull", new Object()); + } + + public void testIfEquals() + { + // both null + assertEvalEquals("foo", "#if( $null == $otherNull )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( $null == $nullToString )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( $nullToString == $null )foo#{else}bar#end"); + // left null, right not + assertEvalEquals("bar", "#if( $nullToString == $notnull )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $null == $notnull )foo#{else}bar#end"); + // right null, left not + assertEvalEquals("bar", "#if( $notnull == $nullToString )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $notnull == $null )foo#{else}bar#end"); + } + + public void testIfNotEquals() + { + // both null + assertEvalEquals("bar", "#if( $null != $otherNull )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $null != $nullToString )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $nullToString != $null )foo#{else}bar#end"); + // left null, right not + assertEvalEquals("foo", "#if( $nullToString != $notnull )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( $null != $notnull )foo#{else}bar#end"); + // right null, left not + assertEvalEquals("foo", "#if( $notnull != $nullToString )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( $notnull != $null )foo#{else}bar#end"); + } + + public void testIfValue() + { + assertEvalEquals("bar", "#if( $null )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $nullToString )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( !$null )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( !$nullToString )foo#{else}bar#end"); + } + + public void testIfAnd() + { + assertEvalEquals("bar", "#if( $null && $nullToString )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $nullToString && $null )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $null && $notnull )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $notnull && $nullToString )foo#{else}bar#end"); + } + + public void testIfOr() + { + assertEvalEquals("bar", "#if( $null || $nullToString )foo#{else}bar#end"); + assertEvalEquals("bar", "#if( $nullToString || $null )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( $null || $notnull )foo#{else}bar#end"); + assertEvalEquals("foo", "#if( $notnull || $nullToString )foo#{else}bar#end"); + } + + public static class NullToString + { + public String getAsString() + { + return null; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IncludeErrorTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IncludeErrorTestCase.java new file mode 100644 index 00000000..a242d05f --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IncludeErrorTestCase.java @@ -0,0 +1,119 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; + +import java.io.StringWriter; + + + + +/** + * Test that #parse and #include pass errors to calling code. + * Specifically checking against VELOCITY-95 and VELOCITY-96. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class IncludeErrorTestCase extends BaseTestCase implements TemplateTestBase +{ + VelocityEngine ve; + + /** + * Default constructor. + */ + public IncludeErrorTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(IncludeErrorTestCase.class); + } + + @Override + public void setUp() throws Exception + { + ve = new VelocityEngine(); + ve.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, TemplateTestBase.TEST_COMPARE_DIR + "/includeerror"); + + ve.init(); + } + + + + public void testMissingParseError() throws Exception + { + checkException("missingparse.vm",ResourceNotFoundException.class); + } + + public void testMissingIncludeError() throws Exception + { + checkException("missinginclude.vm",ResourceNotFoundException.class); + } + + public void testParseError() throws Exception + { + checkException("parsemain.vm",ParseErrorException.class); + } + + public void testParseError2() throws Exception + { + checkException("parsemain2.vm",ParseErrorException.class); + } + + + /** + * Check that an exception is thrown for the given template + * @param templateName + * @param exceptionClass + * @throws Exception + */ + private void checkException(String templateName,Class exceptionClass) + throws Exception + { + Context context = new VelocityContext(); + Template template = ve.getTemplate(templateName, "UTF-8"); + + try (StringWriter writer = new StringWriter()) + { + template.merge(context, writer); + writer.flush(); + fail("File should have thrown an exception"); + } + catch (Exception E) + { + assertTrue(exceptionClass.isAssignableFrom(E.getClass())); + } + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IncludeEventHandlingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IncludeEventHandlingTestCase.java new file mode 100644 index 00000000..720ffc5c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IncludeEventHandlingTestCase.java @@ -0,0 +1,250 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.event.EventCartridge; +import org.apache.velocity.app.event.IncludeEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.RuntimeServicesAware; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Tests event handling + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class IncludeEventHandlingTestCase extends BaseTestCase implements IncludeEventHandler,RuntimeServicesAware +{ + + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/includeevent"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/includeevent"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/includeevent/compare"; + + + private static final int PASS_THROUGH=0; + private static final int RELATIVE_PATH=1; + private static final int BLOCK=2; + + private int EventHandlerBehavior = PASS_THROUGH; + + /** + * Default constructor. + */ + public IncludeEventHandlingTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + Velocity.reset(); + Velocity.addProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + + + } + + + public static Test suite () + { + return new TestSuite(IncludeEventHandlingTestCase.class); + } + + /** + * Runs the test. + */ + public void testIncludeEventHandling () + throws Exception + { + Template template1 = RuntimeSingleton.getTemplate( + getFileName(null, "test1", TMPL_FILE_EXT)); + + Template template2 = RuntimeSingleton.getTemplate( + getFileName(null, "subdir/test2", TMPL_FILE_EXT)); + + Template template3 = RuntimeSingleton.getTemplate( + getFileName(null, "test3", TMPL_FILE_EXT)); + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "test1", RESULT_FILE_EXT)); + + FileOutputStream fos2 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT)); + + FileOutputStream fos3 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "test3", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2)); + Writer writer3 = new BufferedWriter(new OutputStreamWriter(fos3)); + + /* + * lets make a Context and add the event cartridge + */ + + Context context = new VelocityContext(); + + /* + * Now make an event cartridge, register the + * input event handler and attach it to the + * Context + */ + + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(this); + ec.attachToContext( context ); + + + // BEHAVIOR A: pass through #input and #parse with no change + EventHandlerBehavior = PASS_THROUGH; + + template1.merge(context, writer1); + writer1.flush(); + writer1.close(); + + // BEHAVIOR B: pass through #input and #parse with using a relative path + EventHandlerBehavior = RELATIVE_PATH; + + template2.merge(context, writer2); + writer2.flush(); + writer2.close(); + + // BEHAVIOR C: refuse to pass through #input and #parse + EventHandlerBehavior = BLOCK; + + template3.merge(context, writer3); + writer3.flush(); + writer3.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "test1", + RESULT_FILE_EXT, CMP_FILE_EXT) || + !isMatch(RESULTS_DIR, COMPARE_DIR, "test2", + RESULT_FILE_EXT, CMP_FILE_EXT) || + !isMatch(RESULTS_DIR, COMPARE_DIR, "test3", + RESULT_FILE_EXT, CMP_FILE_EXT) + ) + { + fail("Output incorrect."); + } + } + + + @Override + public void setRuntimeServices(RuntimeServices rs ) + { + } + + /** + * Sample handler with different behaviors for the different tests. + */ + @Override + public String includeEvent(Context context, String includeResourcePath, String currentResourcePath, String directiveName) + { + if (EventHandlerBehavior == PASS_THROUGH) + return includeResourcePath; + + + // treat as relative path + else if (EventHandlerBehavior == RELATIVE_PATH) + { + // if the resource name starts with a slash, it's not a relative path + if (includeResourcePath.startsWith("/") || includeResourcePath.startsWith("\\") ) { + return includeResourcePath; + } + + int lastslashpos = Math.max( + currentResourcePath.lastIndexOf("/"), + currentResourcePath.lastIndexOf("\\") + ); + + // root of resource tree + if ( (lastslashpos == -1)) + return includeResourcePath; + + // prepend path to the input path + else + return currentResourcePath.substring(0,lastslashpos) + "/" + includeResourcePath; + + + + } else if (EventHandlerBehavior == BLOCK) + return null; + + // should never happen + else + return null; + + + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IndexTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IndexTestCase.java new file mode 100644 index 00000000..a585de7e --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IndexTestCase.java @@ -0,0 +1,171 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; + +import java.util.ArrayList; +/** + * Test index syntax e.g, $foo[1] + */ +public class IndexTestCase extends BaseTestCase +{ + public IndexTestCase(String name) + { + super(name); + //DEBUG = true; + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + + context.put("NULL", null); + context.put("red", "blue"); + + int[] a = {1, 2, 3}; + context.put("a", a); + String[] str = {"a", "ab", "abc"}; + context.put("str", str); + + ArrayList alist = new ArrayList(); + alist.add(1); + alist.add(2); + alist.add(3); + alist.add(a); + alist.add(null); + context.put("alist", alist); + + Foo foo = new Foo(); + foo.bar = alist; + context.put("foo", foo); + + Boo boo = new Boo(); + context.put("boo", boo); + } + + public void testCallingIndex() + { + assertEvalEquals("1 -3-", "$a[0] -$a[ 2 ]-"); + assertEvalEquals("x21", "#set($i = 1)x$a[$i]1"); + assertEvalEquals("3", "$a[ $a[ $a[0] ] ]"); + assertEvalEquals("ab", "$str[1]"); + assertEvalEquals("123", "$alist[0]$alist[1]$alist[2]"); + assertEvalEquals("1][2-[3]", "$alist[0]][$alist[$a[0]]-[$alist[2]]"); + + assertEvalEquals("2", "$alist[3][1]"); + assertEvalEquals("3 [1]", "$alist[2] [1]"); + + assertEvalEquals("4", "#set($bar = [3, 4, 5])$bar[1]"); + assertEvalEquals("21", "#set($i = 1)#set($bar = [3, $a[$i], $a[0]])$bar[1]$bar[2]"); + + assertEvalEquals("2", "$foo.bar[1]"); + assertEvalEquals("2", "$foo.getBar()[1]"); + assertEvalEquals("2", "$foo.getBar()[3][1]"); + + assertEvalEquals(" a ab abc ", "#foreach($i in $foo.bar[3]) $str[$foreach.index] #end"); + + assertEvalEquals("apple", "#set($hash = {'a':'apple', 'b':'orange'})$hash['a']"); + + assertEvalEquals("xx ", "#if($alist[4] == $NULL)xx#end #if($alist[4])yy#end"); + + assertEvalEquals("BIG TRUEaBIG FALSE", "$foo[true]a$foo[false]"); + assertEvalEquals("junk foobar ", "$foo[\"junk\"]"); + assertEvalEquals("GOT NULL", "#set($i=$NULL)$boo[$i]"); + + assertEvalEquals("321", "$a[-1]$a[ -2]$a[-3 ]"); + assertEvalEquals("67xx", "#set($hash={1:11, 5:67, 23:2})$hash[5]$!hash[6]#if(!$hash[1000])xx#end"); + + // Some cases that should be evaluated as text + assertEvalEquals("[]", "[]"); + assertEvalEquals("$[]", "$[]"); + assertEvalEquals("$.[]", "$.[]"); + assertEvalEquals("$[1]", "$[1]"); + assertEvalEquals("$[1]1", "$[1]1"); + assertEvalEquals("$1[1]1", "$1[1]1"); + assertEvalEquals("blue.[]", "$red.[]"); + assertEvalEquals("blue[]", "${red}[]"); + assertEvalEquals("blue][", "$red]["); + assertEvalEquals("1[]", "${a[0]}[]"); + assertEvalEquals("1a$[]", "$a[0]a$[]"); + assertEvalEquals("$![]", "$![]"); + assertEvalEquals("$\\![]", "$\\![]"); + } + + public void testIndexSetting() + { + assertEvalEquals("foo", "#set($str[1] = \"foo\")$str[1]"); + assertEvalEquals("5150", "#set($alist[1] = 5150)$alist[1]"); + assertEvalEquals("15", "$alist[3][0]#set($alist[3][0] = 5)$alist[3][0]"); + assertEvalEquals("orange","#set($blaa = {\"apple\":\"grape\"})#set($blaa[\"apple\"] = \"orange\")$blaa[\"apple\"]"); + assertEvalEquals("null","#set($str[0] = $NULL)#if($str[0] == $NULL)null#end"); + assertEvalEquals("null","#set($blaa = {\"apple\":\"grape\"})#set($blaa[\"apple\"] = $NULL)#if($blaa[\"apple\"] == $NULL)null#end"); + assertEvalEquals("2112", "#set($a[-1] = 2112)$a[2]"); + assertEvalEquals("3344","#set($hash = {1:11, 2:22, 5:66})#set($hash[2]=33)#set($hash[3]=44)$hash[2]$hash[3]"); + } + + + public void testErrorHandling() + { + assertEvalExceptionAt("$boo['throwex']", 1, 5); + assertEvalExceptionAt("$boo[]", 1, 6); + assertEvalExceptionAt("$boo[blaa]", 1, 6); + assertEvalExceptionAt("#set($foo[1] = 3)", 1, 10); + assertEvalExceptionAt("$a[500]", 1, 3); + } + + + public static class Foo + { + public Object bar = null; + public Object getBar() + { + return bar; + } + + public String get(Boolean bool) + { + if (bool) + return "BIG TRUE"; + else + return "BIG FALSE"; + } + + public String get(String str) + { + return str + " foobar "; + } + } + + public static class Boo + { + public Object get(Object obj) + { + if (obj == null) + return "GOT NULL"; + else if (obj.equals("throwex")) + throw new RuntimeException("Generated Exception"); + + return obj; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/InfoTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/InfoTestCase.java new file mode 100644 index 00000000..0ca5a150 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/InfoTestCase.java @@ -0,0 +1,118 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.test.misc.UberspectTestException; +import org.apache.velocity.util.introspection.Info; + +import java.io.StringWriter; + + + + +/** + * Test that the Info class in the Introspector holds the correct information. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @author <a href="mailto:isidore@setgame.com">Llewellyn Falco</a> + * @version $Id$ + */ +public class InfoTestCase extends BaseTestCase implements TemplateTestBase +{ + VelocityEngine ve; + + /** + * Default constructor. + */ + public InfoTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(InfoTestCase.class); + } + + @Override + public void setUp() throws Exception + { + ve = new VelocityEngine(); + ve.setProperty( + "runtime.introspector.uberspect", "org.apache.velocity.test.misc.UberspectTestImpl"); + + ve.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, TemplateTestBase.TEST_COMPARE_DIR + "/info"); + + ve.init(); + } + + + + public void testInfoProperty() throws Exception + { + // check property + checkInfo("info1.vm", 1, 7); + } + + public void testInfoMethod() throws Exception + { + // check method + checkInfo("info2.vm", 1, 7); + } + + public void checkInfo(String templateName, + int expectedLine, int expectedCol) throws Exception + { + Context context = new VelocityContext(); + Template template = ve.getTemplate(templateName, "UTF-8"); + Info info = null; + + context.put("main", this); + + try (StringWriter writer = new StringWriter()) + { + template.merge(context, writer); + writer.flush(); + fail("Uberspect should have thrown an exception"); + } + catch (UberspectTestException E) + { + info = E.getInfo(); + } + assertInfoEqual(info, templateName, expectedLine, expectedCol); + + } + + private void assertInfoEqual(Info i, String name, int line, int column) + { + assertEquals("Template Name", name, i.getTemplateName()); + assertEquals("Template Line", line, i.getLine()); + assertEquals("Template Column", column, i.getColumn()); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/InlineScopeVMTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/InlineScopeVMTestCase.java new file mode 100644 index 00000000..acaafba9 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/InlineScopeVMTestCase.java @@ -0,0 +1,134 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Tests if the VM template-locality is working. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @author <a href="mailto:dlr@collab.net">Daniel Rall</a> + * @version $Id$ + */ +public class InlineScopeVMTestCase extends BaseTestCase implements TemplateTestBase +{ + public InlineScopeVMTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + /* + * do our properties locally, and just override the ones we want + * changed + */ + + Velocity.reset(); + + Velocity.setProperty( + Velocity.VM_PERM_ALLOW_INLINE_REPLACE_GLOBAL, "true"); + + Velocity.setProperty( + Velocity.VM_PERM_INLINE_LOCAL, "true"); + + Velocity.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.setProperty("space.gobbling", "bc"); + + Velocity.init(); + } + + public static Test suite () + { + return new TestSuite(InlineScopeVMTestCase.class); + } + + /** + * Runs the test. + */ + public void testInlineScopeVM () + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + + /* + * Get the template and the output. Do them backwards. + * vm_test2 uses a local VM and vm_test1 doesn't + */ + + Template template2 = RuntimeSingleton.getTemplate( + getFileName(null, "vm_test2", TMPL_FILE_EXT)); + + Template template1 = RuntimeSingleton.getTemplate( + getFileName(null, "vm_test1", TMPL_FILE_EXT)); + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULT_DIR, "vm_test1", RESULT_FILE_EXT)); + + FileOutputStream fos2 = + new FileOutputStream ( + getFileName(RESULT_DIR, "vm_test2", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2)); + + /* + * put the Vector into the context, and merge both + */ + + VelocityContext context = new VelocityContext(); + + template1.merge(context, writer1); + writer1.flush(); + writer1.close(); + + template2.merge(context, writer2); + writer2.flush(); + writer2.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,"vm_test1", + RESULT_FILE_EXT,CMP_FILE_EXT) || + !isMatch(RESULT_DIR,COMPARE_DIR,"vm_test2", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IntrospectionCacheDataTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IntrospectionCacheDataTestCase.java new file mode 100644 index 00000000..bbd4bfab --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IntrospectionCacheDataTestCase.java @@ -0,0 +1,81 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestCase; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.util.introspection.IntrospectionCacheData; + +import java.io.IOException; +import java.io.StringWriter; + +/** + * Checks that arrays are cached correctly in the Introspector. + * + * @author <a href="Alexey Pachenko">alex+news@olmisoft.com</a> + * @version $Id$ + */ +public class IntrospectionCacheDataTestCase extends TestCase +{ + + private static class CacheHitCountingVelocityContext extends VelocityContext + { + public int cacheHit = 0; + + @Override + public IntrospectionCacheData icacheGet(Object key) + { + final IntrospectionCacheData result = super.icacheGet(key); + if (result != null) { + ++cacheHit; + } + return result; + } + + } + + public void testCache() throws ParseErrorException, MethodInvocationException, + ResourceNotFoundException, IOException + { + CacheHitCountingVelocityContext context = new CacheHitCountingVelocityContext(); + context.put("this", this); + StringWriter w = new StringWriter(); + Velocity.evaluate(context, w, "test", "$this.exec('a')$this.exec('b')"); + assertEquals("[a][b]", w.toString()); + assertTrue(context.cacheHit > 0); + } + + + /** + * For use when acting as a context reference. + * + * @param value + * @return + */ + public String exec(String value) + { + return "[" + value + "]"; + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/Introspector2TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/Introspector2TestCase.java new file mode 100644 index 00000000..f97f1c49 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/Introspector2TestCase.java @@ -0,0 +1,168 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.Introspector; + +import java.lang.reflect.Method; + +/** + * Test case for the Velocity Introspector which + * tests the ability to find a 'best match' + * + * + * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class Introspector2TestCase extends BaseTestCase +{ + + /** + * Creates a new instance. + */ + public Introspector2TestCase(String name) + { + super(name); + } + + /** + * Get the containing <code>TestSuite</code>. + * + * @return The <code>TestSuite</code> to run. + */ + public static Test suite () + { + return new TestSuite(Introspector2TestCase.class); + } + + public void testIntrospector() + throws Exception + { + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + + Method method; + String result; + Tester t = new Tester(); + + Object[] params = { new Foo(), new Foo() }; + + Introspector introspector = new Introspector(log); + + method = introspector + .getMethod( Tester.class, "find", params ); + + if ( method == null) + fail("Returned method was null"); + + result = (String) method.invoke( t, params); + + if ( !result.equals( "Bar-Bar" ) ) + { + fail("Should have gotten 'Bar-Bar' : received '" + result + "'"); + } + + /* + * now test for failure due to ambiguity + */ + + method = introspector + .getMethod( Tester2.class, "find", params ); + + if ( method != null) + fail("Introspector shouldn't have found a method as it's ambiguous."); + } + + public interface Woogie + { + } + + public static class Bar implements Woogie + { + int i; + } + + public static class Foo extends Bar + { + int j; + } + + public static class Tester + { + public static String find(Woogie w, Object o ) + { + return "Woogie-Object"; + } + + public static String find(Object w, Bar o ) + { + return "Object-Bar"; + } + + public static String find(Bar w, Bar o ) + { + return "Bar-Bar"; + } + + public static String find( Object o ) + { + return "Object"; + } + + public static String find( Woogie o ) + { + return "Woogie"; + } + } + + public static class Tester2 + { + public static String find(Woogie w, Object o ) + { + return "Woogie-Object"; + } + + public static String find(Object w, Bar o ) + { + return "Object-Bar"; + } + + public static String find(Bar w, Object o ) + { + return "Bar-Object"; + } + + public static String find( Object o ) + { + return "Object"; + } + + public static String find( Woogie o ) + { + return "Woogie"; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/Introspector3TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/Introspector3TestCase.java new file mode 100644 index 00000000..aef11f2c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/Introspector3TestCase.java @@ -0,0 +1,151 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.util.introspection.Introspector; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +/** + * Simple introspector test case for primitive problem found in 1.3 + * + * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class Introspector3TestCase extends BaseTestCase +{ + /** + * Creates a new instance. + */ + public Introspector3TestCase(String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(Introspector3TestCase.class); + } + + public void testSimple() + throws Exception + { + Method method; + String result; + + MethodProvider mp = new MethodProvider(); + + /* + * string integer + */ + + Object[] listIntInt = { new ArrayList(), 1, 2}; + Object[] listLongList = { new ArrayList(), 1L, new ArrayList() }; + Object[] intInt = {1, 2}; + Object[] longInt = {1L, 2}; + Object[] longLong = {1L, 2L}; + + Introspector introspector = new Introspector(log); + method = introspector.getMethod( + MethodProvider.class, "lii", listIntInt); + result = (String) method.invoke(mp, listIntInt); + + assertTrue(result.equals("lii")); + + method = introspector.getMethod( + MethodProvider.class, "ii", intInt); + result = (String) method.invoke(mp, intInt); + + assertTrue(result.equals("ii")); + + method = introspector.getMethod( + MethodProvider.class, "ll", longInt); + result = (String) method.invoke(mp, longInt); + + assertTrue(result.equals("ll")); + + /* + * test overloading with primitives + */ + + method = introspector.getMethod( + MethodProvider.class, "ll", longLong); + result = (String) method.invoke(mp, longLong); + + assertTrue(result.equals("ll")); + + method = introspector.getMethod( + MethodProvider.class, "lll", listLongList); + result = (String) method.invoke(mp, listLongList); + + assertTrue(result.equals("lll")); + + /* + * test invocation with nulls + */ + + Object [] oa = {null, 0}; + method = introspector.getMethod( + MethodProvider.class, "lll", oa ); + result = (String) method.invoke(mp, oa); + + assertTrue(result.equals("Listl")); + + } + + public static class MethodProvider + { + public String ii(int p, int d) + { + return "ii"; + } + + public String lii(List s, int p, int d) + { + return "lii"; + } + + public String lll(List s, long p, List d) + { + return "lll"; + } + + + public String lll(List s, long p, int d) + { + return "lli"; + } + + public String lll(List s, long p) + { + return "Listl"; + } + + public String ll(long p, long d) + { + return "ll"; + } + + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IntrospectorTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IntrospectorTestCase.java new file mode 100644 index 00000000..ec2fec2b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IntrospectorTestCase.java @@ -0,0 +1,226 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.Introspector; + +import java.lang.reflect.Method; + +/** + * Test case for the Velocity Introspector which uses + * the Java Reflection API to determine the correct + * signature of the methods used in VTL templates. + * + * This should be split into separate tests for each + * of the methods searched for but this is a start + * for now. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @version $Id$ + */ +public class IntrospectorTestCase extends BaseTestCase +{ + private static MethodProvider mp; + + private Introspector introspector; + + @Override + public void setUp() + { + mp = new MethodProvider(); + log = new TestLogger(); + introspector = new Introspector(log); + } + + /** + * Creates a new instance. + */ + public IntrospectorTestCase (String name) + { + super(name); + } + + /** + * Get the containing <code>TestSuite</code>. This is always + * <code>VelocityTestSuite</code>. + * + * @return The <code>TestSuite</code> to run. + */ + public static Test suite () + { + return new TestSuite(IntrospectorTestCase.class); + } + + public void testIntrospectorBoolean() + throws Exception + { + // Test boolean primitive. + Object[] booleanParams = {Boolean.TRUE}; + String type = "boolean"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", booleanParams); + String result = (String) method.invoke(mp, booleanParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorByte() + throws Exception + { + // Test byte primitive. + Object[] byteParams = { new Byte("1") }; + String type = "byte"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", byteParams); + String result = (String) method.invoke(mp, byteParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorChar() + throws Exception + { + // Test char primitive. + Object[] characterParams = {'a'}; + String type = "character"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", characterParams); + String result = (String) method.invoke(mp, characterParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorDouble() + throws Exception + { + + // Test double primitive. + Object[] doubleParams = { 1.0 }; + String type = "double"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", doubleParams); + String result = (String) method.invoke(mp, doubleParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorFloat() + throws Exception + { + + // Test float primitive. + Object[] floatParams = { 1.0f }; + String type = "float"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", floatParams); + String result = (String) method.invoke(mp, floatParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorInteger() + throws Exception + { + + // Test integer primitive. + Object[] integerParams = { 1 }; + String type = "integer"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", integerParams); + String result = (String) method.invoke(mp, integerParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorPrimitiveLong() + throws Exception + { + + // Test long primitive. + Object[] longParams = { 1L }; + String type = "long"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", longParams); + String result = (String) method.invoke(mp, longParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorPrimitiveShort() + throws Exception + { + // Test short primitive. + Object[] shortParams = {(short) 1}; + String type = "short"; + Method method = introspector.getMethod( + MethodProvider.class, type + "Method", shortParams); + String result = (String) method.invoke(mp, shortParams); + + assertEquals("Method could not be found", type, result); + } + + public void testIntrospectorUntouchable() + throws Exception + { + // Test untouchable + + Object[] params = {}; + + Method method = introspector.getMethod( + MethodProvider.class, "untouchable", params); + + assertNull("able to access a private-access method.", method); + } + + public void testIntrospectorReallyUntouchable() + throws Exception + { + // Test really untouchable + Object[] params = {}; + + Method method = introspector.getMethod( + MethodProvider.class, "reallyuntouchable", params); + + assertNull("able to access a private-access method.", method); + } + + public static class MethodProvider + { + /* + * Methods with native parameter types. + */ + public String booleanMethod (boolean p) { return "boolean"; } + public String byteMethod (byte p) { return "byte"; } + public String characterMethod (char p) { return "character"; } + public String doubleMethod (double p) { return "double"; } + public String floatMethod (float p) { return "float"; } + public String integerMethod (int p) { return "integer"; } + public String longMethod (long p) { return "long"; } + public String shortMethod (short p) { return "short"; } + + String untouchable() { return "yech";} + // don't remove! Used through introspection for testing! + private String reallyuntouchable() { return "yech!"; } + + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/InvalidEventHandlerTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/InvalidEventHandlerTestCase.java new file mode 100644 index 00000000..48ba8e61 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/InvalidEventHandlerTestCase.java @@ -0,0 +1,646 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.app.event.EventCartridge; +import org.apache.velocity.app.event.InvalidReferenceEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.util.RuntimeServicesAware; +import org.apache.velocity.util.introspection.Info; + +import java.io.StringWriter; +import java.io.Writer; + +/** + * Tests event handling for all event handlers except IncludeEventHandler. This is tested + * separately due to its complexity. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class InvalidEventHandlerTestCase +extends TestCase +{ + // @@ VELOCITY-553 + public class TestObject { + private String nullValueAttribute = null; + + public String getNullValueAttribute() { + return nullValueAttribute; + } + + public String getRealString() { + return new String("helloFooRealStr"); + } + + public String getString() { + return new String("helloFoo"); + } + + public String getNullString() { + return null; + } + + public java.util.Date getNullDate() { + return null; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TestObject [nullValueAttribute="); + builder.append(nullValueAttribute); + builder.append("]"); + return builder.toString(); + } + } + // @@ VELOCITY-553 + + + /** + * Default constructor. + */ + public InvalidEventHandlerTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(InvalidEventHandlerTestCase.class); + } + + public void testManualEventHandlers() + throws Exception + { + TestEventCartridge te = new TestEventCartridge(); + + /* + * Test attaching the event cartridge to the context + */ + VelocityEngine ve = new VelocityEngine(); + ve.init(); + + /* + * lets make a Context and add the event cartridge + */ + + VelocityContext inner = new VelocityContext(); + + /* + * Now make an event cartridge, register all the + * event handlers (at once) and attach it to the + * Context + */ + + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(te); + ec.attachToContext( inner ); + + doTestInvalidReferenceEventHandler0(ve, inner); + doTestInvalidReferenceEventHandler1(ve, inner); + doTestInvalidReferenceEventHandler2(ve, inner); + doTestInvalidReferenceEventHandler3(ve, inner); + doTestInvalidReferenceEventHandler4(ve, inner); + } + + /** + * Test assigning the event handlers via properties + */ + public void testConfigurationEventHandlers() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.EVENTHANDLER_INVALIDREFERENCES, TestEventCartridge.class.getName()); + + ve.init(); + doTestInvalidReferenceEventHandler0(ve, null); + doTestInvalidReferenceEventHandler1(ve, null); + doTestInvalidReferenceEventHandler2(ve, null); + doTestInvalidReferenceEventHandler3(ve, null); + doTestInvalidReferenceEventHandler4(ve, null); + } + + /** + * Test deeper structures + * @param ve + * @param vc + * @throws Exception + */ + private void doTestInvalidReferenceEventHandler4(VelocityEngine ve, VelocityContext vc) + throws Exception + { + VelocityContext context = new VelocityContext(vc); + + Tree test = new Tree(); + test.setField("10"); + Tree test2 = new Tree(); + test2.setField("12"); + test.setChild(test2); + + context.put("tree",test); + String s; + Writer w; + + // show work fine + s = "$tree.Field $tree.field $tree.child.Field"; + w = new StringWriter(); + ve.evaluate(context, w, "mystring", s); + + s = "$tree.x $tree.field.x $tree.child.y $tree.child.Field.y"; + w = new StringWriter(); + ve.evaluate(context, w, "mystring", s); + + } + + /** + * Test invalid #set + * @param ve + * @param vc + * @throws Exception + */ + private void doTestInvalidReferenceEventHandler3(VelocityEngine ve, VelocityContext vc) + throws Exception + { + VelocityContext context = new VelocityContext(vc); + context.put("a1", 5); + context.put("a4", 5); + context.put("b1","abc"); + + String s; + Writer w; + + // good object, bad right hand side + s = "#set($xx = $a1.afternoon())"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // good object, bad right hand reference + s = "#set($yy = $q1)"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + } + + /** + * Test invalid method calls + * @param ve + * @param vc + * @throws Exception + */ + private void doTestInvalidReferenceEventHandler2(VelocityEngine ve, VelocityContext vc) + throws Exception + { + VelocityContext context = new VelocityContext(vc); + context.put("a1", 5); + context.put("a4", 5); + context.put("b1","abc"); + + String s; + Writer w; + + // good object, bad method + s = "$a1.afternoon()"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // good object, bad method, quiet reference + s = "$!a1.afternoon()"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("", w.toString()); + + // bad object, bad method -- fails on get + s = "$zz.daylight()"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // bad object, bad method, quiet reference + s = "$!zz.daylight()"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("", w.toString()); + + // change result + s = "$b1.baby()"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("www",w.toString()); + } + + /** + * Test invalid gets/references + * @param ve + * @param vc + * @throws Exception + */ + private void doTestInvalidReferenceEventHandler1(VelocityEngine ve, VelocityContext vc) + throws Exception + { + String result; + + VelocityContext context = new VelocityContext(vc); + context.put("a1", 5); + context.put("a4", 5); + context.put("b1","abc"); + + // normal - should be no calls to handler + String s = "$a1 $a1.intValue() $b1 $b1.length() #set($c1 = '5')"; + Writer w = new StringWriter(); + ve.evaluate(context, w, "mystring", s); + + // good object, bad property + s = "$a1.foobar"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // same one as a quiet reference should not fail + s = "$!a1.foobar"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("",w.toString()); + + // same one inside an #if statement should not fail + s = "#if($a1.foobar)yes#{else}no#end"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("no",w.toString()); + + + // bad object, bad property + s = "$a2.foobar"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // same one as a quiet reference should not fail + s = "$!a2.foobar"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("",w.toString()); + + // same one inside an #if statement should still fail + s = "#if($a2.foobar)yes#{else}no#end"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // except if object is tested first + s = "#if($a2 and $a2.foobar)yes#{else}no#end"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + assertEquals("no", w.toString()); + + // bad object, no property + s = "$a3"; + w = new StringWriter(); + try { + ve.evaluate( context, w, "mystring", s ); + fail("Expected exception."); + } catch (RuntimeException e) {} + + // bad object, no property as quiet reference should not fail + s = "$!a3"; + w = new StringWriter(); + ve.evaluate(context, w, "mystring", s); + result = w.toString(); + assertEquals("", result); + + // bad object, no property as #if condition should not fail + s = "#if($a3)yes#{else}no#end"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + result = w.toString(); + assertEquals("no", result); + + // good object, bad property; change the value + s = "$a4.foobar"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + result = w.toString(); + assertEquals("zzz", result); + + } + + /** + * Test invalidGetMethod + * + * Test behaviour (which should be the same) of + * $objRef.myAttribute and $objRef.getMyAttribute() + * + * @param ve + * @param vc + * @throws Exception + */ + private void doTestInvalidReferenceEventHandler0(VelocityEngine ve, VelocityContext vc) + throws Exception + { + String result; + Writer w; + String s; + boolean rc; + + VelocityContext context = new VelocityContext(vc); + context.put("propertyAccess", new String("lorem ipsum")); + context.put("objRef", new TestObject()); + java.util.ArrayList arrayList = new java.util.ArrayList(); + arrayList.add("firstOne"); + arrayList.add(null); + java.util.HashMap hashMap = new java.util.HashMap(); + hashMap.put(41, "41 is not 42"); + + context.put("objRefArrayList", arrayList); + context.put("objRefHashMap", hashMap); + + // good object, good property (returns non null value) + s = "#set($resultVar = $propertyAccess.bytes)"; // -> getBytes() + w = new StringWriter(); + rc = ve.evaluate( context, w, "mystring", s ); + + // good object, good property accessor method (returns non null value) + s = "#set($resultVar = $propertyAccess.getBytes())"; // -> getBytes() + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + // good object, good property (returns non null value) + s = "$objRef.getRealString()"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + // good object, good property accessor method (returns null value) + // No exception shall be thrown, as returning null should be valid + s = "$objRef.getNullValueAttribute()"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + // good object, good property (returns null value) + // No exception shall be thrown, as returning null should be valid + s = "$objRef.nullValueAttribute"; // -> getNullValueAttribute() + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + // good object, good accessor method which returns a non-null object reference + // Test removing a hashmap element which exists + s = "$objRefHashMap.remove(41)"; + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + + // good object, good accessor method which returns null + // Test removing a hashmap element which DOES NOT exist + // Expected behaviour: Returning null as a value should be + // OK and not result in an exception + s = "$objRefHashMap.remove(42)"; // will return null, as the key does not exist + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + // good object, good method invocation (returns non-null object reference) + s = "$objRefArrayList.get(0)"; // element 0 is NOT NULL + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + + // good object, good method invocation (returns null value) + // Expected behaviour: Returning null as a value should be + // OK and not result in an exception + s = "$objRefArrayList.get(1)"; // element 1 is null + w = new StringWriter(); + ve.evaluate( context, w, "mystring", s ); + + } + + + + /** + * Test assigning the event handlers via properties + */ + + public static class TestEventCartridge + implements InvalidReferenceEventHandler, + RuntimeServicesAware + { + private RuntimeServices rs; + + public TestEventCartridge() + { + } + + /** + * Required by EventHandler + */ + @Override + public void setRuntimeServices(RuntimeServices rs ) + { + // make sure this is only called once + if (this.rs == null) + this.rs = rs; + + else + fail("initialize called more than once."); + } + + + @Override + public Object invalidGetMethod(Context context, String reference, Object object, String property, Info info) + { + // as a test, make sure this EventHandler is initialized + if (rs == null) + fail ("Event handler not initialized!"); + + switch (reference) + { + // good object, bad property + case "$a1.foobar": + assertEquals(Integer.valueOf(5), object); + assertEquals("foobar", property); + throw new RuntimeException("expected exception"); + + // bad object, bad property + case "$a2": + assertNull(object); + assertNull(property); + throw new RuntimeException("expected exception"); + + + // bad object, no property + case "$a3": + assertNull(object); + assertNull(property); + throw new RuntimeException("expected exception"); + + + // good object, bad property; change the value + case "$a4.foobar": + assertEquals(Integer.valueOf(5), object); + assertEquals("foobar", property); + return "zzz"; + + + // bad object, bad method -- fail on the object + case "$zz": + assertNull(object); + assertNull(property); + throw new RuntimeException("expected exception"); + + + // pass q1 through + case "$q1": + + break; + case "$tree.x": + assertEquals("x", property); + break; + case "$tree.field.x": + assertEquals("x", property); + break; + case "$tree.child.y": + assertEquals("y", property); + break; + case "$tree.child.Field.y": + assertEquals("y", property); + break; + default: + fail("invalidGetMethod: unexpected reference: " + reference); + break; + } + return null; + } + + @Override + public Object invalidMethod(Context context, String reference, Object object, String method, Info info) + { + // as a test, make sure this EventHandler is initialized + if (rs == null) + fail ("Event handler not initialized!"); + + // good reference, bad method + if (object.getClass().equals(Integer.class)) + { + assertEquals("$a1.afternoon()",reference); + assertEquals("afternoon",method); + throw new RuntimeException("expected exception"); + } + + else if (object.getClass().equals(String.class) && "baby".equals(method)) + { + return "www"; + } + + else + { + fail("Unexpected invalid method. " + method); + } + + return null; + } + + + @Override + public boolean invalidSetMethod(Context context, String leftreference, String rightreference, Info info) + { + + // as a test, make sure this EventHandler is initialized + if (rs == null) + fail ("Event handler not initialized!"); + + // good object, bad method + if (leftreference.equals("xx")) + { + assertEquals("q1.afternoon()",rightreference); + throw new RuntimeException("expected exception"); + } + if (leftreference.equals("yy")) + { + assertEquals("$q1",rightreference); + throw new RuntimeException("expected exception"); + } + else + { + fail("Unexpected left hand side. " + leftreference); + } + + return false; + } + + } + + public static class Tree + { + String field; + Tree child; + + public Tree() + { + + } + + public String getField() + { + return field; + } + + public void setField(String field) + { + this.field = field; + } + + public Tree getChild() + { + return child; + } + + public void setChild(Tree child) + { + this.child = child; + } + + public String testMethod() + { + return "123"; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroAutoReloadTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroAutoReloadTestCase.java new file mode 100644 index 00000000..d8f12dde --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroAutoReloadTestCase.java @@ -0,0 +1,103 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.File; +import java.io.FileWriter; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +/** + * This class tests the velocimacro.library.autoreload functionality, and issue VELOCITY- + */ +public class MacroAutoReloadTestCase extends BaseTestCase +{ + private final String RELOAD_TEMPLATE_PATH = TEST_COMPARE_DIR + "/reload"; + + public MacroAutoReloadTestCase(String name) + { + super(name); + } + + @Override + protected void setUp() throws Exception + { + // always copy macros library before modifying it, to ensure successive tests will pass + Files.copy(FileSystems.getDefault().getPath(RELOAD_TEMPLATE_PATH + "/macros.vtl"), FileSystems.getDefault().getPath(RELOAD_TEMPLATE_PATH + "/macros2.vtl"), StandardCopyOption.REPLACE_EXISTING); + + engine = new VelocityEngine(); + + //by default, make the engine's log output go to the test-report + log = new TestLogger(false, false); + engine.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, log); + + // use file resource loader + engine.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file,string"); + engine.addProperty("file.resource.loader.path", RELOAD_TEMPLATE_PATH); + engine.addProperty("velocimacro.library", "macros2.vtl"); + engine.addProperty("velocimacro.library.autoreload", "true"); + engine.addProperty("file.resource.loader.cache", "false"); + engine.addProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + engine.addProperty("string.resource.loader.repository.name", "stringRepo"); + engine.addProperty("string.resource.loader.repository.static", "false"); + context = new VelocityContext(); + } + + + public void testChangedMacro() throws Exception + { + String template = "#foo('hip')"; + assertEvalEquals("hop_hip", template); + + FileWriter writer = new FileWriter(RELOAD_TEMPLATE_PATH + "/macros2.vtl"); + writer.write("#macro(foo $txt)hip_$txt#{end}"); + writer.close(); + // last modified timestamps resolution is one second before Java 8, + // so force reloading by setting a file date in the future + File macros2 = new File(TEST_COMPARE_DIR + "/reload/macros2.vtl"); + macros2.setLastModified(macros2.lastModified() + 1000); + + assertEvalEquals("hip_hip", template); + } + + public void testNewMacro() throws Exception + { + String template = "#foo('hip')"; + assertEvalEquals("hop_hip", template); + + FileWriter writer = new FileWriter(TEST_COMPARE_DIR + "/reload/macros2.vtl", true); + writer.write("\n#macro(bar $txt)hep_$txt#{end}"); + writer.close(); + // last modified timestamps resolution is one second before Java 8, + // so force reloading by setting a file date in the future + File macros2 = new File(TEST_COMPARE_DIR + "/reload/macros2.vtl"); + macros2.setLastModified(macros2.lastModified() + 1000); + + template = "#foo('hip') #bar('hip')"; + assertEvalEquals("hop_hip hep_hip", template); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroCommentsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroCommentsTestCase.java new file mode 100644 index 00000000..3a38f9e4 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroCommentsTestCase.java @@ -0,0 +1,56 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.ParseErrorException; + +/** + * Test Macro comment functionality + */ +public class MacroCommentsTestCase extends BaseTestCase +{ + public MacroCommentsTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + } + + public void testComments() + { + assertEvalEquals("ab","#macro(foo ##\n $bar \n ## blaa\n $bar2##\n)$bar$bar2#end#foo(\"a\" \"b\")"); + assertEvalEquals("","#macro(foo1##\n)#end#foo1()"); + assertEvalEquals("ab","#macro(foo2##\n\t ####\r $bar \n ##\n## Testing blaa\n $bar2##\n)$bar$bar2#end#foo2(\"a\" \"b\")"); + assertEvalEquals("","#macro(foo4 ## test\n ## test2 ## test3 \n)#end#foo4()"); + assertEvalEquals("","#macro(foo4 ## test\n $x = 5 ## test2 ## test3 \n)#end#foo4()"); + } + + public void testErrors() + { + // We only allow comment lines in macro definitions + assertEvalException("#foo1(## test)", ParseErrorException.class); + assertEvalException("#foo1($test ## test)", ParseErrorException.class); + assertEvalException("#break(## test)", ParseErrorException.class); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroDefaultArgTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroDefaultArgTestCase.java new file mode 100644 index 00000000..368991f4 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroDefaultArgTestCase.java @@ -0,0 +1,73 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * Test macro default parameters. + */ +public class MacroDefaultArgTestCase extends BaseTestCase +{ + public MacroDefaultArgTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + engine.setProperty(RuntimeConstants.VM_ARGUMENTS_STRICT, Boolean.TRUE); + engine.setProperty(RuntimeConstants.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE, Boolean.TRUE); + } + + public void testCompare() + { + assertEvalEquals("121", "#macro(foo $a=1)$a#end#foo()#foo(2)#foo"); + assertEvalEquals("12", "#macro(foo $a = 1)$a#end#foo()#foo(2)"); + assertEvalEquals("12", "#macro(foo $a= 1 )$a#end#foo()#foo(2)"); + assertEvalEquals("1x2x", "#macro(foo $a= 1 $b = \"x\")$a$b#end#foo()#foo(2)"); + assertEvalEquals("1 2 5 2 5 [1, 2] ", "#macro(foo $a=1 $b=2)$a $b #end#foo()#foo(5)#foo(5 [1,2])"); + assertEvalEquals("1 2 5 2 5 [1, 2] ", "#macro(foo $a=1 , $b=2)$a $b #end#foo()#foo(5)#foo(5 [1,2])"); + assertEvalEquals("1 2 5 2 5 [1, 2] ", "#macro(foo, $a=1\n $b =2 )$a $b #end#foo()#foo(5)#foo(5 [1,2])"); + + assertEvalEquals("3 2 5 2 5 [1, 2] ", "#macro(foo, $a=$x $b =2 )$a $b #end#set($x=3)#foo()#foo(5)#foo(5 [1,2])"); + assertEvalEquals("{a=3} 2 5 2 5 [1, 2] ", "#macro(foo, $a = {\"a\":$x} $b =2 )$a $b #end#set($x=3)#foo()#foo(5)#foo(5 [1,2])"); + assertEvalEquals("3 2 5 2 5 [1, 2] ", "#macro(foo, $a = \"$x\" $b =2 )$a $b #end#set($x=3)#foo()#foo(5)#foo(5 [1,2])"); + assertEvalEquals("3$y 2 5 2 5 [1, 2] ", "#macro(foo, $a = \"$x\\$y\" $b =2 )$a $b #end#set($x=3)#foo()#foo(5)#foo(5 [1,2])"); + assertEvalEquals("5 3 2 5 [1, 2] 2 ", "#macro(foo, $c $a = \"$x\" $b =2 )$c $a $b #end#set($x=3)#foo(5)#foo(5 [1,2])"); + + assertEvalEquals("1xno2xyes", "#macro(foo $a= 1 $b = \"x\")$a$b$bodyContent#end#@foo()no#end#@foo(2)yes#end"); + + assertEvalEquals("xy", "#macro(foo $a=\"$b$c\"##\n)$a#end#set($b=\"x\")#set($c=\"y\")#foo()"); + } + + public void testErrors() + { + assertEvalException("#macro(foo $a = 1 $b)#end"); + assertEvalException("#macro(foo $c $a = 3 $b)#end"); + assertEvalException("#macro(foo $a $b = 1)#end#foo()"); // Too few arguments + assertEvalException("#macro(foo $a $b $c = 4)#end#foo(1)"); // Too few arguments + assertEvalException("#macro(foo $a = 3)#end#foo(2 3)"); // Too many arguments + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroForwardDefineTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroForwardDefineTestCase.java new file mode 100644 index 00000000..5a9fb8da --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MacroForwardDefineTestCase.java @@ -0,0 +1,119 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.StringWriter; + +/** + * Make sure that a forward referenced macro inside another macro definition does + * not report an error in the log. + * (VELOCITY-71). + * + * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a> + * @version $Id$ + */ +public class MacroForwardDefineTestCase + extends BaseTestCase +{ + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/macroforwarddefine"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/macroforwarddefine"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/macroforwarddefine/compare"; + + /** + * Collects the log messages. + */ + private TestLogger logger = new TestLogger(false, true); + + /** + * Default constructor. + */ + public MacroForwardDefineTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + // use Velocity.setProperty (instead of properties file) so that we can use actual instance of log + Velocity.reset(); + Velocity.setProperty(RuntimeConstants.RESOURCE_LOADERS,"file"); + Velocity.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH ); + Velocity.setProperty(RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID,"true"); + + // actual instance of logger + logger.setEnabledLevel(TestLogger.LOG_LEVEL_DEBUG); + Velocity.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + Velocity.init(); + } + + public static Test suite() + { + return new TestSuite(MacroForwardDefineTestCase.class); + } + + public void testLogResult() + throws Exception + { + VelocityContext context = new VelocityContext(); + Template template = Velocity.getTemplate("macros.vm"); + + // try to get only messages during merge + logger.startCapture(); + template.merge(context, new StringWriter()); + logger.stopCapture(); + + String resultLog = logger.getLog(); + if ( !isMatch(resultLog, COMPARE_DIR, "velocity.log", "cmp")) + { + String compare = getFileContents(COMPARE_DIR, "velocity.log", CMP_FILE_EXT); + + String msg = "Log output was incorrect\n"+ + "-----Result-----\n"+ resultLog + + "----Expected----\n"+ compare + + "----------------"; + + fail(msg); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodCacheKeyTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodCacheKeyTestCase.java new file mode 100644 index 00000000..43436f0b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodCacheKeyTestCase.java @@ -0,0 +1,88 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestCase; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.velocity.runtime.parser.node.ASTMethod; + +/** + * Checks that the equals method works correctly when caching method keys. + * + * @author <a href="Will Glass-Husain">wglass@forio.com</a> + * @version $Id$ + */ +public class MethodCacheKeyTestCase extends TestCase +{ + + public void testMethodKeyCacheEquals() + { + Class [] elements1 = new Class [] { Object.class }; + ASTMethod.MethodCacheKey mck1 = new ASTMethod.MethodCacheKey("test",elements1, false); + + selfEqualsAssertions(mck1); + + Class [] elements2 = new Class [] { Object.class }; + ASTMethod.MethodCacheKey mck2 = new ASTMethod.MethodCacheKey("test",elements2, false); + + assertTrue(mck1.equals(mck2)); + + Class [] elements3 = new Class [] { String.class }; + ASTMethod.MethodCacheKey mck3 = new ASTMethod.MethodCacheKey("test",elements3, false); + + assertFalse(mck1.equals(mck3)); + + Class [] elements4 = new Class [] { Object.class }; + ASTMethod.MethodCacheKey mck4 = new ASTMethod.MethodCacheKey("boo",elements4, false); + + assertFalse(mck1.equals(mck4)); + + /* check for potential NPE's */ + Class [] elements5 = ArrayUtils.EMPTY_CLASS_ARRAY; + ASTMethod.MethodCacheKey mck5 = new ASTMethod.MethodCacheKey("boo",elements5, false); + selfEqualsAssertions(mck5); + + Class [] elements6 = null; + ASTMethod.MethodCacheKey mck6 = new ASTMethod.MethodCacheKey("boo",elements6, false); + selfEqualsAssertions(mck6); + + Class [] elements7 = new Class [] {}; + ASTMethod.MethodCacheKey mck7 = new ASTMethod.MethodCacheKey("boo",elements7, false); + selfEqualsAssertions(mck7); + + Class [] elements8 = new Class [] {null}; + ASTMethod.MethodCacheKey mck8 = new ASTMethod.MethodCacheKey("boo",elements8, false); + selfEqualsAssertions(mck8); + + Class [] elements9 = new Class [] { Object.class }; + ASTMethod.MethodCacheKey mck9 = new ASTMethod.MethodCacheKey("boo",elements9, false); + selfEqualsAssertions(mck9); + + } + + private void selfEqualsAssertions(ASTMethod.MethodCacheKey mck) + { + assertTrue(mck.equals(mck)); + assertTrue(!mck.equals(null)); + assertTrue(!mck.equals(null)); + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodInvocationExceptionTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodInvocationExceptionTestCase.java new file mode 100644 index 00000000..34f4d813 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodInvocationExceptionTestCase.java @@ -0,0 +1,278 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.StringWriter; + +/** + * Tests if we can hand Velocity an arbitrary class for logging. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class MethodInvocationExceptionTestCase extends TestCase +{ + protected boolean DEBUG = false; + + /** + * Default constructor. + * @param name + */ + public MethodInvocationExceptionTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + /* + * init() Runtime with defaults + */ + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public static Test suite () + { + return new TestSuite(MethodInvocationExceptionTestCase.class); + } + + protected void log(String out) + { + Velocity.getLog().debug(out); + if (DEBUG) + { + System.out.println(out); + } + } + + /** + * Runs the test : + * + * uses the Velocity class to eval a string + * which accesses a method that throws an + * exception. + * @throws Exception + */ + public void testNormalMethodInvocationException () + throws Exception + { + String template = "$woogie.doException() boing!"; + + VelocityContext vc = new VelocityContext(); + + vc.put("woogie", this ); + + StringWriter w = new StringWriter(); + + try + { + Velocity.evaluate( vc, w, "test", template ); + fail("No exception thrown"); + } + catch( MethodInvocationException mie ) + { + log("Caught MIE (good!) :" ); + log(" reference = " + mie.getReferenceName() ); + log(" method = " + mie.getMethodName() ); + + Throwable t = mie.getCause(); + log(" throwable = " + t ); + + if( t instanceof Exception) + { + log(" exception = " + t.getMessage() ); + } + } + } + + + public void testGetterMethodInvocationException () + throws Exception + { + VelocityContext vc = new VelocityContext(); + vc.put("woogie", this ); + + StringWriter w = new StringWriter(); + + /* + * second test - to ensure that methods accessed via get+ construction + * also work + */ + + String template = "$woogie.foo boing!"; + + try + { + Velocity. evaluate( vc, w, "test", template ); + fail("No exception thrown, second test."); + } + catch( MethodInvocationException mie ) + { + log("Caught MIE (good!) :" ); + log(" reference = " + mie.getReferenceName() ); + log(" method = " + mie.getMethodName() ); + + Throwable t = mie.getCause(); + log(" throwable = " + t ); + + if( t instanceof Exception) + { + log(" exception = " + t.getMessage() ); + } + } + } + + + public void testCapitalizedGetterMethodInvocationException () + throws Exception + { + VelocityContext vc = new VelocityContext(); + vc.put("woogie", this ); + + StringWriter w = new StringWriter(); + + String template = "$woogie.Foo boing!"; + + try + { + Velocity. evaluate( vc, w, "test", template ); + fail("No exception thrown, third test."); + } + catch( MethodInvocationException mie ) + { + log("Caught MIE (good!) :" ); + log(" reference = " + mie.getReferenceName() ); + log(" method = " + mie.getMethodName() ); + + Throwable t = mie.getCause(); + log(" throwable = " + t ); + + if( t instanceof Exception) + { + log(" exception = " + t.getMessage() ); + } + } + } + + public void testSetterMethodInvocationException () + throws Exception + { + VelocityContext vc = new VelocityContext(); + vc.put("woogie", this ); + + StringWriter w = new StringWriter(); + + String template = "#set($woogie.foo = 'lala') boing!"; + + try + { + Velocity. evaluate( vc, w, "test", template ); + fail("No exception thrown, set test."); + } + catch( MethodInvocationException mie ) + { + log("Caught MIE (good!) :" ); + log(" reference = " + mie.getReferenceName() ); + log(" method = " + mie.getMethodName() ); + + Throwable t = mie.getCause(); + log(" throwable = " + t ); + + if( t instanceof Exception) + { + log(" exception = " + t.getMessage() ); + } + } + } + + + /** + * test that no exception is thrown when in parameter to macro. + * This is the way we expect the system to work, but it would be better + * to throw an exception. + * @throws Exception + */ + public void testMacroInvocationException () + throws Exception + { + VelocityContext vc = new VelocityContext(); + vc.put("woogie", this ); + + StringWriter w = new StringWriter(); + + String template = "#macro (macro1 $param) $param #end #macro1($woogie.getFoo())"; + + try + { + Velocity. evaluate( vc, w, "test", template ); + fail("No exception thrown, macro invocation test."); + } + catch( MethodInvocationException mie ) + { + log("Caught MIE (good!) :" ); + log(" reference = " + mie.getReferenceName() ); + log(" method = " + mie.getMethodName() ); + + Throwable t = mie.getCause(); + log(" throwable = " + t ); + + if( t instanceof Exception) + { + log(" exception = " + t.getMessage() ); + } + } + catch( Exception e) + { + fail("Wrong exception thrown, test of exception within macro parameter"); + } + } + + public void doException() + throws Exception + { + throw new NullPointerException(); + } + + public void getFoo() + throws Exception + { + throw new Exception("Hello from getFoo()" ); + } + + public void setFoo( String foo ) + throws Exception + { + throw new Exception("Hello from setFoo()"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodOverloadingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodOverloadingTestCase.java new file mode 100644 index 00000000..711481c8 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MethodOverloadingTestCase.java @@ -0,0 +1,184 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Test a reported bug in which method overloading throws IllegalArgumentException + * after a null return value. + * (VELOCITY-132). + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class MethodOverloadingTestCase extends BaseTestCase +{ + String logData; + + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/methodoverloading"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/methodoverloading"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/methodoverloading/compare"; + + /** + * Default constructor. + */ + public MethodOverloadingTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + { + assureResultsDirectoryExists(RESULTS_DIR); + } + + public static Test suite() + { + return new TestSuite(MethodOverloadingTestCase.class); + } + + public void testMethodOverloading() + throws Exception + { + /* + * test overloading in a single template + */ + testFile("single"); + + assertTrue(!logData.contains("IllegalArgumentException")); + } + + public void testParsedMethodOverloading() + throws Exception + { + /* + * test overloading in a file included with #parse + */ + testFile("main"); + + assertTrue(!logData.contains("IllegalArgumentException")); + + } + + public void testFile(String basefilename) + throws Exception + { + TestLogger logger = new TestLogger(); + VelocityEngine ve = new VelocityEngine(); + ve.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + ve.setProperty(VelocityEngine.RUNTIME_LOG_INSTANCE, logger ); + ve.init(); + + Template template; + FileOutputStream fos; + Writer fwriter; + Context context; + + template = ve.getTemplate( getFileName(null, basefilename, TMPL_FILE_EXT) ); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, basefilename, RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + context = new VelocityContext(); + setupContext(context); + logger.on(); + template.merge(context, fwriter); + logger.off(); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, basefilename, RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + logData = logger.getLog(); + } + + public void setupContext(Context context) + { + context.put("test", this); + context.put("nullValue", null); + } + + + public String overloadedMethod ( Integer s ) + { + return "Integer"; + } + + public String overloadedMethod ( String s ) + { + return "String"; + } + + + public String overloadedMethod2 ( Integer s ) + { + return "Integer"; + } + + public String overloadedMethod2 ( String i ) + { + return "String"; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MiscTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MiscTestCase.java new file mode 100644 index 00000000..a1a284a7 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MiscTestCase.java @@ -0,0 +1,74 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.runtime.RuntimeInstance; + +import org.apache.commons.lang3.StringUtils; + +/** + * Test case for any miscellaneous stuff. If it isn't big, and doesn't fit + * anywhere else, it goes here + * + * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class MiscTestCase extends BaseTestCase +{ + public MiscTestCase (String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(MiscTestCase.class); + } + + public void testRuntimeInstanceProperties() + { + // check that runtime instance properties can be set and retrieved + RuntimeInstance ri = new RuntimeInstance(); + ri.setProperty("baabaa.test","the answer"); + assertEquals("the answer",ri.getProperty("baabaa.test")); + } + + public void testStringUtils() + { + /* + * some StringUtils tests + */ + + String arg = null; + String res = StringUtils.trim(arg); + assertNull(arg); + + arg = " test "; + res = StringUtils.trim(arg); + assertEquals("test",res); + + arg = "test"; + res = StringUtils.trim(arg); + assertEquals("test",res); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MultiLoaderTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MultiLoaderTestCase.java new file mode 100644 index 00000000..dc7d67aa --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MultiLoaderTestCase.java @@ -0,0 +1,223 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Load templates from the Classpath. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @author <a href="mailto:daveb@miceda-data.com">Dave Bryson</a> + * @version $Id$ + */ +public class MultiLoaderTestCase extends BaseTestCase +{ + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/multiloader"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/multiloader"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/multiloader/compare"; + + /** + * Default constructor. + */ + public MultiLoaderTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + /* + * Set up the file loader. + */ + + Velocity.reset(); + + Velocity.setProperty(Velocity.RESOURCE_LOADERS, "file"); + + Velocity.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + Velocity.addProperty(Velocity.RESOURCE_LOADERS, "classpath"); + + Velocity.addProperty(Velocity.RESOURCE_LOADERS, "jar"); + + /* + * Set up the classpath loader. + */ + + Velocity.setProperty( + Velocity.RESOURCE_LOADER + ".classpath.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + + Velocity.setProperty( + Velocity.RESOURCE_LOADER + ".classpath.cache", + "false"); + + Velocity.setProperty( + Velocity.RESOURCE_LOADER + ".classpath.modification_check_interval", + "2"); + + /* + * setup the Jar loader + */ + + Velocity.setProperty( + Velocity.RESOURCE_LOADER + ".jar.class", + "org.apache.velocity.runtime.resource.loader.JarResourceLoader"); + + Velocity.setProperty( + Velocity.RESOURCE_LOADER + ".jar.path", + "jar:file:" + FILE_RESOURCE_LOADER_PATH + "/test2.jar" ); + + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public static Test suite () + { + return new TestSuite(MultiLoaderTestCase.class); + } + + /** + * Runs the test. + */ + public void testMultiLoader () + throws Exception + { + /* + * lets ensure the results directory exists + */ + assureResultsDirectoryExists(RESULTS_DIR); + + /* + * Template to find with the file loader. + */ + Template template1 = Velocity.getTemplate( + getFileName(null, "path1", TMPL_FILE_EXT)); + + /* + * Template to find with the classpath loader. + */ + Template template2 = Velocity.getTemplate("includeevent/test1-cp." + TMPL_FILE_EXT); + + /* + * Template to find with the jar loader + */ + Template template3 = Velocity.getTemplate("template/test2." + TMPL_FILE_EXT); + + /* + * and the results files + */ + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "path1", RESULT_FILE_EXT)); + + FileOutputStream fos2 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "test2", RESULT_FILE_EXT)); + + FileOutputStream fos3 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "test3", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2)); + Writer writer3 = new BufferedWriter(new OutputStreamWriter(fos3)); + + /* + * put the Vector into the context, and merge both + */ + + VelocityContext context = new VelocityContext(); + + template1.merge(context, writer1); + writer1.flush(); + writer1.close(); + + template2.merge(context, writer2); + writer2.flush(); + writer2.close(); + + template3.merge(context, writer3); + writer3.flush(); + writer3.close(); + + if (!isMatch(RESULTS_DIR,COMPARE_DIR,"path1",RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Output incorrect for FileResourceLoader test."); + } + + if (!isMatch(RESULTS_DIR,COMPARE_DIR,"test2",RESULT_FILE_EXT,CMP_FILE_EXT) ) + { + fail("Output incorrect for ClasspathResourceLoader test."); + } + + if( !isMatch(RESULTS_DIR,COMPARE_DIR,"test3",RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Output incorrect for JarResourceLoader test."); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/MultipleFileResourcePathTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/MultipleFileResourcePathTestCase.java new file mode 100644 index 00000000..c3cd32f3 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/MultipleFileResourcePathTestCase.java @@ -0,0 +1,144 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Multiple paths in the file resource loader. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @version $Id$ + */ +public class MultipleFileResourcePathTestCase extends BaseTestCase +{ + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH1 = TEST_COMPARE_DIR + "/multi/path1"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH2 = TEST_COMPARE_DIR + "/multi/path2"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/multi"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/multi/compare"; + + /** + * Default constructor. + */ + public MultipleFileResourcePathTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(MultipleFileResourcePathTestCase.class); + } + + @Override + public void setUp() + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + Velocity.reset(); + + Velocity.addProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH1); + + Velocity.addProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH2); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + /** + * Runs the test. + */ + public void testMultipleFileResources () + throws Exception + { + Template template1 = RuntimeSingleton.getTemplate( + getFileName(null, "path1", TMPL_FILE_EXT)); + + Template template2 = RuntimeSingleton.getTemplate( + getFileName(null, "path2", TMPL_FILE_EXT)); + + FileOutputStream fos1 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "path1", RESULT_FILE_EXT)); + + FileOutputStream fos2 = + new FileOutputStream ( + getFileName(RESULTS_DIR, "path2", RESULT_FILE_EXT)); + + Writer writer1 = new BufferedWriter(new OutputStreamWriter(fos1)); + Writer writer2 = new BufferedWriter(new OutputStreamWriter(fos2)); + + /* + * put the Vector into the context, and merge both + */ + + VelocityContext context = new VelocityContext(); + + template1.merge(context, writer1); + writer1.flush(); + writer1.close(); + + template2.merge(context, writer2); + writer2.flush(); + writer2.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "path1", + RESULT_FILE_EXT, CMP_FILE_EXT) || + !isMatch(RESULTS_DIR, COMPARE_DIR, "path2", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/NumberMethodCallsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/NumberMethodCallsTestCase.java new file mode 100644 index 00000000..2a24d39a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/NumberMethodCallsTestCase.java @@ -0,0 +1,142 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.test.provider.NumberMethods; + +import java.io.StringWriter; +import java.math.BigDecimal; +import java.math.BigInteger; + + +/** + * Used to check that method calls with number parameters are executed correctly. + * + * @author <a href="mailto:wglass@forio.com">Peter Romianowski</a> + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + */ +public class NumberMethodCallsTestCase extends TestCase +{ + private VelocityEngine ve = null; + + private final static boolean PRINT_RESULTS = false; + + /** + * Default constructor. + */ + public NumberMethodCallsTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + ve = new VelocityEngine(); + ve.init(); + } + + public void init( RuntimeServices rs ) + { + // do nothing with it + } + + public static Test suite () + { + return new TestSuite(NumberMethodCallsTestCase.class); + } + + /** + * Runs the test. + */ + public void testNumberMethodCalls () + throws Exception + { + VelocityContext vc = new VelocityContext(); + + // context object with overloaded methods with number arguments + vc.put("Test",new NumberMethods()); + + // numbers for context + vc.put("AByte",new Byte("10")); + vc.put("AShort",new Short("10")); + vc.put("AInteger", 10); + vc.put("ALong", 10L); + vc.put("ADouble", 10.0); + vc.put("AFloat", 10f); + vc.put("ABigDecimal",new BigDecimal(10)); + vc.put("ABigInteger",new BigInteger("10")); + + // check context objects + System.out.println("Testing: method calls with arguments as context objects"); + checkResults(vc,"$Test.numMethod($AByte)","byte (10)"); + checkResults(vc,"$Test.numMethod($AShort)","short (10)"); + checkResults(vc,"$Test.numMethod($AInteger)","int (10)"); + checkResults(vc,"$Test.numMethod($ADouble)","double (10.0)"); + checkResults(vc,"$Test.numMethod($AFloat)","double (10.0)"); + checkResults(vc,"$Test.numMethod($ALong)","long (10)"); + checkResults(vc,"$Test.numMethod($ABigDecimal)","BigDecimal (10)"); + checkResults(vc,"$Test.numMethod($ABigInteger)","BigInteger (10)"); + + // check literals + // -- will cast floating point literal to smallest possible of Double, BigDecimal + // -- will cast integer literal to smallest possible of Integer, Long, BigInteger + System.out.println("Testing: method calls with arguments as literals"); + checkResults(vc,"$Test.numMethod(10.0)","double (10.0)"); + checkResults(vc,"$Test.numMethod(10)","int (10)"); + checkResults(vc,"$Test.numMethod(10000000000)","long (10000000000)"); + checkResults(vc,"$Test.numMethod(10000000000000000000000)","BigInteger (10000000000000000000000)"); + + // check calculated results + // -- note calculated value is cast to smallest possible type + // -- method invoked is smallest relevant method + // -- it's an unusual case here of both byte and int methods, but this works as expected + System.out.println("Testing: method calls with arguments as calculated values"); + checkResults(vc,"#set($val = 10.0 + 1.5)$Test.numMethod($val)","double (11.5)"); + checkResults(vc,"#set($val = 100 + 1)$Test.numMethod($val)","int (101)"); + checkResults(vc,"#set($val = 100 * 1000)$Test.numMethod($val)","int (100000)"); + checkResults(vc,"#set($val = 100 + 1.5)$Test.numMethod($val)","double (101.5)"); + checkResults(vc,"#set($val = $ALong + $AInteger)$Test.numMethod($val)","long (20)"); + checkResults(vc,"#set($val = $ABigInteger + $AInteger)$Test.numMethod($val)","BigInteger (20)"); + } + + + private void checkResults(Context vc, String template, String compare) throws Exception + { + + StringWriter writer = new StringWriter(); + ve.evaluate( vc, writer, "test", template); + assertEquals("Incorrect results for template '" + template + "'.",compare,writer.toString()); + + if (PRINT_RESULTS) + System.out.println ("Method call successful: " + template); + + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/OldPropertiesTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/OldPropertiesTestCase.java new file mode 100644 index 00000000..46c3b06d --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/OldPropertiesTestCase.java @@ -0,0 +1,170 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.DeprecationAwareExtProperties; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Tests if we can hand Velocity an arbitrary class for logging. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class OldPropertiesTestCase extends TestCase implements TemplateTestBase +{ + private VelocityEngine ve = null; + private TestLogger logger = null; + + /** + * Default constructor. + */ + public OldPropertiesTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + } + + public static Test suite () + { + return new TestSuite(OldPropertiesTestCase.class); + } + + static Pattern propPattern = Pattern.compile("^([a-z._]+)\\s*=\\s*[^#]+.*$", Pattern.CASE_INSENSITIVE); + static Pattern warnPattern = Pattern.compile("^\\s*\\[warn\\]\\s*configuration key '([a-z._]+)' has been deprecated in favor of '([a-z._]+)'$", Pattern.CASE_INSENSITIVE); + + static class Translator extends DeprecationAwareExtProperties + { + @Override + public String translateKey(String oldName) { return super.translateKey(oldName); } + } + + /** + * Check old properties setting and retrieval + */ + public void testOldProperties() + throws Exception + { + String oldProperties = TEST_COMPARE_DIR + "/oldproperties/velocity.properties"; + ve = new VelocityEngine(); + logger = new TestLogger(false, true); + logger.setEnabledLevel(TestLogger.LOG_LEVEL_WARN); + + // put our test logger where it belongs for this test + Field loggerField = DeprecationAwareExtProperties.class.getDeclaredField("logger"); + loggerField.setAccessible(true); + loggerField.set(null, logger); + + logger.on(); + ve.setProperties(oldProperties); + logger.off(); + + Translator translator = new Translator(); + + // check getting old/new values + List<String> oldPropSettings = FileUtils.readLines(new File(oldProperties)); + Set<String> oldKeys = new HashSet<>(); + for (String oldProp : oldPropSettings) + { + Matcher matcher = propPattern.matcher(oldProp); + if (matcher.matches()) + { + String propName = matcher.group(1); + String translated = translator.translateKey(propName); + if (!translated.equals(propName)) + { + Object oldKeyValue = ve.getProperty(propName); + Object newKeyValue = ve.getProperty(translated); + assertEquals(oldKeyValue, newKeyValue); + oldKeys.add(propName); + } + } + } + + // check warnings in the logs + String log = logger.getLog(); + String logLines[] = log.split("\\r?\\n"); + for (String logLine : logLines) + { + Matcher matcher = warnPattern.matcher(logLine); + if (matcher.matches() && matcher.groupCount() == 2) + { + String oldName = matcher.group(1); + assertTrue(oldKeys.remove(oldName)); + } + } + if (oldKeys.size() > 0) + { + fail("No warning detected for the following properties: " + StringUtils.join(oldKeys, ", ")); + } + } + + /** + * Check default properties + */ + public void testNewProperties() + throws Exception + { + ve = new VelocityEngine(); + logger = new TestLogger(false, true); + logger.setEnabledLevel(TestLogger.LOG_LEVEL_WARN); + + // put our test logger where it belongs for this test + Field loggerField = DeprecationAwareExtProperties.class.getDeclaredField("logger"); + loggerField.setAccessible(true); + loggerField.set(null, logger); + + logger.on(); + ve.init(); + logger.off(); + + // check warnings in the logs + String log = logger.getLog(); + String logLines[] = log.split("\\r?\\n"); + for (String logLine : logLines) + { + Matcher matcher = warnPattern.matcher(logLine); + if (matcher.matches() && matcher.groupCount() == 2) + { + fail("Default properties contain deprecated property '" + matcher.group(1) + "', deprecated in favor of '" + matcher.group(2) + "'"); + } + } + + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ParseExceptionTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ParseExceptionTestCase.java new file mode 100644 index 00000000..5dd2bd24 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ParseExceptionTestCase.java @@ -0,0 +1,179 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.io.StringWriter; +import java.io.Writer; + +/** + * Test parser exception is generated with appropriate info. + * + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class ParseExceptionTestCase extends BaseTestCase +{ + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = "parseexception"; + + + /** + * Default constructor. + * @param name name of test + */ + public ParseExceptionTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + Velocity.reset(); + super.setUp(); + } + + /** + * Tests that parseException has useful info when called by template.marge() + * @throws Exception + */ + public void testParseExceptionFromTemplate () + throws Exception + { + + VelocityEngine ve = new VelocityEngine(); + + ve.setProperty("file.resource.loader.cache", "true"); + ve.setProperty("file.resource.loader.path", TemplateTestBase.TEST_COMPARE_DIR + "/" + FILE_RESOURCE_LOADER_PATH); + ve.init(); + + + Writer writer = new StringWriter(); + + VelocityContext context = new VelocityContext(); + + try + { + Template template = ve.getTemplate("badtemplate.vm"); + template.merge(context, writer); + fail("Should have thown a ParseErrorException"); + } + catch (ParseErrorException e) + { + assertEquals("badtemplate.vm",e.getTemplateName()); + assertEquals(5,e.getLineNumber()); + assertEquals(9,e.getColumnNumber()); + } + finally + { + if (writer != null) + { + writer.close(); + } + } + } + + /** + * Tests that parseException has useful info when thrown in VelocityEngine.evaluate() + * @throws Exception + */ + public void testParseExceptionFromEval () + throws Exception + { + assertEvalExceptionAt(" #set($abc) ", 1, 13); + } + + /** + * Tests that parseException has useful info when thrown in VelocityEngine.evaluate() + * and the problem comes from a macro definition + * @throws Exception + */ + public void testParseExceptionFromMacroDef () + throws Exception + { + assertEvalExceptionAt("#macro($blarg) foo #end", 1, 7); + } + + /** + * Tests that parseException has useful info when thrown in VelocityEngine.evaluate() + * and the problem comes from a macro definition + * @throws Exception + */ + public void testParseExceptionFromMacroDefBody () + throws Exception + { + assertEvalExceptionAt("#macro(aa $blarg) #set(!! = bb) #end #aa('aa')", 1, 24); + } + + /** + * Tests that parseException has useful info when thrown in VelocityEngine.evaluate() + * and the problem comes from a macro invocation + * @throws Exception + */ + public void testParseExceptionFromMacroInvoke () + { + assertEvalExceptionAt("#macro( foo $a) $a #end #foo(woogie)", 1, 32); + } + + + /** + * Tests that parseException has useful info with macro calls with + * invalid number of arguments + * @throws Exception + */ + public void testParseExceptionMacroInvalidArgumentCount () + throws Exception + { + engine.setProperty(RuntimeConstants.VM_ARGUMENTS_STRICT,"true"); + assertEvalExceptionAt("#macro(foo $a) $a #end #foo('test1' 'test2')", 1, 24); + } + + + /** + * Tests that parseException has useful info with macro calls with + * invalid number of arguments + * @throws Exception + */ + public void testParseExceptionMacroInvalidArgumentCountNoException () + throws Exception + { + assertEvalEquals("test1", "#macro(foo $a)$a#end#foo('test1' 'test2')"); + } + + /** + * Minus is not any more allowed inside a symbol (reference, property or method). + * @throws Exception + */ + public void testParseExceptionMinusSignDissalowed() + throws Exception + { + assertEvalExceptionAt("${foo-bar}", 1, 6); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ParseWithMacroLibsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ParseWithMacroLibsTestCase.java new file mode 100644 index 00000000..1b83d5f4 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ParseWithMacroLibsTestCase.java @@ -0,0 +1,309 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Test case for including macro libraries via the #parse method. + */ +public class ParseWithMacroLibsTestCase extends BaseTestCase +{ + private static final String RESULT_DIR = TEST_RESULT_DIR + "/parsemacros"; + + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/parsemacros/compare"; + + public ParseWithMacroLibsTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + super.setUp(); + } + + /** + * Test suite + * @return test suite + */ + public static junit.framework.Test suite() + { + return new TestSuite(ParseWithMacroLibsTestCase.class); + } + + public void testParseMacroLocalCacheOn() + throws Exception + { + /* + * local scope, cache on + */ + VelocityEngine ve = createEngine(true, true); + + // render twice to make sure there is no difference with cached templates + testParseMacro(ve, "vm_library1.vm", "parseMacro1_1", false); + testParseMacro(ve, "vm_library1.vm", "parseMacro1_1", false); + + // run again with different macro library + testParseMacro(ve, "vm_library2.vm", "parseMacro1_1b", false); + testParseMacro(ve, "vm_library2.vm", "parseMacro1_1b", false); + } + + /** + * Runs the tests with global namespace. + */ + public void testParseMacroLocalCacheOff() + throws Exception + { + /* + * local scope, cache off + */ + VelocityEngine ve = createEngine(false, true); + + testParseMacro(ve, "vm_library1.vm", "parseMacro1_2", true); + + // run again with different macro library + testParseMacro(ve, "vm_library2.vm", "parseMacro1_2b", true); + } + + public void testParseMacroGlobalCacheOn() + throws Exception + { + /* + * global scope, cache on + */ + VelocityEngine ve = createEngine(true, false); + + // render twice to make sure there is no difference with cached templates + testParseMacro(ve, "vm_library1.vm", "parseMacro1_3", false); + testParseMacro(ve, "vm_library1.vm", "parseMacro1_3", false); + + // run again with different macro library + testParseMacro(ve, "vm_library2.vm", "parseMacro1_3b", false); + testParseMacro(ve, "vm_library2.vm", "parseMacro1_3b", false); + } + + public void testParseMacroGlobalCacheOff() + throws Exception + { + /* + * global scope, cache off + */ + VelocityEngine ve = createEngine(false, false); + + testParseMacro(ve, "vm_library1.vm", "parseMacro1_4", true); + + // run again with different macro library + testParseMacro(ve, "vm_library2.vm", "parseMacro1_4b", true); + + } + + /** + * Test #parse with macros. Can be used to test different engine configurations + * @param ve + * @param outputBaseFileName + * @param testCachingOff + * @throws Exception + */ + private void testParseMacro(VelocityEngine ve, String includeFile, String outputBaseFileName, boolean testCachingOff) + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, outputBaseFileName, RESULT_FILE_EXT)); + + VelocityContext context = new VelocityContext(); + context.put("includefile", includeFile); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + Template template = ve.getTemplate("parseMacro1.vm"); + template.merge(context, writer); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, outputBaseFileName, + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + String result = getFileContents(RESULT_DIR, outputBaseFileName, RESULT_FILE_EXT); + String compare = getFileContents(COMPARE_DIR, outputBaseFileName, CMP_FILE_EXT); + + String msg = "Processed template did not match expected output\n"+ + "-----Result-----\n"+ result + + "----Expected----\n"+ compare + + "----------------"; + + fail(msg); + } + + /* + * Show that caching is turned off + */ + if (testCachingOff) + { + Template t1 = ve.getTemplate("parseMacro1.vm"); + Template t2 = ve.getTemplate("parseMacro1.vm"); + + assertNotSame("Different objects", t1, t2); + } + } + + /** + * Return and initialize engine + * @return + */ + private VelocityEngine createEngine(boolean cache, boolean local) + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve.setProperty("velocimacro.permissions.allow.inline.to.replace.global", + local); + ve.setProperty("file.resource.loader.cache", cache); + ve.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + ve.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + TEST_COMPARE_DIR + "/parsemacros"); + ve.init(); + + return ve; + } + + + /** + * Test whether the literal text is given if a definition cannot be + * found for a macro. + * + * @throws Exception + */ + public void testParseMacrosWithNoDefinition() + throws Exception + { + /* + * ve1: local scope, cache on + */ + VelocityEngine ve1 = new VelocityEngine(); + + ve1.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve1.setProperty("velocimacro.permissions.allow.inline.to.replace.global", + Boolean.FALSE); + ve1.setProperty("file.resource.loader.cache", Boolean.TRUE); + ve1.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + ve1.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve1.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + TEST_COMPARE_DIR + "/parsemacros"); + ve1.init(); + + assureResultsDirectoryExists(RESULT_DIR); + + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, "parseMacro2", RESULT_FILE_EXT)); + + VelocityContext context = new VelocityContext(); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + Template template = ve1.getTemplate("parseMacro2.vm"); + template.merge(context, writer); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, "parseMacro2", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template did not match expected output"); + } + } + + + /** + * Test that if a macro is duplicated, the second one takes precendence + * + * @throws Exception + */ + public void testDuplicateDefinitions() + throws Exception + { + /* + * ve1: local scope, cache on + */ + VelocityEngine ve1 = new VelocityEngine(); + + ve1.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve1.setProperty("velocimacro.permissions.allow.inline.to.replace.global", + Boolean.FALSE); + ve1.setProperty("file.resource.loader.cache", Boolean.TRUE); + ve1.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + ve1.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve1.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + TEST_COMPARE_DIR + "/parsemacros"); + ve1.init(); + + assureResultsDirectoryExists(RESULT_DIR); + + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, "parseMacro3", RESULT_FILE_EXT)); + + VelocityContext context = new VelocityContext(); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + Template template = ve1.getTemplate("parseMacro3.vm"); + template.merge(context, writer); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, "parseMacro3", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template did not match expected output"); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ParserTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ParserTestCase.java new file mode 100644 index 00000000..f3e4af7b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ParserTestCase.java @@ -0,0 +1,201 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +/** + * More specific parser tests where just templating + * isn't enough. + * + * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class ParserTestCase extends TestCase +{ + public ParserTestCase(String testName) + { + super(testName); + } + + public static Test suite() + { + return new TestSuite(ParserTestCase.class); + } + + /** + * Test to make sure that using '=' in #if() throws a PEE + */ + public void testEquals() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + TestLogger logger = new TestLogger(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + ve.init(); + + /* + * this should parse fine -> uses == + */ + + String template = "#if($a == $b) foo #end"; + + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + + /* + * this should throw an exception + */ + + template = "#if($a = $b) foo #end"; + + try + { + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + fail("Could evaluate template with errors!"); + } + catch(ParseErrorException pe) + { + // Do nothing + } + } + + /** + * Test to see if we force the first arg to #macro() to be a word + */ + public void testMacro() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + TestLogger logger = new TestLogger(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + ve.init(); + + /* + * this should work + */ + + String template = "#macro(foo) foo #end"; + + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + + /* + * this should throw an exception + */ + + template = "#macro($x) foo #end"; + + try + { + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + fail("Could evaluate macro with errors!"); + } + catch(ParseErrorException pe) + { + // Do nothing + } + } + + /** + * Test to see if don't tolerate passing word tokens in anything but the + * 0th arg to #macro() and the 1th arg to foreach() + */ + public void testArgs() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + TestLogger logger = new TestLogger(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + ve.init(); + + /* + * this should work + */ + + String template = "#macro(foo) foo #end"; + + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + + /* + * this should work - spaces intentional + */ + + template = "#foreach( $i in $woogie ) end #end"; + + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + + /* + * this should bomb + */ + + template = "#macro( foo $a) $a #end #foo(woogie)"; + + try + { + ve.evaluate(new VelocityContext(), new StringWriter(), "foo", template); + fail("Evaluation of macro with errors succeeded!"); + } + catch(ParseErrorException pe) + { + // Do nothing + } + } + + /** + * Test to see if we toString is called multiple times on references. + */ + public void testASTReferenceToStringOnlyCalledOnce() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + TestLogger logger = new TestLogger(); + ve.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + ve.init(); + + String template = "$counter"; + + ToStringCounter counter = new ToStringCounter(); + Map m = new HashMap(); + m.put("counter", counter); + + ve.evaluate(new VelocityContext(m), new StringWriter(), "foo", template); + + assertEquals(1, counter.timesCalled); + } + + public static class ToStringCounter { + public int timesCalled = 0; + public String toString() { + this.timesCalled++; + return "foo"; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/PropertyMethodPrecedenceTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/PropertyMethodPrecedenceTestCase.java new file mode 100755 index 00000000..13f2266a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/PropertyMethodPrecedenceTestCase.java @@ -0,0 +1,103 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; + +/** + * Used to check that vararg method calls on references work properly + */ +public class PropertyMethodPrecedenceTestCase extends BaseTestCase +{ + public PropertyMethodPrecedenceTestCase(final String name) + { + super(name); + // DEBUG = true; + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("geta", new getGetgetisTool()); + context.put("getA", new GetgetisTool()); + context.put("geta2", new get2getisTool()); + context.put("get_a", new getisTool()); + context.put("isA", new isTool()); + } + + public void testLowercasePropertyMethods() + { + assertEvalEquals("getfoo", "$geta.foo"); + assertEvalEquals("getFoo", "$getA.foo"); + assertEvalEquals("get(foo)", "$get_a.foo"); + assertEvalEquals("true", "$isA.foo"); + } + + public void testUppercasePropertyMethods() + { + assertEvalEquals("getFoo", "$geta.Foo"); + assertEvalEquals("getfoo", "$geta2.Foo"); + assertEvalEquals("getFoo", "$getA.Foo"); + assertEvalEquals("get(Foo)", "$get_a.Foo"); + assertEvalEquals("true", "$isA.Foo"); + } + + + public static class isTool + { + public boolean isFoo() + { + return true; + } + } + + public static class getisTool extends isTool + { + public String get(String s) + { + return "get("+s+")"; + } + } + + public static class GetgetisTool extends getisTool + { + public String getFoo() + { + return "getFoo"; + } + } + + public static class getGetgetisTool extends GetgetisTool + { + public String getfoo() + { + return "getfoo"; + } + } + + public static class get2getisTool extends getisTool + { + public String getfoo() + { + return "getfoo"; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/RenderVelocityTemplateTest.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/RenderVelocityTemplateTest.java new file mode 100644 index 00000000..74288393 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/RenderVelocityTemplateTest.java @@ -0,0 +1,155 @@ +package org.apache.velocity.test; + +import junit.framework.Assert; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class RenderVelocityTemplateTest +{ + + static class RenderVelocityTemplate + { + static + { + try + { + Properties p = new Properties(); + p.put("velocimacro.permissions.allow.inline.local.scope", "true"); + Velocity.init(p); + } + catch (Exception e) + { + throw new AssertionError("Failed to init Velocity"); + } + } + + private final VelocityContext velocityContext = new VelocityContext(); + + private final String template; + + public RenderVelocityTemplate(String template) + { + this.template = template; + } + + public String getContent() + throws Exception + { + StringWriter stringWriter = new StringWriter(); + Velocity.evaluate(velocityContext, stringWriter, "", template); + return stringWriter.toString(); + } + } + + + private static final String templateString = "" + // + "#macro (showhelloworld $foo)\n" + // + "Hello, World\n" + // + "#end\n" + // + "\n" + // + "<html>\n" + // + "<head>\n" + // + "<title>page title</title>\n" + // + "</head>\n" + // + "<body>\n" + // + "<p>This is a test</p>\n" + // + "<p>#showhelloworld ($foo)</p>\n" + // + "</body>\n" + // + "</html>"; + + public void testMultipleEvals() + throws Exception + { + RenderVelocityTemplate template = new RenderVelocityTemplate(templateString); + + String result = null; + for (int i = 0; i < 1000; ++i) + { + result = template.getContent(); + + // Verify that the original macro invocation has been replaced with its result. + int index = result.indexOf("#showhelloworld"); + if (index != -1) + { + throw new AssertionError("Failed to substitute macro:\n" + result); + } + + // Verify that the macro did indeed expand. + int indexHW = result.indexOf("<p>Hello, World"); + Assert.assertTrue(indexHW >= 0); + + // Assert.assertEquals("", result); // enable to show what we really get + } + } + + /** Helper class for testMultiThreadMultipleEvals(). */ + static class ExceptionHandler + implements Thread.UncaughtExceptionHandler + { + List<Throwable> errors = new ArrayList<>(); + + @Override + public void uncaughtException(Thread t, Throwable e) + { + errors.add(e); + } + } + + /** Helper class for testMultiThreadMultipleEvals(). */ + class RunMultipleEvals + extends Thread + { + @Override + public void run() + { + try + { + testMultipleEvals(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + } + + /** + * Spawn multiple threads that concurrently call testMultipleEvals. + */ + public void testMultiThreadMultipleEvals() + throws Throwable + { + int nthreads = 4; + ExceptionHandler eh = new ExceptionHandler(); + + List<Thread> threads = new ArrayList<>(nthreads); + for (int i = 0; i < nthreads; ++i) + { + Thread t = new RunMultipleEvals(); + t.setUncaughtExceptionHandler(eh); + threads.add(t); + } + + for (Thread t : threads) + { + t.start(); + } + + for (Thread t : threads) + { + t.join(); + } + + if (eh.errors.size() > 0) + { + // Rethrow the first failing exception. + System.out.println("Failed " + eh.errors.size() + " out of " + nthreads + " template evaluations"); + throw eh.errors.get(0); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceCachingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceCachingTestCase.java new file mode 100644 index 00000000..4ca9a5a6 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceCachingTestCase.java @@ -0,0 +1,94 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +import java.io.StringWriter; +import java.io.Writer; + +/** + * Test resource caching related issues. + * + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class ResourceCachingTestCase extends BaseTestCase +{ + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = "/resourcecaching"; + + + /** + * Default constructor. + */ + public ResourceCachingTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + + } + + public static Test suite () + { + return new TestSuite(ResourceCachingTestCase.class); + } + + /** + * Tests for fix of bug VELOCITY-98 where a #include followed by #parse + * of the same file throws ClassCastException when caching is on. + * @throws Exception + */ + public void testIncludeParseCaching () + throws Exception + { + + VelocityEngine ve = new VelocityEngine(); + + ve.setProperty("file.resource.loader.cache", "true"); + ve.setProperty("file.resource.loader.path", TemplateTestBase.TEST_COMPARE_DIR + FILE_RESOURCE_LOADER_PATH); + ve.init(); + + Template template = ve.getTemplate("testincludeparse.vm"); + + Writer writer = new StringWriter(); + + VelocityContext context = new VelocityContext(); + + // will produce a ClassCastException if Velocity-98 is not solved + template.merge(context, writer); + writer.flush(); + writer.close(); + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceExistsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceExistsTestCase.java new file mode 100755 index 00000000..0c50219d --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceExistsTestCase.java @@ -0,0 +1,105 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.test.misc.TestLogger; + +/** + * Test the resource exists method + * + * @version $Id: ResourceExistsTestCase.java 687191 2008-08-19 23:02:41Z nbubna $ + */ +public class ResourceExistsTestCase extends BaseTestCase +{ + private VelocityEngine velocity; + private String path = TEST_COMPARE_DIR + "/resourceexists"; + private TestLogger logger = new TestLogger(); + + public ResourceExistsTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { +try { + velocity = new VelocityEngine(); + velocity.setProperty("resource.loader", "file,string"); + velocity.setProperty("file.resource.loader.path", path); + velocity.setProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + + // actual instance of logger + logger.on(); + velocity.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + velocity.setProperty("runtime.log.logsystem.test.level", "debug"); +} catch (Exception e) { + System.out.println("exception via gump: "+e); + e.printStackTrace(); + System.out.println("log: "+logger.getLog()); +} + } + + public void testFileResourceExists() throws Exception + { +try { + if (!velocity.resourceExists("testfile.vm")) + { + String msg = "testfile.vm was not found in path "+path; + System.out.println(msg); + System.out.println("Log was: "+logger.getLog()); + path = path+"/testfile.vm"; + java.io.File file = new java.io.File(path); + if (file.exists()) { + System.out.println("file system found "+path); + } else { + System.out.println(file+" could not be found as a file"); + } + fail(msg); + } + if (velocity.resourceExists("nosuchfile.vm")) + { + String msg = "nosuchfile.vm should not have been found in path "+path; + System.out.println(msg); + fail(msg); + } +} catch (Exception e) { + System.out.println("exception via gump: "+e); + e.printStackTrace(); + System.out.println("log: "+logger.getLog()); +} + } + + public void testStringResourceExists() throws Exception + { +try { + assertFalse(velocity.resourceExists("foo.vm")); + StringResourceLoader.getRepository().putStringResource("foo.vm", "Make it so!"); + assertTrue(velocity.resourceExists("foo.vm")); +} catch (Exception e) { + System.out.println("exception via gump: "+e); + e.printStackTrace(); + System.out.println("log: "+logger.getLog()); +} + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceLoaderInstanceTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceLoaderInstanceTestCase.java new file mode 100644 index 00000000..e6217b0c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ResourceLoaderInstanceTestCase.java @@ -0,0 +1,154 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.runtime.resource.loader.FileResourceLoader; +import org.apache.velocity.runtime.resource.loader.ResourceLoader; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Test that an instance of a ResourceLoader can be successfully passed in. + * + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class ResourceLoaderInstanceTestCase extends BaseTestCase +{ + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/resourceinstance"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/resourceinstance"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/resourceinstance/compare"; + + private TestLogger logger = new TestLogger(); + + /** + * Default constructor. + */ + public ResourceLoaderInstanceTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + + ResourceLoader rl = new FileResourceLoader(); + + // pass in an instance to Velocity + Velocity.reset(); + Velocity.setProperty( "resource.loader", "testrl" ); + Velocity.setProperty( "testrl.resource.loader.instance", rl ); + Velocity.setProperty( "testrl.resource.loader.path", FILE_RESOURCE_LOADER_PATH ); + + // actual instance of logger + logger.on(); + Velocity.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + Velocity.setProperty("runtime.log.logsystem.test.level", "debug"); + + Velocity.init(); + } + + public static Test suite () + { + return new TestSuite(ResourceLoaderInstanceTestCase.class); + } + + /** + * Runs the test. + */ + public void testResourceLoaderInstance () + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + Template template = RuntimeSingleton.getTemplate( + getFileName(null, "testfile", TMPL_FILE_EXT)); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULTS_DIR, "testfile", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + /* + * put the Vector into the context, and merge both + */ + + VelocityContext context = new VelocityContext(); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if ( !isMatch(RESULTS_DIR, COMPARE_DIR, "testfile", + RESULT_FILE_EXT, CMP_FILE_EXT) ) + { + String result = getFileContents(RESULT_DIR, "testfile", RESULT_FILE_EXT); + String compare = getFileContents(COMPARE_DIR, "testfile", CMP_FILE_EXT); + + String msg = "Processed template did not match expected output\n"+ + "-----Result-----\n"+ result + + "----Expected----\n"+ compare + + "----------------"; + + fail(msg); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/ScopeTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/ScopeTestCase.java new file mode 100755 index 00000000..21a6490d --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/ScopeTestCase.java @@ -0,0 +1,369 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.util.HashMap; + +/** + * This class tests the directive scope controls + */ +public class ScopeTestCase extends BaseTestCase +{ + public ScopeTestCase(String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty("a.provide.scope.control", "true"); + engine.setProperty("define.provide.scope.control", "true"); + engine.setProperty("evaluate.provide.scope.control", "true"); + engine.setProperty("foo.provide.scope.control", "true"); + engine.setProperty("macro.provide.scope.control", "true"); + engine.setProperty("template.provide.scope.control", "true"); + engine.setProperty("vm.provide.scope.control", "true"); + engine.setProperty("space.gobbling", "bc"); + } + + public void testScopeGetLeakIntoInner() + { + addTemplate("foo", "#foreach($i in [1..1])#set($foreach.a=$i)"+ + "#foreach($j in [2..2])$foreach.a#set($foreach.a=$j)"+ + "#foreach($k in [3..3])$foreach.a#end#end$foreach.a#end"); + assertTmplEquals("121", "foo"); + } + + public void testScopeGetLeakDoesntHideNullset() + { + addTemplate("a", "#macro(a)#set($macro.a='a')#b()$macro.a#end"+ + "#macro(b)$macro.a#set($macro.a=$null)$!macro.a#end"+ + "#a()"); + assertTmplEquals("aa", "a"); + } + + public void testRootTemplateMergeScope() + { + addTemplate("foo", "foo#break($template)bar"); + assertTmplEquals("foo", "foo"); + assertNull(context.get("template")); + } + + public void testParseScope() + { + addTemplate("test", "$template.info.depth"+ + "$!parse.parent.info.depth"+ + "#set( $template.foo = 'bar' )"+ + "$template.foo"+ + "#break($template)"+ + "woogie"); + assertEvalEquals("1bar", "#parse( 'test' )"); + assertNull(context.get("template")); + } + + public void testNestedParseScope() + { + HashMap grab = new HashMap(); + context.put("grab", grab); + + addTemplate("inner", "Inner depth: $template.info.depth"+ + "#set( $template.foo = '?' )"+ + "$!grab.put('inner',$template)"+ + "#break($template)$template.foo"); + addTemplate("outer", "#set( $template.foo = '!' )"+ + "Outer depth: $template.info.depth "+ + "#parse('inner')"+ + "$!grab.put('outer', $template)"+ + "$template.foo"); + assertEvalEquals("Outer depth: 1 Inner depth: 2!", "#parse('outer')"); + // make extra sure that the outer control was restored after the stop + assertFalse(grab.get("inner") == grab.get("outer")); + // make sure the outer control was cleaned up + assertNull(context.get("template")); + + addTemplate("3", "$template.topmost.foo#set( $template.topmost.foo = 'bar' )"); + addTemplate("2", "#parse( '3' )$!parse.foo"); + addTemplate("1", "#set( $template.foo = 'foo' )#parse('2')$template.foo"); + assertEvalEquals("foobar", "#parse('1')$!parse"); + // make sure the top control was cleaned up + assertNull(context.get("template")); + } + + public void testForeachScope() + { + String template = "#foreach( $i in [0..2] )"+ + "#if( $i > 1 )#break($foreach)#end"+ + "$foreach.index:$foreach.count:$foreach.hasNext,"+ + "#end"; + assertEvalEquals("0:1:true,1:2:true,", template); + assertNull(context.get("foreach")); + } + + public void testNestedForeachScope() + { + String template = "#foreach( $i in [1..5] )"+ + "#foreach( $j in [1..2] )"+ + "#if ( $i > $foreach.count + $foreach.index + $foreach.info.depth )#break($foreach.topmost)#end"+ + "#end"+ + "$i"+ + "#end"; + assertEvalEquals("123", template); + assertNull(context.get("foreach")); + } + + public void testMacroScope() + { + String template = "#macro( foo $i )"+ + "#if($i > 2 )#break($macro)#end"+ + "$i#end"+ + "#foo( 0 )#foo( 1 )#foo( 2 )"; + assertEvalEquals("012", template); + assertNull(context.get("macro")); + } + + public void testRecursiveMacroScope() + { + String template = "#macro( foo )$macro.info.depth"+ + "#if($macro.info.depth > 2 )#break($macro.topmost)#end"+ + "#foo()#end#foo()"; + assertEvalEquals("123", template); + assertNull(context.get("macro")); + } + + public void testNestedMacroScope() + { + String template = "#macro( a )$macro.info.depth#set($macro.c = 'a')$macro.c#end"+ + "#macro( b )#set($macro.c = 'b' )#a()$macro.c#end"+ + "#b()"; + assertEvalEquals("2ab", template); + assertNull(context.get("macro")); + } + + public void testBodyMacroScope() + { + String template = "#macro( foo $bar )$bodyContent$macro.bar#end"+ + "#@foo( 'bar' )#set( $macro.bar = 'foo'+$bar )"+ + "#set( $foo.d = $foo.info.depth )$foo.d #end"; + assertEvalEquals("1 foobar", template); + assertNull(context.get("foo")); + assertNull(context.get("macro")); + } + + public void testRecursiveBodyMacroScope() + { + engine.setProperty(RuntimeConstants.VM_MAX_DEPTH, "5"); + String template = "#macro( foo )$bodyContent$macro.i#end"+ + "#@foo()#set( $macro.i = \"$!macro.i$foo.info.depth,\" )"+ + "$!bodyContent#end"; + assertEvalEquals("1,2,3,4,5,", template); + assertNull(context.get("foo")); + assertNull(context.get("macro")); + } + + public void testDefineScope() + { + String template = "#define( $foo )#set( $define.bar = 'bar'+$define.info.depth )$define.bar#end$foo"; + assertEvalEquals("bar1", template); + assertNull(context.get("define")); + } + + public void testNestedDefineScope() + { + String template = "#define($a)$b c#end"+ + "#define($b)$define.info.depth#break($define.topmost)#end"+ + "$a"; + assertEvalEquals("2", template); + assertNull(context.get("define")); + } + + public void testRecursiveDefineScope() + { + engine.setProperty(RuntimeConstants.DEFINE_DIRECTIVE_MAXDEPTH, "10"); + String template = "#define($a)$define.info.depth"+ + "#if($define.info.depth == 5)#break($define)#end,$a#end$a"; + assertEvalEquals("1,2,3,4,5", template); + assertNull(context.get("define")); + } + + public void testRootEvaluateScope() + { + assertEvalEquals("1", "$evaluate.info.depth"); + assertEvalEquals("foo", "foo#break($evaluate)bar"); + assertNull(context.get("evaluate")); + } + + public void testEvaluateScope() + { + context.put("h", "#"); + context.put("d", "$"); + String template = "${h}set( ${d}evaluate.foo = 'bar' )"+ + "${d}evaluate.foo ${d}evaluate.info.depth"; + addTemplate("eval", "#evaluate(\""+template+"\")"); + assertTmplEquals("bar 1", "eval"); + assertNull(context.get("evaluate")); + assertNull(context.get("template")); + } + + public void testNestedEvaluateScope() + { + context.put("h", "#"); + context.put("d", "$"); + addTemplate("e", "#evaluate(\"${h}evaluate( '${d}evaluate.info.depth${h}stop(${d}evaluate) blah' )\")"); + assertTmplEquals("2", "e"); + assertNull(context.get("evaluate")); + assertNull(context.get("template")); + } + + public void testTurningOffTemplateScope() + { + engine.setProperty("template."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false"); + // root + addTemplate("test", "$template.info.depth"); + assertTmplEquals("$template.info.depth", "test"); + // #parse + assertEvalEquals("$template.info.depth", "#parse('test')"); + } + + public void testTurningOffEvaluateScope() + { + engine.setProperty("evaluate."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false"); + // root + assertSchmoo("$evaluate.info.depth"); + // #evaluate + assertEvalEquals("$evaluate.info.depth", "#evaluate( '$evaluate.info.depth' )"); + } + + public void testTurningOffMacroScope() + { + engine.setProperty("macro."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false"); + engine.setProperty("foo."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false"); + // macro definition + assertEvalEquals("$macro", "#macro(a)$macro#end#a()"); + // macro body + assertEvalEquals("$macro $foo", "#macro(foo)$bodyContent#end#@foo()$macro $foo#end"); + } + + public void testTurningOffDefineScope() + { + engine.setProperty("define."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false"); + assertEvalEquals("$define", "#define($a)$define#end$a"); + } + + public void testTurningOffForeachScope() + { + engine.setProperty("foreach."+RuntimeConstants.PROVIDE_SCOPE_CONTROL, "false"); + assertEvalEquals("$foreach$foreach", "#foreach($i in [0..1])$foreach#end"); + } + + public void testTemplateReplaced() + { + context.put("template", "foo"); + addTemplate("test", "$template.replaced"); + assertTmplEquals("foo", "test"); + assertEvalEquals("foo", "#parse('test')"); + assertContextValue("template", "foo"); + } + + public void testEvaluateReplaced() + { + context.put("evaluate","foo"); + assertEvalEquals("foo", "$evaluate.replaced"); + assertEvalEquals("foo", "#evaluate('$evaluate.replaced')"); + assertContextValue("evaluate", "foo"); + } + + public void testMacroReplaced() + { + context.put("macro", "foo"); + assertEvalEquals("foo foo foo", "$macro #macro(a)$macro.replaced#end#a() $macro"); + assertContextValue("macro", "foo"); + } + + public void testForeachReplaced() + { + context.put("foreach", "foo"); + assertEvalEquals("foofoofoo", "$foreach#foreach($i in [1..1])$foreach.replaced#end$foreach"); + assertEquals("foo", context.get("foreach")); + context.put("foreach", "a"); + assertEvalEquals("a", "#foreach($i in [1..1])#foreach($j in [1..1])$foreach.replaced#end#end"); + assertContextValue("foreach", "a"); + } + + public void testDefineReplaced() + { + context.put("define", "a"); + assertEvalEquals("a", "#define($a)$define.replaced#end$a"); + assertContextValue("define", "a"); + } + + public void testBodyContentReplaced() + { + context.put("vm", "a"); + assertEvalEquals("a", "#macro(vm)$bodyContent#end#@vm()$vm.replaced#end"); + assertContextValue("vm", "a"); + } + + public void testInfoDepth() + { + String template = "#foreach($i in [1..1])"+ + "#foreach($j in [0..0])"+ + "$foreach.info.depth"+ + "#end"+ + "#end"; + assertEvalEquals("2", template); + } + + public void testInfoName() + { + String template = "#foreach($i in [1..1])"+ + "$foreach.info.name #evaluate('$evaluate.info.name')"+ + "#end"; + assertEvalEquals("foreach evaluate", template); + } + + public void testInfoType() + { + addTemplate("info", "#foreach($i in [1..1])"+ + "$foreach.info.type"+ + "#end "+ + "#evaluate('$evaluate.info.type') "+ + "$template.info.type"); + assertTmplEquals("block line utf-8", "info"); + } + + public void testInfoLineAndColumn() + { + String template = " #evaluate('$evaluate.info.line, $evaluate.info.column')"; + assertEvalEquals(" 1, 2", template); + assertEvalEquals("\n\n 3, 4", "\n\n "+template); + } + + public void testInfoTemplate() + { + addTemplate("test", "#evaluate('$evaluate.info.template')"); + assertTmplEquals("test", "test"); + assertEvalEquals("test", "#parse('test')"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/SecureIntrospectionTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/SecureIntrospectionTestCase.java new file mode 100644 index 00000000..f504029f --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/SecureIntrospectionTestCase.java @@ -0,0 +1,179 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.util.introspection.SecureUberspector; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collection; +import java.util.HashSet; + +/** + * Checks that the secure introspector is working properly. + * + * @author <a href="Will Glass-Husain">wglass@forio.com</a> + * @version $Id$ + */ +public class SecureIntrospectionTestCase extends BaseTestCase +{ + + /** + * Default constructor. + * @param name + */ + public SecureIntrospectionTestCase(String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(SecureIntrospectionTestCase.class); + } + + + private String [] badTemplateStrings = + { + "$test.Class.Methods", + "$test.Class.ClassLoader", + "$test.Class.ClassLoader.loadClass('java.util.HashMap').newInstance().size()" + }; + + private String [] goodTemplateStrings = + { + "#foreach($item in $test.collection)$item#end", + "$test.Class.Name", + "#set($test.Property = 'abc')$test.Property", + "$test.aTestMethod()" + }; + + /** + * Test to see that "dangerous" methods are forbidden + * @exception Exception + */ + public void testBadMethodCalls() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, SecureUberspector.class.getName()); + ve.init(); + + /* + * all of the following method calls should not work + */ + doTestMethods(ve, badTemplateStrings, false); + } + + /** + * Test to see that "dangerous" methods are forbidden + * @exception Exception + */ + public void testGoodMethodCalls() + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.UBERSPECT_CLASSNAME, SecureUberspector.class.getName()); + ve.init(); + + /* + * all of the following method calls should not work + */ + doTestMethods(ve, goodTemplateStrings, true); + } + + private void doTestMethods(VelocityEngine ve, String[] templateStrings, boolean shouldeval) + { + Context c = new VelocityContext(); + c.put("test", this); + + try + { + for (String templateString : templateStrings) + { + if (shouldeval && !doesStringEvaluate(ve, c, templateString)) + { + fail("Should have evaluated: " + templateString); + } + + if (!shouldeval && doesStringEvaluate(ve, c, templateString)) + { + fail("Should not have evaluated: " + templateString); + } + } + + } + catch (Exception e) + { + fail(e.toString()); + } + } + + private boolean doesStringEvaluate(VelocityEngine ve, Context c, String inputString) throws ParseErrorException, MethodInvocationException, ResourceNotFoundException, IOException + { + // assume that an evaluation is bad if the input and result are the same (e.g. a bad reference) + // or the result is an empty string (e.g. bad #foreach) + Writer w = new StringWriter(); + ve.evaluate(c, w, "foo", inputString); + String result = w.toString(); + return (result.length() > 0 ) && !result.equals(inputString); + } + + private String testProperty; + public String getProperty() + { + return testProperty; + } + + public int aTestMethod() + { + return 1; + } + + public void setProperty(String val) + { + testProperty = val; + } + + + public Collection getCollection() + { + Collection c = new HashSet(); + c.add("aaa"); + c.add("bbb"); + c.add("ccc"); + return c; + } +} + + diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/SetTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/SetTestCase.java new file mode 100644 index 00000000..e6794800 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/SetTestCase.java @@ -0,0 +1,144 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Test that an instance of a ResourceLoader can be successfully passed in. + * + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class SetTestCase extends BaseTestCase +{ + /** + * VTL file extension. + */ + private static final String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + private final static String FILE_RESOURCE_LOADER_PATH = TEST_COMPARE_DIR + "/set"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/set"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/set/compare"; + + /** + * Default constructor. + */ + public SetTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.addProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + assureResultsDirectoryExists(RESULTS_DIR); + } + + /** + * Runs the test. + */ + public void testSetNull() + throws Exception + { + /* + * Check that #set does accept nulls + */ + checkTemplate("set1"); + + /* + * Check that #set can accept nulls, and has the correct behaviour for complex LHS + */ + checkTemplate("set2"); + } + + public void checkTemplate(String templateName) throws Exception + { + Template template; + FileOutputStream fos; + Writer fwriter; + + template = engine.getTemplate(getFileName(null, templateName, TMPL_FILE_EXT)); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, templateName, RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, templateName, RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + } + + public void testInvalidSet() throws Exception + { + /* the purpose of this test is to check that in case of error, the calculation of the + literal representation of the expression, which is displayed in the logs, does not raise a null exception + */ + assertEvalEquals("", "#set($c = $a - $b - $c)"); + assertEvalEquals("", "#set($c = $a + $b + $c)"); + assertEvalEquals("", "#set($c = $a * $b * $c)"); + assertEvalEquals("", "#set($c = $a / $b / $c)"); + assertEvalEquals("", "#set($c = $a % $b % $c)"); + assertEvalEquals("", "#set($c = $a && $b && $c)"); + assertEvalEquals("", "#set($c = $a || $b || $c)"); + assertEvalEquals("", "#set($c = $a + $b + !$c)"); + assertEvalEquals("", "#set($c = $a + $b + (-$c))"); + assertEvalEquals("", "#set($c = $a && ($b < $c))"); + assertEvalEquals("", "#set($c = !$a)"); + assertEvalEquals("", "#set($c = ($a < $b) - ($c < $d))"); + assertEvalEquals("","#set($b = !$a)"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/SpaceGobblingTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/SpaceGobblingTestCase.java new file mode 100644 index 00000000..e8d22bdf --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/SpaceGobblingTestCase.java @@ -0,0 +1,143 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.RuntimeConstants.SpaceGobbling; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Test case for conversion handler + */ +public class SpaceGobblingTestCase extends BaseTestCase +{ + private static final String RESULT_DIR = TEST_RESULT_DIR + "/gobbling"; + + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/gobbling/compare"; + + public SpaceGobblingTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + super.setUp(); + } + + /** + * Test suite + * @return test suite + */ + public static junit.framework.Test suite() + { + return new TestSuite(SpaceGobblingTestCase.class); + } + + /** + * Return and initialize engine + * @return + */ + private VelocityEngine createEngine(SpaceGobbling mode) + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(Velocity.RUNTIME_LOG_INSTANCE, log); + ve.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, TEST_COMPARE_DIR + "/gobbling"); + ve.setProperty(RuntimeConstants.SPACE_GOBBLING, mode.toString()); + ve.init(); + + return ve; + } + + public void testSpaceGobbling() throws Exception + { + for (SpaceGobbling mode : SpaceGobbling.values()) + { + testMode(mode); + } + } + + private void testMode(SpaceGobbling mode) throws Exception + { + File dir = new File(TEST_COMPARE_DIR + "/gobbling"); + File[] directoryListing = dir.listFiles(); + if (directoryListing != null) + { + for (File child : directoryListing) + { + if (child.isFile()) + { + testTemplate(child.getName(), mode); + } + } + } + else + { + throw new Exception("cannot read input templates"); + } + } + + private void testTemplate(String templateFile, SpaceGobbling mode) throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + FileOutputStream fos = new FileOutputStream (getFileName(RESULT_DIR, templateFile, mode.toString())); + VelocityContext context = new VelocityContext(); + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityEngine ve = createEngine(mode); + Template template = ve.getTemplate(templateFile); + template.merge(context, writer); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, templateFile, mode.toString(), mode.toString())) + { + String result = getFileContents(RESULT_DIR, templateFile, mode.toString()); + String compare = getFileContents(COMPARE_DIR, templateFile, mode.toString()); + + String msg = "Processed template did not match expected output for template " + templateFile + " and mode " + mode + "\n"+ + "-----Result-----\n"+ result + + "----Expected----\n"+ compare + + "----------------"; + + fail(msg); + } + + } +} + diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StaticUtilityMethodsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StaticUtilityMethodsTestCase.java new file mode 100755 index 00000000..60cabbf6 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StaticUtilityMethodsTestCase.java @@ -0,0 +1,57 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + + +/** + * This class tests support for putting static utility classes + * like java.lang.Math directly into the context in order to + * use their methods. + */ +public class StaticUtilityMethodsTestCase extends BaseTestCase +{ + public StaticUtilityMethodsTestCase(String name) + { + super(name); + } + + public void testMath() + { + context.put("Math", Math.class); + assertEvalEquals("java.lang.Math", "$Math.name"); + assertEvalEquals("3.0", "$Math.ceil(2.5)"); + } + + public void testFoo() + { + context.put("Foo", Foo.class); + assertEvalEquals("test", "$Foo.foo('test')"); + } + + + public static class Foo + { + private Foo() {} + public static String foo(String s) + { + return s == null ? "foo" : s; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StopDirectiveTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StopDirectiveTestCase.java new file mode 100644 index 00000000..f09a53d0 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StopDirectiveTestCase.java @@ -0,0 +1,85 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +/** + * Test the #stop directive + */ +public class StopDirectiveTestCase extends BaseTestCase +{ + public StopDirectiveTestCase(String name) + { + super(name); + //DEBUG=true; + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, TemplateTestBase.TEST_COMPARE_DIR + "/stop"); + engine.setProperty(RuntimeConstants.VM_LIBRARY, "vmlib1.vm"); + } + + public void testStop() + { + // Make it work through the evaluate method call + assertEvalEquals("Text1", "Text1#{stop}Text2"); + // Make sure stop works in a template + assertTmplEquals("Text 1", "stop1.vm"); + // Make sure stop works when called from a velocity macro + assertTmplEquals("Text123stuff1", "stop2.vm"); + // Make sure stop works when called located in another parsed file + assertTmplEquals("text1blaa1", "stop3.vm"); + } + + public void testNestedStopAll() + { + addTemplate("ns", ",template"+ + "#macro(vm),macro${bodyContent}macro#end"+ + "#define($define),define"+ + "#foreach($i in [1..2]),foreach"+ + "#{stop}foreach"+ + "#{end}define"+ + "#{end}"+ + "#@vm(),bodyContent"+ + "${define}bodyContent"+ + "#{end}template"); + String expected = "evaluate,template,macro,bodyContent,define,foreach"; + assertEvalEquals(expected, "#evaluate('evaluate#parse(\"ns\")evaluate')"); + } + + public void testStopMessage() + { + log.setEnabledLevel(TestLogger.LOG_LEVEL_DEBUG); + context.put("log", log); + + assertEvalEquals("a", "a$!log.startCapture()#stop('woogie!')b"); + + log.stopCapture(); + log.on(); + info("Log: "+log.getLog()); + assertTrue(log.getLog().contains("StopCommand: woogie!")); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictAlternateValuesTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictAlternateValuesTestCase.java new file mode 100644 index 00000000..36fe903b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictAlternateValuesTestCase.java @@ -0,0 +1,76 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * Base test case that provides utility methods for + * the rest of the tests. + * + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> + * @author Nathan Bubna + * @version $Id: AlternateValuesTestCase.java 1843764 2018-10-13 14:52:28Z cbrisson $ + */ +public class StrictAlternateValuesTestCase extends BaseTestCase +{ + public StrictAlternateValuesTestCase(String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("foo", null); + } + + public void testDefault() + { + assertEvalEquals("<foo>", "<${foo|'foo'}>"); + assertEvalEquals("bar", "#set($bar='bar')${foo|$bar}"); + assertEvalEquals("bar", "#set($bar='bar')${foo|${bar}}"); + assertEvalException("${foo.bar.baz()[5]|'hop'}", VelocityException.class); + assertEvalEquals("{foo}", "{${foo|'foo'}}"); + assertEvalException("$foo", VelocityException.class); + } + + public void testComplexEval() + { + assertEvalException("<${date.format('medium', $date.date)|'no date tool'}>", VelocityException.class); + assertEvalEquals("true", "#set($val=false)${val.toString().replace(\"false\", \"true\")|'so what'}"); + assertEvalEquals("so what", "#set($foo='foo')${foo.contains('bar')|'so what'}"); + assertEvalEquals("so what", "#set($val=false)${val.toString().contains('bar')|'so what'}"); + assertEvalEquals("true", "#set($val=false)${val.toString().contains('false')|'so what'}"); + assertEvalException("$!{null|$null}", VelocityException.class); + assertEvalEquals("null", "$!{null|'null'}"); + assertEvalEquals("so what", "#set($spaces=' ')${spaces.trim()|'so what'}"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictCompareTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictCompareTestCase.java new file mode 100644 index 00000000..5174f248 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictCompareTestCase.java @@ -0,0 +1,76 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * Make sure exceptions are thrown for strict comparisons that + * cannot be compared. + */ +public class StrictCompareTestCase extends BaseTestCase +{ + public StrictCompareTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + context.put("NULL", null); + context.put("a", "abc"); + context.put("b", 3); + context.put("TRUE", Boolean.TRUE); + } + + public void testCompare() + { + assertVelocityEx("#if($a > $NULL)#end"); + assertVelocityEx("#if($a < $NULL)#end"); + assertVelocityEx("#if($a >= $NULL)#end"); + assertVelocityEx("#if($a <= $NULL)#end"); + + assertVelocityEx("#if($NULL > $a)#end"); + assertVelocityEx("#if($NULL < $a)#end"); + assertVelocityEx("#if($NULL >= $a)#end"); + assertVelocityEx("#if($NULL <= $a)#end"); + + assertVelocityEx("#if($NULL >= $NULL)#end"); + assertVelocityEx("#if($a >= $b)#end"); + assertVelocityEx("#if($a <= $b)#end"); + assertVelocityEx("#if($a > $b)#end"); + assertVelocityEx("#if($a < $b)#end"); + + assertVelocityEx("#if($a < 5)#end"); + assertVelocityEx("#if($a > 5)#end"); + } + + /** + * Assert that we get a VelocityException when calling evaluate + */ + public void assertVelocityEx(String template) + { + assertEvalException(template, VelocityException.class); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictEscapeTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictEscapeTestCase.java new file mode 100644 index 00000000..b3ab04a6 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictEscapeTestCase.java @@ -0,0 +1,139 @@ +package org.apache.velocity.test; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +import org.apache.velocity.runtime.RuntimeConstants; + + +/** + * Test Strict escape mode + * property: RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE set to true + */ +public class StrictEscapeTestCase extends BaseTestCase +{ + public StrictEscapeTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE, Boolean.TRUE); + context.put("pow", "bang"); + context.put("NULL", null); + context.put("animal", new Animal()); + // DEBUG = true; + } + + public void testReferenceEscape() + { + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + + assertEvalException("\\\\$bogus"); + assertEvalException("\\\\\\\\$bogus"); + + assertEvalEquals("$bogus", "\\$bogus"); + assertEvalEquals("$bogus.xyz", "\\$bogus.xyz"); + assertEvalEquals("${bogus}", "\\${bogus}"); + assertEvalEquals("${bogus.xyz}", "\\${bogus.xyz}"); + assertEvalEquals("\\$bogus", "\\\\\\$bogus"); + assertEvalEquals("\\xyz","#set($foo = \"xyz\")\\\\$foo"); + assertEvalEquals("\\$foo","#set($foo = \"xyz\")\\\\\\$foo"); + assertEvalEquals("$foo\\","#set($foo = \"xyz\")\\$foo\\"); + assertEvalEquals("$pow", "#set($foo = \"\\$pow\")$foo"); + assertEvalEquals("\\bang", "#set($foo = \"\\\\$pow\")$foo"); + assertEvalEquals("\\$pow", "#set($foo = \"\\\\\\$pow\")$foo"); + + assertEvalEquals("\\$%", "\\$%"); + + // This should work but does not... may be related to VELOCITY-679 + // This is broken from existing escape behavior + // assertEvalEquals("\\$bang", "\\$$pow"); + + assertEvalEquals("$!foo", "#set($foo = $NULL)\\$!foo"); + assertEvalEquals("$!animal.null", "\\$!animal.null"); + assertEvalEquals("$!animal", "\\$!animal"); + } + + public void testMacroEscape() + { + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + assertEvalException("\\\\#bogus()"); + + // define the foo macro + assertEvalEquals("", "#macro(foo)bar#end"); + + assertEvalEquals("#foo()", "\\#foo()"); + assertEvalEquals("\\bar", "\\\\#foo()"); + assertEvalEquals("\\#foo()", "\\\\\\#foo()"); + + assertEvalEquals("bar", "#set($abc = \"#foo()\")$abc"); + assertEvalEquals("#foo()", "#set($abc = \"\\#foo()\")$abc"); + assertEvalEquals("\\bar", "#set($abc = \"\\\\#foo()\")$abc"); + + assertEvalEquals("#@foo()", "\\#@foo()"); + assertEvalEquals("#@foo", "\\#@foo"); + assertEvalEquals("#@bar", "\\#@bar"); + assertEvalEquals("\\bar", "\\\\#@foo()#end"); + assertEvalEquals("#@foo()#end", "\\#@foo()\\#end"); + assertEvalEquals("#@foo#end", "\\#@foo\\#end"); + assertEvalEquals("#@bar #end", "\\#@bar \\#end"); + + assertEvalEquals("#end #foreach #define() #elseif", "\\#end \\#foreach \\#define() \\#elseif"); + assertEvalEquals("#{end} #{foreach} #{define}() #{elseif}", "\\#{end} \\#{foreach} \\#{define}() \\#{elseif}"); + assertEvalEquals("#macro(foo) #end", "\\#macro(foo) \\#end"); + + assertEvalException("\\\\#end"); + assertEvalException("\\\\#if()"); + + // This should work but does not, probably related to VELOCITY-678 + // this is broken from existing behavior + //assertEvalEquals("\\$bar", "\\$#foo()"); + } + + /** + * Tests for non strict-mode + */ + public void testStrictMode() + { + assertEvalEquals("#bogus()", "\\#bogus()"); + assertEvalEquals("\\#bogus", "\\\\#bogus"); + + assertEvalEquals("\\$bogus", "\\\\$bogus"); + assertEvalEquals("\\\\$bogus", "\\\\\\\\$bogus"); + assertEvalEquals("\\$bogus", "#set($foo = \"\\\\$bogus\")$foo"); + } + + /** + * Test object for escaping + */ + public static class Animal + { + public Object getNull() + { + return null; + } + + public String toString() + { + return null; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictForeachTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictForeachTestCase.java new file mode 100755 index 00000000..3632016b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictForeachTestCase.java @@ -0,0 +1,110 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * This class tests support for strict foreach mode. + */ +public class StrictForeachTestCase extends BaseTestCase +{ + public StrictForeachTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.SKIP_INVALID_ITERATOR, Boolean.FALSE); + context.put("good", new GoodIterable()); + context.put("bad", new BadIterable()); + context.put("ugly", new UglyIterable()); + } + + public void testGood() + { + try + { + evaluate("#foreach( $i in $good )$i#end"); + } + catch (VelocityException ve) + { + fail("Doing #foreach on $good should not have exploded!"); + } + } + + public void testBad() + { + try + { + evaluate("#foreach( $i in $bad )$i#end"); + fail("Doing #foreach on $bad should have exploded!"); + } + catch (VelocityException ve) + { + // success! + } + } + + public void testUgly() + { + try + { + evaluate("#foreach( $i in $ugly )$i#end"); + fail("Doing #foreach on $ugly should have exploded!"); + } + catch (VelocityException ve) + { + // success! + } + } + + + public static class GoodIterable + { + public Iterator iterator() + { + return new ArrayList().iterator(); + } + } + + public static class BadIterable + { + public Object iterator() + { + return new Object(); + } + } + + public static class UglyIterable + { + public Iterator iterator() + { + return null; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictMathTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictMathTestCase.java new file mode 100755 index 00000000..4515a899 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictMathTestCase.java @@ -0,0 +1,86 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.MathException; +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * This class tests support for strict math mode. + */ +public class StrictMathTestCase extends BaseTestCase +{ + public StrictMathTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.STRICT_MATH, Boolean.TRUE); + context.put("num", 5); + context.put("zero", 0); + } + + protected void assertNullMathEx(String operation) + { + String leftnull = "#set( $foo = $null "+operation+" $num )"; + assertEvalException(leftnull, MathException.class); + String rightnull = "#set( $foo = $num "+operation+" $null )"; + assertEvalException(rightnull, MathException.class); + } + + protected void assertImaginaryMathEx(String operation) + { + String infinity = "#set( $foo = $num "+operation+" $zero )"; + assertEvalException(infinity, MathException.class); + } + + + public void testAdd() + { + assertNullMathEx("+"); + } + + public void testSub() + { + assertNullMathEx("-"); + } + + public void testMul() + { + assertNullMathEx("*"); + } + + public void testMod() + { + assertNullMathEx("%"); + assertImaginaryMathEx("%"); + } + + public void testDiv() + { + assertNullMathEx("/"); + assertImaginaryMathEx("/"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictReferenceTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictReferenceTestCase.java new file mode 100644 index 00000000..5a6b6d17 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StrictReferenceTestCase.java @@ -0,0 +1,257 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.runtime.RuntimeConstants; + +/** + * Test strict reference mode turned on by the velocity property + * runtime.references.strict + */ +public class StrictReferenceTestCase extends BaseTestCase +{ + public StrictReferenceTestCase(String name) + { + super(name); + } + + // second engine to test WITH conversions + VelocityEngine engine2; + + @Override + public void setUp() throws Exception + { + super.setUp(); + + /* first engine without conversions */ + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + engine.setProperty(RuntimeConstants.CONVERSION_HANDLER_CLASS, "none"); + + /* second engine with conversions */ + engine2 = createEngine(); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + + context.put("NULL", null); + context.put("bar", null); + context.put("TRUE", Boolean.TRUE); + } + + /** + * Test the modified behavior of #if in strict mode. Mainly, that + * single variables references in #if statements use non strict rules + */ + public void testIfStatement() + { + Fargo fargo = new Fargo(); + fargo.next = new Fargo(); + context.put("fargo", fargo); + assertEvalEquals("", "#if($bogus)xxx#end"); + assertEvalEquals("xxx", "#if($fargo)xxx#end"); + assertEvalEquals("", "#if( ! $fargo)xxx#end"); + assertEvalEquals("xxx", "#if($bogus || $fargo)xxx#end"); + assertEvalEquals("", "#if($bogus && $fargo)xxx#end"); + assertEvalEquals("", "#if($fargo != $NULL && $bogus)xxx#end"); + assertEvalEquals("xxx", "#if($fargo == $NULL || ! $bogus)xxx#end"); + assertEvalEquals("xxx", "#if(! $bogus1 && ! $bogus2)xxx#end"); + assertEvalEquals("xxx", "#if($fargo.prop == \"propiness\" && ! $bogus && $bar == $NULL)xxx#end"); + assertEvalEquals("", "#if($bogus && $bogus.foo)xxx#end"); + + assertMethodEx("#if($bogus.foo)#end"); + assertMethodEx("#if(!$bogus.foo)#end"); + } + + + /** + * We make sure that variables can actuall hold null + * values. + */ + public void testAllowNullValues() + throws Exception + { + evaluate("$!bar"); + assertEvalEquals("true", "#if($bar == $NULL)true#end"); + assertEvalEquals("true", "#set($foobar = $NULL)#if($foobar == $NULL)true#end"); + assertEvalEquals("13", "#set($list = [1, $NULL, 3])#foreach($item in $list)#if($item != $NULL)$item#end#end"); + } + + /** + * Test that variables references that have not been defined throw exceptions + */ + public void testStrictVariableRef() + throws Exception + { + // We expect a Method exception on the following + assertMethodEx("$bogus"); + assertMethodEx("#macro(test)$bogus#end #test()"); + + assertMethodEx("#set($bar = $bogus)"); + + assertMethodEx("#if($bogus == \"bar\") #end"); + assertMethodEx("#if($bogus != \"bar\") #end"); + assertMethodEx("#if(\"bar\" == $bogus) #end"); + assertMethodEx("#if($bogus > 1) #end"); + assertMethodEx("#foreach($item in $bogus)#end"); + + // make sure no exceptions are thrown here + evaluate("#set($foo = \"bar\") $foo"); + evaluate("#macro(test1 $foo1) $foo1 #end #test1(\"junk\")"); + evaluate("#macro(test2) #set($foo2 = \"bar\") $foo2 #end #test2()"); + } + + /** + * Test that exceptions are thrown when methods are called on + * references that contains objects that do not contains those + * methods. + */ + public void testStrictMethodRef() + { + Fargo fargo = new Fargo(); + fargo.next = new Fargo(); + context.put("fargo", fargo); + + // Mainly want to make sure no exceptions are thrown here + assertEvalEquals("propiness", "$fargo.prop"); + assertEvalEquals("", "$!fargo.nullVal"); + assertEvalEquals("propiness", "$fargo.next.prop"); + + assertMethodEx("$fargo.foobar"); + assertMethodEx("$fargo.next.foobar"); + assertMethodEx("$fargo.foobar()"); + assertMethodEx("#set($fargo.next.prop = $TRUE)"); + assertMethodEx("$fargo.next.setProp($TRUE)"); + } + + /** + * Make sure exceptions are thrown when when we attempt to call + * methods on null values. + */ + public void testStrictMethodOnNull() + { + Fargo fargo = new Fargo(); + fargo.next = new Fargo(); + context.put("fargo", fargo); + + assertVelocityEx("$NULL.bogus"); + assertVelocityEx("$fargo.nullVal.bogus"); + assertVelocityEx("$fargo.next.nullVal.bogus"); + assertVelocityEx("#if (\"junk\" == $fargo.nullVal.bogus)#end"); + assertVelocityEx("#if ($fargo.nullVal.bogus > 2)#end"); + assertVelocityEx("#set($fargo.next.nullVal.bogus = \"junk\")"); + assertVelocityEx("#set($foo = $NULL.bogus)"); + assertVelocityEx("#foreach($item in $fargo.next.nullVal.bogus)#end"); + + evaluate("$fargo.prop.toString()"); + assertVelocityEx("#set($fargo.prop = $NULL)$fargo.prop.next"); + + // make sure no exceptions are thrown here + evaluate("$!fargo.next.next"); + evaluate("$!fargo.next.nullVal"); + evaluate("#foreach($item in $fargo.nullVal)#end"); + } + + /** + * Make sure undefined macros throw exceptions + */ + public void testMacros() + { + assertVelocityEx("#bogus()"); + assertVelocityEx("#bogus ( )"); + assertVelocityEx("#bogus( $a )"); + assertVelocityEx("abc#bogus ( $a )a "); + + assertEvalEquals(" true ", "#macro(test1) true #end#test1()"); + assertEvalEquals(" true ", "#macro(test2 $a) $a #end#test2 ( \"true\")"); + assertEvalEquals("#CCFFEE", "#CCFFEE"); + assertEvalEquals("#F - ()", "#F - ()"); + assertEvalEquals("#F{}", "#F{}"); + } + + + public void testRenderingNull() + { + Fargo fargo = new Fargo(); + fargo.next = new Fargo(); + context.put("fargo", fargo); + + assertVelocityEx("#set($foo = $NULL)$foo"); + assertEvalEquals("", "#set($foo = $NULL)$!foo"); + assertVelocityEx("$fargo.nullVal"); + assertEvalEquals("", "$!fargo.nullVal"); + assertVelocityEx("$fargo.next.next"); + assertEvalEquals("", "$!fargo.next.next"); + assertVelocityEx("$fargo.next.nullVal"); + assertEvalEquals("", "$!fargo.next.nullVal"); + } + + /** + * Assert that we get a MethodInvocationException when calling evaluate + */ + public void assertMethodEx(String template) + { + assertEvalException(template, MethodInvocationException.class); + } + + /** + * Assert that we get a VelocityException when calling evaluate + */ + public void assertVelocityEx(String template) + { + assertEvalException(template, VelocityException.class); + } + + /** + * Assert that we get a MethodInvocationException when calling evaluate + */ + public void assertParseEx(String template) + { + assertEvalException(template, ParseErrorException.class); + } + + + public static class Fargo + { + String prop = "propiness"; + Fargo next = null; + + public String getProp() + { + return prop; + } + + public void setProp(String val) + { + this.prop = val; + } + + public String getNullVal() + { + return null; + } + + public Fargo getNext() + { + return next; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StringConcatenationTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StringConcatenationTestCase.java new file mode 100755 index 00000000..f86e06c4 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StringConcatenationTestCase.java @@ -0,0 +1,66 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + + +/** + * This class tests support for string concatenation. + */ +public class StringConcatenationTestCase extends BaseTestCase +{ + public StringConcatenationTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + context.put("foo", "foo"); + context.put("baz", "baz"); + } + + public void testStringRefLeft() + { + assertEvalEquals("foobar", "#set( $o = $foo + 'bar' )$o"); + assertEvalEquals("foo$bar", "#set( $o = $foo + $bar )$o"); + assertEvalEquals("foo1", "#set( $o = $foo + 1 )$o"); + assertEvalEquals("foobaz", "#set( $o = $foo + $baz )$o"); + } + + public void testStringRefRight() + { + assertEvalEquals("barfoo", "#set( $o = 'bar' + $foo )$o"); + assertEvalEquals("$barfoo", "#set( $o = $bar + $foo )$o"); + assertEvalEquals("1foo", "#set( $o = 1 + $foo )$o"); + } + + public void testNoRef() + { + assertEvalEquals("bar1", "#set( $o = 'bar' + 1 )$o"); + } + + public void testAll() + { + assertEvalEquals("foobar$bar1baz", "#set( $o = $foo + 'bar' + $bar + 1 + $baz )$o"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StringResourceLoaderRepositoryTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StringResourceLoaderRepositoryTestCase.java new file mode 100644 index 00000000..23aee4ce --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StringResourceLoaderRepositoryTestCase.java @@ -0,0 +1,214 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestCase; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.runtime.resource.util.StringResourceRepository; +import org.apache.velocity.runtime.resource.util.StringResourceRepositoryImpl; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.StringWriter; + +/** + * Tests ability to have multiple repositories in the same app. + * + * @author Nathan Bubna + * @version $Id: StringResourceLoaderRepositoryTestCase.java 479058 2006-11-25 00:26:32Z henning $ + */ +public class StringResourceLoaderRepositoryTestCase extends TestCase +{ + private VelocityContext context; + + public StringResourceLoaderRepositoryTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + Velocity.reset(); + Velocity.setProperty(Velocity.RESOURCE_LOADERS, "string"); + Velocity.addProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + Velocity.addProperty("string.resource.loader.modificationCheckInterval", "1"); + Velocity.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + Velocity.init(); + + StringResourceRepository repo = getRepo(null, null); + repo.putStringResource("foo", "This is $foo"); + repo.putStringResource("bar", "This is $bar"); + + context = new VelocityContext(); + context.put("foo", "wonderful!"); + context.put("bar", "horrible!"); + context.put("woogie", "a woogie"); + } + + + protected VelocityEngine newStringEngine(String repoName, boolean isStatic) + { + VelocityEngine engine = new VelocityEngine(); + TestLogger logger = new TestLogger(); + engine.setProperty(Velocity.RESOURCE_LOADERS, "string"); + engine.addProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + if (repoName != null) + { + engine.addProperty("string.resource.loader.repository.name", repoName); + } + if (!isStatic) + { + engine.addProperty("string.resource.loader.repository.static", "false"); + } + engine.addProperty("string.resource.loader.modificationCheckInterval", "1"); + engine.setProperty(Velocity.RUNTIME_LOG_INSTANCE, logger); + return engine; + } + + protected StringResourceRepository getRepo(String name, VelocityEngine engine) + { + if (engine == null) + { + if (name == null) + { + return StringResourceLoader.getRepository(); + } + else + { + return StringResourceLoader.getRepository(name); + } + } + else + { + if (name == null) + { + return (StringResourceRepository)engine.getApplicationAttribute(StringResourceLoader.REPOSITORY_NAME_DEFAULT); + } + else + { + return (StringResourceRepository)engine.getApplicationAttribute(name); + } + } + } + + protected String render(Template template) throws Exception + { + StringWriter out = new StringWriter(); + template.merge(this.context, out); + return out.toString(); + } + + + public void testSharedRepo() throws Exception + { + // this engine's string resource loader should share a repository + // with the singleton's string resource loader + VelocityEngine engine = newStringEngine(null, true); + + // get and merge the same template from both runtimes with the same context + String engineOut = render(engine.getTemplate("foo")); + String singletonOut = render(RuntimeSingleton.getTemplate("foo")); + + // make sure they're equal + assertEquals(engineOut, singletonOut); + } + + public void testAlternateStaticRepo() throws Exception + { + VelocityEngine engine = newStringEngine("alternate.repo", true); + // should be null be for init + StringResourceRepository repo = getRepo("alternate.repo", null); + assertNull(repo); + engine.init(); + // and not null after init + repo = getRepo("alternate.repo", null); + assertNotNull(repo); + repo.putStringResource("foo", "This is NOT $foo"); + + // get and merge template with the same name from both runtimes with the same context + String engineOut = render(engine.getTemplate("foo")); + String singletonOut = render(RuntimeSingleton.getTemplate("foo")); + + // make sure they're NOT equal + assertFalse(engineOut.equals(singletonOut)); + } + + public void testPreCreatedStaticRepo() throws Exception + { + VelocityEngine engine = newStringEngine("my.repo", true); + MyRepo repo = new MyRepo(); + repo.put("bar", "This is NOT $bar"); + StringResourceLoader.setRepository("my.repo", repo); + + String out = render(engine.getTemplate("bar")); + assertEquals(out, "This is NOT horrible!"); + } + + public void testAppRepo() throws Exception + { + VelocityEngine engine = newStringEngine(null, false); + engine.init(); + + StringResourceRepository repo = getRepo(null, engine); + assertNotNull(repo); + repo.putStringResource("woogie", "What is $woogie?"); + + String out = render(engine.getTemplate("woogie")); + assertEquals(out, "What is a woogie?"); + } + + public void testAlternateAppRepo() throws Exception + { + VelocityEngine engine = newStringEngine("alternate.app.repo", false); + engine.init(); + + StringResourceRepository repo = getRepo("alternate.app.repo", engine); + assertNotNull(repo); + repo.putStringResource("you/foo.vm", "You look $foo"); + + String out = render(engine.getTemplate("you/foo.vm")); + assertEquals(out, "You look wonderful!"); + } + + public void testPreCreatedAppRepo() throws Exception + { + VelocityEngine engine = newStringEngine("my.app.repo", false); + MyRepo repo = new MyRepo(); + repo.put("you/bar.vm", "You look $bar"); + engine.setApplicationAttribute("my.app.repo", repo); + + String out = render(engine.getTemplate("you/bar.vm")); + assertEquals(out, "You look horrible!"); + } + + public static class MyRepo extends StringResourceRepositoryImpl + { + public void put(String name, String template) + { + putStringResource(name, template); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/StringResourceLoaderTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/StringResourceLoaderTestCase.java new file mode 100644 index 00000000..69c09bb5 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/StringResourceLoaderTestCase.java @@ -0,0 +1,209 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * Multiple paths in the file resource loader. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @version $Id$ + */ +public class StringResourceLoaderTestCase extends BaseTestCase +{ + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/stringloader"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/stringloader/compare"; + + /** + * Default constructor. + */ + public StringResourceLoaderTestCase(String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(StringResourceLoaderTestCase.class); + } + + @Override + public void setUp() + throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + + Velocity.reset(); + + Velocity.setProperty(Velocity.RESOURCE_LOADERS, "string"); + Velocity.addProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + Velocity.addProperty("string.resource.loader.modificationCheckInterval", "1"); + + // Silence the logger. + Velocity.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public void testSimpleTemplate() + throws Exception + { + StringResourceLoader.getRepository().putStringResource("simpletemplate.vm", "This is a test for ${foo}"); + + Template template = RuntimeSingleton.getTemplate(getFileName(null, "simpletemplate", TMPL_FILE_EXT)); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULTS_DIR, "simpletemplate", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityContext context = new VelocityContext(); + context.put("foo", "a foo object"); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "simpletemplate", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect."); + } + } + + public void testMultipleTemplates() + throws Exception + { + StringResourceLoader.getRepository().putStringResource("multi1.vm", "I am the $first template."); + StringResourceLoader.getRepository().putStringResource("multi2.vm", "I am the $second template."); + + Template template1 = RuntimeSingleton.getTemplate(getFileName(null, "multi1", TMPL_FILE_EXT)); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULTS_DIR, "multi1", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityContext context = new VelocityContext(); + context.put("first", 1); + context.put("second", "two"); + + template1.merge(context, writer); + writer.flush(); + writer.close(); + + Template template2 = RuntimeSingleton.getTemplate(getFileName(null, "multi2", TMPL_FILE_EXT)); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, "multi2", RESULT_FILE_EXT)); + + writer = new BufferedWriter(new OutputStreamWriter(fos)); + + template2.merge(context, writer); + writer.flush(); + writer.close(); + + + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "multi1", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Template 1 incorrect."); + } + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "multi2", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Template 2 incorrect."); + } + } + + public void testContentChange() + throws Exception + { + StringResourceLoader.getRepository().putStringResource("change.vm", "I am the $first template."); + + Template template = RuntimeSingleton.getTemplate(getFileName(null, "change", TMPL_FILE_EXT)); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULTS_DIR, "change1", RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityContext context = new VelocityContext(); + context.put("first", 1); + context.put("second", "two"); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + StringResourceLoader.getRepository().putStringResource("change.vm", "I am the $second template."); + Thread.sleep(2000L); + template = RuntimeSingleton.getTemplate(getFileName(null, "change", TMPL_FILE_EXT)); + + fos = new FileOutputStream ( + getFileName(RESULTS_DIR, "change2", RESULT_FILE_EXT)); + + writer = new BufferedWriter(new OutputStreamWriter(fos)); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "change1", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Template 1 incorrect."); + } + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, "change2", + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Template 2 incorrect."); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestBase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestBase.java new file mode 100644 index 00000000..e35e00d7 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestBase.java @@ -0,0 +1,84 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * This is a base interface that contains a bunch of static final + * strings that are of use when testing templates. + * + * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> + * @version $Id$ + */ +public interface TemplateTestBase +{ + /** + * Directory relative to the distribution root, where the + * values to compare test results to are stored. + */ + String TEST_COMPARE_DIR = System.getProperty("test.compare.dir"); + + /** + * Directory relative to the distribution root, where the + * test cases should put their output + */ + String TEST_RESULT_DIR = System.getProperty("test.result.dir"); + + + /** + * VTL file extension. + */ + String TMPL_FILE_EXT = "vm"; + + /** + * Comparison file extension. + */ + String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + String RESULT_FILE_EXT = "res"; + + /** + * Path for templates. This property will override the + * value in the default velocity properties file. + */ + String FILE_RESOURCE_LOADER_PATH = + TEST_COMPARE_DIR + "/templates"; + + /** + * Properties file that lists which template tests to run. + */ + String TEST_CASE_PROPERTIES = + FILE_RESOURCE_LOADER_PATH + "/templates.properties"; + + /** + * Results relative to the build directory. + */ + String RESULT_DIR = + TEST_RESULT_DIR + "/templates"; + + /** + * Results relative to the build directory. + */ + String COMPARE_DIR = + FILE_RESOURCE_LOADER_PATH + "/compare"; + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestCase.java new file mode 100644 index 00000000..99a4eacf --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestCase.java @@ -0,0 +1,237 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.FieldMethodizer; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.test.provider.BoolObj; +import org.apache.velocity.test.provider.NullToStringObject; +import org.apache.velocity.test.provider.TestNumber; +import org.apache.velocity.test.provider.TestProvider; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Vector; + +/** + * Easily add test cases which evaluate templates and check their output. + * + * NOTE: + * This class DOES NOT extend RuntimeTestCase because the TemplateTestSuite + * already initializes the Velocity runtime and adds the template + * test cases. Having this class extend RuntimeTestCase causes the + * Runtime to be initialized twice which is not good. I only discovered + * this after a couple hours of wondering why all the properties + * being setup were ending up as Vectors. At first I thought it + * was a problem with the Configuration class, but the Runtime + * was being initialized twice: so the first time the property + * is seen it's stored as a String, the second time it's seen + * the Configuration class makes a Vector with both Strings. + * As a result all the getBoolean(property) calls were failing because + * the Configurations class was trying to create a Boolean from + * a Vector which doesn't really work that well. I have learned + * my lesson and now have to add some code to make sure the + * Runtime isn't initialized more then once :-) + * + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> + * @version $Id$ + */ +public class TemplateTestCase extends BaseTestCase implements TemplateTestBase +{ + /** + * The base file name of the template and comparison file (i.e. array for + * array.vm and array.cmp). + */ + protected String baseFileName; + + private TestProvider provider; + private ArrayList al; + private Hashtable h; + private VelocityContext context; + private VelocityContext context1; + private VelocityContext context2; + private Vector vec; + + /** + * Creates a new instance. + * + * @param baseFileName The base name of the template and comparison file to + * use (i.e. array for array.vm and array.cmp). + */ + public TemplateTestCase (String baseFileName) + { + super(getTestCaseName(baseFileName)); + this.baseFileName = baseFileName; + } + + public static junit.framework.Test suite() + { + return new TemplateTestSuite(); + } + + /** + * Sets up the test. + */ + @Override + protected void setUp () + throws Exception + { + super.setUp(); + Velocity.reset(); + Velocity.setProperty( + Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.setProperty("space.gobbling", "bc"); + + Velocity.init(); + + provider = new TestProvider(); + al = provider.getCustomers(); + h = new Hashtable(); + + h.put("Bar", "this is from a hashtable!"); + h.put("Foo", "this is from a hashtable too!"); + + /* + * lets set up a vector of objects to test late introspection. See ASTMethod.java + */ + + vec = new Vector(); + + vec.addElement(new String("string1")); + vec.addElement(new String("string2")); + + /* + * set up 3 chained contexts, and add our data + * throught the 3 of them. + */ + + context2 = new VelocityContext(); + context1 = new VelocityContext( context2 ); + context = new VelocityContext( context1 ); + + context.put("provider", provider); + context1.put("name", "jason"); + context1.put("name2", new StringBuffer("jason")); + context1.put("name3", new StringBuffer("geoge")); + context2.put("providers", provider.getCustomers2()); + context.put("list", al); + context1.put("hashtable", h); + context2.put("hashmap", new HashMap()); + context2.put("search", provider.getSearch()); + context.put("relatedSearches", provider.getRelSearches()); + context1.put("searchResults", provider.getRelSearches()); + context2.put("stringarray", provider.getArray()); + context.put("vector", vec ); + context.put("mystring", new String()); + context.put("runtime", new FieldMethodizer( "org.apache.velocity.runtime.RuntimeSingleton" )); + context.put("fmprov", new FieldMethodizer( provider )); + context.put("Floog", "floogie woogie"); + context.put("boolobj", new BoolObj() ); + + /* + * we want to make sure we test all types of iterative objects + * in #foreach() + */ + + Object[] oarr = { "a","b","c","d" } ; + int intarr[] = { 10, 20, 30, 40, 50 }; + int emptyarr[] = {}; + + context.put( "collection", vec ); + context2.put("iterator", vec.iterator()); + context1.put("map", h ); + context.put("obarr", oarr ); + context.put("enumerator", vec.elements()); + context.put("intarr", intarr ); + context.put("emptyarr", emptyarr ); + + // Add some Numbers + context.put ("int1", 1000); + context.put ("long1", 10000000000l); + context.put ("float1", 1000.1234f); + context.put ("double1", 10000000000d); + + // Add a TemplateNumber + context.put ("templatenumber1", new TestNumber (999.125)); + + /* + * Test #foreach() with a list containing nulls + */ + ArrayList nullList = new ArrayList(); + nullList.add("a"); + nullList.add("b"); + nullList.add(null); + nullList.add("d"); + context.put("nullList", nullList); + + // test silent references with a null tostring + context.put("nullToString",new NullToStringObject()); + } + + /** + * Runs the test. + */ + @Override + public void runTest () + throws Exception + { + Template template = RuntimeSingleton.getTemplate + (getFileName(null, baseFileName, TMPL_FILE_EXT)); + + assureResultsDirectoryExists(RESULT_DIR); + + /* get the file to write to */ + FileOutputStream fos = + new FileOutputStream (getFileName( + RESULT_DIR, baseFileName, RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + /* process the template */ + template.merge( context, writer); + + /* close the file */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR,COMPARE_DIR,baseFileName, + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template "+getFileName( + RESULT_DIR, baseFileName, RESULT_FILE_EXT)+" did not match expected output"); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestSuite.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestSuite.java new file mode 100644 index 00000000..36c46951 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/TemplateTestSuite.java @@ -0,0 +1,95 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestSuite; + +import java.io.FileInputStream; +import java.util.Properties; + +/** + * Test suite for Templates. + * + * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a> + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> + * @version $Id$ + */ +public class TemplateTestSuite extends TestSuite implements TemplateTestBase +{ + private Properties testProperties; + + /** + * Creates an instace of the Apache Velocity test suite. + */ + public TemplateTestSuite() + { + try + { + testProperties = new Properties(); + testProperties.load(new FileInputStream(TEST_CASE_PROPERTIES)); + } + catch (Exception e) + { + System.err.println("Cannot setup TemplateTestSuite!"); + e.printStackTrace(); + System.exit(1); + } + + addTemplateTestCases(); + } + + /** + * Adds the template test cases to run to this test suite. Template test + * cases are listed in the <code>TEST_CASE_PROPERTIES</code> file. + */ + private void addTemplateTestCases() + { + String template; + for (int i = 1 ;; i++) + { + template = testProperties.getProperty(getTemplateTestKey(i)); + + if (template != null) + { + System.out.println("Adding TemplateTestCase : " + template); + addTest(new TemplateTestCase(template)); + } + else + { + // Assume we're done adding template test cases. + break; + } + } + } + + /** + * Macro which returns the properties file key for the specified template + * test number. + * + * @param nbr The template test number to return a property key for. + * @return The property key. + */ + private static String getTemplateTestKey(int nbr) + { + return ("test.template." + nbr); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/TestBaseTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/TestBaseTestCase.java new file mode 100644 index 00000000..ee4afe7c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/TestBaseTestCase.java @@ -0,0 +1,64 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; + +import java.io.File; + +/** + * I keep breaking the getFileName method all the time... + */ +public class TestBaseTestCase + extends BaseTestCase +{ + public TestBaseTestCase(final String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(TestBaseTestCase.class); + } + + public void testGetFileName() + throws Exception + { + String fs = System.getProperty("file.separator"); + String pwd = System.getProperty("user.dir"); + + String root = new File("/").getCanonicalPath(); + + assertEquals(pwd + fs + "baz" + fs + "foo.bar", getFileName("baz", "foo", "bar")); + assertEquals(root + "baz" + fs + "foo.bar", getFileName(root + "baz", "foo", "bar")); + assertEquals(root + "foo.bar", getFileName("baz", root + "foo", "bar")); + assertEquals(root + "foo.bar", getFileName(root + "baz", root + "foo", "bar")); + assertEquals("", getFileName(null, "", "")); + assertEquals(root + "", getFileName("", "", "")); + assertEquals(".x", getFileName(null, "", "x")); + assertEquals(root + ".x", getFileName("", "", "x")); + assertEquals("foo.bar", getFileName(null, "foo", "bar")); + assertEquals(root + "foo.bar", getFileName(null, root + "foo", "bar")); + assertEquals(root + "foo.bar", getFileName("", "foo", "bar")); + assertEquals(root + "foo.bar", getFileName("", root + "foo", "bar")); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/TextblockTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/TextblockTestCase.java new file mode 100644 index 00000000..fc042544 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/TextblockTestCase.java @@ -0,0 +1,163 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeInstance; +import org.apache.velocity.runtime.parser.Parser; +import org.apache.velocity.runtime.parser.node.ASTTextblock; + +import java.lang.reflect.Field; + +/** + * This class tests the Textblock directive. + */ +public class TextblockTestCase extends BaseTestCase +{ + // these are all here so that the test case adapts instantly + // to changes in the textblock start/end sequences + private String START = null; + private String END = null; + private String PARTIAL_START = null; + private String PARTIAL_END = null; + private String END_OF_START = null; + private String START_OF_END = null; + + public TextblockTestCase(String name) + { + super(name); + //DEBUG = true; + } + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + // get a valid parser instance to initialize string constants + Field riField = engine.getClass().getDeclaredField("ri"); + riField.setAccessible(true); + RuntimeInstance ri = (RuntimeInstance)riField.get(engine); + Parser parser = ri.createNewParser(); + ASTTextblock astTextblock = new ASTTextblock(parser, 0); + START = astTextblock.START; + END = astTextblock.END; + PARTIAL_START = START.substring(0, START.length() - 1); + PARTIAL_END = END.substring(1); + END_OF_START = START.substring(START.length() - 1); + START_OF_END = END.substring(0, 1); + } + + public String textblock(String s) + { + return START + s + END; + } + + public void assertTextblockEvalEquals(String s) throws Exception + { + assertEvalEquals(s, textblock(s)); + } + + /** + * https://issues.apache.org/jira/browse/VELOCITY-661 + */ + public void testTextblockAjaxcode() throws Exception + { + String s = "var myId = 'someID';$('#test).append($.template('<div id=\"${myId}\"></div>').apply({myId: myId}));"; + assertEvalEquals(s + " 123", textblock(s)+" #foreach($i in [1..3])$i#end"); + } + + public void testLooseTextblockEnd() throws Exception + { + // just like a multi-line comment end (*#), this must be + // followed by a character. by itself, it bombs for some reason. + assertEvalEquals(END+" ", END+" "); + } + + public void testTextblockStartInTextblock() throws Exception + { + assertTextblockEvalEquals(START); + } + + public void testTextblockEndBetweenTwoTextblockHalves() throws Exception + { + // just like a multi-line comment end (*#), the end token + // in the middle must be followed by some character. + // by itself, it bombs. not sure why that is, but the + // same has been true of multi-line comments without complaints, + // so i'm not going to worry about it just yet. + assertEvalEquals(" "+END+" ", textblock(" ")+END+" "+textblock(" ")); + } + + public void testZerolengthTextblock() throws Exception + { + assertTextblockEvalEquals(""); + } + + public void testTextblockInsideForeachLoop() throws Exception + { + String s = "var myId = 'someID';$('#test).append($.template('<div id=\"${myId}\"></div>').apply({myId: myId}));"; + assertEvalEquals("1 "+s+"2 "+s+"3 "+s, "#foreach($i in [1..3])$i "+ textblock(s) + "#end"); + } + + public void testSingleHashInsideTextblock() throws Exception + { + assertTextblockEvalEquals(" # "); + } + + public void testDollarInsideTextblock() throws Exception + { + assertTextblockEvalEquals("$"); + } + + public void testTextblockInsideComment() throws Exception + { + String s = "FOOBAR"; + assertEvalEquals("", "#* comment "+textblock(s) + " *#"); + } + + public void testPartialStartEndTokensInsideTextblock() throws Exception + { + assertTextblockEvalEquals(PARTIAL_START+"foo"+PARTIAL_END); + } + + public void testDupeTokenChars() throws Exception + { + assertTextblockEvalEquals(END_OF_START+START_OF_END); + assertTextblockEvalEquals(END_OF_START+END_OF_START+START_OF_END+START_OF_END); + assertTextblockEvalEquals(END_OF_START+END_OF_START+"#"+START_OF_END+START_OF_END); + } + + /** + * https://issues.apache.org/jira/browse/VELOCITY-584 + */ + public void testServerSideIncludeEscaping() throws Exception + { + assertTextblockEvalEquals("<!--#include file=\"wisdom.inc\"--> "); + } + + /** + * https://issues.apache.org/jira/browse/VELOCITY-676 + */ + public void testLineCommentInsideTextblock() throws Exception + { + assertTextblockEvalEquals("##x"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/URLResourceLoaderTimeoutTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/URLResourceLoaderTimeoutTestCase.java new file mode 100755 index 00000000..775a75b3 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/URLResourceLoaderTimeoutTestCase.java @@ -0,0 +1,82 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.URLResourceLoader; +import org.apache.velocity.test.misc.TestLogger; + +/** + * This class tests support for custom timeouts in URLResourceLoader. + */ +public class URLResourceLoaderTimeoutTestCase extends BaseTestCase +{ + private static boolean isJava5plus; + static + { + try + { + Class.forName("java.lang.annotation.Annotation"); + isJava5plus = true; + } + catch (ClassNotFoundException cnfe) + { + isJava5plus = false; + } + } + private TestLogger logger = new TestLogger(); + private URLResourceLoader loader = new URLResourceLoader(); + private int timeout = 2000; + + public URLResourceLoaderTimeoutTestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty("resource.loader", "url"); + engine.setProperty("url.resource.loader.instance", loader); + engine.setProperty("url.resource.loader.timeout", timeout); + + // actual instance of logger + logger.on(); + engine.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, logger); + engine.setProperty("runtime.log.logsystem.test.level", "debug"); + engine.init(); + } + + public void testTimeout() + { + if (isJava5plus) + { + System.out.println("Testing a 1.5+ JDK"); + assertEquals(timeout, loader.getTimeout()); + } + else + { + System.out.println("Testing a pre-1.5 JDK"); + assertEquals(-1, loader.getTimeout()); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/UberspectorTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/UberspectorTestCase.java new file mode 100644 index 00000000..4e243c3b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/UberspectorTestCase.java @@ -0,0 +1,300 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.runtime.RuntimeInstance; +import org.apache.velocity.test.misc.GetPutObject; +import org.apache.velocity.test.misc.UberspectorTestObject; +import org.apache.velocity.util.introspection.Uberspect; +import org.apache.velocity.util.introspection.VelPropertyGet; +import org.apache.velocity.util.introspection.VelPropertySet; + +import java.util.HashMap; +import java.util.Map; + + +public class UberspectorTestCase + extends BaseTestCase +{ + private RuntimeInstance ri; + + public UberspectorTestCase(String name) + { + super(name); + } + + public static Test suite() + { + return new TestSuite(UberspectorTestCase.class); + } + + @Override + public void setUp() + throws Exception + { + ri = new RuntimeInstance(); + ri.init(); + } + + public void testNullObjects() + throws Exception + { + // How about some null objects... Gee, I'm mean. ;-) + Uberspect u = ri.getUberspect(); + + VelPropertyGet getter = u.getPropertyGet(null, "foo", null); + assertNull(getter); + + VelPropertySet setter = u.getPropertySet(null, "foo", Object.class, null); + assertNull(setter); + } + + public void testEmptyPropertyGetter() + throws Exception + { + Uberspect u = ri.getUberspect(); + Map map = new HashMap(); + + VelPropertyGet getter = u.getPropertyGet(map, "", null); + + // Don't screw up on empty properties. That should map to get("") + assertNotNull(getter); + assertEquals("Found wrong method", "get", getter.getMethodName()); + } + + public void testEmptyPropertySetter() + throws Exception + { + Uberspect u = ri.getUberspect(); + Map map = new HashMap(); + + VelPropertySet setter = u.getPropertySet(map, "", Object.class, null); + + // Don't screw up on empty properties. That should map to put("", Object) + assertNotNull(setter); + assertEquals("Found wrong method", "put", setter.getMethodName()); + } + + public void testNullPropertyGetter() + throws Exception + { + Uberspect u = ri.getUberspect(); + GetPutObject gpo = new GetPutObject(); + Map map = new HashMap(); + + VelPropertyGet getter = u.getPropertyGet(gpo, null, null); + + // Don't screw up on null properties. That should map to get() on the GPO. + assertNotNull(getter); + assertEquals("Found wrong method", "get", getter.getMethodName()); + + // And should be null on a Map which does not have a get() + getter = u.getPropertyGet(map, null, null); + assertNull(getter); + + } + + public void testNullPropertySetter() + throws Exception + { + Uberspect u = ri.getUberspect(); + GetPutObject gpo = new GetPutObject(); + Map map = new HashMap(); + + // Don't screw up on null properties. That should map to put() on the GPO. + VelPropertySet setter = u.getPropertySet(gpo, null, "", null); + assertNotNull(setter); + assertEquals("Found wrong method", "put", setter.getMethodName()); + + // And should be null on a Map which does not have a put() + setter = u.getPropertySet(map, null, "", null); + assertNull(setter); + } + + public void testNullParameterType() + throws Exception + { + VelPropertySet setter; + + Uberspect u = ri.getUberspect(); + UberspectorTestObject uto = new UberspectorTestObject(); + + // setRegular() + setter = u.getPropertySet(uto, "Regular", null, null); + assertNotNull(setter); + assertEquals("Found wrong method", "setRegular", setter.getMethodName()); + + // setAmbigous() - String and StringBuffer available + setter = u.getPropertySet(uto, "Ambigous", null, null); + assertNull(setter); + + // setAmbigous() - same with Object? + setter = u.getPropertySet(uto, "Ambigous", new Object(), null); + assertNull(setter); + } + + public void testMultipleParameterTypes() + throws Exception + { + VelPropertySet setter; + + Uberspect u = ri.getUberspect(); + UberspectorTestObject uto = new UberspectorTestObject(); + + // setAmbigous() - String + setter = u.getPropertySet(uto, "Ambigous", "", null); + assertNotNull(setter); + assertEquals("Found wrong method", "setAmbigous", setter.getMethodName()); + + // setAmbigous() - StringBuffer + setter = u.getPropertySet(uto, "Ambigous", new StringBuffer(), null); + assertNotNull(setter); + assertEquals("Found wrong method", "setAmbigous", setter.getMethodName()); + } + + + public void testRegularGetters() + throws Exception + { + VelPropertyGet getter; + + Uberspect u = ri.getUberspect(); + UberspectorTestObject uto = new UberspectorTestObject(); + + // getRegular() + getter = u.getPropertyGet(uto, "Regular", null); + assertNotNull(getter); + assertEquals("Found wrong method", "getRegular", getter.getMethodName()); + + // Lowercase regular + getter = u.getPropertyGet(uto, "regular", null); + assertNotNull(getter); + assertEquals("Found wrong method", "getRegular", getter.getMethodName()); + + // lowercase: getpremium() + getter = u.getPropertyGet(uto, "premium", null); + assertNotNull(getter); + assertEquals("Found wrong method", "getpremium", getter.getMethodName()); + + // test uppercase: getpremium() + getter = u.getPropertyGet(uto, "Premium", null); + assertNotNull(getter); + assertEquals("Found wrong method", "getpremium", getter.getMethodName()); + } + + public void testBooleanGetters() + throws Exception + { + VelPropertyGet getter; + + Uberspect u = ri.getUberspect(); + UberspectorTestObject uto = new UberspectorTestObject(); + + // getRegular() + getter = u.getPropertyGet(uto, "RegularBool", null); + assertNotNull(getter); + assertEquals("Found wrong method", "isRegularBool", getter.getMethodName()); + + // Lowercase regular + getter = u.getPropertyGet(uto, "regularBool", null); + assertNotNull(getter); + assertEquals("Found wrong method", "isRegularBool", getter.getMethodName()); + + // lowercase: getpremiumBool() + getter = u.getPropertyGet(uto, "premiumBool", null); + assertNotNull(getter); + assertEquals("Found wrong method", "ispremiumBool", getter.getMethodName()); + + // test uppercase: () + getter = u.getPropertyGet(uto, "PremiumBool", null); + assertNotNull(getter); + assertEquals("Found wrong method", "ispremiumBool", getter.getMethodName()); + } + + + public void testRegularSetters() + throws Exception + { + VelPropertySet setter; + + Uberspect u = ri.getUberspect(); + UberspectorTestObject uto = new UberspectorTestObject(); + + // setRegular() + setter = u.getPropertySet(uto, "Regular", "", null); + assertNotNull(setter); + assertEquals("Found wrong method", "setRegular", setter.getMethodName()); + + // Lowercase regular + setter = u.getPropertySet(uto, "regular", "", null); + assertNotNull(setter); + assertEquals("Found wrong method", "setRegular", setter.getMethodName()); + + // lowercase: setpremium() + setter = u.getPropertySet(uto, "premium", "", null); + assertNotNull(setter); + assertEquals("Found wrong method", "setpremium", setter.getMethodName()); + + // test uppercase: getpremium() + setter = u.getPropertySet(uto, "Premium", "", null); + assertNotNull(setter); + assertEquals("Found wrong method", "setpremium", setter.getMethodName()); + } + + public void testDisambiguation() + throws Exception + { + VelPropertySet setter; + + Uberspect u = ri.getUberspect(); + UberspectorTestObject uto = new UberspectorTestObject(); + + // setUnambigous() - String + setter = u.getPropertySet(uto, "unambiguous", "string", null); + assertNotNull(setter); + setter.invoke(uto, "string"); + + // setUnambigous() - HashMap + setter = u.getPropertySet(uto, "unambiguous", new HashMap(), null); + assertNotNull(setter); + setter.invoke(uto, new HashMap()); + } + + /* + * + * public void testMapGetSet() + * throws Exception + * { + * Uberspect u = ri.getUberspect(); + * Map map = new HashMap(); + * + * VelPropertyGet getter = u.getPropertyGet(map, "", null); + * VelPropertySet setter = u.getPropertySet(map, "", Object.class, null); + * + * assertNotNull("Got a null getter", getter); + * assertNotNull("Got a null setter", setter); + * + * assertEquals("Got wrong getter", "foo", getter.getMethodName()); + * assertEquals("Got wrong setter", "bar", setter.getMethodName()); + * } + */ +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/UnicodeEscapeTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/UnicodeEscapeTestCase.java new file mode 100644 index 00000000..1cb45475 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/UnicodeEscapeTestCase.java @@ -0,0 +1,61 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.parser.node.ASTStringLiteral; + +/** + * Test Case for <a href="https://issues.apache.org/jira/browse/VELTOOLS-520">Velocity Tools Issue 520</a>. + */ +public class UnicodeEscapeTestCase extends BaseTestCase +{ + public UnicodeEscapeTestCase(final String name) throws Exception + { + super(name); + } + + public void testUnicodeEscape() throws Exception + { + assertEvalEquals("a", "#set($v = \"\\u0061\")$v"); + } + + private void assertUnescape(String expected, String escaped) + { + String unescaped = ASTStringLiteral.unescape(escaped); + assertEquals(expected, unescaped); + if (escaped.equals(expected)) + { + // checking that no new string allocated, for perfomance + assertSame(unescaped, escaped); + } + } + + public void testASTStringLiteralUnescape() + { + assertUnescape("", ""); + assertUnescape("bebe", "bebe"); + assertUnescape("as\\nsd", "as\\nsd"); + assertUnescape("a", "\\u0061"); + assertUnescape("abc", "\\u0061bc"); + assertUnescape("\u0061bc\u0064", "\\u0061bc\\u0064"); + assertUnescape("z\u0061bc\u0064f", "z\\u0061bc\\u0064f"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/VMLibraryTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/VMLibraryTestCase.java new file mode 100644 index 00000000..dde8cbd7 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/VMLibraryTestCase.java @@ -0,0 +1,325 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +/** + * Macro library inclution via the Template.merge method is tested using this + * class. + */ + +public class VMLibraryTestCase extends BaseTestCase +{ + /** + * This engine is used with local namespaces + */ + private VelocityEngine ve1 = new VelocityEngine(); + + /** + * This engine is used with global namespaces + */ + private VelocityEngine ve2 = new VelocityEngine(); + + private static final String RESULT_DIR = TEST_RESULT_DIR + "/macrolibs"; + + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/macrolibs/compare"; + + public VMLibraryTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + /* + * setup local scope for templates + */ + ve1.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve1.setProperty("velocimacro.permissions.allow.inline.to.replace.global", + Boolean.FALSE); + /* + * Turn on the cache + */ + ve1.setProperty("file.resource.loader.cache", Boolean.TRUE); + + ve1.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + ve1.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve1.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + TEST_COMPARE_DIR + "/macrolibs"); + ve1.init(); + + /* + * Set to global namespaces + */ + ve2.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.FALSE); + ve2.setProperty("velocimacro.permissions.allow.inline.to.replace.global", + Boolean.TRUE); + /* + * Turn on the cache + */ + ve2.setProperty("file.resource.loader.cache", Boolean.FALSE); + + ve2.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + ve2.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve2.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, + TEST_COMPARE_DIR + "/macrolibs"); + ve2.init(); + } + + public static junit.framework.Test suite() + { + return new TestSuite(VMLibraryTestCase.class); + } + + /* + * Runs the tests with local namespace. + */ + public void testVelociMacroLibWithLocalNamespace() + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + /* + * Clear the file before proceeding + */ + File file = new File(getFileName( + RESULT_DIR, "vm_library_local", RESULT_FILE_EXT)); + if (file.exists()) + { + file.delete(); + } + + /* + * Create a file output stream for appending + */ + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, "vm_library_local", RESULT_FILE_EXT), true); + + List templateList = new ArrayList(); + VelocityContext context = new VelocityContext(); + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + templateList.add("vm_library1.vm"); + + Template template = ve1.getTemplate("vm_library_local.vm"); + template.merge(context, writer, templateList); + + /* + * remove the first template library and includes a new library + * with a new definition for macros + */ + templateList.remove(0); + templateList.add("vm_library2.vm"); + template = ve1.getTemplate("vm_library_local.vm"); + template.merge(context, writer, templateList); + + /* + *Show that caching is working + */ + Template t1 = ve1.getTemplate("vm_library_local.vm"); + Template t2 = ve1.getTemplate("vm_library_local.vm"); + + assertEquals("Both templates refer to the same object", t1, t2); + + /* + * Remove the libraries + */ + template = ve1.getTemplate("vm_library_local.vm"); + template.merge(context, writer); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, "vm_library_local", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template did not match expected output"); + } + } + + /* + * Runs the tests with global namespace. + */ + public void testVelociMacroLibWithGlobalNamespace() + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + /* + * Clear the file before proceeding + */ + File file = new File(getFileName( + RESULT_DIR, "vm_library_global", RESULT_FILE_EXT)); + if (file.exists()) + { + file.delete(); + } + + /* + * Create a file output stream for appending + */ + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, "vm_library_global", RESULT_FILE_EXT), true); + + List templateList = new ArrayList(); + VelocityContext context = new VelocityContext(); + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + templateList.add("vm_library1.vm"); + + Template template = ve1.getTemplate("vm_library_global.vm"); + template.merge(context, writer, templateList); + + /* + * remove the first template library and includes a new library + * with a new definition for macros + */ + templateList.remove(0); + templateList.add("vm_library2.vm"); + template = ve1.getTemplate("vm_library_global.vm"); + template.merge(context, writer, templateList); + + /* + *Show that caching is not working (We have turned off cache) + */ + Template t1 = ve2.getTemplate("vm_library_global.vm"); + Template t2 = ve2.getTemplate("vm_library_global.vm"); + + assertNotSame("Defferent objects", t1, t2); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, "vm_library_global", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template did not match expected output"); + } + } + + /* + * Runs the tests with global namespace. + */ + public void testVelociMacroLibWithDuplicateDefinitions() + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + /* + * Clear the file before proceeding + */ + File file = new File(getFileName( + RESULT_DIR, "vm_library_duplicate", RESULT_FILE_EXT)); + if (file.exists()) + { + file.delete(); + } + + /* + * Create a file output stream for appending + */ + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, "vm_library_duplicate", RESULT_FILE_EXT), true); + + List templateList = new ArrayList(); + VelocityContext context = new VelocityContext(); + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + templateList.add("vm_library1.vm"); + templateList.add("vm_library2.vm"); + + Template template = ve1.getTemplate("vm_library.vm"); + template.merge(context, writer, templateList); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, "vm_library_duplicate", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template did not match expected output"); + } + } + + /* + * Test whether the literal text is given if a definition cannot be + * found for a macro. + * + * @throws Exception + */ + public void testMacrosWithNoDefinition() + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, "vm_library", RESULT_FILE_EXT)); + + VelocityContext context = new VelocityContext(); + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + Template template = ve1.getTemplate("vm_library.vm"); + template.merge(context, writer, null); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + /* + * outputs the macro calls + */ + if (!isMatch(RESULT_DIR, COMPARE_DIR, "vm_library", + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + fail("Processed template did not match expected output"); + } + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/VarargMethodsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/VarargMethodsTestCase.java new file mode 100644 index 00000000..a87bba8e --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/VarargMethodsTestCase.java @@ -0,0 +1,278 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; + +/** + * Used to check that vararg method calls on references work properly + */ +public class VarargMethodsTestCase extends BaseTestCase +{ + public VarargMethodsTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("nice", new NiceTool()); + context.put("nasty", new NastyTool()); + context.put("objects", new Object[] { this, VelocityContext.class }); + context.put("strings", new String[] { "one", "two" }); + context.put("doubles", new double[] { 1.5, 2.5 }); + context.put("float", 1f); + context.put("ints", new int[] { 1, 2 }); + } + + public void testStrings() + { + assertEvalEquals("onetwo", "$nice.var($strings)"); + assertEvalEquals("onetwo", "$nice.var('one','two')"); + assertEvalEquals("one", "$nice.var('one')"); + assertEvalEquals("", "$nice.var()"); + } + + public void testDoubles() + { + assertEvalEquals("4.0", "$nice.add($doubles)"); + assertEvalEquals("3.0", "$nice.add(1,2)"); + assertEvalEquals("1.0", "$nice.add(1)"); + assertEvalEquals("0.0", "$nice.add()"); + } + + public void testFloatToDoubleVarArg() + { + assertEvalEquals("1.0", "$nice.add($float)"); + } + + public void testStringVsStrings() + { + assertEvalEquals("onlyone", "$nasty.var('one')"); + assertEvalEquals("onlynull", "$nasty.var($null)"); + assertEvalEquals("", "$nasty.var()"); + } + + public void testIntVsDoubles() + { + assertEvalEquals("1", "$nasty.add(1)"); + assertEvalEquals("1.0", "$nasty.add(1.0)"); + assertEvalEquals("3.0", "$nasty.add(1.0,2)"); + } + + public void testInts() + { + assertEvalEquals("3", "$nasty.add($ints)"); + assertEvalEquals("3", "$nasty.add(1,2)"); + assertEvalEquals("1", "$nasty.add(1)"); + // add(int[]) wins because it is "more specific" + assertEvalEquals("0", "$nasty.add()"); + } + + public void testStringsVsObjectsAKASubclassVararg() + { + assertEvalEquals("objects", "$nice.test($objects)"); + assertEvalEquals("objects", "$nice.test($nice,$nasty,$ints)"); + assertEvalEquals("strings", "$nice.test('foo')"); + } + + public void testObjectVarArgVsObjectEtc() + { + assertEvalEquals("object,string", "$nasty.test($nice,'foo')"); + } + + public void testObjectVarArgVsObjectVelocity605() + { + assertEvalEquals("string", "$nasty.test('joe')"); + assertEvalEquals("object", "$nasty.test($nice)"); + } + + public void testNoArgs() + { + assertEvalEquals("noargs", "$nasty.test()"); + } + + public void testPassingArrayToVarArgVelocity642() + { + assertEvalEquals("[one, two]", "$nasty.test642($strings)"); + assertEvalEquals("[1, 2]", "#set( $list = [1..2] )$nasty.test642($list.toArray())"); + } + + public void testNullToPrimitiveVarArg() + { + assertEvalEquals("int[]", "$nasty.test649($null)"); + } + + public void testArgsBeforeVarargWithNoArgs() + { + assertEvalEquals("String,String,Object[]", "$nasty.test651('a','b')"); + } + + public void testVelocity651() + { + assertEvalEquals("String,List", "$nasty.test651('test',['TEST'])"); + } + + public void testMax() + { + assertEvalEquals("4", "$nasty.max(4, 3.5)"); + } + + public static class NiceTool + { + public String var(String[] ss) + { + StringBuilder out = new StringBuilder(); + for (String s : ss) + { + out.append(s); + } + return out.toString(); + } + + public double add(double[] dd) + { + double total = 0; + for (double aDd : dd) + { + total += aDd; + } + return total; + } + + public String test(Object[] oo) + { + return "objects"; + } + + public String test(String[] oo) + { + return "strings"; + } + + } + + public static class NastyTool extends NiceTool + { + public String var(String s) + { + return "only"+s; + } + + public int add(int[] ii) + { + int total = 0; + for (int anIi : ii) + { + total += anIi; + } + return total; + } + + public int add(int i) + { + return i; + } + + public String test() + { + return "noargs"; + } + + public Object test(Object arg) + { + return "object"; + } + + public Object test(String arg) + { + return "string"; + } + + @Override + public String test(Object[] array) + { + return "object[]"; + } + + public String test(Object object, String property) + { + return "object,string"; + } + + public String test642(Object[] array) + { + //JDK5: return Arrays.deepToString(array); + if (array == null) + { + return null; + } + StringBuilder o = new StringBuilder("["); + for (int i=0; i < array.length; i++) + { + if (i > 0) + { + o.append(", "); + } + o.append((array[i])); + } + o.append("]"); + return o.toString(); + } + + public String test649(int[] array) + { + return "int[]"; + } + + public String test651(String s, String s2, Object[] args) + { + return "String,String,Object[]"; + } + + public String test651(String s, java.util.List l) + { + return "String,List"; + } + + public Number max(Number n1, Number n2) { return max(new Number[] { n1, n2 }); } + + public Number max(Number[] numbers) + { + if (numbers.length == 0) return null; + int minindex = -1, i = 0; + double val = Double.MIN_VALUE; + for (Number n : numbers) + { + if (n.floatValue() > val) + { + minindex = i; + val = n.floatValue(); + } + ++i; + } + if (minindex < 0) minindex = 0; + return numbers[minindex]; + } + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocimacroBCModeTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocimacroBCModeTestCase.java new file mode 100644 index 00000000..e41fe434 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocimacroBCModeTestCase.java @@ -0,0 +1,100 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * This class tests the mode where velocimacros do preserve arguments literals + */ + +public class VelocimacroBCModeTestCase extends BaseTestCase +{ + private static final String BASE_DIR = TEST_COMPARE_DIR + "/bc_mode"; + private static final String CMP_DIR = BASE_DIR + "/compare"; + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/bc_mode"; + + public VelocimacroBCModeTestCase(final String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + boolean bcMode = !getName().contains("NoPreserve"); + engine.setProperty(RuntimeConstants.VM_ENABLE_BC_MODE, bcMode); + engine.setProperty("file.resource.loader.path", TEST_COMPARE_DIR + "/bc_mode"); + } + + public void testPreserveLiterals() + { + assertEvalEquals("$bar","#macro(m $foo)$foo#end#m($bar)"); + } + + public void testGlobalDefaults() + { + assertEvalEquals("foo","#macro(m $foo)$foo#end#set($foo='foo')#m()"); + } + + public void testVariousCasesPreserve() throws Exception + { + doTestVariousCases("bc_mode_enabled"); + } + + public void testVariousCasesNoPreserve() throws Exception + { + doTestVariousCases("bc_mode_disabled"); + } + + private void doTestVariousCases(String compare_ext) throws Exception + { + assureResultsDirectoryExists(RESULTS_DIR); + String basefilename = "test_bc_mode"; + Template template = engine.getTemplate( getFileName(null, basefilename, "vtl") ); + context = new VelocityContext(); + FileOutputStream fos; + Writer fwriter; + + fos = new FileOutputStream (getFileName(RESULTS_DIR, basefilename, RESULT_FILE_EXT)); + + fwriter = new BufferedWriter( new OutputStreamWriter(fos) ); + + template.merge(context, fwriter); + fwriter.flush(); + fwriter.close(); + + if (!isMatch(RESULTS_DIR, CMP_DIR, basefilename, RESULT_FILE_EXT, compare_ext)) + { + String result = getFileContents(RESULTS_DIR, basefilename, RESULT_FILE_EXT); + String compare = getFileContents(CMP_DIR, basefilename, compare_ext); + + assertEquals(compare, result); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocimacroTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocimacroTestCase.java new file mode 100644 index 00000000..445cf44a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocimacroTestCase.java @@ -0,0 +1,135 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.exception.MacroOverflowException; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.StringWriter; + +/** + * This class tests strange Velocimacro issues. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @version $Id$ + */ +public class VelocimacroTestCase extends TestCase +{ + private String template1 = "#macro(foo $a)$a#end #macro(bar $b)#foo($b)#end #foreach($i in [1..3])#if($i == 3)#foo($i)#else#bar($i)#end#end"; + private String result1 = " 123"; + private String template2 = "#macro(bar $a)#set($a = $a + 1)$a#bar($a)#end#bar(0)"; + private String template3 = "#macro(baz $a)#set($a = $a + 1)$a#inner($a)#end#macro(inner $b)#baz($b)#end#baz(0)"; + private String template4 = "#macro(bad $a)#set($a = $a + 1)$a#inside($a)#end#macro(inside $b)#loop($b)#end#macro(loop $c)#bad($c)#end#bad(0)"; + + public VelocimacroTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + /* + * setup local scope for templates + */ + Velocity.reset(); + Velocity.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + Velocity.setProperty( Velocity.VM_MAX_DEPTH, 5); + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + Velocity.init(); + } + + public static Test suite() + { + return new TestSuite(VelocimacroTestCase.class); + } + + /** + * Runs the test. + */ + public void testVelociMacro () + throws Exception + { + VelocityContext context = new VelocityContext(); + + StringWriter writer = new StringWriter(); + Velocity.evaluate(context, writer, "vm_chain1", template1); + + String out = writer.toString(); + + if( !result1.equals( out ) ) + { + fail("output incorrect."); + } + } + + /** + * Test case for evaluating max calling depths of macros + */ + public void testVelociMacroCallMax() + throws Exception + { + VelocityContext context = new VelocityContext(); + StringWriter writer = new StringWriter(); + + try + { + Velocity.evaluate(context, writer, "vm_chain2", template2); + fail("Did not exceed max macro call depth as expected"); + } + catch (MacroOverflowException e) + { + assertEquals("Max calling depth of 5 was exceeded in macro 'bar'"+ + " with Call Stack:bar->bar->bar->bar->bar at vm_chain2[line 1, column 15]", + e.getMessage()); + } + + try + { + Velocity.evaluate(context, writer, "vm_chain3", template3); + fail("Did not exceed max macro call depth as expected"); + } + catch (MacroOverflowException e) + { + assertEquals("Max calling depth of 5 was exceeded in macro 'inner'"+ + " with Call Stack:baz->inner->baz->inner->baz at vm_chain3[line 1, column 64]", + e.getMessage()); + } + + try + { + Velocity.evaluate(context, writer, "vm_chain4", template4); + fail("Did not exceed max macro call depth as expected"); + } + catch (MacroOverflowException e) + { + assertEquals("Max calling depth of 5 was exceeded in macro 'loop'"+ + " with Call Stack:bad->inside->loop->bad->inside at vm_chain4[line 1, column 94]", + e.getMessage()); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocityAppTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocityAppTestCase.java new file mode 100644 index 00000000..ecc9f8fc --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/VelocityAppTestCase.java @@ -0,0 +1,80 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; + +import java.io.StringWriter; + +/** + * This class is intended to test the app.Velocity.java class. + * + * @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a> + * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a> + * @version $Id$ + */ +public class VelocityAppTestCase extends BaseTestCase implements TemplateTestBase +{ + private StringWriter compare1 = new StringWriter(); + private String input1 = "My name is $name -> $Floog"; + private String result1 = "My name is jason -> floogie woogie"; + + public VelocityAppTestCase(String name) + { + super(name); + } + + public void testVelocityApp() + throws Exception + { + engine.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + engine.init(); + + // the usage of engine here is equivalent to using static calls to Velocity. class + + VelocityContext context = new VelocityContext(); + context.put("name", "jason"); + context.put("Floog", "floogie woogie"); + + String cmp = "Hello jason! Nice floogie woogie!"; + + engine.evaluate(context, compare1, "evaltest", input1); + if (!result1.equals(compare1.toString())) + { + fail("Output 1 incorrect."); + } + + StringWriter result2 = new StringWriter(); + engine.mergeTemplate("mergethis.vm", "UTF-8", context, result2); + if (!result2.toString().equals(cmp)) + { + fail("Output 2 incorrect."); + } + + StringWriter result3 = new StringWriter(); + engine.invokeVelocimacro("floog", "test", new String[]{"name", "Floog"}, context, result3); + + if (!result3.toString().equals(cmp)) + { + fail("Output 3 incorrect."); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/WrappedExceptionTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/WrappedExceptionTestCase.java new file mode 100644 index 00000000..1c8bd11f --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/WrappedExceptionTestCase.java @@ -0,0 +1,84 @@ +package org.apache.velocity.test; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.context.Context; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.test.provider.TestProvider; + +import java.io.StringWriter; + +/** + * Test thrown exceptions include a proper cause (under JDK 1.4+). + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class WrappedExceptionTestCase extends BaseTestCase implements TemplateTestBase +{ + VelocityEngine ve; + + /** + * Default constructor. + */ + public WrappedExceptionTestCase(String name) + { + super(name); + } + + public static Test suite () + { + return new TestSuite(WrappedExceptionTestCase.class); + } + + @Override + public void setUp() throws Exception + { + ve = new VelocityEngine(); + ve.init(); + } + + + public void testMethodException() throws Exception + { + + // accumulate a list of invalid references + Context context = new VelocityContext(); + StringWriter writer = new StringWriter(); + context.put("test",new TestProvider()); + + try + { + ve.evaluate(context,writer,"test","$test.getThrow()"); + fail ("expected an exception"); + } + catch (MethodInvocationException E) + { + assertEquals(Exception.class,E.getCause().getClass()); + assertEquals("From getThrow()",E.getCause().getMessage()); + } + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/eventhandler/Handler1.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/eventhandler/Handler1.java new file mode 100644 index 00000000..52220557 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/eventhandler/Handler1.java @@ -0,0 +1,75 @@ +package org.apache.velocity.test.eventhandler; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.event.IncludeEventHandler; +import org.apache.velocity.app.event.MethodExceptionEventHandler; +import org.apache.velocity.app.event.ReferenceInsertionEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.util.introspection.Info; + +import java.util.Locale; + +/** + * This is a test set of event handlers, used to test event handler sequences. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class Handler1 + implements ReferenceInsertionEventHandler, MethodExceptionEventHandler, IncludeEventHandler { + + /** + * display output twice, once uppercase and once lowercase + */ + @Override + public Object referenceInsert(Context context, String reference, Object value) + { + if (value == null) + return null; + else + return value.toString().toUpperCase(Locale.ROOT) + value.toString().toLowerCase(Locale.ROOT); + } + + /** + * throw the exception + */ + @Override + public Object methodException(Context context, Class<?> claz, String method, Exception e, Info info) + { + throw new RuntimeException(e); + } + + /* + * redirect all requests to a page "login.vm" (simulates access control). + */ + @Override + public String includeEvent( + Context context, + String includeResourcePath, + String currentResourcePath, + String directiveName) + { + + return "notfound.vm"; + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/eventhandler/Handler2.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/eventhandler/Handler2.java new file mode 100644 index 00000000..033c9655 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/eventhandler/Handler2.java @@ -0,0 +1,75 @@ +package org.apache.velocity.test.eventhandler; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.event.IncludeEventHandler; +import org.apache.velocity.app.event.MethodExceptionEventHandler; +import org.apache.velocity.app.event.ReferenceInsertionEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.util.introspection.Info; + +import java.util.Locale; + +/** + * This is a test set of event handlers, used to test event handler sequences. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class Handler2 + implements ReferenceInsertionEventHandler, MethodExceptionEventHandler, IncludeEventHandler { + + /** + * convert output to upper case + */ + @Override + public Object referenceInsert(Context context, String reference, Object value) + { + if (value == null) + return null; + else + return value.toString().toUpperCase(Locale.ROOT); + } + + /** + * print the exception + */ + @Override + public Object methodException(Context context, Class<?> claz, String method, Exception e, Info info) + { + return "Exception: " + e; + } + + /* + * redirect all requests to a new directory "subdir" (simulates localization). + */ + @Override + public String includeEvent( + Context context, + String includeResourcePath, + String currentResourcePath, + String directiveName) + { + + return "subdir/" + includeResourcePath; + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/StackOverflow32805217TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/StackOverflow32805217TestCase.java new file mode 100755 index 00000000..d70e0bcd --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/StackOverflow32805217TestCase.java @@ -0,0 +1,39 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests bugfix for http://stackoverflow.com/questions/32805217/bug-or-hidden-feature-in-apache-velocity + */ +public class StackOverflow32805217TestCase extends BaseTestCase +{ + public StackOverflow32805217TestCase(String name) + { + super(name); + } + + public void testIt() + { + assertEvalEquals("$map{value}", "$map{value}"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/VelTools66TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/VelTools66TestCase.java new file mode 100644 index 00000000..529683ff --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/VelTools66TestCase.java @@ -0,0 +1,181 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeInstance; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.Introspector; + +import java.lang.reflect.Method; +import java.security.AccessControlException; +import java.security.Permission; + +/** + * Test Case for <a href="https://issues.apache.org/jira/browse/VELTOOLS-66">Velocity Tools Issue 66</a>. + */ +public class VelTools66TestCase + extends BaseTestCase +{ + protected static boolean DEBUG = false; + + public VelTools66TestCase(final String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(VelTools66TestCase.class); + } + + @Override + public void setUp() + throws Exception + { + Velocity.setProperty( + Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + System.setSecurityManager(new TestSecurityManager()); + + } + + protected static void log(String out) + { + Velocity.getLog().debug(out); + if (DEBUG) + { + System.out.println(out); + } + } + + @Override + public void tearDown() + { + System.setSecurityManager(null); + } + + public void testVelTools66() + throws Exception + { + /* the testcase is obsolete in JDK 8, as SystemManager.checkMemberAccess is not anymore called + * by Class.getMethods() */ + + String [] javaVersionFields = System.getProperty("java.version").split("\\."); + int javaVersion = Integer.parseInt(javaVersionFields[0]); + if (javaVersion == 1) + { + javaVersion = Integer.parseInt(javaVersionFields[1]); + } + + if (javaVersion >= 8) + { + return; + } + + Method verifyMethod = TestInterface.class.getMethod("getTestValue"); + + RuntimeInstance ri = new RuntimeInstance(); + log = new TestLogger(false, false); + Introspector introspector = new Introspector(log); + + Method testMethod = introspector.getMethod(TestObject.class, "getTestValue", new Object[0]); + assertNotNull(testMethod); + assertEquals("Method object does not match!", verifyMethod, testMethod); + } + + public interface TestInterface + { + String getTestValue(); + + void setTestValue(String testValue); + } + + public static final class TestObject + implements TestInterface + { + String testValue = null; + + public TestObject() + { + } + + @Override + public String getTestValue() + { + return testValue; + } + + @Override + public void setTestValue(final String testValue) + { + this.testValue = testValue; + } + } + + public static final class TestSecurityManager extends SecurityManager + { + private final Class<?> clazz = TestObject.class; + + public TestSecurityManager() + { + super(); + } + + public void checkMemberAccess(final Class<?> c, final int i) + { + log("checkMemberAccess(" + c.getName() + ", " + i + ")"); + + if (c.equals(clazz)) + { + throw new AccessControlException("You are not allowed to access TestObject directly!"); + } + } + + @Override + public void checkRead(final String file) + { + log("checkRead(" + file + ")"); + } + + @Override + public void checkPackageAccess(final String s) + { + log("checkPackageAccess(" + s + ")"); + } + + @Override + public void checkPropertyAccess(final String s) + { + log("checkPropertyAccess(" + s + ")"); + } + + @Override + public void checkPermission(final Permission p) + { + log("checkPermission(" + p + ")"); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity532TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity532TestCase.java new file mode 100755 index 00000000..16eaef1c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity532TestCase.java @@ -0,0 +1,52 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-532. + */ +public class Velocity532TestCase extends BaseTestCase +{ + public Velocity532TestCase(String name) + { + super(name); + } + + public void test532() + { + String template = "#macro( test )$foreach.count#end"+ + "#foreach( $i in [1..5] )#test()#end"; + assertEvalEquals("12345", template); + } + + public void test532b() + { + // try something a little more like Matt's example + String template = "#macro( test $baz )"+ + "#if( $foo == $null )"+ + "#if( $foreach.count == 3 )bar#end"+ + "#end#end"+ + "#foreach( $i in [1..5] )#test($i)#end"; + assertEvalEquals("bar", template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity537TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity537TestCase.java new file mode 100755 index 00000000..02ee5efb --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity537TestCase.java @@ -0,0 +1,121 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE + * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; + +/** + * Test Case for <a href="https://issues.apache.org/jira/browse/VELOCITY-537">Velocity Issue 537</a>. + */ +public class Velocity537TestCase extends BaseTestCase +{ + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/issues/velocity-537"; + + /** + * Template Directory + */ + private static final String TEMPLATE_DIR = TEST_COMPARE_DIR + "/issues/velocity-537/templates"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/issues/velocity-537/compare"; + + public Velocity537TestCase(final String name) throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(Velocity537TestCase.class); + } + + private VelocityEngine velocityEngine; + @Override + public void setUp() throws Exception + { + + assureResultsDirectoryExists(RESULTS_DIR); + + velocityEngine = new VelocityEngine(); + velocityEngine.addProperty(Velocity.FILE_RESOURCE_LOADER_PATH, TEMPLATE_DIR); + + velocityEngine.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + velocityEngine.init(); + } + + public void testVelocity537() throws Exception + { + executeTest("velocity537.vm"); + } + + public void testVelocity537Again() throws Exception + { + executeTest("velocity537b.vm"); + } + + protected Template executeTest(final String templateName) throws Exception + { + Template template = velocityEngine.getTemplate(templateName); + + FileOutputStream fos = new FileOutputStream(getFileName(RESULTS_DIR, templateName, RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityContext context = new VelocityContext(); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, templateName, RESULT_FILE_EXT, CMP_FILE_EXT)) + { + // just to be useful, output the output in the fail message + StringWriter out = new StringWriter(); + template.merge(context, out); + + String compare = getFileContents(COMPARE_DIR, templateName, CMP_FILE_EXT); + + fail("Output incorrect for Template: " + templateName + ": \""+out+"\""+ + "; it did not match: \""+compare+"\""); + } + + return template; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity544TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity544TestCase.java new file mode 100644 index 00000000..1018208c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity544TestCase.java @@ -0,0 +1,75 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.test.BaseTestCase; + +/** + * @see <a href="https://issues.apache.org/jira/browse/VELOCITY-544">VELOCITY-544</a> + */ +public class Velocity544TestCase + extends BaseTestCase +{ + public Velocity544TestCase(final String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(Velocity544TestCase.class); + } + + public void testBooleanPropertyExecutor() + throws Exception + { + context.put("foobarTrue", new Foobar(true)); + context.put("foobarFalse", new Foobar(false)); + + String template = "$foobarTrue.True $foobarFalse.True $foobarTrue.TrueObject $foobarFalse.TrueObject"; + + String result = evaluate(template); + + assertEquals("true false true false", result); + } + + public static class Foobar + { + private boolean value; + + public Foobar(boolean value) + { + this.value = value; + } + + public boolean isTrue() + { + return(value); + } + + public Boolean isTrueObject() + { + return(value); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity579TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity579TestCase.java new file mode 100755 index 00000000..3918178a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity579TestCase.java @@ -0,0 +1,82 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-579 and with some related stuff + * from VELOCITY-70 thrown in. + */ +public class Velocity579TestCase extends BaseTestCase +{ + public Velocity579TestCase(String name) + { + super(name); + } + + public void testPublicMethodInPrivateImplOfPublicInterface() + { + context.put("foo", new Foobar()); + assertEvalEquals("bar", "$foo.foo('bar')"); + assertEvalEquals("$foo.bar()", "$foo.bar()"); + } + + public void testPublicMethodInheritedFromPrivateClass() throws Exception + { + context.put("bar", new MyBar()); + // ugly hack to avoid failed test when running JDK 1.5 or earlier + String javaVersion = System.getProperty("java.version"); + if (javaVersion.startsWith("1.6")) + assertEvalEquals("bar", "$bar.bar()"); + } + + public interface Foo + { + String foo(String s); + } + + private static abstract class FooImpl implements Foo + { + @Override + public String foo(String s) + { + return s == null ? "foo" : s; + } + } + + private static class Foobar extends FooImpl + { + public String bar() + { + return "bar"; + } + } + + public static class MyBar extends Foobar + { + @Override + public String bar() + { + return super.bar(); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity580TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity580TestCase.java new file mode 100755 index 00000000..14904163 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity580TestCase.java @@ -0,0 +1,116 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE + * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; + +/** + * Test Case for <a href="https://issues.apache.org/jira/browse/VELOCITY-580">Velocity Issue 580</a>. + */ +public class Velocity580TestCase extends BaseTestCase +{ + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/issues/velocity-580"; + + /** + * Template Directory + */ + private static final String TEMPLATE_DIR = TEST_COMPARE_DIR + "/issues/velocity-580/templates"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/issues/velocity-580/compare"; + + public Velocity580TestCase(final String name) throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(Velocity580TestCase.class); + } + + @Override + public void setUp() throws Exception + { + + assureResultsDirectoryExists(RESULTS_DIR); + + Velocity.reset(); + + Velocity.addProperty(Velocity.FILE_RESOURCE_LOADER_PATH, TEMPLATE_DIR); + + Velocity.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + + Velocity.init(); + } + + public void testVelocity580() throws Exception + { + executeTest("velocity580.vm"); + } + + protected Template executeTest(final String templateName) throws Exception + { + Template template = RuntimeSingleton.getTemplate(templateName); + + FileOutputStream fos = new FileOutputStream(getFileName(RESULTS_DIR, templateName, RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityContext context = new VelocityContext(); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, templateName, RESULT_FILE_EXT, CMP_FILE_EXT)) + { + // just to be useful, output the output in the fail message + StringWriter out = new StringWriter(); + template.merge(context, out); + + String compare = getFileContents(COMPARE_DIR, templateName, CMP_FILE_EXT); + + fail("Output incorrect for Template: " + templateName + ": \""+out+"\""+ + "; it did not match: \""+compare+"\""); + } + + return template; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity587TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity587TestCase.java new file mode 100755 index 00000000..7d5da4c2 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity587TestCase.java @@ -0,0 +1,64 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-587. + */ +public class Velocity587TestCase extends BaseTestCase +{ + public Velocity587TestCase(String name) + { + super(name); + } + + // remember, they're all doubled, since java will use them as escapes first. + public void testLiteralTwoBackslashes() + { + String template = "#set( $bs2 = \'\\\\\' )$bs2"; + String expected = "\\\\"; + assertEvalEquals(expected, template); + } + + public void testLiteralOneBackslash() + { + String template = "#set( $bs = \'\\\' )$bs"; + String expected = "\\"; + assertEvalEquals(expected, template); + } + + // remember, they're all doubled, since java will use them as escapes first. + public void testInterpolatedTwoBackslashes() + { + String template = "#set( $bs2 = \"\\\\\" )$bs2"; + String expected = "\\\\"; + assertEvalEquals(expected, template); + } + + public void testInterpolatedOneBackslash() + { + String template = "#set( $bs = \"\\\" )$bs"; + String expected = "\\"; + assertEvalEquals(expected, template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity589TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity589TestCase.java new file mode 100755 index 00000000..6502dc26 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity589TestCase.java @@ -0,0 +1,40 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-589. + */ +public class Velocity589TestCase extends BaseTestCase +{ + public Velocity589TestCase(String name) + { + super(name); + } + + public void testIt() + { + context.put("myId", "test"); + assertEvalEquals("#test_bg", "#${myId}_bg"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity614TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity614TestCase.java new file mode 100755 index 00000000..746b40a6 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity614TestCase.java @@ -0,0 +1,90 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.TemplateInitException; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-614. + */ +public class Velocity614TestCase extends BaseTestCase +{ + public Velocity614TestCase(String name) + { + super(name); + } + + public void testSchmoo() + { + String template = "#something(Stuff)"; + assertEvalEquals(template, template); + } + + public void testEscapeSchmooButNotReallySinceSchmooHasNoEscaping() + { + String template = "\\#something(Stuff)"; + assertEvalEquals(template, template); + } + + public void testEscapeMacroWithBadArg() + { + String template = "#macro( evil $arg )$arg#end \\#evil(bar)"; + assertEvalEquals(" #evil(bar)", template); + } + + public void testEarlyDefinedMacroWithBadArg() + { + // make sure this still bombs, but don't spam sysout + log.off(); + assertEvalException("#macro( evil $arg )$arg#end #evil(bar)"); + log.on(); + } + + // just make sure this doesn't get broken + public void testLateDefinedMacroWithGoodArg() + { + String good = "#good('bar') #macro( good $arg )$arg#end"; + assertEvalEquals("bar ", good); + } + + public void testDirectivesWithBadArg() + { + // make sure these all still bomb, but don't spam sysout + log.off(); + assertEvalException("#foreach(Stuff in That)foo#end"); + assertEvalException("#include(Stuff)"); + assertEvalException("#parse(Stuff)"); + assertEvalException("#define(Stuff)foo#end"); + assertEvalException("#macro( name Stuff)foo#end"); + assertEvalException("#foreach($i in [1..3])#break(Stuff)#end"); + assertEvalException("#literal(Stuff)foo#end"); + assertEvalException("#evaluate(Stuff)", ParseErrorException.class); + log.on(); + } + + public void testLateDefinedMacroWithBadArg() + { + String evil = "#evil(bar) #macro( evil $arg )$arg#end"; + assertEvalException(evil, TemplateInitException.class); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity615TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity615TestCase.java new file mode 100755 index 00000000..fec7796d --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity615TestCase.java @@ -0,0 +1,139 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-615. + */ +public class Velocity615TestCase extends BaseTestCase +{ + public Velocity615TestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty("velocimacro.permissions.allow.inline", "true"); + engine.setProperty("velocimacro.permissions.allow.inline.to.replace.global", "false"); + engine.setProperty("velocimacro.permissions.allow.inline.local.scope", "true"); + engine.setProperty("velocimacro.arguments.strict", "true"); + engine.setProperty("space.gobbling", "bc"); + } + + public void testIt() + { + String template = "#set( $foo = 'old' )"+ + "#macro( test $foo )"+ + "#set( $foo = \"new $foo \" )"+ + "$foo"+ + "#end"+ + "#test( 'foo' )"+ + "$foo"; + assertEvalEquals("new foo new foo ", template); + } + + public void testForIrrationallyFearedRelatedPossibleProblem() + { + context.put("i", new Inc()); + String template = "#macro( test $a )"+ + "$a"+ + "$a"+ + "#end"+ + "#test( \"$i\" )$i"; + assertEvalEquals("001", template); + } + + public void testForIrrationallyFearedRelatedPossibleProblem2() + { + context.put("i", new Inc()); + String template = "#macro( test $a )"+ + "#set( $a = 'a' )"+ + "$a"+ + "$a"+ + "#end"+ + "#test( \"$i\" )$i"; + assertEvalEquals("aa1", template); + } + + public void testForIrrationallyFearedRelatedPossibleProblem3() + { + context.put("i", new Inc()); + String template = "#macro( test $a )"+ + "$a"+ + "$a"+ + "#end"+ + "#test( $i )$i"; + assertEvalEquals("012", template); + } + + public void testForIrrationallyFearedRelatedPossibleProblem4() + { + context.put("i", new Inc()); + String template = "#macro( test $a )"+ + "$a"+ + "$a"+ + "#end"+ + "#test( $i.plus() )$i"; + assertEvalEquals("001", template); + } + + public void testForIrrationallyFearedRelatedPossibleProblem5() + { + context.put("i", new Inc()); + String template = "#macro( test $a )"+ + "#set( $a = $i )"+ + "$a"+ + "$a"+ + "#end"+ + "#test( 'a' )$i"; + assertEvalEquals("012", template); + } + + public void testVelocity681() + { + String template = "#macro(myMacro $result)"+ + " #set($result = 'some value')"+ + "#end"+ + "#myMacro($x)"+ + "$x"; + assertEvalEquals("$x", template); + } + + public static class Inc + { + private int i=0; + + public int plus() + { + return i++; + } + + public String toString() + { + return String.valueOf(i++); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity616TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity616TestCase.java new file mode 100755 index 00000000..e2974e26 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity616TestCase.java @@ -0,0 +1,70 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-616. + */ +public class Velocity616TestCase extends BaseTestCase +{ + public Velocity616TestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + context.put("bar", "bar"); + context.put("foo", Boolean.FALSE); + } + + public void testIfNoBrackets() + { + String template = "\\#if ($foo) \\$bar \\#end"; + String expected = "#if (false) $bar #end"; + assertEvalEquals(expected, template); + } + + public void testForeachBrackets() + { + String template = "\\#{foreach}( $i in [1..3] )$i\\#{end}"; + String expected = "#{foreach}( $i in [1..3] )$i#{end}"; + assertEvalEquals(expected, template); + } + + public void testIfBrackets() + { + String template = "\\#{if} ($foo) \\$bar \\#{end}"; + String expected = "#{if} (false) $bar #{end}"; + assertEvalEquals(expected, template); + } + + public void testIfBracketsOnEndOnly() + { + String template = "\\#if( $foo ) \\$bar \\#{end}"; + String expected = "#if( false ) $bar #{end}"; + assertEvalEquals(expected, template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity625TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity625TestCase.java new file mode 100755 index 00000000..bdbf43fe --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity625TestCase.java @@ -0,0 +1,40 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-625. + */ +public class Velocity625TestCase extends BaseTestCase +{ + public Velocity625TestCase(String name) + { + super(name); + } + + public void test1() + { + String template = "#macro(test $a $b)test#end#test('x')"; + assertEvalEquals("test", template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity627TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity627TestCase.java new file mode 100644 index 00000000..faff4cad --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity627TestCase.java @@ -0,0 +1,49 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-627. Make sure Foreach + * Error message reports correct line numbers. + */ + +public class Velocity627TestCase extends BaseTestCase +{ + public Velocity627TestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.SKIP_INVALID_ITERATOR, Boolean.FALSE); + } + + public void test627() + { + // Make sure the error ouput contains "line 3, column 16" + assertEvalExceptionAt("##\n##\n#foreach($i in \"junk\")blaa#end", 3, 16); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity629TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity629TestCase.java new file mode 100644 index 00000000..aa9132cf --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity629TestCase.java @@ -0,0 +1,55 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-629. Make sure string literals + * Error message reports correct line and column numbers. + */ +public class Velocity629TestCase extends BaseTestCase +{ + public Velocity629TestCase(String name) + { + super(name); + } + + public void test629() + { + String template = "##\n"+ + "##\n"+ + "#set($list=[1])#set($x=\"\n"+ + "$list.get(1)\n"+ + "\")"; + // Make sure the error ouput contains "line 4, column 7" if not throw + assertEvalExceptionAt(template, 4, 7); + + template = "##\n"+ + "##\n"+ + "#set($x=\"#if\")"; + assertEvalExceptionAt(template, 3, 9); + + template = "##\n"+ + "##\n"+ + "#macro(test $i)$i#end#set($list=[1])#test(\"$list.get(1)\")"; + assertEvalExceptionAt(template, 3, 50); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity62TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity62TestCase.java new file mode 100755 index 00000000..e76a18bd --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity62TestCase.java @@ -0,0 +1,63 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-62. + */ +public class Velocity62TestCase extends BaseTestCase +{ + public Velocity62TestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + context.put("foo", "foo"); + } + + public void testNested() + { + String template = "#macro( outer )#set( $foo = 'bar' )#inner()#end"+ + "#macro( inner )$foo#end"+ + "#inner()#outer()#inner()"; + assertEvalEquals("foobarbar", template); + } + + public void testRecursive() + { + context.put("i", 1); + String template = "#macro(recurse $i)"+ + "$i"+ + "#if( $i < 5 )"+ + "#set( $i = $i + 1 )"+ + "#recurse($i)"+ + "#end"+ + "#end"+ + "#recurse(1)"; + assertEvalEquals("12345", template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity631TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity631TestCase.java new file mode 100755 index 00000000..99289433 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity631TestCase.java @@ -0,0 +1,49 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-631. + */ +public class Velocity631TestCase extends BaseTestCase +{ + public Velocity631TestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty("space.gobbling", "bc"); + } + + + public void test631() + { + assertEvalEquals("$a", "$a #set($b = 1)"); + assertEvalEquals("$a", "$a#set($b = 1)"); + assertEvalEquals("$a.b", "$a.b#set($b = 1)"); + assertEvalEquals("$a.b(", "$a.b(#set($b = 1)"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity644TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity644TestCase.java new file mode 100644 index 00000000..9e74fe24 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity644TestCase.java @@ -0,0 +1,57 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-644. Make sure the reported filename + * is correct in exceptions when an error occurs in another template file. + */ +public class Velocity644TestCase extends BaseTestCase +{ + public Velocity644TestCase(String name) + { + super(name); + } + + @Override + public void setUp() throws Exception + { + super.setUp(); + engine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, FILE_RESOURCE_LOADER_PATH); + engine.setProperty(RuntimeConstants.VM_LIBRARY, "testCase644.vm"); + engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE); + context.put("NULL", null); + } + + public void test629() + { + // Calling a null method + assertEvalExceptionAt("#nullMethod()", "testCase644.vm", 9, 8); + // An invalid array + assertEvalExceptionAt("#arrayError()", "testCase644.vm", 4, 8); + // An invalid reference + assertEvalExceptionAt("#badRef()", "testCase644.vm", 13, 3); + // Non iterable object + assertEvalExceptionAt("#forloop()", "testCase644.vm", 18, 18); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity667TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity667TestCase.java new file mode 100644 index 00000000..87f4e5a9 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity667TestCase.java @@ -0,0 +1,39 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-667. Make "#macro" throws a parse exception + */ +public class Velocity667TestCase extends BaseTestCase +{ + public Velocity667TestCase(String name) + { + super(name); + } + + public void test667() + { + assertEvalExceptionAt("#macro", 1, 7); + assertEvalExceptionAt("#macro #macro", 1, 7); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity682TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity682TestCase.java new file mode 100644 index 00000000..8808ac3d --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity682TestCase.java @@ -0,0 +1,63 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-682. + */ +public class Velocity682TestCase extends BaseTestCase +{ + public Velocity682TestCase(String name) + { + super(name); + //DEBUG = true; + } + + public void test682() + { + engine.setProperty(RuntimeConstants.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + assertEvalEquals("foo1foo2", "#macro(eval $e)#evaluate($e)#end#eval('foo1')#eval('foo2')"); + } + + public void test682b() + { + String template = "#macro( eval $e )#evaluate($e)#end" + + "#eval('foo')" + + "#eval('bar')"; + String expected = "foo"+ + "bar"; + assertEvalEquals(expected, template); + } + + public void test682c() + { + //NOTE: #eval call is apparently swallowing preceding newlines. :( + // appears to be a parser issue unrelated to VELOCITY-682 + String template = "#macro( eval $e )#evaluate($e)#end" + + "\n#eval('foo')" + + "\n\n#eval('bar')"; + String expected = "foo"+ + "\nbar"; + assertEvalEquals(expected, template); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity689TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity689TestCase.java new file mode 100755 index 00000000..7ff2ddf8 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity689TestCase.java @@ -0,0 +1,78 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-689. + */ +public class Velocity689TestCase extends BaseTestCase +{ + public Velocity689TestCase(String name) + { + super(name); + //DEBUG = true; + } + + @Override + public void setUpContext(VelocityContext ctx) + { + ctx.put("foo", new Foo()); + } + + public void testIt() + { + String template = "$foo.baz, $foo.bar"; + assertEvalEquals("baz, bar", template); + } + + public interface HasMethod + { + String getBar(); + } + + public interface HasOtherMethod extends HasMethod + { + String getBaz(); + } + + public interface NoMethod extends HasOtherMethod + { + // nada! + } + + private static class Foo implements NoMethod + { + @Override + public String getBar() + { + return "bar"; + } + + @Override + public String getBaz() + { + return "baz"; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity701TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity701TestCase.java new file mode 100755 index 00000000..69bbf21e --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity701TestCase.java @@ -0,0 +1,72 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-701. + */ +public class Velocity701TestCase extends BaseTestCase +{ + public Velocity701TestCase(String name) + { + super(name); + //DEBUG = true; + } + + public void testAbstractClass() + { + context.put("foo", new Foo() { + @Override + public String getBar() { + return "bar"; + } + }); + assertEvalEquals("bar", "$foo.bar"); + } + + public static abstract class Foo { + + public abstract String getBar(); + + } + + public void testEnum() + { + context.put("bar", Bar.ONE); + assertEvalEquals("foo", "$bar.foo"); + } + + public enum Bar { + + ONE(){ + @Override + public String getFoo() { + return "foo"; + } + }; + + //This was an abstract method, but Velocity 1.6 quit working with it. + public abstract String getFoo(); + + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity702TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity702TestCase.java new file mode 100755 index 00000000..ed74c6e3 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity702TestCase.java @@ -0,0 +1,99 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.runtime.resource.util.StringResourceRepository; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-702. + */ +public class Velocity702TestCase extends BaseTestCase +{ + public Velocity702TestCase(String name) + { + super(name); + } + + @Override + public void setUpEngine(VelocityEngine engine) + { + engine.setProperty(RuntimeConstants.RESOURCE_LOADERS, "high,low"); + engine.addProperty("high.resource.loader.class", StringResourceLoader.class.getName()); + engine.addProperty("high.resource.loader.cache", "false"); + engine.addProperty("high.resource.loader.repository.name", "high"); + engine.addProperty("high.resource.loader.repository.static", "false"); + engine.addProperty("high.resource.loader.modificationCheckInterval", "1"); + engine.addProperty("low.resource.loader.class", StringResourceLoader.class.getName()); + engine.addProperty("low.resource.loader.cache", "true"); + engine.addProperty("low.resource.loader.repository.name", "low"); + engine.addProperty("low.resource.loader.repository.static", "false"); + engine.addProperty("low.resource.loader.modificationCheckInterval", "1"); + engine.init(); + } + + public void testIt() throws Exception + { + addToHigh("foo", "foo"); + addToLow("foo", "bar"); + assertTmplEquals("foo", "foo"); + + removeFromHigh("foo"); + assertTmplEquals("bar", "foo"); + + Thread.sleep(1500); + addToHigh("foo", "woogie"); + assertTmplEquals("woogie", "foo"); + } + + private void addToHigh(String name, String content) + { + getHighRepo().putStringResource(name, content); + } + + private void removeFromHigh(String name) + { + getHighRepo().removeStringResource(name); + } + + private StringResourceRepository getHighRepo() + { + return (StringResourceRepository)engine.getApplicationAttribute("high"); + } + + private void addToLow(String name, String content) + { + getLowRepo().putStringResource(name, content); + } + + private void removeFromLow(String name) + { + getLowRepo().removeStringResource(name); + } + + private StringResourceRepository getLowRepo() + { + return (StringResourceRepository)engine.getApplicationAttribute("low"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity709TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity709TestCase.java new file mode 100644 index 00000000..50219726 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity709TestCase.java @@ -0,0 +1,54 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-709. + */ +public class Velocity709TestCase extends BaseTestCase +{ + public Velocity709TestCase(String name) + { + super(name); + // DEBUG = true; + } + + public void testEscapedBackslashInSetDirective() + { + String backslash = "\\"; + String template = "#set($var = \"" + backslash + "\" )#set($var2 = \"${var}\")$var2"; + System.out.println(template); + assertEvalEquals("\\", template); + } + + public void testEscapedDoubleQuote() + { + String template = "#set($foo = \"jeah \"\"baby\"\" jeah! \"\"\"\"\")$foo"; + assertEvalEquals("jeah \"baby\" jeah! \"\"", template); + } + + public void testEscapedSingleQuote() + { + String template = "#set($foo = 'jeah ''baby'' jeah!')$foo"; + assertEvalEquals("jeah 'baby' jeah!", template); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity727TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity727TestCase.java new file mode 100644 index 00000000..46038152 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity727TestCase.java @@ -0,0 +1,40 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-727. + */ +public class Velocity727TestCase extends BaseTestCase +{ + public Velocity727TestCase(String name) + { + super(name); + DEBUG = false; + } + + public void testDefineWithNoArgument() + { + assertEvalException("#define() foo bar #end", VelocityException.class); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity728TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity728TestCase.java new file mode 100644 index 00000000..824576d8 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity728TestCase.java @@ -0,0 +1,40 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.VelocityException; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-728. + */ +public class Velocity728TestCase extends BaseTestCase +{ + public Velocity728TestCase(String name) + { + super(name); + DEBUG = false; + } + + public void testParseWithNoArgument() + { + assertEvalException("#parse()", VelocityException.class); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity729TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity729TestCase.java new file mode 100644 index 00000000..869c609f --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity729TestCase.java @@ -0,0 +1,46 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-729. + */ +public class Velocity729TestCase extends BaseTestCase +{ + public Velocity729TestCase(String name) + { + super(name); + // DEBUG = true; + } + + public void testDotRightAfterDollarReference() + { + String s = "$.x schmoo $jee"; + context.put("jee", "foo"); + assertEvalEquals("$.x schmoo foo", s); + } + + public void testVelocity754jQueryPost() + { + assertSchmoo("$.post(\"someUrl\", \"\")"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity736TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity736TestCase.java new file mode 100644 index 00000000..0a62dce3 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity736TestCase.java @@ -0,0 +1,76 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-736. + */ +public class Velocity736TestCase extends BaseTestCase +{ + public Velocity736TestCase(String name) + { + super(name); + DEBUG = true; + } + + public void testPublicMethodInheritedFromAbstractProtectedClass() throws Exception + { + try + { + toobig(100); + } + catch (Exception e) + { + context.put("e", e); + assertEvalEquals("100", "$e.permittedSize"); + } + } + + public void toobig(long permitted) throws Exception + { + throw new FileSizeLimitExceededException(permitted); + } + + public static class FileUploadException extends Exception {} + + protected abstract static class SizeException extends FileUploadException + { + private final long permitted; + protected SizeException(long permitted) + { + this.permitted = permitted; + } + public long getPermittedSize() + { + return this.permitted; + } + } + + public static class FileSizeLimitExceededException extends SizeException + { + public FileSizeLimitExceededException(long permitted) + { + super(permitted); + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity742TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity742TestCase.java new file mode 100644 index 00000000..45b7dfde --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity742TestCase.java @@ -0,0 +1,57 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-742. + */ +public class Velocity742TestCase extends BaseTestCase +{ + public Velocity742TestCase(String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + // we need to call init here because otherwise it is not called until assertEvalEquals + // and therefore the removeDirective call is ignored. + engine.init(); + } + + public void testDisableAndRestoreDirective() + { + String s = "#include('doesnotexist.vm') directive is disabled"; + + // first remove the #include directive and see that is treated as normal text + engine.removeDirective("include"); + assertEvalEquals(s, s); + + // now reload the directive and see that the include directive works again and + // Velocity throws ResourceNotFoundException because it can't find the template + engine.loadDirective("org.apache.velocity.runtime.directive.Include"); + assertEvalException(s, ResourceNotFoundException.class); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity747TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity747TestCase.java new file mode 100644 index 00000000..5dba3633 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity747TestCase.java @@ -0,0 +1,102 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; + +import java.io.FileReader; +import java.io.StringWriter; +import java.util.Properties; + +/** + * This class tests VELOCITY-785. + */ +public class Velocity747TestCase extends BaseTestCase +{ + public Velocity747TestCase(String name) + { + super(name); + } + + VelocityEngine engine1; + VelocityEngine engine2; + + @Override + protected void setUp() throws Exception + { + Properties props = new Properties(); + /* The props file contains *spaces* at the end of the line: + * velocimacro.permissions.allow.inline.local.scope = true + * which caused the initial problem + */ + props.load(new FileReader(TEST_COMPARE_DIR + "/issues/velocity-747/vel.props")); + props.setProperty("file.resource.loader.path", TEST_COMPARE_DIR + "/issues/velocity-747/"); + engine1 = new VelocityEngine(props); + + //by default, make the engine's log output go to the test-report + log = new TestLogger(false, false); + engine1.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, log); + + engine2 = new VelocityEngine(); + engine2.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file,string"); + engine2.addProperty("file.resource.loader.path", TEST_COMPARE_DIR + "/issues/velocity-747/"); + engine2.addProperty("file.resource.loader.cache", "true"); + engine2.addProperty("file.resource.loader.modificationCheckInterval", "-1"); + engine2.addProperty("velocimacro.permissions.allow.inline.local.scope", "true"); + engine2.addProperty("velocimacro.max.depth", "-1"); + engine2.addProperty("string.resource.loader.class", StringResourceLoader.class.getName()); + engine2.addProperty("string.resource.loader.repository.name", "stringRepo"); + engine2.addProperty("string.resource.loader.repository.static", "false"); + log = new TestLogger(false, false); + engine2.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, log); + } + + public void testMacroIsolation1() + { + StringWriter writer = new StringWriter(); + VelocityContext ctx = new VelocityContext(); + engine1.mergeTemplate("one.vm", "UTF-8", new VelocityContext(), writer); + String result = writer.toString(); + assertEquals(result, "This is from Test1 macro of one.vm"); + writer = new StringWriter(); + engine1.mergeTemplate("two.vm", "UTF-8", ctx, writer); + result = writer.toString(); + assertEquals(result, "This is from Test1 macro of two.vm"); + } + + public void testMacroIsolation2() + { + StringWriter writer = new StringWriter(); + VelocityContext ctx = new VelocityContext(); + engine2.mergeTemplate("one.vm", "UTF-8", new VelocityContext(), writer); + String result = writer.toString(); + assertEquals(result, "This is from Test1 macro of one.vm"); + + writer = new StringWriter(); + engine2.mergeTemplate("two.vm", "UTF-8", ctx, writer); + result = writer.toString(); + assertEquals(result, "This is from Test1 macro of two.vm"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity753TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity753TestCase.java new file mode 100755 index 00000000..21fff75c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity753TestCase.java @@ -0,0 +1,62 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-753. + */ +public class Velocity753TestCase extends BaseTestCase +{ + public Velocity753TestCase(String name) + { + super(name); + } + + public void testFloatArg() throws Exception + { + // verify precedence outside of Velocity + Tool tool = new Tool(); + Float f = 5.23f; + assertEquals("object", tool.test(f)); + + context.put("tool", tool); + context.put("float", f); + + String template = "$tool.test($float)"; + // in reflection-land, Float and float are equivalent, so double is selected + assertEvalEquals("double", template); + } + + public static class Tool + { + public String test(double d) + { + return "double"; + } + + public String test(Object o) + { + return "object"; + } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity755TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity755TestCase.java new file mode 100755 index 00000000..c3261da4 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity755TestCase.java @@ -0,0 +1,41 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-755. + */ +public class Velocity755TestCase extends BaseTestCase +{ + public Velocity755TestCase(String name) + { + super(name); + } + + public void testMapOrder() + { + String template = "#set( $map = {'a': 1, 'b': true, 'c': 3, 'd': false, 'e': 5} )"+ + "#foreach( $i in $map )$i#end"; + assertEvalEquals("1true3false5", template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity758TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity758TestCase.java new file mode 100644 index 00000000..4c8d84c2 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity758TestCase.java @@ -0,0 +1,66 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.event.EventCartridge; +import org.apache.velocity.app.event.IncludeEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-758. + */ +public class Velocity758TestCase extends BaseTestCase +{ + public Velocity758TestCase(String name) + { + super(name); + } + + public void testNullArgumentForParse() + { + assertEvalEquals("", "#parse($foo)"); + } + + public void testOverrideNullArgumentForParse() + { + String nullContent = "Parse arg was null"; + addTemplate("null.vm", nullContent); + + EventCartridge ec = new EventCartridge(); + ec.addEventHandler(new Handler()); + ec.attachToContext(context); + + assertEvalEquals(nullContent, "#parse($foo)"); + } + + public static class Handler implements IncludeEventHandler + { + @Override + public String includeEvent(Context context, String parsePath, String parentPath, String directive) + { + if (parsePath == null) + { + parsePath = "null.vm"; + } + return parsePath; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity762TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity762TestCase.java new file mode 100755 index 00000000..ea025ef3 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity762TestCase.java @@ -0,0 +1,40 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-762. + */ +public class Velocity762TestCase extends BaseTestCase +{ + public Velocity762TestCase(String name) + { + super(name); + } + + public void testForeachIsLast() + { + String template = "#foreach( $i in [1..3] )$foreach.last #end"; + assertEvalEquals("false false true ", template); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity785TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity785TestCase.java new file mode 100644 index 00000000..83a60a09 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity785TestCase.java @@ -0,0 +1,42 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-785. + */ +public class Velocity785TestCase extends BaseTestCase +{ + public Velocity785TestCase(String name) + { + super(name); + // DEBUG = true; + } + + public void testQuoteEscapes() + { + assertEvalEquals("\"", "#set($double_double = \"\"\"\")$double_double"); + assertEvalEquals("'", "#set($single_single = '''')$single_single"); + assertEvalEquals("''", "#set($double_single = \"''\")$double_single"); + assertEvalEquals("\"\"", "#set($single_double = '\"\"')$single_double"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity830TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity830TestCase.java new file mode 100644 index 00000000..4f014f4c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity830TestCase.java @@ -0,0 +1,58 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests the VELOCITY-830 issue. + * + * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a> + */ +public class Velocity830TestCase extends BaseTestCase +{ + public Velocity830TestCase(String name) + { + super(name); + } + + public static class UnderscoreMethodObject + { + public String check() { return "ok"; } + public String _1() { return "gotit"; } + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("obj", new UnderscoreMethodObject()); + } + + /** + * Tests methods name beginning with _ + */ + public void testUnderscoreMethod() + throws Exception + { + assertEvalEquals("ok", "$obj.check()"); + assertEvalEquals("gotit", "$obj._1()"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity855TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity855TestCase.java new file mode 100755 index 00000000..5d2c94da --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity855TestCase.java @@ -0,0 +1,47 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-855. + */ +public class Velocity855TestCase extends BaseTestCase +{ + + public Velocity855TestCase(String name) + { + super(name); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("elementKind", javax.lang.model.element.ElementKind.class); + context.put("typeKind", javax.lang.model.type.TypeKind.class); + } + + public void testVelocity855() + { + assertEvalEquals("ENUM DECLARED", "$elementKind.valueOf('ENUM') $typeKind.valueOf('DECLARED')"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity889TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity889TestCase.java new file mode 100755 index 00000000..d4532f84 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity889TestCase.java @@ -0,0 +1,51 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-589. + */ +public class Velocity889TestCase extends BaseTestCase +{ + public Velocity889TestCase(String name) + { + super(name); + } + + public void testSpaceBeforeRParen() + { + assertEvalEquals("#foo(\n)", "#foo(\n)"); + assertEvalEquals("#foo(\n )", "#foo(\n )"); + } + + public void testSpaceBeforeRParenWithArg() + { + assertEvalEquals("#foo(\n$bar\n)", "#foo(\n$bar\n)"); + assertEvalEquals("#foo(\n $bar\n )", "#foo(\n $bar\n )"); + } + + public void testSpaceBeforeRParenWithDefaultArg() + { + assertEvalEquals("", "#macro(\nfoo\n,\n$bar\n=\n'bar')\n#end"); + assertEvalEquals("", "#macro(\n foo\n ,\n $bar\n =\n 'bar'\n )\n #end"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity896TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity896TestCase.java new file mode 100755 index 00000000..d7ea45da --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity896TestCase.java @@ -0,0 +1,40 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-589. + */ +public class Velocity896TestCase extends BaseTestCase +{ + public Velocity896TestCase(String name) + { + super(name); + } + + public void testTailingHash() + { + assertEvalEquals("#", "#"); + assertEvalEquals("$", "$"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity904TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity904TestCase.java new file mode 100755 index 00000000..86caa7cf --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity904TestCase.java @@ -0,0 +1,116 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-904. + */ +public class Velocity904TestCase extends BaseTestCase +{ + public Velocity904TestCase(String name) + { + super(name); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + // that will also test the deprecation of velocimacro.arguments.preserve_literals towards velocimacro.enable_bc_mode + engine.setProperty("velocimacro.arguments.preserve_literals", getName().contains("NoPreserve") ? "false" : "true"); + } + + public void testNullArgNoPreserve() + { + assertEvalEquals("$parameter", "#macro(testmacro $parameter)$parameter#end#testmacro($return)"); + } + + public void testNullArgPreserve() + { + assertEvalEquals("$return", "#macro(testmacro $parameter)$parameter#end#testmacro($return)"); + } + + public void testArgSetToNullNoPreserve() + { + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#set($variable = 'value')#mymacro($variable)"); + } + + public void testArgSetToNullPreserve() + { + assertEvalEquals("$variable", "#macro(mymacro $input)#set($input = $null)$input#end#set($variable = 'value')#mymacro($variable)"); + } + + public void testSubMacroNoPreserve() + { + assertEvalEquals("$return$return$return", "#macro(macro1 $return)$return#macro2($param2)$return#end#macro(macro2 $return)$return#end#macro1($param)"); + } + + public void testSubMacroPreserve() + { + assertEvalEquals("$param$param2$param", "#macro(macro1 $return)$return#macro2($param2)$return#end#macro(macro2 $return)$return#end#macro1($param)"); + } + + public void testNoArgNoPreserve() + { + assertEvalEquals("","#macro(testMacro $param)#end#testMacro()"); + } + + public void testNoArgPreserve() + { + assertEvalEquals("","#macro(testMacro $param)#end#testMacro()"); + } + + public void testConstantSetToNullNoPreserve() + { + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro('string-value')"); + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro(\"interpolated-$bar-value\")"); + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro(true)"); + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro(4.5)"); + } + + public void testConstantSetToNullPreserve() + { + assertEvalEquals("'string-value'", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro('string-value')"); + assertEvalEquals("\"interpolated-$bar-value\"", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro(\"interpolated-$bar-value\")"); + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro(true)"); + assertEvalEquals("$input", "#macro(mymacro $input)#set($input = $null)$input#end#mymacro(4.5)"); + } + + public void testConstantNoPreserve() + { + assertEvalEquals("true", "#macro(mymacro $input)$input#end#mymacro(true)"); + assertEvalEquals("1.5", "#macro(mymacro $input)$input#end#mymacro(1.5)"); + assertEvalEquals("foo", "#macro(mymacro $input)$input#end#mymacro('foo')"); + assertEvalEquals("{}", "#macro(mymacro $input)$input#end#mymacro({})"); + assertEvalEquals("[]", "#macro(mymacro $input)$input#end#mymacro([])"); + } + + public void testConstantPreserve() + { + assertEvalEquals("true", "#macro(mymacro $input)$input#end#mymacro(true)"); + assertEvalEquals("1.5", "#macro(mymacro $input)$input#end#mymacro(1.5)"); + assertEvalEquals("foo", "#macro(mymacro $input)$input#end#mymacro('foo')"); + assertEvalEquals("{}", "#macro(mymacro $input)$input#end#mymacro({})"); + assertEvalEquals("[]", "#macro(mymacro $input)$input#end#mymacro([])"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity919TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity919TestCase.java new file mode 100644 index 00000000..33397cfc --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity919TestCase.java @@ -0,0 +1,23 @@ +package org.apache.velocity.test.issues; + +import org.apache.velocity.test.BaseTestCase; + +public class Velocity919TestCase extends BaseTestCase +{ + public Velocity919TestCase(String name) + { + super(name); + } + + public void testUnbreakableSpace() throws Exception + { + assertEvalEquals("before\u200Bafter", "before\u200Bafter"); + } + + public void testUserFileSeparator() throws Exception + { + assertEvalEquals("before\u001Cafter", "before\u001Cafter"); + } + +} + diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity924TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity924TestCase.java new file mode 100755 index 00000000..5c1ee041 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity924TestCase.java @@ -0,0 +1,65 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-855. + */ +public class Velocity924TestCase extends BaseTestCase +{ + public Velocity924TestCase(String name) + { + super(name); + } + + public static class Foo + { + public String getName() { return "foo"; } + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("var", new Foo()); + } + + public void testVelocity924Getter() + { + assertEvalEquals("org.apache.velocity.test.issues.Velocity924TestCase$Foo foo", "$var.class.name $var.name"); + } + + public void testVelocity924Method() + { + assertEvalEquals("org.apache.velocity.test.issues.Velocity924TestCase$Foo foo", "$var.class.getName() $var.getName()");assertEvalEquals("org.apache.velocity.test.issues.Velocity924TestCase$Foo foo", "$var.class.name $var.name"); + } + + public void testVelocity924Getter2() + { + assertEvalEquals("foo org.apache.velocity.test.issues.Velocity924TestCase$Foo", "$var.name $var.class.name"); + } + + public void testVelocity924Method2() + { + assertEvalEquals("foo org.apache.velocity.test.issues.Velocity924TestCase$Foo", "$var.getName() $var.class.getName()");assertEvalEquals("org.apache.velocity.test.issues.Velocity924TestCase$Foo foo", "$var.class.name $var.name"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity926TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity926TestCase.java new file mode 100755 index 00000000..41a33213 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity926TestCase.java @@ -0,0 +1,38 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests VELOCITY-926. + */ +public class Velocity926TestCase extends BaseTestCase +{ + public Velocity926TestCase(String name) + { + super(name); + } + + public void testNamesCollision() + { + assertEvalEquals("bar foo", "#set($foo='foo')#set($bar='bar')#macro(test, $foo, $bar)$foo $bar#end#test($bar, $foo)"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity927TestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity927TestCase.java new file mode 100755 index 00000000..218ed7f2 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/issues/Velocity927TestCase.java @@ -0,0 +1,39 @@ +package org.apache.velocity.test.issues; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +/** + * This class tests bugfix for http://stackoverflow.com/questions/32805217/bug-or-hidden-feature-in-apache-velocity + */ +public class Velocity927TestCase extends BaseTestCase +{ + public Velocity927TestCase(String name) + { + super(name); + } + + public void testIt() + { + assertEvalEquals("", "#set($map = {\n })"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingDirective.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingDirective.java new file mode 100644 index 00000000..0717310a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingDirective.java @@ -0,0 +1,61 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.context.InternalContextAdapter; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.directive.Directive; +import org.apache.velocity.runtime.parser.node.Node; + +import java.io.IOException; +import java.io.Writer; + +/** + * that always throws an exception. Used to test + * that RuntimeExceptions are passed through. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class ExceptionGeneratingDirective extends Directive +{ + @Override + public String getName() + { + return "Exception"; + } + + @Override + public int getType() + { + return Directive.BLOCK; + } + + @Override + public boolean render(InternalContextAdapter context, Writer writer, Node node) + throws IOException, ResourceNotFoundException, ParseErrorException, + MethodInvocationException + { + throw new RuntimeException("exception"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingEventHandler.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingEventHandler.java new file mode 100644 index 00000000..037594ac --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingEventHandler.java @@ -0,0 +1,55 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.app.event.IncludeEventHandler; +import org.apache.velocity.app.event.MethodExceptionEventHandler; +import org.apache.velocity.app.event.ReferenceInsertionEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.util.introspection.Info; + +/** + * Event handlers that always throws an exception. Used to test + * that RuntimeExceptions are passed through. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class ExceptionGeneratingEventHandler implements IncludeEventHandler, + MethodExceptionEventHandler, ReferenceInsertionEventHandler +{ + + @Override + public String includeEvent(Context context, String includeResourcePath, String currentResourcePath, + String directiveName) + { + throw new RuntimeException("exception"); + } + + @Override + public Object methodException(Context context, Class<?> claz, String method, Exception e, Info info) { throw new RuntimeException("exception"); } + + @Override + public Object referenceInsert(Context context, String reference, Object value) + { + throw new RuntimeException("exception"); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingResourceLoader.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingResourceLoader.java new file mode 100644 index 00000000..fef7adb3 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/ExceptionGeneratingResourceLoader.java @@ -0,0 +1,62 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.resource.Resource; +import org.apache.velocity.runtime.resource.loader.ResourceLoader; +import org.apache.velocity.util.ExtProperties; + +import java.io.Reader; + +/** + * Resource Loader that always throws an exception. Used to test + * that RuntimeExceptions are passed through. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class ExceptionGeneratingResourceLoader extends ResourceLoader +{ + + @Override + public void init(ExtProperties configuration) + { + } + + @Override + public Reader getResourceReader(String source, String encoding) throws ResourceNotFoundException + { + throw new RuntimeException("exception"); + } + + @Override + public boolean isSourceModified(Resource resource) + { + return false; + } + + @Override + public long getLastModified(Resource resource) + { + return 0; + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/GetPutObject.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/GetPutObject.java new file mode 100644 index 00000000..1cc528c2 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/GetPutObject.java @@ -0,0 +1,35 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +public class GetPutObject +{ + private Object value; + + public Object get() + { + return value; + } + + public void put(final Object value) + { + this.value = value; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/TestContext.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/TestContext.java new file mode 100644 index 00000000..4b8e3bda --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/TestContext.java @@ -0,0 +1,85 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.context.Context; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Used for testing EvaluateContext. For testing purposes, this is a case insensitive + * context. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @version $Id$ + */ +public class TestContext implements Context +{ + Context innerContext = new VelocityContext(); + Map<String, String> originalKeys = new HashMap<>(); + + @Override + public boolean containsKey(String key) + { + return innerContext.containsKey(normalizeKey(key)); + } + + @Override + public Object get(String key) + { + return innerContext.get(normalizeKey(key)); + } + + @Override + public String[] getKeys() + { + return originalKeys.values().toArray(new String[originalKeys.size()]); + } + + @Override + public Object put(String key, Object value) + { + String normalizedKey = normalizeKey(key); + originalKeys.put(key, normalizedKey); + return innerContext.put(normalizedKey, value); + } + + @Override + public Object remove(String key) + { + originalKeys.remove(key); + return innerContext.remove(normalizeKey(key)); + } + + private String normalizeKey(String key) + { + if (key == null) + { + return null; + } + else + { + return key.toUpperCase(Locale.ROOT); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/TestLogger.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/TestLogger.java new file mode 100644 index 00000000..e7a4e990 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/TestLogger.java @@ -0,0 +1,360 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.slf4j.helpers.FormattingTuple; +import org.slf4j.helpers.MarkerIgnoringBase; +import org.slf4j.helpers.MessageFormatter; +import org.slf4j.spi.LocationAwareLogger; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +/** + * Logger implementation that can easily capture output + * or suppress it entirely. By default, both capture and suppress + * are on. To have this behave like a normal Logger, + * you must turn it on() and stopCapture(). + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @author Nathan Bubna + * @author <a href="mailto:cbrisson@apache.org">Claude Brisson</a> + * @version $Id$ + */ +public class TestLogger extends MarkerIgnoringBase +{ + private ByteArrayOutputStream log; + private PrintStream systemDotIn; + + private boolean suppress = true; + private boolean capture = true; + private int enabledLevel = LOG_LEVEL_INFO; + + public TestLogger() + { + this(true, true); + } + + public TestLogger(boolean suppress, boolean capture) + { + this.suppress = suppress; + this.capture = capture; + if (suppress) + { + off(); + } + else if (capture) + { + startCapture(); + } + } + + public static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT; + public static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT; + public static final int LOG_LEVEL_INFO = LocationAwareLogger.INFO_INT; + public static final int LOG_LEVEL_WARN = LocationAwareLogger.WARN_INT; + public static final int LOG_LEVEL_ERROR = LocationAwareLogger.ERROR_INT; + + private static int stringToLevel(String levelStr) + { + if ("trace".equalsIgnoreCase(levelStr)) return LOG_LEVEL_TRACE; + else if ("debug".equalsIgnoreCase(levelStr)) return LOG_LEVEL_DEBUG; + else if ("info".equalsIgnoreCase(levelStr)) return LOG_LEVEL_INFO; + else if ("warn".equalsIgnoreCase(levelStr)) return LOG_LEVEL_WARN; + else if ("error".equalsIgnoreCase(levelStr)) return LOG_LEVEL_ERROR; + // assume INFO by default + return LOG_LEVEL_INFO; + } + + private static String getPrefix(int level) + { + if (level <= LOG_LEVEL_TRACE) return " [trace] "; + else if (level <= LOG_LEVEL_DEBUG) return " [debug] "; + else if (level <= LOG_LEVEL_INFO) return " [info] "; + else if (level <= LOG_LEVEL_WARN) return " [warn] "; + else return " [error]"; + } + + public synchronized void on() + { + if (suppress) + { + suppress = false; + if (capture) + { + startCapture(); + } + } + } + + public synchronized void off() + { + suppress = true; + } + + public synchronized void startCapture() + { + capture = true; + if (!suppress) + { + log = new ByteArrayOutputStream(); + systemDotIn = new PrintStream(log, true); + } + } + + public synchronized void stopCapture() + { + capture = false; + } + + public void setEnabledLevel(int level) + { + enabledLevel = level; + } + + public boolean isLevelEnabled(int level) + { + return !suppress && level >= enabledLevel; + } + + /** + * Return the captured log messages to date. + * @return log messages + */ + public String getLog() + { + return log.toString(); + } + + private synchronized void log(int level, String msg, Throwable t) + { + if(!suppress && level >= enabledLevel) + { + PrintStream writer = capture ? systemDotIn : System.err; + writer.print(getPrefix(enabledLevel)); + writer.println(msg); + if (t != null) + { + writer.println(t.getMessage()); + t.printStackTrace(writer); + } + writer.flush(); + } + } + + /** + * Logging API + */ + + @Override + public boolean isTraceEnabled() + { + return isLevelEnabled(LOG_LEVEL_TRACE); + } + + @Override + public void trace(String msg) + { + log(LOG_LEVEL_TRACE, msg, null); + } + + @Override + public void trace(String format, Object arg) + { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(LOG_LEVEL_TRACE, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void trace(String format, Object arg1, Object arg2) + { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + log(LOG_LEVEL_TRACE, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void trace(String format, Object[] argArray) + { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(LOG_LEVEL_TRACE, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void trace(String msg, Throwable t) + { + log(LOG_LEVEL_TRACE, msg, t); + } + + @Override + public boolean isDebugEnabled() + { + return isLevelEnabled(LOG_LEVEL_DEBUG); + } + + @Override + public void debug(String msg) + { + log(LOG_LEVEL_DEBUG, msg, null); + } + + @Override + public void debug(String format, Object arg) + { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(LOG_LEVEL_DEBUG, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void debug(String format, Object arg1, Object arg2) + { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + log(LOG_LEVEL_DEBUG, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void debug(String format, Object[] argArray) + { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(LOG_LEVEL_DEBUG, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void debug(String msg, Throwable t) + { + log(LOG_LEVEL_DEBUG, msg, t); + } + + @Override + public boolean isInfoEnabled() + { + return isLevelEnabled(LOG_LEVEL_INFO); + } + + @Override + public void info(String msg) + { + log(LOG_LEVEL_INFO, msg, null); + } + + @Override + public void info(String format, Object arg) + { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(LOG_LEVEL_INFO, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void info(String format, Object arg1, Object arg2) + { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + log(LOG_LEVEL_INFO, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void info(String format, Object[] argArray) + { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(LOG_LEVEL_INFO, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void info(String msg, Throwable t) + { + log(LOG_LEVEL_INFO, msg, t); + } + + @Override + public boolean isWarnEnabled() + { + return isLevelEnabled(LOG_LEVEL_WARN); + } + + @Override + public void warn(String msg) + { + log(LOG_LEVEL_WARN, msg, null); + } + + @Override + public void warn(String format, Object arg) + { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(LOG_LEVEL_WARN, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void warn(String format, Object arg1, Object arg2) + { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + log(LOG_LEVEL_WARN, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void warn(String format, Object[] argArray) + { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(LOG_LEVEL_WARN, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void warn(String msg, Throwable t) + { + log(LOG_LEVEL_WARN, msg, t); + } + + @Override + public boolean isErrorEnabled() + { + return isLevelEnabled(LOG_LEVEL_ERROR); + } + + @Override + public void error(String msg) + { + log(LOG_LEVEL_ERROR, msg, null); + } + + @Override + public void error(String format, Object arg) + { + FormattingTuple ft = MessageFormatter.format(format, arg); + log(LOG_LEVEL_ERROR, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void error(String format, Object arg1, Object arg2) + { + FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); + log(LOG_LEVEL_ERROR, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void error(String format, Object[] argArray) + { + FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray); + log(LOG_LEVEL_ERROR, ft.getMessage(), ft.getThrowable()); + } + + @Override + public void error(String msg, Throwable t) + { + log(LOG_LEVEL_ERROR, msg, t); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectTestException.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectTestException.java new file mode 100644 index 00000000..71a96a4a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectTestException.java @@ -0,0 +1,62 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.util.introspection.Info; + + + +/** + * Exception that returns an Info object for testing after a introspection problem. + * This extends Error so that it will stop parsing and allow + * internal info to be examined. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + * @author <a href="mailto:isidore@setgame.com">Llewellyn Falco</a> + * @version $Id$ + */ +public class UberspectTestException extends RuntimeException +{ + + /** + * Version Id for serializable + */ + private static final long serialVersionUID = 3956896150436225712L; + + Info info; + + public UberspectTestException(String message, Info i) + { + super(message); + info = i; + } + + public Info getInfo() + { + return info; + } + + @Override + public String getMessage() + { + return super.getMessage() + "\n failed at " + info; + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectTestImpl.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectTestImpl.java new file mode 100644 index 00000000..b07f6725 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectTestImpl.java @@ -0,0 +1,66 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.util.introspection.Info; +import org.apache.velocity.util.introspection.UberspectImpl; +import org.apache.velocity.util.introspection.VelMethod; +import org.apache.velocity.util.introspection.VelPropertyGet; + + +/** + * A introspector that allows testing when methods are not found. + */ +public class UberspectTestImpl extends UberspectImpl +{ + + @Override + public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) + { + VelMethod method = super.getMethod(obj, methodName, args, i); + + if (method == null) + { + if (obj == null) + throw new UberspectTestException("Can't call method '" + methodName + "' on null object",i); + else + throw new UberspectTestException("Did not find method "+ obj.getClass().getName()+"."+methodName, i); + } + + return method; + } + + @Override + public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) + { + VelPropertyGet propertyGet = super.getPropertyGet(obj, identifier, i); + + if (propertyGet == null) + { + if (obj == null) + throw new UberspectTestException("Can't call getter '" + identifier + "' on null object",i); + else + throw new UberspectTestException("Did not find "+ obj.getClass().getName()+"."+identifier, i); + } + + return propertyGet; + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectorTestObject.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectorTestObject.java new file mode 100644 index 00000000..34b9cbe0 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/misc/UberspectorTestObject.java @@ -0,0 +1,133 @@ +package org.apache.velocity.test.misc; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.util.Map; + +public class UberspectorTestObject +{ + private String regular; + private String premium; + + private boolean regularBool; + private boolean premiumBool; + + private String ambigous; + + private String unambiguous; + + /** + * @return the premium + */ + public String getpremium() + { + return premium; + } + + /** + * @param premium the premium to set + */ + public void setpremium(String premium) + { + this.premium = premium; + } + + /** + * @return the premiumBool + */ + public boolean ispremiumBool() + { + return premiumBool; + } + + /** + * @param premiumBool the premiumBool to set + */ + public void setpremiumBool(boolean premiumBool) + { + this.premiumBool = premiumBool; + } + + /** + * @return the regular + */ + public String getRegular() + { + return regular; + } + + /** + * @param regular the regular to set + */ + public void setRegular(String regular) + { + this.regular = regular; + } + + /** + * @return the regularBool + */ + public boolean isRegularBool() + { + return regularBool; + } + + /** + * @param regularBool the regularBool to set + */ + public void setRegularBool(boolean regularBool) + { + this.regularBool = regularBool; + } + + /** + * @return the ambigous + */ + public String getAmbigous() + { + return ambigous; + } + + /** + * @param ambigous the ambigous to set + */ + public void setAmbigous(String ambigous) + { + this.ambigous = ambigous; + } + + /** + * @param ambigous the ambigous to set + */ + public void setAmbigous(StringBuffer ambigous) + { + this.ambigous = ambigous.toString(); + } + + public void setUnambiguous(String unambiguous) + { + this.unambiguous = unambiguous; + } + + public void setUnambiguous(Map unambiguous) + { + this.unambiguous = unambiguous.toString(); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/BoolObj.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/BoolObj.java new file mode 100644 index 00000000..0e90299b --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/BoolObj.java @@ -0,0 +1,46 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * simple class to test boolean property + * introspection - can't use TestProvider + * as there is a get( String ) + * and that comes before isProperty + * in the search pattern + * + * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a> + */ +public class BoolObj +{ + public boolean isBoolean() + { + return true; + } + + /* + * not isProperty as it's not + * boolean return valued... + */ + public String isNotboolean() + { + return "hello"; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/Child.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/Child.java new file mode 100644 index 00000000..6515c752 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/Child.java @@ -0,0 +1,37 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Rudimentary class used in the testbed to test + * introspection with subclasses of a particular + * class. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @version $Id$ + */ +public class Child extends Person +{ + @Override + public String getName() + { + return "Child"; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/ForeachMethodCallHelper.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/ForeachMethodCallHelper.java new file mode 100644 index 00000000..042f8657 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/ForeachMethodCallHelper.java @@ -0,0 +1,31 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Provides overloaded methods for testing method execution within a foreach + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class ForeachMethodCallHelper +{ + public String getFoo(Integer v) { return "int "+v; } + public String getFoo(String v) { return "str "+v; } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/NullToStringObject.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/NullToStringObject.java new file mode 100644 index 00000000..f30e81cb --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/NullToStringObject.java @@ -0,0 +1,33 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Used to confirm that a null to string is processed properly + * @author <a href="mailto:wglass@apache.org">Will Glass-Husain</a> + * @version $Id$ + */ +public class NullToStringObject +{ + public String toString() + { + return null; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/NumberMethods.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/NumberMethods.java new file mode 100644 index 00000000..eb70fd9c --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/NumberMethods.java @@ -0,0 +1,70 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.math.BigDecimal; +import java.math.BigInteger; + + +/** + * Used to check that method calls with number parameters are executed correctly. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + */ +public class NumberMethods +{ + + public String numMethod(byte val) + { + return "byte (" + val + ")"; + } + + public String numMethod(short val) + { + return "short (" + val + ")"; + } + + public String numMethod(int val) + { + return "int (" + val + ")"; + } + + public String numMethod(double val) + { + return "double (" + val + ")"; + } + + public String numMethod(long val) + { + return "long (" + val + ")"; + } + + public String numMethod(BigInteger val) + { + return "BigInteger (" + val + ")"; + } + + public String numMethod(BigDecimal val) + { + return "BigDecimal (" + val + ")"; + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/Person.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/Person.java new file mode 100644 index 00000000..239739d0 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/Person.java @@ -0,0 +1,39 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Rudimentary class used in the testbed to test + * introspection with subclasses of a particular + * class. + * + * This class need to be greatly extended to + * be useful :-) + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @version $Id$ + */ +public class Person +{ + public String getName() + { + return "Person"; + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/TestNumber.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/TestNumber.java new file mode 100644 index 00000000..5850eec5 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/TestNumber.java @@ -0,0 +1,47 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.util.TemplateNumber; + +/** + * Used for testing purposes to check that an object implementing TemplateNumber + * will be treated as a Number. + * + * @author <a href="mailto:wglass@forio.com">Will Glass-Husain</a> + */ +public class TestNumber implements TemplateNumber +{ + + private Number n; + + public TestNumber(double val) + { + n = val; + } + + @Override + public Number getAsNumber() + { + return n; + } + + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/TestProvider.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/TestProvider.java new file mode 100644 index 00000000..60eea81f --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/provider/TestProvider.java @@ -0,0 +1,362 @@ +package org.apache.velocity.test.provider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.Stack; +import java.util.Vector; + +/** + * This class is used by the testbed. Instances of the class + * are fed into the context that is set before the AST + * is traversed and dynamic content generated. + * + * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a> + * @version $Id$ + */ +public class TestProvider +{ + String title = "lunatic"; + boolean state; + Object ob = null; + + public static String PUB_STAT_STRING = "Public Static String"; + + int stateint = 0; + + + public String getName() + { + return "jason"; + } + + public Stack getStack() + { + Stack stack = new Stack(); + stack.push("stack element 1"); + stack.push("stack element 2"); + stack.push("stack element 3"); + return stack; + } + + public List getEmptyList() + { + return new ArrayList(); + } + + public List getList() + { + List list = new ArrayList(); + list.add("list element 1"); + list.add("list element 2"); + list.add("list element 3"); + + return list; + } + + public Hashtable getSearch() + { + Hashtable h = new Hashtable(); + h.put("Text", "this is some text"); + h.put("EscText", "this is escaped text"); + h.put("Title", "this is the title"); + h.put("Index", "this is the index"); + h.put("URL", "http://periapt.com"); + + ArrayList al = new ArrayList(); + al.add(h); + + h.put("RelatedLinks", al); + + return h; + } + + public Hashtable getHashtable() + { + Hashtable h = new Hashtable(); + h.put("key0", "value0"); + h.put("key1", "value1"); + h.put("key2", "value2"); + + return h; + } + + public ArrayList getRelSearches() + { + ArrayList al = new ArrayList(); + al.add(getSearch()); + + return al; + } + + public String getTitle() + { + return title; + } + + public void setTitle(String title) + { + this.title = title; + } + + public Object[] getMenu() + { + //ArrayList al = new ArrayList(); + Object[] menu = new Object[3]; + for (int i = 0; i < 3; i++) + { + Hashtable item = new Hashtable(); + item.put("id", "item" + (i+1)); + item.put("name", "name" + (i+1)); + item.put("label", "label" + (i+1)); + //al.add(item); + menu[i] = item; + } + + //return al; + return menu; + } + + public ArrayList getCustomers() + { + ArrayList list = new ArrayList(); + + list.add("ArrayList element 1"); + list.add("ArrayList element 2"); + list.add("ArrayList element 3"); + list.add("ArrayList element 4"); + + return list; + } + + public ArrayList getCustomers2() + { + ArrayList list = new ArrayList(); + + list.add(new TestProvider()); + list.add(new TestProvider()); + list.add(new TestProvider()); + list.add(new TestProvider()); + + return list; + } + + public Object me() + { + return this; + } + + public String toString() + { + return ("test provider"); + } + + public Vector getVector() + { + Vector list = new Vector(); + + list.addElement("vector element 1"); + list.addElement("vector element 2"); + + return list; + } + + public String[] getArray() + { + String[] strings = new String[2]; + strings[0] = "first element"; + strings[1] = "second element"; + return strings; + } + + public boolean theAPLRules() + { + return true; + } + + public boolean getStateTrue() + { + return true; + } + + public boolean getStateFalse() + { + return false; + } + + public String objectArrayMethod(Object[] o) + { + return "result of objectArrayMethod"; + } + + public String concat(Object[] strings) + { + StringBuilder result = new StringBuilder(); + + for (Object string : strings) + { + result.append((String) string).append(' '); + } + + return result.toString(); + } + + public String concat(List strings) + { + StringBuilder result = new StringBuilder(); + + for (Object string : strings) + { + result.append((String) string).append(' '); + } + + return result.toString(); + } + + public String objConcat(List objects) + { + StringBuilder result = new StringBuilder(); + + for (Object object : objects) + { + result.append(object).append(' '); + } + + return result.toString(); + } + + public String parse(String a, Object o, String c, String d) + { + return a + o.toString() + c + d; + } + + public String concat(String a, String b) + { + return a + b; + } + + // These two are for testing subclasses. + + public Person getPerson() + { + return new Person(); + } + + public Child getChild() + { + return new Child(); + } + + public String showPerson(Person person) + { + return person.getName(); + } + + /** + * Chop i characters off the end of a string. + * + * @param string String to chop. + * @param i Number of characters to chop. + * @return String with processed answer. + */ + public String chop(String string, int i) + { + return(string.substring(0, string.length() - i)); + } + + public boolean allEmpty(Object[] list) + { + int size = list.length; + + for (Object aList : list) + if (aList.toString().length() > 0) + return false; + + return true; + } + + /* + * This can't have the signature + * + * public void setState(boolean state) + * + * or dynamically invoking the method + * doesn't work ... you would have to + * put a wrapper around a method for a + * real boolean property that takes a + * Boolean object if you wanted this to + * work. Not really sure how useful it + * is anyway. Who cares about boolean + * values you can just set a variable. + * + */ + + public void setState(Boolean state) + { + } + + public void setBangStart( Integer i ) + { + System.out.println("SetBangStart() : called with val = " + i ); + stateint = i; + } + public Integer bang() + { + System.out.println("Bang! : " + stateint ); + Integer ret = stateint; + stateint++; + return ret; + } + + /** + * Test the ability of vel to use a get(key) + * method for any object type, not just one + * that implements the Map interface. + */ + public String get(String key) + { + return key; + } + + /** + * Test the ability of vel to use a put(key) + * method for any object type, not just one + * that implements the Map interface. + */ + public String put(String key, Object o) + { + ob = o; + return key; + } + + public String getFoo() + throws Exception + { + throw new Exception("From getFoo()"); + } + + public String getThrow() + throws Exception + { + throw new Exception("From getThrow()"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/BaseSQLTest.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/BaseSQLTest.java new file mode 100644 index 00000000..8bf31dca --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/BaseSQLTest.java @@ -0,0 +1,96 @@ +package org.apache.velocity.test.sql; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.test.BaseTestCase; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * A base class to implement tests that need a running + * Velocity engine and an initialized HSQLDB Database. + * It can also be used to test against other database engines + * by means of the proper environment parameters, see velocity-engine-core pom.xml file. + * + * @author <a href="mailto:henning@apache.org">Henning P. Schmiedehausen</a> + * @version $Id$ + */ + +public abstract class BaseSQLTest + extends BaseTestCase +{ + private static DBHelper dbHelper = null; + + protected String TEST_JDBC_DRIVER_CLASS = System.getProperty("test.jdbc.driver.className"); + protected String TEST_JDBC_URI = System.getProperty("test.jdbc.uri"); + protected String TEST_JDBC_LOGIN = System.getProperty("test.jdbc.login"); + protected String TEST_JDBC_PASSWORD = System.getProperty("test.jdbc.password"); + + /** + * String (not containing any VTL) used to test unicode + */ + protected String UNICODE_TEMPLATE = "\\u00a9 test \\u0410 \\u0411"; + + /** + * Name of template for testing unicode. + */ + protected String UNICODE_TEMPLATE_NAME = "testUnicode"; + + + public BaseSQLTest(String name, String path) + throws Exception + { + super(name); + + if (dbHelper == null) + { + dbHelper = new DBHelper(TEST_JDBC_DRIVER_CLASS, TEST_JDBC_URI, TEST_JDBC_LOGIN, TEST_JDBC_PASSWORD,path + "/create-db.sql"); + setUpUnicode(); + } + } + + private void setUpUnicode() + throws Exception + { + String insertString = "insert into velocity_template_varchar (vt_id, vt_timestamp, vt_def) VALUES " + + "( '" + UNICODE_TEMPLATE_NAME + "', current_timestamp, '" + UNICODE_TEMPLATE + "');"; + executeSQL(insertString); + insertString = "insert into velocity_template_clob (vt_id, vt_timestamp, vt_def) VALUES " + + "( '" + UNICODE_TEMPLATE_NAME + "', current_timestamp, '" + UNICODE_TEMPLATE + "');"; + executeSQL(insertString); + } + + + public void executeSQL(String sql) + throws SQLException + { + Connection connection = dbHelper.getConnection(); + Statement statement = connection.createStatement(); + // Oracle and Derby do not want any final ';' + if ((TEST_JDBC_DRIVER_CLASS.equals("oracle.jdbc.OracleDriver") + || TEST_JDBC_DRIVER_CLASS.equals("org.apache.derby.jdbc.EmbeddedDriver")) && sql.endsWith(";")) + { + sql = sql.substring(0, sql.length() - 1); + } + statement.executeUpdate(sql); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/DBHelper.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/DBHelper.java new file mode 100644 index 00000000..4acef0f8 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/DBHelper.java @@ -0,0 +1,123 @@ +package org.apache.velocity.test.sql; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.commons.lang3.StringUtils; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class DBHelper +{ + private String driverClass = null; + private Connection connection = null; + + public DBHelper(String driverClass, String uri, String login, String password, String loadFile) throws Exception + { + this.driverClass = driverClass; + Class.forName(driverClass); + + this.connection = DriverManager.getConnection(uri, login, password); + + if (StringUtils.isNotEmpty(loadFile)) + { + loadSqlFile(loadFile); + } + } + + public Connection getConnection() + { + return connection; + } + + public void close() + { + + try + { + connection.close(); + } + catch (Exception e) + { + System.out.println("While closing Connection" + e.getMessage()); + } + } + + // avoid ';' inside BEGIN/END blocks + private static int nextSemiColon(final String cmd) + { + int start = 0; + int ret = -1; + while (true) + { + ret = cmd.indexOf(';', start); + if (ret == -1) break; + int begin = cmd.lastIndexOf("BEGIN", ret); + int end = cmd.lastIndexOf("END;", ret); + if (begin == -1) break; + if (end > begin) break; + start = ret + 1; + } + return ret; + } + + private void loadSqlFile(String fileName) throws Exception + { + Statement statement = null; + + try + { + String commands = new String(Files.readAllBytes(Paths.get(fileName)), StandardCharsets.UTF_8); + // manually eat comments, some engines don't like them + Pattern removeComments = Pattern.compile("^--.*$", Pattern.MULTILINE); + Matcher matcher = removeComments.matcher(commands); + commands = matcher.replaceAll(""); + for (int targetPos = nextSemiColon(commands); targetPos > -1; targetPos = nextSemiColon(commands)) + { + statement = connection.createStatement(); + String cmd = commands.substring(0, targetPos + 1); + // Oracle doesn't like semi-colons at the end, except for BEGIN/END blocks... + // nor does Derby + if (driverClass.equals("oracle.jdbc.OracleDriver") && !cmd.endsWith("END;") || + driverClass.equals("org.apache.derby.jdbc.EmbeddedDriver")) + { + cmd = cmd.substring(0, cmd.length() - 1); + } + statement.executeUpdate(cmd); + commands = commands.substring(targetPos + 2); + statement.close(); + } + } + finally + { + if (statement != null) + { + statement.close(); + } + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/DataSourceResourceLoaderTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/DataSourceResourceLoaderTestCase.java new file mode 100644 index 00000000..757b6e84 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/DataSourceResourceLoaderTestCase.java @@ -0,0 +1,229 @@ +package org.apache.velocity.test.sql; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.runtime.RuntimeInstance; +import org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.ExtProperties; + +import javax.sql.DataSource; +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; + + +public class DataSourceResourceLoaderTestCase + extends BaseSQLTest +{ + /** + * Comparison file extension. + */ + private static final String CMP_FILE_EXT = "cmp"; + + /** + * Comparison file extension. + */ + private static final String RESULT_FILE_EXT = "res"; + + /** + * Path to template file. This will get combined with the + * application directory to form an absolute path + */ + private final static String DATA_PATH = TEST_COMPARE_DIR + "/ds"; + + /** + * Results relative to the build directory. + */ + private static final String RESULTS_DIR = TEST_RESULT_DIR + "/ds"; + + /** + * Results relative to the build directory. + */ + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/ds/templates"; + + /* engine with VARCHAR templates data source */ + private RuntimeInstance varcharTemplatesEngine = null; + + /* engine with CLOB templates data source */ + private RuntimeInstance clobTemplatesEngine = null; + + public DataSourceResourceLoaderTestCase(final String name) + throws Exception + { + super(name, DATA_PATH); + } + + public static Test suite() + { + return new TestSuite(DataSourceResourceLoaderTestCase.class); + } + + @Override + public void setUp() + throws Exception + { + + assureResultsDirectoryExists(RESULTS_DIR); + + DataSource ds1 = new TestDataSource(TEST_JDBC_DRIVER_CLASS, TEST_JDBC_URI, TEST_JDBC_LOGIN, TEST_JDBC_PASSWORD); + DataSourceResourceLoader rl1 = new DataSourceResourceLoader(); + rl1.setDataSource(ds1); + + DataSource ds2 = new TestDataSource(TEST_JDBC_DRIVER_CLASS, TEST_JDBC_URI, TEST_JDBC_LOGIN, TEST_JDBC_PASSWORD); + DataSourceResourceLoader rl2 = new DataSourceResourceLoader(); + rl2.setDataSource(ds2); + + ExtProperties props = new ExtProperties(); + props.addProperty( "resource.loader", "ds" ); + props.setProperty( "ds.resource.loader.instance", rl1); + props.setProperty( "ds.resource.loader.resource.table", "velocity_template_varchar"); + props.setProperty( "ds.resource.loader.resource.keycolumn", "vt_id"); + props.setProperty( "ds.resource.loader.resource.templatecolumn", "vt_def"); + props.setProperty( "ds.resource.loader.resource.timestampcolumn", "vt_timestamp"); + props.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger(false, false)); + + varcharTemplatesEngine = new RuntimeInstance(); + varcharTemplatesEngine.setConfiguration(props); + varcharTemplatesEngine.init(); + + ExtProperties props2 = (ExtProperties)props.clone(); + props2.setProperty( "ds.resource.loader.instance", rl2); + props2.setProperty( "ds.resource.loader.resource.table", "velocity_template_clob"); + clobTemplatesEngine = new RuntimeInstance(); + clobTemplatesEngine.setConfiguration(props2); + clobTemplatesEngine.init(); + } + + /** + * Tests loading and rendering of a simple template. If that works, we are able to get data + * from the database. + */ + public void testSimpleTemplate() + throws Exception + { + Template t = executeTest("testTemplate1", varcharTemplatesEngine); + assertFalse("Timestamp is 0", 0 == t.getLastModified()); + t = executeTest("testTemplate1", clobTemplatesEngine); + assertFalse("Timestamp is 0", 0 == t.getLastModified()); } + + public void testUnicode(RuntimeInstance engine) + throws Exception + { + Template template = engine.getTemplate(UNICODE_TEMPLATE_NAME); + + Writer writer = new StringWriter(); + VelocityContext context = new VelocityContext(); + template.merge(context, writer); + writer.flush(); + writer.close(); + + String outputText = writer.toString(); + + if (!normalizeNewlines(UNICODE_TEMPLATE).equals( + normalizeNewlines( outputText ) )) + { + fail("Output incorrect for Template: " + UNICODE_TEMPLATE_NAME); + } + } + + /** + * Now we have a more complex example. Run a very simple tool. + * from the database. + */ + public void testRenderTool() + throws Exception + { + Template t = executeTest("testTemplate2", varcharTemplatesEngine); + assertFalse("Timestamp is 0", 0 == t.getLastModified()); + t = executeTest("testTemplate2", clobTemplatesEngine); + assertFalse("Timestamp is 0", 0 == t.getLastModified()); + } + + /** + * Will a NULL timestamp choke the loader? + */ + public void testNullTimestamp() + throws Exception + { + Template t = executeTest("testTemplate3", varcharTemplatesEngine); + assertEquals("Timestamp is not 0", 0, t.getLastModified()); + t = executeTest("testTemplate3", clobTemplatesEngine); + assertEquals("Timestamp is not 0", 0, t.getLastModified()); } + + /** + * Does it load the global Macros from the DB? + */ + public void testMacroInvocation() + throws Exception + { + Template t = executeTest("testTemplate4", varcharTemplatesEngine); + assertFalse("Timestamp is 0", 0 == t.getLastModified()); + t = executeTest("testTemplate4", clobTemplatesEngine); + assertFalse("Timestamp is 0", 0 == t.getLastModified()); + } + + protected Template executeTest(final String templateName, RuntimeInstance engine) + throws Exception + { + Template template = engine.getTemplate(templateName); + + FileOutputStream fos = + new FileOutputStream ( + getFileName(RESULTS_DIR, templateName, RESULT_FILE_EXT)); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + VelocityContext context = new VelocityContext(); + context.put("tool", new DSRLTCTool()); + + template.merge(context, writer); + writer.flush(); + writer.close(); + + if (!isMatch(RESULTS_DIR, COMPARE_DIR, templateName, + RESULT_FILE_EXT, CMP_FILE_EXT)) + { + fail("Output incorrect for Template: " + templateName); + } + + return template; + } + + public static final class DSRLTCTool + { + public int add(final int a, final int b) + { + return a + b; + } + + public String getMessage() + { + return "And the result is:"; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/TestDataSource.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/TestDataSource.java new file mode 100644 index 00000000..286cfc2a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/sql/TestDataSource.java @@ -0,0 +1,105 @@ +package org.apache.velocity.test.sql; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import javax.sql.DataSource; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +public class TestDataSource implements DataSource +{ + + private final String url; + private final String user; + private final String password; + + private PrintWriter logWriter = null; + + private int loginTimeout = 0; + + public TestDataSource(final String driverClass, final String url, final String user, final String password) throws Exception + { + this.url = url; + this.user = user; + this.password = password; + Class.forName(driverClass); + } + + @Override + public Connection getConnection() throws SQLException + { + return DriverManager.getConnection(url, user, password); + } + + @Override + public Connection getConnection(final String username, final String password) + throws SQLException + { + return DriverManager.getConnection(url, username, password); + } + + @Override + public PrintWriter getLogWriter() throws SQLException + { + return logWriter; + } + + @Override + public int getLoginTimeout() throws SQLException + { + return loginTimeout; + } + + @Override + public void setLogWriter(final PrintWriter logWriter) throws SQLException + { + this.logWriter = logWriter; + } + + @Override + public void setLoginTimeout(final int loginTimeout) throws SQLException + { + this.loginTimeout = loginTimeout; + } + + @Override + public boolean isWrapperFor(final Class iface) throws SQLException + { + return false; + } + + @Override + public Object unwrap(final Class iface) throws SQLException + { + throw new SQLException("Not implemented"); + } + + /* added to be able to compile with jdk 1.7+ */ + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException + { + throw new SQLFeatureNotSupportedException(); + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java new file mode 100644 index 00000000..2687d662 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ChainedUberspectorsTestCase.java @@ -0,0 +1,121 @@ +package org.apache.velocity.test.util.introspection; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.AbstractChainableUberspector; +import org.apache.velocity.util.introspection.Info; +import org.apache.velocity.util.introspection.UberspectImpl; +import org.apache.velocity.util.introspection.VelPropertyGet; +import org.apache.velocity.util.introspection.VelPropertySet; + +import java.io.StringWriter; + +/** + * Tests uberspectors chaining + */ +public class ChainedUberspectorsTestCase extends BaseTestCase { + + public ChainedUberspectorsTestCase(String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(ChainedUberspectorsTestCase.class); + } + + @Override + public void setUp() + throws Exception + { + Velocity.reset(); + Velocity.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + Velocity.addProperty(Velocity.UBERSPECT_CLASSNAME,"org.apache.velocity.util.introspection.UberspectImpl"); + Velocity.addProperty(Velocity.UBERSPECT_CLASSNAME,"org.apache.velocity.test.util.introspection.ChainedUberspectorsTestCase$ChainedUberspector"); + Velocity.addProperty(Velocity.UBERSPECT_CLASSNAME,"org.apache.velocity.test.util.introspection.ChainedUberspectorsTestCase$LinkedUberspector"); + Velocity.init(); + } + + @Override + public void tearDown() + { + } + + public void testChaining() + throws Exception + { + VelocityContext context = new VelocityContext(); + context.put("foo",new Foo()); + StringWriter writer = new StringWriter(); + + Velocity.evaluate(context,writer,"test","$foo.zeMethod()"); + assertEquals(writer.toString(),"ok"); + + Velocity.evaluate(context,writer,"test","#set($foo.foo = 'someValue')"); + + writer = new StringWriter(); + Velocity.evaluate(context,writer,"test","$foo.bar"); + assertEquals(writer.toString(),"someValue"); + + writer = new StringWriter(); + Velocity.evaluate(context,writer,"test","$foo.foo"); + assertEquals(writer.toString(),"someValue"); + } + + // replaces getFoo by getBar + public static class ChainedUberspector extends AbstractChainableUberspector + { + @Override + public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info info) + { + identifier = identifier.replaceAll("foo","bar"); + return inner.getPropertySet(obj,identifier,arg,info); + } + } + + // replaces setFoo by setBar + public static class LinkedUberspector extends UberspectImpl + { + @Override + public VelPropertyGet getPropertyGet(Object obj, String identifier, Info info) + { + identifier = identifier.replaceAll("foo","bar"); + return super.getPropertyGet(obj,identifier,info); + } + } + + public static class Foo + { + private String bar; + + public String zeMethod() { return "ok"; } + public String getBar() { return bar; } + public void setBar(String s) { bar = s; } + } + +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ClassMapTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ClassMapTestCase.java new file mode 100644 index 00000000..be0a1e31 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ClassMapTestCase.java @@ -0,0 +1,110 @@ +package org.apache.velocity.test.util.introspection; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.ClassMap; +import org.slf4j.Logger; + +/** + * Test the ClassMap Lookup + */ +public class ClassMapTestCase + extends BaseTestCase +{ + public ClassMapTestCase(final String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(ClassMapTestCase.class); + } + + @Override + public void setUp() + throws Exception + { + Velocity.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger()); + Velocity.init(); + } + + @Override + public void tearDown() + { + } + + public void testPrimitives() + throws Exception + { + Logger log = Velocity.getLog(); + + ClassMap c = new ClassMap(TestClassMap.class, log); + assertNotNull(c.findMethod("setBoolean", new Object[] { Boolean.TRUE })); + assertNotNull(c.findMethod("setByte", new Object[] { new Byte((byte) 4)})); + assertNotNull(c.findMethod("setCharacter", new Object[] { new Character('c')})); + assertNotNull(c.findMethod("setDouble", new Object[] { new Double(8.0) })); + assertNotNull(c.findMethod("setFloat", new Object[] { new Float(15.0) })); + assertNotNull(c.findMethod("setInteger", new Object[] { new Integer(16) })); + assertNotNull(c.findMethod("setLong", new Object[] { new Long(23) })); + assertNotNull(c.findMethod("setShort", new Object[] { new Short((short)42)})); + } + + public static final class TestClassMap + { + public void setBoolean(boolean b) + { + } + + public void setByte(byte b) + { + } + + public void setCharacter(char c) + { + } + + public void setDouble(double d) + { + } + + public void setFloat(float f) + { + } + + public void setInteger(int i) + { + } + + public void setLong(long l) + { + } + + public void setShort(short s) + { + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java new file mode 100644 index 00000000..c15b18fc --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/ConversionHandlerTestCase.java @@ -0,0 +1,454 @@ +package org.apache.velocity.test.util.introspection; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.TestSuite; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.reflect.TypeUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.app.event.MethodExceptionEventHandler; +import org.apache.velocity.context.Context; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.RuntimeInstance; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; +import org.apache.velocity.util.introspection.Converter; +import org.apache.velocity.util.introspection.Info; +import org.apache.velocity.util.introspection.IntrospectionUtils; +import org.apache.velocity.util.introspection.TypeConversionHandler; +import org.apache.velocity.util.introspection.TypeConversionHandlerImpl; +import org.apache.velocity.util.introspection.Uberspect; +import org.apache.velocity.util.introspection.UberspectImpl; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TreeMap; + +/** + * Test case for conversion handler + */ +public class ConversionHandlerTestCase extends BaseTestCase +{ + private static final String RESULT_DIR = TEST_RESULT_DIR + "/conversion"; + + private static final String COMPARE_DIR = TEST_COMPARE_DIR + "/conversion/compare"; + + public ConversionHandlerTestCase(String name) + { + super(name); + } + + @Override + public void setUp() + throws Exception + { + super.setUp(); + } + + /** + * Test suite + * @return test suite + */ + public static junit.framework.Test suite() + { + return new TestSuite(ConversionHandlerTestCase.class); + } + + public void testConversionsWithoutHandler() + throws Exception + { + /* + * local scope, cache on + */ + VelocityEngine ve = createEngine(false); + + testConversions(ve, "test_conv.vtl", "test_conv_without_handler"); + } + + public void testConversionsWithHandler() + throws Exception + { + /* + * local scope, cache on + */ + VelocityEngine ve = createEngine(true); + + testConversions(ve, "test_conv.vtl", "test_conv_with_handler"); + } + + public void testConversionMatrix() + throws Exception + { + VelocityEngine ve = createEngine(true); + testConversions(ve, "matrix.vhtml", "matrix"); + } + + public void testCustomConverter() + { + RuntimeInstance ve = new RuntimeInstance(); + ve.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve.setProperty(Velocity.RUNTIME_LOG_INSTANCE, log); + ve.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, TEST_COMPARE_DIR + "/conversion"); + ve.init(); + Uberspect uberspect = ve.getUberspect(); + assertTrue(uberspect instanceof UberspectImpl); + UberspectImpl ui = (UberspectImpl)uberspect; + TypeConversionHandler ch = ui.getConversionHandler(); + assertTrue(ch != null); + ch.addConverter(Float.class, Obj.class, new Converter<Float>() + { + @Override + public Float convert(Object o) + { + return 4.5f; + } + }); + ch.addConverter(TypeUtils.parameterize(List.class, Integer.class), String.class, new Converter<List<Integer>>() + { + @Override + public List<Integer> convert(Object o) + { + return Arrays.<Integer>asList(1,2,3); + } + }); + ch.addConverter(TypeUtils.parameterize(List.class, String.class), String.class, new Converter<List<String>>() + { + @Override + public List<String> convert(Object o) + { + return Arrays.<String>asList("a", "b", "c"); + } + }); + VelocityContext context = new VelocityContext(); + context.put("obj", new Obj()); + Writer writer = new StringWriter(); + ve.evaluate(context, writer, "test", "$obj.integralFloat($obj) / $obj.objectFloat($obj)"); + assertEquals("float ok: 4.5 / Float ok: 4.5", writer.toString()); + writer = new StringWriter(); + ve.evaluate(context, writer, "test", "$obj.iWantAStringList('anything')"); + assertEquals("correct", writer.toString()); + writer = new StringWriter(); + ve.evaluate(context, writer, "test", "$obj.iWantAnIntegerList('anything')"); + assertEquals("correct", writer.toString()); + } + + /* converts *everything* to string "foo" */ + public static class MyCustomConverter implements TypeConversionHandler + { + Converter<String> myCustomConverter = new Converter<String>() + { + + @Override + public String convert(Object o) + { + return "foo"; + } + }; + + @Override + public boolean isExplicitlyConvertible(Type formal, Class<?> actual, boolean possibleVarArg) + { + return true; + } + + @Override + public Converter<?> getNeededConverter(Type formal, Class<?> actual) + { + return myCustomConverter; + } + + @Override + public void addConverter(Type formal, Class<?> actual, Converter<?> converter) + { + throw new RuntimeException("not implemented"); + } + } + + public void testCustomConversionHandlerInstance() + { + RuntimeInstance ve = new RuntimeInstance(); + ve.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve.setProperty(Velocity.RUNTIME_LOG_INSTANCE, log); + ve.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, TEST_COMPARE_DIR + "/conversion"); + ve.setProperty(RuntimeConstants.CONVERSION_HANDLER_INSTANCE, new MyCustomConverter()); + ve.init(); + Uberspect uberspect = ve.getUberspect(); + assertTrue(uberspect instanceof UberspectImpl); + UberspectImpl ui = (UberspectImpl)uberspect; + TypeConversionHandler ch = ui.getConversionHandler(); + assertTrue(ch != null); + assertTrue(ch instanceof MyCustomConverter); + VelocityContext context = new VelocityContext(); + context.put("obj", new Obj()); + Writer writer = new StringWriter(); + ve.evaluate(context, writer, "test", "$obj.objectString(1.0)"); + assertEquals("String ok: foo", writer.toString()); + } + + /** + * Test conversions + * @param ve + * @param templateFile template + * @param outputBaseFileName + * @throws Exception + */ + private void testConversions(VelocityEngine ve, String templateFile, String outputBaseFileName) + throws Exception + { + assureResultsDirectoryExists(RESULT_DIR); + + FileOutputStream fos = new FileOutputStream (getFileName( + RESULT_DIR, outputBaseFileName, RESULT_FILE_EXT)); + + VelocityContext context = createContext(); + + Writer writer = new BufferedWriter(new OutputStreamWriter(fos)); + + log.setEnabledLevel(TestLogger.LOG_LEVEL_ERROR); + + Template template = ve.getTemplate(templateFile); + template.merge(context, writer); + + /* + * Write to the file + */ + writer.flush(); + writer.close(); + + if (!isMatch(RESULT_DIR, COMPARE_DIR, outputBaseFileName, + RESULT_FILE_EXT,CMP_FILE_EXT)) + { + String result = getFileContents(RESULT_DIR, outputBaseFileName, RESULT_FILE_EXT); + String compare = getFileContents(COMPARE_DIR, outputBaseFileName, CMP_FILE_EXT); + + String msg = "Processed template did not match expected output\n"+ + "-----Result-----\n"+ result + + "----Expected----\n"+ compare + + "----------------"; + + fail(msg); + } + } + + public void testOtherConversions() throws Exception + { + VelocityEngine ve = createEngine(false); + VelocityContext context = createContext(); + StringWriter writer = new StringWriter(); + ve.evaluate(context, writer,"test", "$strings.join(['foo', 'bar'], ',')"); + assertEquals("foo,bar", writer.toString()); + } + + /** + * Return and initialize engine + * @return + */ + private VelocityEngine createEngine(boolean withConversionsHandler) + throws Exception + { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty( Velocity.VM_PERM_INLINE_LOCAL, Boolean.TRUE); + ve.setProperty(Velocity.RUNTIME_LOG_INSTANCE, log); + ve.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file"); + ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, TEST_COMPARE_DIR + "/conversion"); + if (withConversionsHandler) + { + ve.setProperty(RuntimeConstants.EVENTHANDLER_METHODEXCEPTION, PrintException.class.getName()); + } + else + { + ve.setProperty(RuntimeConstants.CONVERSION_HANDLER_CLASS, "none"); + } + ve.init(); + + return ve; + } + + public static class PrintException implements MethodExceptionEventHandler + { + @Override + public Object methodException(Context context, + Class claz, + String method, + Exception e, + Info info) + { + // JDK 11+ changed the exception message for big decimal conversion exceptions, + // which breaks the (brittle) tests. Clearly, it would be preferred to fix this + // right by comparing the result according to the JDK version, this is just a + // quick fix to get the build to pass on JDK 11+ + // + if (e.getClass() == NumberFormatException.class && e.getMessage() != null && e.getMessage().startsWith("Character")) + { + return method + " -> " + e.getClass().getSimpleName() + ": null"; // compatible with JDK8 + } + + return method + " -> " + e.getClass().getSimpleName() + ": " + e.getMessage(); + } + } + + private VelocityContext createContext() + { + VelocityContext context = new VelocityContext(); + Map<String, Object> map = new TreeMap<>(); + map.put("A. bool-true", true); + map.put("B. bool-false", false); + map.put("C. byte-0", (byte)0); + map.put("D. byte-1", (byte)1); + map.put("E. short", (short)125); + map.put("F. int", 24323); + map.put("G. long", 5235235L); + map.put("H. float", 34523.345f); + map.put("I. double", 54235.3253d); + map.put("J. char", '@'); + map.put("K. object", new Obj()); + map.put("L. enum", Obj.Color.GREEN); + map.put("M. string", new String("foo")); + map.put("M. string-green", new String("green")); + map.put("N. string-empty", new String()); + map.put("O. string-false", new String("false")); + map.put("P. string-true", new String("true")); + map.put("Q. string-zero", new String("0")); + map.put("R. string-integral", new String("123")); + map.put("S. string-big-integral", new String("12345678")); + map.put("T. string-floating", new String("123.345")); + map.put("U. null", null); + map.put("V. locale", "fr_FR"); + map.put("W. BigInteger zero", BigInteger.ZERO); + map.put("X. BigInteger one", BigInteger.ONE); + map.put("Y. BigInteger ten", BigInteger.TEN); + map.put("Y. BigInteger bigint", new BigInteger("12345678901234567890")); + map.put("Z. BigDecimal zero", BigDecimal.ZERO); + map.put("ZA. BigDecimal one", BigDecimal.ONE); + map.put("ZB. BigDecimal ten", BigDecimal.TEN); + map.put("ZC. BigDecimal bigdec", new BigDecimal("12345678901234567890.01234567890123456789")); + context.put("map", map); + context.put("target", new Obj()); + Class[] types = + { + Boolean.TYPE, + Character.TYPE, + Byte.TYPE, + Short.TYPE, + Integer.TYPE, + Long.TYPE, + Float.TYPE, + Double.TYPE, + Boolean.class, + Character.class, + Byte.class, + Short.class, + Integer.class, + Long.class, + BigInteger.class, + Float.class, + Double.class, + BigDecimal.class, + Number.class, + String.class, + Object.class + }; + context.put("types", types); + context.put("introspect", new Introspect()); + context.put("strings", new StringUtils()); + return context; + } + + public static class Obj + { + public enum Color { RED, GREEN } + + public String integralBoolean(boolean b) { return "boolean ok: " + b; } + public String integralByte(byte b) { return "byte ok: " + b; } + public String integralShort(short s) { return "short ok: " + s; } + public String integralInt(int i) { return "int ok: " + i; } + public String integralLong(long l) { return "long ok: " + l; } + public String integralFloat(float f) { return "float ok: " + f; } + public String integralDouble(double d) { return "double ok: " + d; } + public String integralChar(char c) { return "char ok: " + c; } + public String objectBoolean(Boolean b) { return "Boolean ok: " + b; } + public String objectByte(Byte b) { return "Byte ok: " + b; } + public String objectShort(Short s) { return "Short ok: " + s; } + public String objectInt(Integer i) { return "Integer ok: " + i; } + public String objectLong(Long l) { return "Long ok: " + l; } + public String objectBigInteger(BigInteger bi) { return "BigInteger ok: " + bi; } + public String objectFloat(Float f) { return "Float ok: " + f; } + public String objectDouble(Double d) { return "Double ok: " + d; } + public String objectBigDecimal(BigDecimal bd) { return "BigDecimal ok: " + bd; } + public String objectCharacter(Character c) { return "Character ok: " + c; } + public String objectNumber(Number b) { return "Number ok: " + b; } + public String objectObject(Object o) { return "Object ok: " + o; } + public String objectString(String s) { return "String ok: " + s; } + public String objectEnum(Color c) { return "Enum ok: " + c; } + public String locale(Locale loc) { return "Locale ok: " + loc; } + + public String toString() { return "instance of Obj"; } + + public String iWantAStringList(List<String> list) + { + if (list != null && list.size() == 3 && list.get(0).equals("a") && list.get(1).equals("b") && list.get(2).equals("c")) + return "correct"; + else return "wrong"; + } + + public String iWantAnIntegerList(List<Integer> list) + { + if (list != null && list.size() == 3 && list.get(0).equals(1) && list.get(1).equals(2) && list.get(2).equals(3)) + return "correct"; + else return "wrong"; + } + } + + public static class Introspect + { + private TypeConversionHandler handler; + public Introspect() + { + handler = new TypeConversionHandlerImpl(); + } + public boolean isStrictlyConvertible(Class expected, Class provided) + { + return IntrospectionUtils.isStrictMethodInvocationConvertible(expected, provided, false); + } + public boolean isImplicitlyConvertible(Class expected, Class provided) + { + return IntrospectionUtils.isMethodInvocationConvertible(expected, provided, false); + } + public boolean isExplicitlyConvertible(Class expected, Class provided) + { + return handler.isExplicitlyConvertible(expected, provided, false); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/DeprecatedCheckUberspectorsTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/DeprecatedCheckUberspectorsTestCase.java new file mode 100644 index 00000000..6b5b8857 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/DeprecatedCheckUberspectorsTestCase.java @@ -0,0 +1,108 @@ +package org.apache.velocity.test.util.introspection; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; + + +import java.io.StringWriter; + +/** + * Tests DeprecatedCheckUberspector + */ +public class DeprecatedCheckUberspectorsTestCase extends BaseTestCase { + + public DeprecatedCheckUberspectorsTestCase(String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(DeprecatedCheckUberspectorsTestCase.class); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty(Velocity.RUNTIME_LOG_INSTANCE, new TestLogger(false, true)); + engine.addProperty(Velocity.UBERSPECT_CLASSNAME, "org.apache.velocity.util.introspection.UberspectImpl"); + engine.addProperty(Velocity.UBERSPECT_CLASSNAME, "org.apache.velocity.util.introspection.DeprecatedCheckUberspector"); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("obj1", new StandardObject()); + context.put("obj2", new DeprecatedObject()); + } + + public void testDeprecatedCheck() + throws Exception + { + engine.init(); // make sure the engine is initialized, so that we get the logger we configured + TestLogger logger =(TestLogger)engine.getLog(); + logger.startCapture(); // reset log capture + StringWriter writer = new StringWriter(); + engine.evaluate(context, writer, "test", "$obj1.foo() $obj1.bar $obj2.foo() $obj2.bar"); + String log = logger.getLog(); + String lines[] = log.split("\\r?\\n"); + assertEquals(lines[0], " [info] Deprecated usage of method [org.apache.velocity.test.util.introspection.DeprecatedCheckUberspectorsTestCase.StandardObject.foo] in test@1,7"); + assertEquals(lines[1], " [info] Deprecated usage of getter [org.apache.velocity.test.util.introspection.DeprecatedCheckUberspectorsTestCase.StandardObject.getBar] in test@1,19"); + assertEquals(lines[2], " [info] Deprecated usage of method [org.apache.velocity.test.util.introspection.DeprecatedCheckUberspectorsTestCase.DeprecatedObject.foo] in test@1,29"); + assertEquals(lines[3], " [info] Deprecated usage of getter [org.apache.velocity.test.util.introspection.DeprecatedCheckUberspectorsTestCase.DeprecatedObject.getBar] in test@1,41"); + } + + public static class StandardObject + { + @Deprecated + public String foo() + { + return "foo"; + } + + @Deprecated + public String getBar() + { + return "bar"; + } + } + + @Deprecated + public static class DeprecatedObject + { + public String foo() + { + return "foo"; + } + + public String getBar() + { + return "bar"; + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/EnumConstantConversionTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/EnumConstantConversionTestCase.java new file mode 100644 index 00000000..3fbddf22 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/EnumConstantConversionTestCase.java @@ -0,0 +1,77 @@ +package org.apache.velocity.test.util.introspection; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.test.BaseTestCase; + +/** + * Tests DeprecatedCheckUberspector + */ +public class EnumConstantConversionTestCase extends BaseTestCase { + + public EnumConstantConversionTestCase(String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(EnumConstantConversionTestCase.class); + } + + public static class Obj + { + public enum Color { RED, GREEN } + + public String getAction(Color color) + { + switch (color) + { + case RED: return "Stop"; + case GREEN: return "Go"; + default: return "???"; + } + } + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("obj", new Obj()); + } + + public void testStringToEnumConversion() + throws Exception + { + assertEvalEquals("Stop", "$obj.getAction('RED')"); + assertEvalEquals("Go", "$obj.getAction('GREEN')"); + try + { + String result = evaluate("$obj.getAction('BLUE')"); + fail(); + } + catch(MethodInvocationException mie) {} + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/UberspectImplTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/UberspectImplTestCase.java new file mode 100644 index 00000000..c074be5e --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/util/introspection/UberspectImplTestCase.java @@ -0,0 +1,134 @@ +package org.apache.velocity.test.util.introspection; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.test.BaseTestCase; +import org.apache.velocity.test.misc.TestLogger; + +import java.util.Arrays; +import java.util.Iterator; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * Tests the default uberspector. + */ +public class UberspectImplTestCase extends BaseTestCase +{ + + public UberspectImplTestCase(String name) + throws Exception + { + super(name); + } + + public static Test suite() + { + return new TestSuite(UberspectImplTestCase.class); + } + + @Override + protected void setUpEngine(VelocityEngine engine) + { + engine.setProperty(RuntimeConstants.RUNTIME_LOG_INSTANCE, new TestLogger()); + engine.addProperty(RuntimeConstants.UBERSPECT_CLASSNAME, "org.apache.velocity.util.introspection.UberspectImpl"); + } + + @Override + protected void setUpContext(VelocityContext context) + { + context.put("privateClass", new PrivateClass()); + context.put("privateMethod", new PrivateMethod()); + context.put("publicMethod", new PublicMethod()); + context.put("iterable", new SomeIterable()); + context.put("over", new OverloadedMethods()); + } + + public void testPrivateIterator() + throws Exception + { + assertEvalEquals("", "#foreach($i in $privateClass)$i#end"); + assertEvalEquals("", "#foreach($i in $privateMethod)$i#end"); + assertEvalEquals("123", "#foreach($i in $publicMethod)$i#end"); + } + + public void testIterableForeach() + { + assertEvalEquals("123", "#foreach($i in $iterable)$i#end"); + } + + private class PrivateClass + { + public Iterator iterator() + { + return Arrays.asList("X", "Y", "Z").iterator(); + } + } + + public class PrivateMethod + { + private Iterator iterator() + { + return Arrays.asList("A", "B", "C").iterator(); + } + } + + public class PublicMethod + { + public Iterator iterator() + { + return Arrays.asList("1", "2", "3").iterator(); + } + } + + public class SomeIterable implements Iterable + { + @Override + public Iterator iterator() + { + return Arrays.asList("1", "2", "3").iterator(); + } + } + + public class OverloadedMethods + { + public String foo() { return "foo0"; } + public String foo(String arg1) { return "foo1"; } + public String foo(String arg1, String arg2) { return "foo2"; } + + public String bar(Number n, int i) { return "bar1"; } + public String bar(Number n, String s) { return "bar2"; } + } + + public void testOverloadedMethods() + { + assertEvalEquals("foo0", "$over.foo()"); + assertEvalEquals("foo1", "$over.foo('a')"); + assertEvalEquals("foo1", "$over.foo($null)"); + assertEvalEquals("foo2", "$over.foo('a', 'b')"); + assertEvalEquals("foo2", "$over.foo('a', $null)"); + assertEvalEquals("bar1", "$over.bar(1,1)"); + assertEvalEquals("$over.bar(1,1.1)", "$over.bar(1,1.1)"); // this one is definitely ambiguous + assertEvalEquals("bar2", "$over.bar(1,'1.1')"); + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/view/TemplateNodeView.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/view/TemplateNodeView.java new file mode 100644 index 00000000..2fcf411a --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/view/TemplateNodeView.java @@ -0,0 +1,85 @@ +package org.apache.velocity.test.view; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import org.apache.velocity.Template; +import org.apache.velocity.runtime.RuntimeSingleton; +import org.apache.velocity.runtime.parser.node.SimpleNode; +import org.apache.velocity.runtime.visitor.NodeViewMode; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; + +/** + * Simple class for dumping the AST for a template. + * Good for debugging and writing new directives. + */ +public class TemplateNodeView +{ + /** + * Root of the AST node structure that results from + * parsing a template. + */ + private SimpleNode document; + + /** + * Visitor used to traverse the AST node structure + * and produce a visual representation of the + * node structure. Very good for debugging and + * writing new directives. + */ + private NodeViewMode visitor; + + /** + * Default constructor: sets up the Velocity + * Runtime, creates the visitor for traversing + * the node structure and then produces the + * visual representation by the visitation. + */ + public TemplateNodeView(String templateFile) + { + try + { + RuntimeSingleton.init("velocity.properties"); + + InputStreamReader isr = new InputStreamReader( + new FileInputStream(templateFile), + RuntimeSingleton.getString(RuntimeSingleton.INPUT_ENCODING)); + + BufferedReader br = new BufferedReader( isr ); + + Template tmpl = new Template(); + tmpl.setName(templateFile); + document = RuntimeSingleton.parse( br, tmpl); + + visitor = new NodeViewMode(); + visitor.setContext(null); + visitor.setWriter(new PrintWriter(System.out)); + document.jjtAccept(visitor, null); + } + catch (Exception e) + { + System.out.println(e); + e.printStackTrace(); + } + } +} diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/util/SimplePoolTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/util/SimplePoolTestCase.java new file mode 100644 index 00000000..87a52b68 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/util/SimplePoolTestCase.java @@ -0,0 +1,67 @@ +package org.apache.velocity.util; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Simpletest for the SimplePool + * + * @version $Id$ + */ +public class SimplePoolTestCase extends TestCase +{ + public static Test suite() + { + return new TestSuite(SimplePoolTestCase.class); + } + + public SimplePoolTestCase(String testName) + { + super(testName); + } + + public void testPool() + throws Exception + { + SimplePool sp = new SimplePool(10); + + for (int i=0; i<10; i++) + { + sp.put(i); + } + + for (int i=9; i>=0; i--) + { + Integer obj = (Integer) sp.get(); + + assertTrue(i == obj); + } + + Object[] pool = sp.getPool(); + + for (int i=0; i<10; i++) + { + assertTrue("Pool not empty", pool[i] == null); + } + } +} |