You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2026/09/11 09:15:42 UTC
(velocity-engine) branch master updated (6c6e84da -> c9707967)
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/velocity-engine.git
from 6c6e84da Un-deprecate informal navigation $foo.bar, introduce ${foo ?: bar} as alternative to ${foo | bar} ; deprecation warnings now shown by default
new d1914e91 Un-deprecate ${}}
new e724d9fa Deprecate 'and', 'or', 'not', 'lt', 'gt', ... in favor of '&&', '||', '!', '<', '>', ...
new c9707967 Corner case: a final backslash in a double quoted string is deprecated
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
src/changes/changes.xml | 5 +-
.../runtime/parser/node/ASTBinaryOperator.java | 18 +++
.../velocity/runtime/parser/node/ASTNotNode.java | 18 +++
.../velocity/runtime/parser/node/ASTReference.java | 7 +-
.../runtime/parser/node/ASTStringLiteral.java | 28 ++++
.../velocity/runtime/parser/node/SimpleNode.java | 46 ++++++
.../velocity/runtime/defaults/velocity.properties | 2 +-
.../velocity/test/DeprecationWarningTestCase.java | 175 +++++++++++++++++++--
8 files changed, 279 insertions(+), 20 deletions(-)
(velocity-engine) 02/03: Deprecate 'and', 'or', 'not', 'lt', 'gt', ... in favor of '&&', '||', '!', '<', '>', ...
Posted by cb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/velocity-engine.git
commit e724d9fa02c4d3609e75f8db0d9c0d72f01c0c7a
Author: Claude Brisson <cl...@renegat.net>
AuthorDate: Fri Sep 11 08:19:38 2026 +0200
Deprecate 'and', 'or', 'not', 'lt', 'gt', ... in favor of '&&', '||', '!', '<', '>', ...
---
src/changes/changes.xml | 3 +-
.../runtime/parser/node/ASTBinaryOperator.java | 18 +++++
.../velocity/runtime/parser/node/ASTNotNode.java | 18 +++++
.../velocity/runtime/parser/node/SimpleNode.java | 46 +++++++++++
.../velocity/test/DeprecationWarningTestCase.java | 93 ++++++++++++++++++++++
5 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index c09ff62b..255a1269 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -44,7 +44,8 @@
<code>BigDecimal</code> in VTL math operations.
</action>
<action type="add" dev="cbrisson" issue="VELOCITY-995">
- Deprecate <code>${foo|bar}</code> in favor of <code>${foo?:bar}</code>, along with
+ Deprecate <code>${foo|bar}</code> in favor of <code>${foo?:bar}</code>, the textual
+ operators <code>and or not gt ge lt le eq ne</code> in favor of their symbols, and
the <code>parser.allow_hyphen_in_identifiers</code> option; warnings gated by
<code>runtime.deprecation.warn</code>, on by default.
</action>
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTBinaryOperator.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTBinaryOperator.java
index 8b776eaf..4c225667 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTBinaryOperator.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTBinaryOperator.java
@@ -3,9 +3,15 @@
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.runtime.parser.Token;
public abstract class ASTBinaryOperator extends SimpleNode
{
+ /**
+ * The operator token, kept until init
+ */
+ private Token operator;
+
public ASTBinaryOperator(int id)
{
super(id);
@@ -16,6 +22,16 @@ public ASTBinaryOperator(Parser p, int id)
super(p, id);
}
+ /**
+ * @see org.apache.velocity.runtime.parser.node.Node#jjtOpen()
+ */
+ @Override
+ public void jjtOpen()
+ {
+ super.jjtOpen();
+ operator = parser.getToken(0); // the operator has just been consumed
+ }
+
/**
* @throws TemplateInitException
* @see org.apache.velocity.runtime.parser.node.Node#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)
@@ -24,6 +40,8 @@ public ASTBinaryOperator(Parser p, int id)
public Object init(InternalContextAdapter context, Object data) throws TemplateInitException
{
Object obj = super.init(context, data);
+ warnTextualOperator(operator);
+ operator = null;
cleanupParserAndTokens(); // drop reference to Parser and all JavaCC Tokens
return obj;
}
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNotNode.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNotNode.java
index 1ad97978..3dad7edd 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNotNode.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNotNode.java
@@ -23,12 +23,18 @@
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.parser.Parser;
+import org.apache.velocity.runtime.parser.Token;
/**
*
*/
public class ASTNotNode extends SimpleNode
{
+ /**
+ * The operator token, kept until init
+ */
+ private Token operator;
+
/**
* @param id
*/
@@ -47,6 +53,16 @@ public ASTNotNode(Parser p, int id)
}
+ /**
+ * @see org.apache.velocity.runtime.parser.node.Node#jjtOpen()
+ */
+ @Override
+ public void jjtOpen()
+ {
+ super.jjtOpen();
+ operator = parser.getToken(0); // the operator has just been consumed
+ }
+
/**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.StandardParserVisitor, java.lang.Object)
*/
@@ -84,6 +100,8 @@ public Object value(InternalContextAdapter context)
public Object init(InternalContextAdapter context, Object data) throws TemplateInitException
{
Object obj = super.init(context, data);
+ warnTextualOperator(operator);
+ operator = null;
cleanupParserAndTokens(); // drop reference to Parser and all JavaCC Tokens
return obj;
}
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SimpleNode.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
index 9b5218a1..1bc1c68a 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/SimpleNode.java
@@ -406,6 +406,52 @@ public Object init(InternalContextAdapter context, Object data) throws TemplateI
return data;
}
+ /**
+ * The symbol spelling of an operator written with its deprecated word spelling.
+ *
+ * @param operator image of an operator token
+ * @return the symbol to use instead, or null if this is not a word spelling
+ */
+ private static String symbolFor(String operator)
+ {
+ switch (operator)
+ {
+ case "and": return "&&";
+ case "or": return "||";
+ case "not": return "!";
+ case "eq": return "==";
+ case "ne": return "!=";
+ case "lt": return "<";
+ case "le": return "<=";
+ case "gt": return ">";
+ case "ge": return ">=";
+ default: return null;
+ }
+ }
+
+ /**
+ * VTL syntax deprecation warning (VELOCITY-995), gated by runtime.deprecation.warn:
+ * the word spellings of the operators are deprecated in favour of the symbols.
+ * <p>
+ * Called by the operator nodes at init time, with the operator token they captured
+ * while parsing. Silent when the symbol spelling was used.
+ *
+ * @param operator the operator token, may be null
+ */
+ protected void warnTextualOperator(Token operator)
+ {
+ if (operator == null)
+ {
+ return;
+ }
+ String symbol = symbolFor(operator.image);
+ if (symbol != null && rsvc.getBoolean(RuntimeConstants.RUNTIME_DEPRECATION_WARN, true))
+ {
+ log.warn("the textual operator '{}' is deprecated; write '{}' instead - {} [line {}, column {}]",
+ operator.image, symbol, getTemplateName(), operator.beginLine, operator.beginColumn);
+ }
+ }
+
/**
* @see org.apache.velocity.runtime.parser.node.Node#evaluate(org.apache.velocity.context.InternalContextAdapter)
*/
diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
index 3d51afc2..0efe0339 100644
--- a/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
+++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
@@ -163,6 +163,99 @@ public void testHyphenOptionSilentWhenDeprecationOff()
assertFalse(warningsAtInit(hyphenEngine(false, true)).contains("allow_hyphen_in_identifiers"));
}
+ /* ---- the word spellings of the operators: deprecated in favour of the symbols ---- */
+
+ /** so that the comparisons have something to compare, keeping the log to warnings */
+ private void operands()
+ {
+ context.put("a", 2);
+ context.put("b", 3);
+ }
+
+ private int warningCount(String vtl)
+ {
+ String out = warningsFor(vtl);
+ return out.split("textual operator", -1).length - 1;
+ }
+
+ public void testTextualOperatorsWarn()
+ {
+ operands();
+ assertWarns("#if($a and $b)x#end");
+ assertWarns("#if($a or $b)x#end");
+ assertWarns("#if(not $a)x#end");
+ assertWarns("#if($a eq $b)x#end");
+ assertWarns("#if($a ne $b)x#end");
+ assertWarns("#if($a lt $b)x#end");
+ assertWarns("#if($a le $b)x#end");
+ assertWarns("#if($a gt $b)x#end");
+ assertWarns("#if($a ge $b)x#end");
+ assertWarns("#set($x = $a lt $b)");
+ }
+
+ public void testTextualOperatorWarningNamesTheSymbol()
+ {
+ operands();
+ String out = warningsFor("#if($a and $b)x#end");
+ assertTrue("the warning must name the '&&' spelling, log was:\n" + out,
+ out.contains("the textual operator 'and' is deprecated; write '&&' instead"));
+
+ out = warningsFor("#if($a ge $b)x#end");
+ assertTrue("the warning must name the '>=' spelling, log was:\n" + out,
+ out.contains("the textual operator 'ge' is deprecated; write '>=' instead"));
+ }
+
+ public void testSymbolOperatorsNeverWarn()
+ {
+ operands();
+ assertNoWarn("#if($a && $b)x#end");
+ assertNoWarn("#if($a || $b)x#end");
+ assertNoWarn("#if(!$a)x#end");
+ assertNoWarn("#if($a == $b)x#end");
+ assertNoWarn("#if($a != $b)x#end");
+ assertNoWarn("#if($a < $b)x#end");
+ assertNoWarn("#if($a <= $b)x#end");
+ assertNoWarn("#if($a > $b)x#end");
+ assertNoWarn("#if($a >= $b)x#end");
+ assertNoWarn("#set($x = $a + $b * 2 - 1)");
+ assertNoWarn("#set($x = \"and or not gt\")");
+ assertNoWarn("#set($x = $a)#if($x)x#end");
+ }
+
+ public void testOneWarningPerTextualOperatorOccurrence()
+ {
+ operands();
+ context.put("c", 4);
+ assertEquals("one warning per operator expected",
+ 3, warningCount("#if($a and $b and not $c)x#end"));
+ assertEquals("only the word spellings count",
+ 1, warningCount("#if($a && $b or $a == $b)x#end"));
+ assertEquals("one warning per operator expected, nesting included",
+ 2, warningCount("#if(not ($a gt $b))x#end"));
+ }
+
+ public void testTextualOperatorWarnsFromATemplateFile()
+ {
+ operands();
+ addTemplate("wordops.vm", "#if($a and $b)x#end");
+ log.startCapture();
+ assertTmplEquals("x", "wordops.vm");
+ log.stopCapture();
+ String out = log.getLog();
+ assertTrue("a template file must warn just like evaluate(), log was:\n" + out,
+ out.contains("the textual operator 'and' is deprecated"));
+ assertTrue("the warning must point at the operator itself, log was:\n" + out,
+ out.contains("wordops.vm [line 1, column 8]"));
+ }
+
+ public void testTextualOperatorSilentWhenDeprecationOff()
+ {
+ operands();
+ String out = warningsWithoutSetting("#if($a and not $b)x#end", "false");
+ assertFalse("no warning expected with runtime.deprecation.warn = false, log was:\n" + out,
+ out.contains("deprecated"));
+ }
+
/* ---- on by default, silenced explicitly ---- */
private String warningsWithoutSetting(String vtl, String deprecationWarn)
(velocity-engine) 01/03: Un-deprecate ${}}
Posted by cb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/velocity-engine.git
commit d1914e91aa0153f9e3a93dba06ff8ee81ca42f88
Author: Claude Brisson <cl...@renegat.net>
AuthorDate: Thu Sep 10 15:08:35 2026 +0200
Un-deprecate ${}}
---
src/changes/changes.xml | 3 +--
.../apache/velocity/runtime/parser/node/ASTReference.java | 7 +------
.../apache/velocity/runtime/defaults/velocity.properties | 2 +-
.../apache/velocity/test/DeprecationWarningTestCase.java | 14 +++++---------
4 files changed, 8 insertions(+), 18 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7c7fa010..c09ff62b 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -45,8 +45,7 @@
</action>
<action type="add" dev="cbrisson" issue="VELOCITY-995">
Deprecate <code>${foo|bar}</code> in favor of <code>${foo?:bar}</code>, along with
- the extra <code>$</code> in <code>${$foo}</code> and the
- <code>parser.allow_hyphen_in_identifiers</code> option; warnings gated by
+ the <code>parser.allow_hyphen_in_identifiers</code> option; warnings gated by
<code>runtime.deprecation.warn</code>, on by default.
</action>
<action type="update" dev="cbrisson" issue="VELOCITY-994">
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
index 50b09c22..37dbe8bb 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
@@ -253,7 +253,7 @@ else if (lastNode instanceof ASTExpression)
/*
* VTL syntax deprecation warnings (VELOCITY-995), gated by runtime.deprecation.warn.
* The '|' spelling of the alternate value is deprecated in favour of '?:', which
- * has the very same semantics; the extra '$' in ${$foo} is deprecated outright.
+ * has the very same semantics.
*/
if (rsvc.getBoolean(RuntimeConstants.RUNTIME_DEPRECATION_WARN, true))
{
@@ -262,11 +262,6 @@ else if (lastNode instanceof ASTExpression)
log.warn("the '|' alternate-value notation is deprecated; write ${foo?:alt} rather than ${foo|alt} - {} [line {}, column {}]",
getTemplateName(), getLine(), getColumn());
}
- if (extraDollar)
- {
- log.warn("the extra '$' after '{' is deprecated; write ${foo} rather than ${$foo} - {} [line {}, column {}]",
- getTemplateName(), getLine(), getColumn());
- }
}
/*
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 728fc581..38cdb51e 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
@@ -161,7 +161,7 @@ runtime.immutable_ranges = true
# DEPRECATION WARNINGS
# ----------------------------------------------------------------------------
# Warn about VTL syntax constructs deprecated for the next major version
-# (the '|' alternate-value notation, the extra '$' in '${$foo}', ...).
+# (the '|' alternate-value notation, the hyphenated-identifiers option).
# ON by default: the deprecated constructs left are rare enough that the warnings
# do not flood a log, and they say what to write instead. Set it to false to
# silence them.
diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
index c6e0ae7b..3d51afc2 100644
--- a/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
+++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
@@ -116,17 +116,13 @@ public void testOnlyThePipeSpellingWarnsWhenBothAreMixed()
1, out.split("alternate-value notation is deprecated", -1).length - 1);
}
- /* ---- the extra '$' after '{' (${$foo}): always deprecated, but still formal ---- */
+ /* ---- the extra '$' after '{' (${$foo}, re-added in 2.5 for 1.7 BC): supported, never warns ---- */
- public void testExtraDollarWarns()
- {
- assertWarns("${$foo}");
- assertWarns("${$foo.bar}");
- assertWarns("$!{$foo}");
- }
-
- public void testFormalWithoutExtraDollarNeverWarns()
+ public void testExtraDollarNeverWarns()
{
+ assertNoWarn("${$foo}");
+ assertNoWarn("${$foo.bar}");
+ assertNoWarn("$!{$foo}");
assertNoWarn("${foo}");
assertNoWarn("${foo.bar}");
}
(velocity-engine) 03/03: Corner case: a final backslash in a double quoted string is deprecated
Posted by cb...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/velocity-engine.git
commit c9707967625f5e9177718bb806eb3b68b86881b4
Author: Claude Brisson <cl...@renegat.net>
AuthorDate: Fri Sep 11 11:15:13 2026 +0200
Corner case: a final backslash in a double quoted string is deprecated
---
src/changes/changes.xml | 5 +-
.../runtime/parser/node/ASTStringLiteral.java | 28 +++++++++
.../velocity/test/DeprecationWarningTestCase.java | 68 +++++++++++++++++++++-
3 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 255a1269..a1a8016e 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -45,8 +45,9 @@
</action>
<action type="add" dev="cbrisson" issue="VELOCITY-995">
Deprecate <code>${foo|bar}</code> in favor of <code>${foo?:bar}</code>, the textual
- operators <code>and or not gt ge lt le eq ne</code> in favor of their symbols, and
- the <code>parser.allow_hyphen_in_identifiers</code> option; warnings gated by
+ operators <code>and or not gt ge lt le eq ne</code> in favor of their symbols, a
+ backslash right before the closing quote of a double-quoted string, and the
+ <code>parser.allow_hyphen_in_identifiers</code> option; warnings gated by
<code>runtime.deprecation.warn</code>, on by default.
</action>
<action type="update" dev="cbrisson" issue="VELOCITY-994">
diff --git a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java
index c1122d4e..e7b1bf1a 100644
--- a/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java
+++ b/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java
@@ -112,6 +112,8 @@ && getFirstToken().image.startsWith("\"")
image = img.substring(1, img.length() - 1);
+ warnTrailingBackslash(img);
+
if (img.startsWith("\""))
{
image = unescape(image);
@@ -172,6 +174,32 @@ && getFirstToken().image.startsWith("\"")
return data;
}
+ /**
+ * A backslash right before the closing quote of a double-quoted string is deprecated.
+ *
+ * @param img the authored image of the literal, enclosing quotes included, before any
+ * unescaping
+ */
+ private void warnTrailingBackslash(String img)
+ {
+ if (img.charAt(0) != '"' || !rsvc.getBoolean(RuntimeConstants.RUNTIME_DEPRECATION_WARN, true))
+ {
+ return;
+ }
+
+ int backslashes = 0;
+ for (int i = img.length() - 2; i >= 1 && img.charAt(i) == '\\'; i--)
+ {
+ backslashes++;
+ }
+
+ if (backslashes % 2 == 1)
+ {
+ log.warn("a backslash right before the closing quote of a double-quoted string is deprecated; use a single-quoted string instead ('a\\') - {} [line {}, column {}]",
+ getTemplateName(), getLine(), getColumn());
+ }
+ }
+
/**
* Adjust all the line and column numbers that comprise a node so that they
* are corrected for the string literals position within the template file.
diff --git a/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java b/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
index 0efe0339..9fceebcf 100644
--- a/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
+++ b/velocity-engine-core/src/test/java/org/apache/velocity/test/DeprecationWarningTestCase.java
@@ -25,8 +25,9 @@
/**
* Tests the gated VTL syntax deprecation warnings (VELOCITY-995): the {@code |}
- * spelling of the alternate value, the extra {@code $} of {@code ${$foo}}, and the
- * {@code parser.allow_hyphen_in_identifiers} option. The warning fires at parse/init
+ * spelling of the alternate value, the extra {@code $} of {@code ${$foo}}, the
+ * {@code parser.allow_hyphen_in_identifiers} option, the word spellings of the operators
+ * and a lone backslash right before the closing quote of a double-quoted string. The warning fires at parse/init
* time and is independent of whether the reference resolves, so the templates need no
* context.
*/
@@ -256,6 +257,69 @@ public void testTextualOperatorSilentWhenDeprecationOff()
out.contains("deprecated"));
}
+ /* ---- a lone backslash right before the closing quote of a double-quoted string ---- */
+
+ /** the authored VTL is #set($s = "a\") - a backslash against the closing quote */
+ private static final String TRAILING_BACKSLASH = "#set($s = \"a\\\")";
+
+ public void testTrailingBackslashInDoubleQuotesWarns()
+ {
+ assertWarns(TRAILING_BACKSLASH);
+ /* #m("a\") - a macro argument warns just the same */
+ assertWarns("#macro(m $x)$x#end#m(\"a\\\")");
+ /* "$foo\" - an interpolated literal warns just the same */
+ assertWarns("#set($s = \"$foo\\\")");
+ }
+
+ public void testTrailingBackslashWarningNamesTheSingleQuotedRecipe()
+ {
+ String out = warningsFor(TRAILING_BACKSLASH);
+ assertTrue("the warning must name the single-quoted spelling, log was:\n" + out,
+ out.contains("use a single-quoted string instead ('a\\')"));
+ }
+
+ public void testEvenRunOfBackslashesNeverWarns()
+ {
+ /* "a\\" - both backslashes are kept literally here and \\ escapes a backslash there */
+ assertNoWarn("#set($s = \"a\\\\\")");
+ /* "a\\\\" */
+ assertNoWarn("#set($s = \"a\\\\\\\\\")");
+ }
+
+ public void testOtherStringsNeverWarn()
+ {
+ /* "a\nb", "a\\b", "ab", 'a\', 'a\\' */
+ assertNoWarn("#set($s = \"a\\nb\")");
+ assertNoWarn("#set($s = \"a\\\\b\")");
+ assertNoWarn("#set($s = \"ab\")");
+ assertNoWarn("#set($s = '')");
+ assertNoWarn("#set($s = \"\")");
+ assertNoWarn("#set($s = 'a\\')");
+ assertNoWarn("#set($s = 'a\\\\')");
+ }
+
+ public void testOneWarningPerDoubleQuotedLiteral()
+ {
+ /* "a\" then 'b\' then "c\" - only the two double-quoted ones count */
+ String out = warningsFor("#set($s = \"a\\\")#set($t = 'b\\')#set($u = \"c\\\")");
+ assertEquals("one warning per double-quoted literal expected, log was:\n" + out,
+ 2, out.split("right before the closing quote", -1).length - 1);
+ }
+
+ public void testTrailingBackslashSilentWhenDeprecationOff()
+ {
+ String out = warningsWithoutSetting(TRAILING_BACKSLASH, "false");
+ assertFalse("no warning expected with runtime.deprecation.warn = false, log was:\n" + out,
+ out.contains("deprecated"));
+ }
+
+ /** the warning changes nothing: the backslash is still a literal backslash here */
+ public void testTrailingBackslashStillRendersTheBackslash()
+ {
+ assertEvalEquals("a\\", "#set($s = \"a\\\")$s");
+ assertEvalEquals("a\\\\", "#set($s = \"a\\\\\")$s");
+ }
+
/* ---- on by default, silenced explicitly ---- */
private String warningsWithoutSetting(String vtl, String deprecationWarn)