You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2023/12/16 20:47:44 UTC

(freemarker) 01/02: For PR #88 forceAutoEscape: Better error messages. Some more test coverage.

This is an automated email from the ASF dual-hosted git repository.

ddekany pushed a commit to branch 2.3-gae
in repository https://gitbox.apache.org/repos/asf/freemarker.git

commit cf5164cadb191d58f645bc4d2917482a29105561
Author: ddekany <dd...@apache.org>
AuthorDate: Sat Dec 16 21:45:02 2023 +0100

    For PR #88 forceAutoEscape: Better error messages. Some more test coverage.
---
 src/main/javacc/FTL.jj                             | 72 ++++++++++++----------
 .../java/freemarker/core/OutputFormatTest.java     | 23 ++++++-
 2 files changed, 59 insertions(+), 36 deletions(-)

diff --git a/src/main/javacc/FTL.jj b/src/main/javacc/FTL.jj
index a7447275..55955c5c 100644
--- a/src/main/javacc/FTL.jj
+++ b/src/main/javacc/FTL.jj
@@ -237,11 +237,9 @@ public class FMParser {
                 outputFormat = outputFormatFromExt;
             }
         }
-	if (!(outputFormat instanceof MarkupOutputFormat)
-	    && autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
-	    throw new IllegalArgumentException(
-                    "Non-markup output format cannot be used when auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY.");
-	}
+        if (!(outputFormat instanceof MarkupOutputFormat) && autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
+            throw new IllegalArgumentException(forcedAutoEscapingPolicyExceptionMessage(outputFormat));
+        }
         recalculateAutoEscapingField();
 
         token_source.setParser(this);
@@ -286,17 +284,17 @@ public class FMParser {
             _TemplateAPI.setOutputFormat(template, outputFormat);
         }
     }
-    
+
     void setupStringLiteralMode(FMParser parentParser, OutputFormat outputFormat) {
         FMParserTokenManager parentTokenSource = parentParser.token_source;
-         
+
         token_source.initialNamingConvention = parentTokenSource.initialNamingConvention;
         token_source.namingConvention = parentTokenSource.namingConvention;
         token_source.namingConventionEstabilisher = parentTokenSource.namingConventionEstabilisher;
         token_source.SwitchTo(NO_DIRECTIVE);
-        
+
         this.outputFormat = outputFormat;
-        recalculateAutoEscapingField();                                
+        recalculateAutoEscapingField();
         if (incompatibleImprovements < _VersionInts.V_2_3_24) {
             // Emulate bug, where the string literal parser haven't inherited the IcI:
             incompatibleImprovements = _VersionInts.V_2_3_0;
@@ -527,6 +525,15 @@ public class FMParser {
         }
     }
 
+    private static String forcedAutoEscapingPolicyExceptionMessage(OutputFormat outputFormat) {
+        return forcedAutoEscapingPolicyExceptionMessage("Non-markup output format " + outputFormat);
+    }
+
+    private static String forcedAutoEscapingPolicyExceptionMessage(String whatCanNotBeUsed) {
+        return whatCanNotBeUsed + " can't be used when the \"" + Configuration.AUTO_ESCAPING_POLICY_KEY + "\" "
+                + "configuration setting was set to \"force\" (FORCE_AUTO_ESCAPING_POLICY).";
+    }
+
     private ParserIteratorBlockContext pushIteratorBlockContext() {
         if (iteratorBlockContexts == null) {
             iteratorBlockContexts = new ArrayList<ParserIteratorBlockContext>(4);
@@ -571,7 +578,7 @@ public class FMParser {
 	    // [2.4] Use camel case as the default
 	    return token_source.namingConvention == Configuration.CAMEL_CASE_NAMING_CONVENTION ? "#forEach" : "#foreach";
 	}
-    
+
 }
 
 PARSER_END(FMParser)
@@ -2230,13 +2237,13 @@ Expression BuiltIn(Expression lhoExp) :
             return result;
         }
 
-	if (result instanceof BuiltInBannedWhenForcedAutoEscaping) {
-	    if (autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
-	        throw new ParseException(
-		        "Using ?" + t.image + " is not allowed while auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY.",
-			template, t);
-	    }
-	}
+        if (result instanceof BuiltInBannedWhenForcedAutoEscaping) {
+            if (autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
+                throw new ParseException(
+                        forcedAutoEscapingPolicyExceptionMessage("The ?" + t.image + " expression"),
+                        template, t);
+            }
+        }
 
         if (result instanceof MarkupOutputFormatBoundBuiltIn) {
             if (!(outputFormat instanceof MarkupOutputFormat)) {
@@ -4060,12 +4067,10 @@ OutputFormatBlock OutputFormat() :
             } else {
                 outputFormat = template.getConfiguration().getOutputFormat(paramStr);
             }
-	    if (!(outputFormat instanceof MarkupOutputFormat)
-	    	&& autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
-	        throw new ParseException(
-			"Non-markup output format cannot be used when auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY.",
-			template, start);
-	    }
+            if (!(outputFormat instanceof MarkupOutputFormat)
+                    && autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
+                throw new ParseException(forcedAutoEscapingPolicyExceptionMessage(outputFormat), template, start);
+            }
             recalculateAutoEscapingField();
         } catch (IllegalArgumentException e) {
             throw new ParseException("Invalid format name: " + e.getMessage(), template, start, e.getCause());
@@ -4120,11 +4125,12 @@ NoAutoEscBlock NoAutoEsc() :
 {
     start = <NOAUTOESC>
     {
-	if (autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
-	    throw new ParseException(
-	    	"<#noautoesc> cannot be used when auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY.",
-		template, start);
-	}
+        if (autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
+            throw new ParseException(
+                    forcedAutoEscapingPolicyExceptionMessage(
+                            "<#" + (token_source.namingConvention == Configuration.CAMEL_CASE_NAMING_CONVENTION ? "noAutoEsc" : "noautoesc") + ">"),
+                    template, start);
+        }
         lastAutoEscapingPolicy = autoEscapingPolicy;
         autoEscapingPolicy = Configuration.DISABLE_AUTO_ESCAPING_POLICY;
         recalculateAutoEscapingField();
@@ -4564,11 +4570,11 @@ void HeaderElement() :
                                 autoEscRequester = key;
                                 autoEscapingPolicy = Configuration.ENABLE_IF_SUPPORTED_AUTO_ESCAPING_POLICY;
                             } else {
-				if (autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
-				    throw new ParseException(
-				            "auto_esc setting cannot be used when auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY.",
-					    exp);
-				}
+                                if (autoEscapingPolicy == Configuration.FORCE_AUTO_ESCAPING_POLICY) {
+                                    throw new ParseException(
+                                            forcedAutoEscapingPolicyExceptionMessage("auto_esc setting"),
+                                            exp);
+                                }
                                 autoEscapingPolicy = Configuration.DISABLE_AUTO_ESCAPING_POLICY;
                             }
                             recalculateAutoEscapingField();
diff --git a/src/test/java/freemarker/core/OutputFormatTest.java b/src/test/java/freemarker/core/OutputFormatTest.java
index 14d3ecfc..03672c76 100644
--- a/src/test/java/freemarker/core/OutputFormatTest.java
+++ b/src/test/java/freemarker/core/OutputFormatTest.java
@@ -868,10 +868,27 @@ public class OutputFormatTest extends TemplateTest {
         cfg.setOutputFormat(DummyOutputFormat.INSTANCE);
         assertOutput(commonFTL, esced);
 
+        // TODO Should work:
+        // cfg.setOutputFormat(PlainTextOutputFormat.INSTANCE);
+        // assertOutput("<#ftl outputFormat='seldomEscaped'>" + commonFTL, esced);
+
+        cfg.setOutputFormat(HTMLOutputFormat.INSTANCE);
+        assertOutput("<#outputFormat 'seldomEscaped'>" + commonFTL + "</#outputFormat>", esced);
+
+        cfg.setOutputFormat(PlainTextOutputFormat.INSTANCE);
+        assertErrorContains("", IllegalArgumentException.class,
+                "plainText", "auto_escaping_policy", "force");
         cfg.setOutputFormat(DummyOutputFormat.INSTANCE);
-        assertErrorContains("<#outputformat 'plainText'></#outputformat>", "auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY");
-        assertErrorContains("<#noAutoEsc></#noAutoEsc>", "auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY");
-        assertErrorContains("<#assign foo='bar'>${foo?noEsc}", "auto_escaping_policy is FORCE_AUTO_ESCAPING_POLICY");
+        assertErrorContains("<#outputformat 'plainText'></#outputformat>", ParseException.class,
+                "plainText", "auto_escaping_policy", "force");
+        assertErrorContains("<#noAutoEsc></#noAutoEsc>", ParseException.class,
+                "noAutoEsc", "auto_escaping_policy", "force");
+        assertErrorContains("<#noautoesc></#noautoesc>", ParseException.class,
+                "noautoesc", "auto_escaping_policy", "force");
+        assertErrorContains("<#assign foo='bar'>${foo?no_esc}", ParseException.class,
+                "?no_esc", "auto_escaping_policy", "force");
+        assertErrorContains("<#assign foo='bar'>${foo?noEsc}", ParseException.class,
+                "?noEsc", "auto_escaping_policy", "force");
     }
 
     @Test