16
16
17
17
package org .springframework .ai .template .st ;
18
18
19
+ import static org .assertj .core .api .Assertions .*;
20
+
21
+ import java .io .ByteArrayOutputStream ;
22
+ import java .io .PrintStream ;
23
+ import java .nio .charset .StandardCharsets ;
19
24
import java .util .HashMap ;
20
25
import java .util .Map ;
21
26
22
27
import org .junit .jupiter .api .Test ;
23
-
28
+ import org . slf4j . LoggerFactory ;
24
29
import org .springframework .ai .template .ValidationMode ;
25
30
import org .springframework .test .util .ReflectionTestUtils ;
26
31
27
- import static org .assertj .core .api .Assertions .assertThat ;
28
- import static org .assertj .core .api .Assertions .assertThatThrownBy ;
32
+ import ch .qos .logback .classic .Level ;
33
+ import ch .qos .logback .classic .Logger ;
34
+ import ch .qos .logback .classic .spi .ILoggingEvent ;
35
+ import ch .qos .logback .core .read .ListAppender ;
29
36
30
37
/**
31
38
* Unit tests for {@link StTemplateRenderer}.
@@ -37,8 +44,8 @@ class StTemplateRendererTests {
37
44
@ Test
38
45
void shouldNotAcceptNullValidationMode () {
39
46
assertThatThrownBy (() -> StTemplateRenderer .builder ().validationMode (null ).build ())
40
- .isInstanceOf (IllegalArgumentException .class )
41
- .hasMessageContaining ("validationMode cannot be null" );
47
+ .isInstanceOf (IllegalArgumentException .class )
48
+ .hasMessageContaining ("validationMode cannot be null" );
42
49
}
43
50
44
51
@ Test
@@ -80,14 +87,14 @@ void shouldNotRenderEmptyTemplate() {
80
87
Map <String , Object > variables = new HashMap <>();
81
88
82
89
assertThatThrownBy (() -> renderer .apply ("" , variables )).isInstanceOf (IllegalArgumentException .class )
83
- .hasMessageContaining ("template cannot be null or empty" );
90
+ .hasMessageContaining ("template cannot be null or empty" );
84
91
}
85
92
86
93
@ Test
87
94
void shouldNotAcceptNullVariables () {
88
95
StTemplateRenderer renderer = StTemplateRenderer .builder ().build ();
89
96
assertThatThrownBy (() -> renderer .apply ("Hello!" , null )).isInstanceOf (IllegalArgumentException .class )
90
- .hasMessageContaining ("variables cannot be null" );
97
+ .hasMessageContaining ("variables cannot be null" );
91
98
}
92
99
93
100
@ Test
@@ -98,7 +105,7 @@ void shouldNotAcceptVariablesWithNullKeySet() {
98
105
variables .put (null , "Spring AI" );
99
106
100
107
assertThatThrownBy (() -> renderer .apply (template , variables )).isInstanceOf (IllegalArgumentException .class )
101
- .hasMessageContaining ("variables keys cannot be null" );
108
+ .hasMessageContaining ("variables keys cannot be null" );
102
109
}
103
110
104
111
@ Test
@@ -108,7 +115,7 @@ void shouldThrowExceptionForInvalidTemplateSyntax() {
108
115
variables .put ("name" , "Spring AI" );
109
116
110
117
assertThatThrownBy (() -> renderer .apply ("Hello {name!" , variables )).isInstanceOf (IllegalArgumentException .class )
111
- .hasMessageContaining ("The template string is not valid." );
118
+ .hasMessageContaining ("The template string is not valid." );
112
119
}
113
120
114
121
@ Test
@@ -118,9 +125,9 @@ void shouldThrowExceptionForMissingVariablesInThrowMode() {
118
125
variables .put ("greeting" , "Hello" );
119
126
120
127
assertThatThrownBy (() -> renderer .apply ("{greeting} {name}!" , variables ))
121
- .isInstanceOf (IllegalStateException .class )
122
- .hasMessageContaining (
123
- "Not all variables were replaced in the template. Missing variable names are: [name]" );
128
+ .isInstanceOf (IllegalStateException .class )
129
+ .hasMessageContaining (
130
+ "Not all variables were replaced in the template. Missing variable names are: [name]" );
124
131
}
125
132
126
133
@ Test
@@ -148,9 +155,9 @@ void shouldRenderWithoutValidationInNoneMode() {
148
155
@ Test
149
156
void shouldRenderWithCustomDelimiters () {
150
157
StTemplateRenderer renderer = StTemplateRenderer .builder ()
151
- .startDelimiterToken ('<' )
152
- .endDelimiterToken ('>' )
153
- .build ();
158
+ .startDelimiterToken ('<' )
159
+ .endDelimiterToken ('>' )
160
+ .build ();
154
161
Map <String , Object > variables = new HashMap <>();
155
162
variables .put ("name" , "Spring AI" );
156
163
@@ -162,9 +169,9 @@ void shouldRenderWithCustomDelimiters() {
162
169
@ Test
163
170
void shouldHandleSpecialCharactersAsDelimiters () {
164
171
StTemplateRenderer renderer = StTemplateRenderer .builder ()
165
- .startDelimiterToken ('$' )
166
- .endDelimiterToken ('$' )
167
- .build ();
172
+ .startDelimiterToken ('$' )
173
+ .endDelimiterToken ('$' )
174
+ .build ();
168
175
Map <String , Object > variables = new HashMap <>();
169
176
variables .put ("name" , "Spring AI" );
170
177
@@ -297,4 +304,34 @@ void shouldRenderTemplateWithBuiltInFunctions() {
297
304
assertThat (result ).isEqualTo ("Hello!" );
298
305
}
299
306
307
+ @ Test
308
+ void malformedTemplateShouldLogErrorViaSlf4j () {
309
+ Logger logger = (Logger ) LoggerFactory .getLogger (StTemplateRenderer .class );
310
+ ListAppender <ILoggingEvent > appender = new ListAppender <>();
311
+ appender .start ();
312
+ logger .addAppender (appender );
313
+
314
+ PrintStream originalErr = System .err ;
315
+ ByteArrayOutputStream err = new ByteArrayOutputStream ();
316
+ System .setErr (new PrintStream (err ));
317
+ try {
318
+ StTemplateRenderer renderer = StTemplateRenderer .builder ().build ();
319
+ Map <String , Object > variables = new HashMap <>();
320
+ variables .put ("name" , "Spring AI" );
321
+ assertThatThrownBy (() -> renderer .apply ("Hello {name!" , variables ))
322
+ .isInstanceOf (IllegalArgumentException .class );
323
+ }
324
+ finally {
325
+ System .setErr (originalErr );
326
+ logger .detachAppender (appender );
327
+ appender .stop ();
328
+ }
329
+
330
+ assertThat (appender .list ).isNotEmpty ();
331
+ ILoggingEvent event = appender .list .get (0 );
332
+ assertThat (event .getLevel ()).isEqualTo (Level .ERROR );
333
+ assertThat (event .getFormattedMessage ()).contains ("StringTemplate compile error" );
334
+ assertThat (err .toString (StandardCharsets .UTF_8 )).isEmpty ();
335
+ }
336
+
300
337
}
0 commit comments