This is an automated email from the ASF dual-hosted git repository. cbrisson pushed a commit to branch VELOCITY-948 in repository https://gitbox.apache.org/repos/asf/velocity-engine.git
commit 00a2089c60e31fd1ae5febef475a4a3cd50dc5ee Author: Claude Brisson <[email protected]> AuthorDate: Fri Aug 23 15:09:02 2024 +0200 Add a new compatibility flag for integer ranges immutability --- .../apache/velocity/runtime/RuntimeConstants.java | 3 ++ .../runtime/parser/node/ASTIntegerRange.java | 28 ++++++++++++- .../velocity/runtime/defaults/velocity.properties | 9 +++++ .../org/apache/velocity/test/BaseTestCase.java | 30 ++++++++++++-- .../velocity/test/IntegerRangeMutabilityTest.java | 46 ++++++++++++++++++++++ 5 files changed, 111 insertions(+), 5 deletions(-) diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java index ced9d349..d0187f73 100644 --- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java +++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java @@ -456,6 +456,9 @@ public interface RuntimeConstants extends DeprecatedRuntimeConstants /** Switch for the interpolation facility for string literals. */ String INTERPOLATE_STRINGLITERALS = "runtime.interpolate_string_literals"; + /** Switch for the immutability of integer ranges. */ + String IMMUTABLE_RANGES = "runtime.immutable_ranges"; + /** Switch for ignoring nulls in math equations vs throwing exceptions. */ String STRICT_MATH = "runtime.strict_math"; diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java index a4128935..37e95d8b 100644 --- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java +++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIntegerRange.java @@ -22,12 +22,15 @@ package org.apache.velocity.runtime.parser.node; import org.apache.velocity.context.InternalContextAdapter; import org.apache.velocity.exception.MethodInvocationException; import org.apache.velocity.exception.TemplateInitException; +import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.parser.Parser; import org.apache.velocity.util.DuckType; import org.apache.velocity.util.StringUtils; import java.util.AbstractList; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.ListIterator; /** @@ -275,10 +278,31 @@ public class ASTIntegerRange extends SimpleNode int delta = ( l >= r ) ? -1 : 1; /* - * Return the corresponding integer range + * Build the corresponding integer range */ - return new IntegerRange(l, r, delta); + IntegerRange range = new IntegerRange(l, r, delta); + + /* + * Returns the range, or a concrete list if mutable ranges are requested by the configuration + */ + + boolean immutable = rsvc.getBoolean(RuntimeConstants.IMMUTABLE_RANGES, true); + if (immutable) + { + return range; + } + else + { + // backward compatible behavior: the list is instanciated in memory + int n = Math.abs(r - l) + 1; + List mutableRange = new ArrayList<>(n); + for (Iterator<Integer> it = range.iterator(); it.hasNext();) + { + mutableRange.add(it.next()); + } + return mutableRange; + } } /** diff --git a/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties b/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties index 3d96b636..6a3eaa3d 100644 --- a/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties +++ b/velocity-engine-core/src/main/resources/org/apache/velocity/runtime/defaults/velocity.properties @@ -149,6 +149,15 @@ runtime.strict_mode.enable = false runtime.interpolate_string_literals = true +# ---------------------------------------------------------------------------- +# INTEGER RANGES +# ---------------------------------------------------------------------------- +# Whether integer ranges created with [a..b] expressions are immutable. +# ON by default :) +# ---------------------------------------------------------------------------- +runtime.immutable_ranges = true + + # ---------------------------------------------------------------------------- # RESOURCE MANAGEMENT # ---------------------------------------------------------------------------- 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 index c6456dff..1d43a835 100644 --- 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 @@ -203,9 +203,17 @@ public abstract class BaseTestCase extends TestCase implements TemplateTestBase * Ensure that a template renders as expected. */ protected void assertEvalEquals(String expected, String template) + { + assertEvalEquals(expected, template, engine); + } + + /** + * Ensure that a template renders as expected against the provided engine. + */ + protected void assertEvalEquals(String expected, String template, VelocityEngine ve) { info("Expectation: "+expected); - assertEquals(expected, evaluate(template)); + assertEquals(expected, evaluate(template, ve)); } /** @@ -228,6 +236,14 @@ public abstract class BaseTestCase extends TestCase implements TemplateTestBase * Ensure that a specified type of exception occurs when evaluating the string. */ protected Exception assertEvalException(String evil, Class<?> exceptionType) + { + return assertEvalException(evil, exceptionType, engine); + } + + /** + * Ensure that a specified type of exception occurs when evaluating the string with the provided engine. + */ + protected Exception assertEvalException(String evil, Class<?> exceptionType, VelocityEngine ve) { try { @@ -243,7 +259,7 @@ public abstract class BaseTestCase extends TestCase implements TemplateTestBase { info("Expectation: "+Exception.class.getName()); } - evaluate(evil); + evaluate(evil, ve); String msg = "Template '"+evil+"' should have thrown an exception."; info("Fail: "+msg); fail(msg); @@ -299,6 +315,14 @@ public abstract class BaseTestCase extends TestCase implements TemplateTestBase * Evaluate the specified String as a template and return the result as a String. */ protected String evaluate(String template) + { + return evaluate(template, engine); + } + + /** + * Evaluate the specified String as a template against the provided engine and return the result as a String. + */ + protected String evaluate(String template, VelocityEngine ve) { StringWriter writer = new StringWriter(); try @@ -308,7 +332,7 @@ public abstract class BaseTestCase extends TestCase implements TemplateTestBase // 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); + ve.evaluate(context, writer, name, template); String result = writer.toString(); info("Result: "+result); diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/IntegerRangeMutabilityTest.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/IntegerRangeMutabilityTest.java new file mode 100644 index 00000000..887c0553 --- /dev/null +++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/IntegerRangeMutabilityTest.java @@ -0,0 +1,46 @@ +package org.apache.velocity.test; + +import junit.framework.TestSuite; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.MethodInvocationException; +import org.apache.velocity.runtime.RuntimeConstants; +import org.apache.velocity.runtime.resource.loader.StringResourceLoader; +import org.junit.Test; + +/** + * Testing mutable and immutable integer ranges. Note that this test assumes that the test executions is not done in parallel. + */ + +public class IntegerRangeMutabilityTest extends BaseTestCase { + + public static junit.framework.Test suite() + { + return new TestSuite(IntegerRangeMutabilityTest.class); + } + + public IntegerRangeMutabilityTest(String name) { + super(name); + } + + @Test + public void testImmutableRange() + { + VelocityEngine ve = createEngine(); + ve.init(); + + Exception e = assertEvalException("#set($range = [1..2])#set($range[0] = 4)", MethodInvocationException.class, ve); + Throwable cause = e.getCause(); + assertNotNull(cause); + assertEquals(UnsupportedOperationException.class, cause.getClass()); + } + + @Test + public void testMutableRange() + { + VelocityEngine ve = createEngine(); + ve.setProperty(RuntimeConstants.IMMUTABLE_RANGES, false); + ve.init(); + + assertEvalEquals("4", "#set($range = [1..2])#set($range[0] = 4)$range[0]", ve); + } +}
