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

lukaszlenart pushed a commit to branch feature/WW-5256-freemarker-compress
in repository https://gitbox.apache.org/repos/asf/struts.git

commit f3fe49f60a6f2e739c5b959229f4d0e904233d83
Author: Lukasz Lenart <[email protected]>
AuthorDate: Sun Jul 14 09:23:34 2024 +0200

    WW-5256 Implements dedicated tag to compress output
---
 .../org/apache/struts2/components/Compress.java    | 102 ++++++++++++++++
 .../org/apache/struts2/views/jsp/CompressTag.java  |  55 +++++++++
 .../resources/template/css_xhtml/controlfooter.ftl |  17 ++-
 .../resources/template/css_xhtml/form-validate.ftl |  10 +-
 .../main/resources/template/css_xhtml/label.ftl    |   1 -
 .../main/resources/template/simple/actionerror.ftl |  14 +--
 .../template/simple/form-close-tooltips.ftl        |   1 -
 .../main/resources/template/simple/form-close.ftl  |   2 -
 .../resources/template/xhtml/controlheader.ftl     |  12 +-
 .../resources/template/xhtml/form-validate.ftl     |  12 +-
 .../site/resources/tags/compress-attributes.html   |  32 +++++
 .../site/resources/tags/compress-description.html  |   1 +
 .../apache/struts2/components/CompressTest.java    | 132 +++++++++++++++++++++
 .../struts2/views/jsp/AbstractUITagTest.java       |  15 +++
 .../apache/struts2/views/jsp/CompressTagTest.java  |  73 ++++++++++++
 .../apache/struts2/views/jsp/ui/DebugTagTest.java  |  16 ---
 16 files changed, 441 insertions(+), 54 deletions(-)

diff --git a/core/src/main/java/org/apache/struts2/components/Compress.java 
b/core/src/main/java/org/apache/struts2/components/Compress.java
new file mode 100644
index 000000000..6131e5f33
--- /dev/null
+++ b/core/src/main/java/org/apache/struts2/components/Compress.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+package org.apache.struts2.components;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.struts2.util.ValueStack;
+import org.apache.struts2.views.annotations.StrutsTag;
+import org.apache.struts2.views.annotations.StrutsTagAttribute;
+
+import java.io.Writer;
+
+/**
+ * <p>
+ * Used to compress HTML output. Just wrap a given section with the tag.
+ * </p>
+ *
+ * <p>
+ * Configurable attributes are:
+ * </p>
+ *
+ * <ul>
+ *    <li>force (true/false) - always compress output, this can be useful in 
DevMode as devMode disables compression</li>
+ * </ul>
+ *
+ * <p><b>Examples</b></p>
+ * <pre>
+ *  <!-- START SNIPPET: example -->
+ *  &lt;s:compress&gt;
+ *    &lt;s:form action="submit"&gt;
+ *    &lt;s:text name="name" /&gt;
+ *    ...
+ *    &lt;/s:form&gt;
+ *  &lt;/s:compress&gt;
+ *  <!-- END SNIPPET: example -->
+ * </pre>
+ *
+ * <p>Uses conditional compression depending on action</p>
+ * <pre>
+ *  <!-- START SNIPPET: example -->
+ *  &lt;s:compress force="shouldCompress"&gt;
+ *    &lt;s:form action="submit"&gt;
+ *    &lt;s:text name="name" /&gt;
+ *    ...
+ *    &lt;/s:form&gt;
+ *  &lt;/s:compress&gt;
+ *  <!-- END SNIPPET: example -->
+ * </pre>
+ * "shouldCompress" is a field with getter define on action used in expression 
evaluation
+ */
+@StrutsTag(name = "compress", tldTagClass = 
"org.apache.struts2.views.jsp.CompressTag",
+        description = "Compress wrapped content")
+public class Compress extends Component {
+
+    private static final Logger LOG = LogManager.getLogger(Compress.class);
+
+    private String force;
+
+    public Compress(ValueStack stack) {
+        super(stack);
+    }
+
+    @Override
+    public boolean end(Writer writer, String body) {
+        Object forceValue = findValue(force, Boolean.class);
+        boolean forced = forceValue != null && 
Boolean.parseBoolean(forceValue.toString());
+        if (devMode && !forced) {
+            LOG.debug("Avoids compressing output: {} in DevMode", body);
+            return super.end(writer, body, true);
+        }
+        LOG.trace("Compresses: {}", body);
+        String compressed = body.trim().replaceAll(">\\s+<", "><");
+        LOG.trace("Compressed: {}", compressed);
+        return super.end(writer, compressed, true);
+    }
+
+    @Override
+    public boolean usesBody() {
+        return true;
+    }
+
+    @StrutsTagAttribute(description = "Force output compression")
+    public void setForce(String force) {
+        this.force = force;
+    }
+}
diff --git a/core/src/main/java/org/apache/struts2/views/jsp/CompressTag.java 
b/core/src/main/java/org/apache/struts2/views/jsp/CompressTag.java
new file mode 100644
index 000000000..4b9821e53
--- /dev/null
+++ b/core/src/main/java/org/apache/struts2/views/jsp/CompressTag.java
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+package org.apache.struts2.views.jsp;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.struts2.components.Component;
+import org.apache.struts2.components.Compress;
+import org.apache.struts2.util.ValueStack;
+
+import java.io.Serial;
+
+/**
+ * @see org.apache.struts2.components.Compress
+ */
+public class CompressTag extends ComponentTagSupport {
+
+    @Serial
+    private static final long serialVersionUID = 7572566991679717145L;
+
+    private String force;
+
+    @Override
+    public Component getBean(ValueStack stack, HttpServletRequest req, 
HttpServletResponse res) {
+        return new Compress(stack);
+    }
+
+    @Override
+    protected void populateParams() {
+        super.populateParams();
+
+        Compress compress = (Compress) component;
+        compress.setForce(force);
+    }
+
+    public void setForce(String force) {
+        this.force = force;
+    }
+}
diff --git a/core/src/main/resources/template/css_xhtml/controlfooter.ftl 
b/core/src/main/resources/template/css_xhtml/controlfooter.ftl
index d25b5790c..0099b6df8 100644
--- a/core/src/main/resources/template/css_xhtml/controlfooter.ftl
+++ b/core/src/main/resources/template/css_xhtml/controlfooter.ftl
@@ -19,29 +19,26 @@
  */
 -->
 ${attributes.after!}<#t/>
-    <#lt/>
 <#if !attributes.labelPosition?? && (attributes.form.labelPosition)??>
 <#assign labelPos = attributes.form.labelPosition/>
 <#elseif attributes.labelPosition??>
 <#assign labelPos = attributes.labelPosition/>
 </#if>
 <#if (labelPos!"top") == 'top'>
-</div> <#rt/>
+</div><#rt/>
 <#else>
-</span> <#rt/>
+</span><#rt/>
 </#if>
 <#if (attributes.errorposition!"top") == 'bottom'>
 <#assign hasFieldErrors = attributes.name?? && fieldErrors?? && 
fieldErrors.get(attributes.name)??/>
 <#if hasFieldErrors>
 <div <#rt/><#if attributes.id??>id="wwerr_${attributes.id}"<#rt/></#if> 
class="wwerr">
 <#list fieldErrors.get(attributes.name) as error>
-    <div<#rt/>
-    <#if attributes.id??>
-     errorFor="${attributes.id}"<#rt/>
-    </#if>
-    class="errorMessage">
-             ${error}
-    </div><#t/>
+<div<#rt/>
+<#if attributes.id??>
+ errorFor="${attributes.id}"<#rt/>
+</#if>
+ class="errorMessage">${error}</div><#rt/>
 </#list>
 </div><#t/>
 </#if>
diff --git a/core/src/main/resources/template/css_xhtml/form-validate.ftl 
b/core/src/main/resources/template/css_xhtml/form-validate.ftl
index 7beb7fab5..1f1bff261 100644
--- a/core/src/main/resources/template/css_xhtml/form-validate.ftl
+++ b/core/src/main/resources/template/css_xhtml/form-validate.ftl
@@ -20,9 +20,9 @@
 -->
 <#if attributes.validate!false == true>
 <@s.script 
src="${base}${attributes.staticContentPath}/css_xhtml/validation.js"/>
-    <#if attributes.onsubmit??>
-        ${tag.addParameter('onsubmit', "${attributes.onsubmit}; return 
validateForm_${attributes.escapedId}();")}
-    <#else>
-        ${tag.addParameter('onsubmit', "return 
validateForm_${attributes.escapedId}();")}
-    </#if>
+<#if attributes.onsubmit??>
+    ${tag.addParameter('onsubmit', "${attributes.onsubmit}; return 
validateForm_${attributes.escapedId}();")}
+<#else>
+    ${tag.addParameter('onsubmit', "return 
validateForm_${attributes.escapedId}();")}
+</#if>
 </#if>
diff --git a/core/src/main/resources/template/css_xhtml/label.ftl 
b/core/src/main/resources/template/css_xhtml/label.ftl
index 23701e715..4c03cd19a 100644
--- a/core/src/main/resources/template/css_xhtml/label.ftl
+++ b/core/src/main/resources/template/css_xhtml/label.ftl
@@ -18,7 +18,6 @@
  * under the License.
  */
 -->
-<#--include "/${attributes.templateDir}/css_xhtml/controlheader.ftl" /-->
 <#include 
"/${attributes.templateDir}/${attributes.expandTheme}/controlheader.ftl" />
 <label<#rt/>
 <#if attributes.id??>
diff --git a/core/src/main/resources/template/simple/actionerror.ftl 
b/core/src/main/resources/template/simple/actionerror.ftl
index 4cd9a60b9..54b3f3ca2 100644
--- a/core/src/main/resources/template/simple/actionerror.ftl
+++ b/core/src/main/resources/template/simple/actionerror.ftl
@@ -19,7 +19,7 @@
  */
 -->
 <#if (actionErrors?? && actionErrors?size > 0)>
-       <ul<#rt/>
+<ul<#rt/>
 <#if attributes.id??>
  id="${attributes.id}"<#rt/>
 </#if>
@@ -32,10 +32,10 @@
  style="${attributes.cssStyle}"<#rt/>
 </#if>
 >
-       <#list actionErrors as error>
-               <#if error??>
-            <li><span><#if 
attributes.escape>${error!}<#else>${error!?no_esc}</#if></span><#rt/></li><#rt/>
-        </#if>
-       </#list>
-       </ul>
+<#list actionErrors as error>
+<#if error??>
+  <li><span><#if 
attributes.escape>${error!}<#else>${error!?no_esc}</#if></span><#rt/></li><#rt/>
+</#if>
+</#list>
+</ul>
 </#if>
\ No newline at end of file
diff --git a/core/src/main/resources/template/simple/form-close-tooltips.ftl 
b/core/src/main/resources/template/simple/form-close-tooltips.ftl
index 1bf45e909..e57bdcc1e 100644
--- a/core/src/main/resources/template/simple/form-close-tooltips.ftl
+++ b/core/src/main/resources/template/simple/form-close-tooltips.ftl
@@ -18,7 +18,6 @@
  * under the License.
  */
 -->
-
 <#--
  Code that will add javascript needed for tooltips
 --><#t/>
diff --git a/core/src/main/resources/template/simple/form-close.ftl 
b/core/src/main/resources/template/simple/form-close.ftl
index 59d4f0dbc..291af0977 100644
--- a/core/src/main/resources/template/simple/form-close.ftl
+++ b/core/src/main/resources/template/simple/form-close.ftl
@@ -19,7 +19,6 @@
  */
 -->
 </form>
-
 <#if (attributes.customOnsubmitEnabled??)>
 <@s.script>
 <#--
@@ -98,5 +97,4 @@
 </#if>
 </@s.script>
 </#if>
-
 <#include 
"/${attributes.templateDir}/${attributes.expandTheme}/form-close-tooltips.ftl" 
/>
diff --git a/core/src/main/resources/template/xhtml/controlheader.ftl 
b/core/src/main/resources/template/xhtml/controlheader.ftl
index ec9372d92..2df6b1cb0 100644
--- a/core/src/main/resources/template/xhtml/controlheader.ftl
+++ b/core/src/main/resources/template/xhtml/controlheader.ftl
@@ -19,10 +19,10 @@
  */
 -->
 <#include 
"/${attributes.templateDir}/${attributes.expandTheme}/controlheader-core.ftl" />
-    <td
-        <#if attributes.align?? >
-            class="align-${attributes.align}"
-         <#else >
-            class="tdInput"
-        </#if>
+    <td<#rt/>
+<#if attributes.align?? >
+ class="align-${attributes.align}"<#rt/>
+<#else >
+ class="tdInput"<#rt/>
+</#if>
 ><#t/>
diff --git a/core/src/main/resources/template/xhtml/form-validate.ftl 
b/core/src/main/resources/template/xhtml/form-validate.ftl
index a074bef2f..cbd03a7f6 100644
--- a/core/src/main/resources/template/xhtml/form-validate.ftl
+++ b/core/src/main/resources/template/xhtml/form-validate.ftl
@@ -19,10 +19,10 @@
  */
 -->
 <#if attributes.validate!false == true>
-       <@s.script 
src="${base}${attributes.staticContentPath}/xhtml/validation.js" />
-       <#if attributes.onsubmit??>
-               ${tag.addParameter('onsubmit', "${attributes.onsubmit}; return 
validateForm_${attributes.escapedId}();")}
-       <#else>
-               ${tag.addParameter('onsubmit', "return 
validateForm_${attributes.escapedId}();")}
-       </#if>
+<@s.script src="${base}${attributes.staticContentPath}/xhtml/validation.js" />
+<#if attributes.onsubmit??>
+    ${tag.addParameter('onsubmit', "${attributes.onsubmit}; return 
validateForm_${attributes.escapedId}();")}
+<#else>
+    ${tag.addParameter('onsubmit', "return 
validateForm_${attributes.escapedId}();")}
+</#if>
 </#if>
diff --git a/core/src/site/resources/tags/compress-attributes.html 
b/core/src/site/resources/tags/compress-attributes.html
new file mode 100644
index 000000000..9ecf24227
--- /dev/null
+++ b/core/src/site/resources/tags/compress-attributes.html
@@ -0,0 +1,32 @@
+<table class="tag-reference">
+    <tr>
+        <td colspan="6"><h4>Dynamic Attributes Allowed:</h4> false</td>
+    </tr>
+    <tr>
+        <td colspan="6"><hr/></td>
+    </tr>
+    <tr>
+        <th class="tag-header"><h4>Name</h4></th>
+        <th class="tag-header"><h4>Required</h4></th>
+        <th class="tag-header"><h4>Default</h4></th>
+        <th class="tag-header"><h4>Evaluated</h4></th>
+        <th class="tag-header"><h4>Type</h4></th>
+        <th class="tag-header"><h4>Description</h4></th>
+    </tr>
+    <tr>
+        <td class="tag-attribute">force</td>
+        <td class="tag-attribute">false</td>
+        <td class="tag-attribute"></td>
+        <td class="tag-attribute">false</td>
+        <td class="tag-attribute">String</td>
+        <td class="tag-attribute">Force output compression</td>
+    </tr>
+    <tr>
+        <td class="tag-attribute">performClearTagStateForTagPoolingServers</td>
+        <td class="tag-attribute">false</td>
+        <td class="tag-attribute">false</td>
+        <td class="tag-attribute">false</td>
+        <td class="tag-attribute">Boolean</td>
+        <td class="tag-attribute">Whether to clear all tag state during 
doEndTag() processing (if applicable)</td>
+    </tr>
+</table>
diff --git a/core/src/site/resources/tags/compress-description.html 
b/core/src/site/resources/tags/compress-description.html
new file mode 100644
index 000000000..6865f0b72
--- /dev/null
+++ b/core/src/site/resources/tags/compress-description.html
@@ -0,0 +1 @@
+Compress wrapped content
diff --git a/core/src/test/java/org/apache/struts2/components/CompressTest.java 
b/core/src/test/java/org/apache/struts2/components/CompressTest.java
new file mode 100644
index 000000000..6631850ab
--- /dev/null
+++ b/core/src/test/java/org/apache/struts2/components/CompressTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+package org.apache.struts2.components;
+
+import org.apache.struts2.StrutsInternalTestCase;
+import org.apache.struts2.util.ValueStack;
+import org.apache.struts2.util.ValueStackFactory;
+
+import java.io.StringWriter;
+import java.util.Map;
+
+public class CompressTest extends StrutsInternalTestCase {
+
+    private ValueStack stack;
+    private Map<String, Object> context;
+
+    public void testCompressHtmlOutput() {
+        Compress compress = new Compress(stack);
+
+        String body = """
+                <html>
+                <head>
+                    <title>File upload: result</title>
+                </head>
+                <body>
+                    <h1>File upload: result</h1>
+                </body>
+                </html>
+                """;
+
+        StringWriter writer = new StringWriter();
+
+        compress.setDevMode("false");
+        compress.setForce("false");
+        compress.end(writer, body);
+
+        assertEquals("<html><head><title>File upload: 
result</title></head><body><h1>File upload: result</h1></body></html>", 
writer.toString());
+    }
+
+    public void testAvoidCompressingInDevModeHtmlOutput() {
+        Compress compress = new Compress(stack);
+
+        String body = """
+                <html>
+                <head>
+                    <title>File upload: result</title>
+                </head>
+                <body>
+                    <h1>File upload: result</h1>
+                </body>
+                </html>
+                """;
+
+        StringWriter writer = new StringWriter();
+
+        compress.setDevMode("true");
+        compress.end(writer, body);
+
+        assertEquals(body, writer.toString());
+    }
+
+    public void testCompressHtmlOutputEvenInDevMode() {
+        Compress compress = new Compress(stack);
+
+        String body = """
+                <html>
+                <head>
+                    <title>File upload: result</title>
+                </head>
+                <body>
+                    <h1>File upload: result</h1>
+                </body>
+                </html>
+                """;
+
+        StringWriter writer = new StringWriter();
+
+        compress.setDevMode("true");
+        compress.setForce("true");
+        compress.end(writer, body);
+
+        assertEquals("<html><head><title>File upload: 
result</title></head><body><h1>File upload: result</h1></body></html>", 
writer.toString());
+    }
+
+    public void testCompressHtmlOutputEvenInDevModeAndForceIsExpression() {
+        Compress compress = new Compress(stack);
+
+        String body = """
+                <html>
+                <head>
+                    <title>File upload: result</title>
+                </head>
+                <body>
+                    <h1>File upload: result</h1>
+                </body>
+                </html>
+                """;
+
+        this.context.put("shouldCompress", Boolean.TRUE);
+
+        compress.setDevMode("true");
+        compress.setForce("shouldCompress");
+
+        StringWriter writer = new StringWriter();
+        compress.end(writer, body);
+
+        assertEquals("<html><head><title>File upload: 
result</title></head><body><h1>File upload: result</h1></body></html>", 
writer.toString());
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        stack = 
container.getInstance(ValueStackFactory.class).createValueStack();
+        context = stack.getContext();
+    }
+}
diff --git 
a/core/src/test/java/org/apache/struts2/views/jsp/AbstractUITagTest.java 
b/core/src/test/java/org/apache/struts2/views/jsp/AbstractUITagTest.java
index df1e4323d..6252c4554 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/AbstractUITagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/AbstractUITagTest.java
@@ -23,6 +23,7 @@ import org.apache.commons.beanutils.BeanUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.dispatcher.mapper.ActionMapper;
 import org.apache.struts2.dispatcher.mapper.DefaultActionMapper;
 import org.apache.struts2.views.jsp.ui.AbstractUITag;
@@ -295,4 +296,18 @@ public abstract class AbstractUITagTest extends 
AbstractTagTest {
 
         return buffer.toString();
     }
+
+    protected void setDevMode(final boolean devMode) {
+        
setStrutsConstant(Collections.singletonMap(StrutsConstants.STRUTS_DEVMODE, 
Boolean.toString(devMode)));
+    }
+
+    /**
+     * Overwrite the Struts Constant and reload container
+     */
+    @Override
+    protected void setStrutsConstant(final Map<String, String> 
overwritePropeties) {
+        super.setStrutsConstant(overwritePropeties);
+        stack.getActionContext().withContainer(container);
+    }
+
 }
diff --git 
a/core/src/test/java/org/apache/struts2/views/jsp/CompressTagTest.java 
b/core/src/test/java/org/apache/struts2/views/jsp/CompressTagTest.java
new file mode 100644
index 000000000..994e948af
--- /dev/null
+++ b/core/src/test/java/org/apache/struts2/views/jsp/CompressTagTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+package org.apache.struts2.views.jsp;
+
+import org.apache.struts2.views.jsp.ui.StrutsBodyContent;
+
+public class CompressTagTest extends AbstractUITagTest {
+
+    public void testNoCompression() throws Exception {
+        setDevMode(true);
+
+        CompressTag tag = new CompressTag();
+        tag.setPageContext(pageContext);
+
+        StrutsBodyContent bc = new StrutsBodyContent(null);
+        bc.print("""
+                <form action="/" method="post">
+                <table class="wwFormTable"></table></form>
+                """
+        );
+
+        tag.doStartTag();
+        tag.setBodyContent(bc);
+        tag.doEndTag();
+
+        assertEquals("""
+                        <form action="/" method="post">
+                        <table class="wwFormTable"></table></form>
+                        """.stripTrailing(),
+                this.writer.toString());
+    }
+
+    public void testForceCompression() throws Exception {
+        setDevMode(true);
+
+        CompressTag tag = new CompressTag();
+        tag.setPageContext(pageContext);
+        tag.setForce("true");
+
+        StrutsBodyContent bc = new StrutsBodyContent(null);
+        bc.print("""
+                <form action="/" method="post">
+                <table class="wwFormTable"></table></form>
+                """
+        );
+
+        tag.doStartTag();
+        tag.setBodyContent(bc);
+        tag.doEndTag();
+
+        assertEquals("""
+                        <form action="/" method="post"><table 
class="wwFormTable"></table></form>
+                        """.stripTrailing(),
+                this.writer.toString());
+    }
+
+}
\ No newline at end of file
diff --git 
a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java 
b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
index d1e89a099..ffc706e0f 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java
@@ -19,13 +19,9 @@
 package org.apache.struts2.views.jsp.ui;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.struts2.StrutsConstants;
 import org.apache.struts2.dispatcher.PrepareOperations;
 import org.apache.struts2.views.jsp.AbstractUITagTest;
 
-import java.util.Collections;
-import java.util.Map;
-
 /**
  * Test case for {@link org.apache.struts2.components.Debug}.
  */
@@ -203,16 +199,4 @@ public class DebugTagTest extends AbstractUITagTest {
         PrepareOperations.clearDevModeOverride();  // Clear DevMode override. 
Avoid ThreadLocal side-effects if test thread re-used.
     }
 
-    private void setDevMode(final boolean devMode) {
-        
setStrutsConstant(Collections.singletonMap(StrutsConstants.STRUTS_DEVMODE, 
Boolean.toString(devMode)));
-    }
-
-    /**
-     * Overwrite the Struts Constant and reload container
-     */
-    @Override
-    protected void setStrutsConstant(final Map<String, String> 
overwritePropeties) {
-        super.setStrutsConstant(overwritePropeties);
-        stack.getActionContext().withContainer(container);
-    }
 }

Reply via email to