diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/CompletedStage.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/CompletedStage.java index 372fa9df306de..27d7ee9451ce7 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/CompletedStage.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/CompletedStage.java @@ -61,7 +61,7 @@ public boolean isFailure() { public T get() { if (exception != null) { - // Throw an exception if completed exceptionally + // Always wrap the original exception if completed exceptionally throw new TemplateException(exception); } return result; @@ -285,8 +285,12 @@ public CompletionStage whenComplete(BiConsumer Objects.requireNonNull(action).accept(result, exception); } catch (Throwable e) { if (exception == null) { + // "if this stage completed normally but the supplied action throws an exception, + // then the returned stage completes exceptionally with the supplied action's exception" return new CompletedStage<>(null, e); } + // if this stage completed exceptionally and the supplied action throws an exception, + // then the returned stage completes exceptionally with this stage's exception } return this; } diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatorImpl.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatorImpl.java index 3724328368b19..590f9617a5fe9 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatorImpl.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/EvaluatorImpl.java @@ -109,7 +109,7 @@ private CompletionStage resolveNamespace(EvalContext context, Resolution // Continue to the next part of the expression return resolveReference(false, r, parts, resolutionContext, expression, 1); } else if (strictRendering) { - throw propertyNotFound(r, expression); + return CompletedStage.failure(propertyNotFound(r, expression)); } return Results.notFound(context); } @@ -199,9 +199,9 @@ private CompletionStage resolve(EvalContextImpl evalContext, Iteratorhttps://github.com/quarkusio/quarkus/issues/44674. + */ +public class LetTimeoutTest { + + Engine engine = Engine.builder().addDefaults().build(); + + private static final Map DATA = Map.of( + "a", Map.of("b", Map.of())); + + @Test + void withDataFactoryMethod() { + TemplateInstance instance = engine.parse(""" + {#let b = a.b} + {c} + {/let} + """).data(DATA); + + assertThatThrownBy(instance::render) + .isInstanceOf(TemplateException.class) + .hasRootCauseMessage("Rendering error: Key \"c\" not found in the map with keys [a] in expression {c}"); + } + + @Test + void withInstanceThenDataForEachEntry() { + TemplateInstance instance = engine.parse(""" + {#let b=a.b} + {c} + {/let} + """).instance(); + for (var e : DATA.entrySet()) { + instance.data(e.getKey(), e.getValue()); + } + assertThatThrownBy(instance::render) + .isInstanceOf(TemplateException.class) + .hasRootCauseMessage( + "Rendering error: Key \"c\" not found in the template data map with keys [a] in expression {c}"); + } + + @Test + void withSet_withInstanceThenDataForEachEntry() { + TemplateInstance instance = engine.parse(""" + {#set b = a.b} + {c} + {/set} + """).instance(); + for (var e : DATA.entrySet()) { + instance.data(e.getKey(), e.getValue()); + } + assertThatThrownBy(instance::render) + .isInstanceOf(TemplateException.class) + .hasRootCauseMessage( + "Rendering error: Key \"c\" not found in the template data map with keys [a] in expression {c}"); + } + + @Test + void withLetWithoutEndTagwithInstanceThenDataForEachEntry() { + TemplateInstance instance = engine.parse(""" + {#let b = a.b} + {c} + """).instance(); + for (var e : DATA.entrySet()) { + instance.data(e.getKey(), e.getValue()); + } + assertThatThrownBy(instance::render) + .isInstanceOf(TemplateException.class) + .hasRootCauseMessage( + "Rendering error: Key \"c\" not found in the template data map with keys [a] in expression {c}"); + } +}