Repository: quarkusio/quarkus
Issue: Qute - computed section helpers used during validation don't play well with {#include}

As a result section blocks  in an `{#include}` section must also define an end tag which is normally optional.

Changed files:
independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineImpl.java
extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/include/IncludeTest.java
independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java
independent-projects/qute/core/src/test/java/io/quarkus/qute/IncludeTest.java

diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/include/IncludeTest.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/include/IncludeTest.java
index ce75ef68f87..b0c80dd229f 100644
--- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/include/IncludeTest.java
+++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/include/IncludeTest.java
@@ -18,15 +18,16 @@ public class IncludeTest {
     @RegisterExtension
     static final QuarkusUnitTest config = new QuarkusUnitTest()
             .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
-                    .addAsResource(new StringAsset("{#insert item}NOK{/}"), "templates/base.html")
-                    .addAsResource(new StringAsset("{#include base}{#item}OK{/}{/}"), "templates/detail.html"));
+                    .addAsResource(new StringAsset("{#insert item}NOK{/}:{#insert foo}default foo{/}"), "templates/base.html")
+                    .addAsResource(new StringAsset("{#include base}{#item}OK{/}{#foo}my foo{/include}"),
+                            "templates/detail.html"));
 
     @Inject
     Template detail;
 
     @Test
     public void testIncludeSection() {
-        assertEquals("OK", detail.render());
+        assertEquals("OK:my foo", detail.render());
     }
 
 }
diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineImpl.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineImpl.java
index 385c0b097df..0dfdf59ccca 100644
--- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineImpl.java
+++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EngineImpl.java
@@ -44,7 +44,7 @@ class EngineImpl implements Engine {
     EngineImpl(Map<String, SectionHelperFactory<?>> sectionHelperFactories, List<ValueResolver> valueResolvers,
             List<NamespaceResolver> namespaceResolvers, List<TemplateLocator> locators,
             List<ResultMapper> resultMappers, Function<String, SectionHelperFactory<?>> sectionHelperFunc) {
-        this.sectionHelperFactories = new HashMap<>(sectionHelperFactories);
+        this.sectionHelperFactories = Collections.unmodifiableMap(new HashMap<>(sectionHelperFactories));
         this.valueResolvers = sort(valueResolvers);
         this.namespaceResolvers = ImmutableList.copyOf(namespaceResolvers);
         this.evaluator = new EvaluatorImpl(this.valueResolvers);
@@ -82,7 +82,7 @@ public SectionHelperFactory<?> getSectionHelperFactory(String name) {
     }
 
     public Map<String, SectionHelperFactory<?>> getSectionHelperFactories() {
-        return Collections.unmodifiableMap(sectionHelperFactories);
+        return sectionHelperFactories;
     }
 
     public List<ValueResolver> getValueResolvers() {
diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java
index c91eb18173c..6eef6d20bf3 100644
--- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java
+++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java
@@ -263,7 +263,7 @@ private void flushTag() {
             // Add a section block if the section name matches a section block label or does not map to any section helper and the last section treats unknown subsections as blocks
             if (lastSection != null && lastSection.factory.getBlockLabels().contains(sectionName)
                     || (lastSection.factory.treatUnknownSectionsAsBlocks()
-                            && engine.getSectionHelperFactory(sectionName) == null)) {
+                            && !engine.getSectionHelperFactories().containsKey(sectionName))) {
 
                 // Section block
                 if (!ignoreContent) {
diff --git a/independent-projects/qute/core/src/test/java/io/quarkus/qute/IncludeTest.java b/independent-projects/qute/core/src/test/java/io/quarkus/qute/IncludeTest.java
index cf87f46fdf5..147cb0de2a8 100644
--- a/independent-projects/qute/core/src/test/java/io/quarkus/qute/IncludeTest.java
+++ b/independent-projects/qute/core/src/test/java/io/quarkus/qute/IncludeTest.java
@@ -50,4 +50,12 @@ public void testIncludeSimpleData() {
                 engine.parse("{#include detail/}").render(data));
     }
 
+    @Test
+    public void testOptionalBlockEndTags() {
+        Engine engine = Engine.builder().addDefaults().build();
+        engine.putTemplate("super", engine.parse("{#insert header}header{/}:{#insert footer /}"));
+        assertEquals("super header:super footer",
+                engine.parse("{#include super}{#header}super header{#footer}super footer{/include}").render());
+    }
+
 }