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);
+    }
+}

Reply via email to