1+ package org .slf4j .test ;
2+
3+ import org .junit .Test ;
4+ import org .slf4j .Logger ;
5+ import org .slf4j .event .Level ;
6+
7+ import java .io .IOException ;
8+ import java .io .OutputStream ;
9+ import java .util .ArrayList ;
10+ import java .util .List ;
11+
12+ import static org .junit .Assert .assertEquals ;
13+ import static org .junit .Assert .assertTrue ;
14+
15+
16+ public abstract class LoggerTestSuite {
17+
18+ public static class ListAppendingOutputStream extends OutputStream {
19+ private final StringBuilder word = new StringBuilder ();
20+ private int index = 0 ;
21+ private final List <String > list ;
22+
23+ private ListAppendingOutputStream (List <String > list ) {this .list = list ;}
24+
25+
26+ @ Override
27+ public void write (int b ) throws IOException {
28+ word .append ((char ) b );
29+ }
30+
31+ @ Override
32+ public void flush () {
33+ list .add (word .toString ());
34+ word .delete (0 , word .length ());
35+ index ++;
36+ }
37+ }
38+
39+ private ListAppendingOutputStream prepareSink (List <String > source ) {
40+ return new ListAppendingOutputStream (source );
41+
42+ }
43+
44+ @ Test
45+ public void testTrace () {
46+ ArrayList <String > loggingEvents = new ArrayList <>();
47+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .TRACE );
48+
49+ assertTrue ("Trace level should be enabled for this test" , configuredLogger .isTraceEnabled ());
50+ configuredLogger .trace ("Simple trace message" );
51+
52+ assertEquals ("Trace message should've been captured" , 1 , loggingEvents .size ());
53+ assertTrue ("Message should be logged in trace level" , isTraceMessage (loggingEvents .get (0 )));
54+ assertEquals ("Supplied trace message wasn't found in the log" ,
55+ "Simple trace message" ,
56+ extractMessage (loggingEvents .get (0 )));
57+
58+ loggingEvents .clear ();
59+
60+ configuredLogger .debug ("Simple debug message" );
61+ configuredLogger .info ("Simple info message" );
62+ configuredLogger .warn ("Simple warn message" );
63+ configuredLogger .error ("Simple error message" );
64+ assertEquals ("The other levels should have been captured" , 4 , loggingEvents .size ());
65+
66+ }
67+
68+ @ Test
69+ public void testDebug () {
70+ ArrayList <String > loggingEvents = new ArrayList <>();
71+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .DEBUG );
72+
73+ configuredLogger .trace ("Simple trace message" );
74+ assertEquals ("Lower levels should have been ignored" , 0 , loggingEvents .size ());
75+
76+ assertTrue ("Debug level should be enabled for this test" , configuredLogger .isDebugEnabled ());
77+ configuredLogger .debug ("Simple debug message" );
78+
79+ assertEquals ("Debug message should've been captured" , 1 , loggingEvents .size ());
80+ assertTrue ("Message should be logged in debug level" , isDebugMessage (loggingEvents .get (0 )));
81+ assertEquals ("Supplied debug message wasn't found in the log" ,
82+ "Simple debug message" ,
83+ extractMessage (loggingEvents .get (0 )));
84+
85+ loggingEvents .clear ();
86+
87+ configuredLogger .info ("Simple info message" );
88+ configuredLogger .warn ("Simple warn message" );
89+ configuredLogger .error ("Simple error message" );
90+ assertEquals ("The other levels should have been captured" , 3 , loggingEvents .size ());
91+ }
92+
93+
94+ @ Test
95+ public void testInfo () {
96+ ArrayList <String > loggingEvents = new ArrayList <>();
97+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .INFO );
98+
99+ configuredLogger .trace ("Simple trace message" );
100+ configuredLogger .debug ("Simple debug message" );
101+ assertEquals ("Lower levels should have been ignored" , 0 , loggingEvents .size ());
102+
103+ assertTrue ("Info level should be enabled for this test" , configuredLogger .isInfoEnabled ());
104+ configuredLogger .info ("Simple info message" );
105+
106+ assertEquals ("Info message should've been captured" , 1 , loggingEvents .size ());
107+ assertTrue ("Message should be logged in debug level" , isInfoMessage (loggingEvents .get (0 )));
108+ assertEquals ("Supplied info message wasn't found in the log" ,
109+ "Simple info message" ,
110+ extractMessage (loggingEvents .get (0 )));
111+
112+ loggingEvents .clear ();
113+
114+ configuredLogger .warn ("Simple warn message" );
115+ configuredLogger .error ("Simple error message" );
116+ assertEquals ("The other levels should have been captured" , 2 , loggingEvents .size ());
117+ }
118+
119+ @ Test
120+ public void testWarn () {
121+ ArrayList <String > loggingEvents = new ArrayList <>();
122+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .WARN );
123+
124+ configuredLogger .trace ("Simple trace message" );
125+ configuredLogger .debug ("Simple debug message" );
126+ configuredLogger .info ("Simple info message" );
127+ assertEquals ("Lower levels should have been ignored" , 0 , loggingEvents .size ());
128+
129+ assertTrue ("Warn level should be enabled for this test" , configuredLogger .isWarnEnabled ());
130+ configuredLogger .warn ("Simple warn message" );
131+
132+ assertEquals ("Warn message should've been captured" , 1 , loggingEvents .size ());
133+ assertTrue ("Message should be logged in warn level" , isWarnMessage (loggingEvents .get (0 )));
134+ assertEquals ("Supplied warn message wasn't found in the log" ,
135+ "Simple warn message" ,
136+ extractMessage (loggingEvents .get (0 )));
137+
138+ loggingEvents .clear ();
139+
140+ configuredLogger .error ("Simple error message" );
141+ assertEquals ("The other levels should have been captured" , 1 , loggingEvents .size ());
142+ }
143+
144+ @ Test
145+ public void testError () {
146+ ArrayList <String > loggingEvents = new ArrayList <>();
147+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .ERROR );
148+
149+ configuredLogger .trace ("Simple trace message" );
150+ configuredLogger .debug ("Simple debug message" );
151+ configuredLogger .info ("Simple info message" );
152+ configuredLogger .warn ("Simple warn message" );
153+ assertEquals ("Lower levels should have been ignored" , 0 , loggingEvents .size ());
154+
155+ assertTrue ("Error level should be enabled for this test" , configuredLogger .isErrorEnabled ());
156+ configuredLogger .error ("Simple error message" );
157+
158+ assertEquals ("Error message should've been captured" , 1 , loggingEvents .size ());
159+ assertTrue ("Message should be logged in error level" , isErrorMessage (loggingEvents .get (0 )));
160+ assertEquals ("Supplied error message wasn't found in the log" ,
161+ "Simple error message" ,
162+ extractMessage (loggingEvents .get (0 )));
163+ }
164+
165+ @ Test
166+ public void testFormatting () {
167+ ArrayList <String > loggingEvents = new ArrayList <>();
168+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .INFO );
169+
170+ configuredLogger .info ("Some {} string" , "formatted" );
171+ assertEquals ("The formatted message should've been captured" , 1 , loggingEvents .size ());
172+ assertEquals ("Message should've been formatted" , "Some formatted string" , extractMessage (loggingEvents .get (0 )));
173+ }
174+
175+ @ Test
176+ public void testException () {
177+ ArrayList <String > loggingEvents = new ArrayList <>();
178+ Logger configuredLogger = createLogger (prepareSink (loggingEvents ), Level .INFO );
179+
180+ Exception exception = new RuntimeException ("My error" );
181+
182+ configuredLogger .info ("Logging with an exception" , exception );
183+ assertEquals ("The formatted message should've been captured" , 1 , loggingEvents .size ());
184+ assertEquals ("Message should've been formatted" ,
185+ "My error" ,
186+ extractExceptionMessage (loggingEvents .get (0 )));
187+
188+ assertEquals ("Message should've been formatted" ,
189+ "java.lang.RuntimeException" ,
190+ extractExceptionType (loggingEvents .get (0 )));
191+ }
192+
193+
194+ /**
195+ * Allows tests to check whether the log message contains a trace message.
196+ * Override if needed.
197+ * @param message String containing the full log message
198+ * @return whether it is a trace message or not
199+ */
200+ protected boolean isTraceMessage (String message ) {
201+ return message .toLowerCase ().contains ("trace" );
202+ }
203+
204+ /**
205+ * Allows tests to check whether the log message contains a debug message.
206+ * Override if needed.
207+ * @param message String containing the full log message
208+ * @return whether it is a debug message or not
209+ */
210+ protected boolean isDebugMessage (String message ) {
211+ return message .toLowerCase ().contains ("debug" );
212+ }
213+
214+ /**
215+ * Allows tests to check whether the log message contains an info message.
216+ * Override if needed.
217+ * @param message String containing the full log message
218+ * @return whether it is an info message or not
219+ */
220+ protected boolean isInfoMessage (String message ) {
221+ return message .toLowerCase ().contains ("info" );
222+ }
223+
224+ /**
225+ * Allows tests to check whether the log message contains a warn message.
226+ * Override if needed.
227+ * @param message String containing the full log message
228+ * @return whether it is a warn message or not
229+ */
230+ protected boolean isWarnMessage (String message ) {
231+ return message .toLowerCase ().contains ("warn" );
232+ }
233+
234+ /**
235+ * Allows tests to check whether the log message contains an error message.
236+ * Override if needed.
237+ * @param message String containing the full log message
238+ * @return whether it is an error message or not
239+ */
240+ protected boolean isErrorMessage (String message ) {
241+ return message .toLowerCase ().contains ("error" );
242+ }
243+
244+ /**
245+ * Extracts only the part of the log string that should represent the `message` string.
246+ * @param message the full log message
247+ * @return only the supplied message
248+ */
249+ public abstract String extractMessage (String message );
250+
251+ /**
252+ * Extracts only the part of the log string that should represent the supplied exception message, if any.
253+ * @param message the full log message
254+ * @return only the supplied exception message
255+ */
256+ public abstract String extractExceptionMessage (String message );
257+
258+ /**
259+ * Extracts only the part of the log string that should represent the supplied exception type.
260+ * @param message the full log message
261+ * @return only the supplied exception type name
262+ */
263+ public abstract String extractExceptionType (String message );
264+
265+ /**
266+ * Configures the logger for running the tests.
267+ * @param outputStream The output stream for logs to be written to
268+ * @param level The expected level the tests will run for this logger
269+ * @return a configured logger able to run the tests
270+ */
271+ public abstract Logger createLogger (ListAppendingOutputStream outputStream , Level level );
272+
273+ }
0 commit comments