View Javadoc
1   package org.djutils.logger;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertNotNull;
5   import static org.junit.Assert.assertNull;
6   import static org.junit.Assert.assertTrue;
7   
8   import java.lang.reflect.InvocationTargetException;
9   import java.lang.reflect.Method;
10  import java.util.EnumSet;
11  import java.util.LinkedHashSet;
12  import java.util.Set;
13  import java.util.function.BooleanSupplier;
14  
15  import org.junit.Test;
16  import org.pmw.tinylog.Configuration;
17  import org.pmw.tinylog.Level;
18  import org.pmw.tinylog.LogEntry;
19  import org.pmw.tinylog.writers.ConsoleWriter;
20  import org.pmw.tinylog.writers.LogEntryValue;
21  import org.pmw.tinylog.writers.Writer;
22  
23  /**
24   * LoggerTest.java. <br>
25   * <br>
26   * Copyright (c) 2003-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
27   * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
28   * source code and binary code of this software is proprietary information of Delft University of Technology.
29   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
30   */
31  public class LoggerTest
32  {
33      /** Records last output of logger. */
34      private StringWriter stringWriter = new StringWriter();
35  
36      /**
37       * Helper method.
38       * @param expectedMessage String; expected subString in result of stringWriter. If null; there should be no message recorded
39       *            in the stringWriter.
40       */
41      private void verifyLogMessage(final String expectedMessage)
42      {
43          String actualMessage = this.stringWriter.getResult();
44          if (expectedMessage != null)
45          {
46              assertNotNull(actualMessage);
47              assertTrue(actualMessage.contains(expectedMessage));
48          }
49          else
50          {
51              assertNull(actualMessage);
52          }
53          this.stringWriter.clear();
54      }
55  
56      /**
57       * (Temporary) remove the ConsoleWriter to avoid lots of clutter on the screen during the test.
58       */
59      private void removeConsoleWriter()
60      {
61          Writer consoleWriter = null;
62          for (Writer writer : CategoryLogger.getWriters())
63          {
64              if (writer instanceof ConsoleWriter)
65              {
66                  consoleWriter = writer;
67              }
68          }
69          if (consoleWriter != null)
70          {
71              CategoryLogger.removeWriter(consoleWriter);
72          }
73      }
74  
75      /**
76       * Add the ConsoleWriter again.
77       */
78      private void addConsoleWriter()
79      {
80          CategoryLogger.addWriter(new ConsoleWriter());
81      }
82  
83      /**
84       * Test whether Logger works correctly.
85       */
86      @Test
87      public final void loggerTest()
88      {
89          removeConsoleWriter();
90          CategoryLogger.addWriter(this.stringWriter);
91          CategoryLogger.setAllLogLevel(Level.DEBUG);
92          String testMessage = "test message";
93          CategoryLogger.always().error(testMessage);
94          verifyLogMessage(testMessage);
95          CategoryLogger.when(false).error(testMessage);
96          verifyLogMessage(null);
97          CategoryLogger.when(true).error(testMessage);
98          verifyLogMessage(testMessage);
99  
100         LogCategory testLogCategory = new LogCategory("TEST");
101         CategoryLogger.removeLogCategory(LogCategory.ALL);
102         CategoryLogger.filter(testLogCategory).info(testMessage);
103         verifyLogMessage(null);
104         CategoryLogger.addLogCategory(testLogCategory);
105         CategoryLogger.filter(testLogCategory).info(testMessage);
106         verifyLogMessage(testMessage);
107         CategoryLogger.removeLogCategory(testLogCategory);
108         CategoryLogger.filter(testLogCategory).info(testMessage);
109         verifyLogMessage(null);
110         CategoryLogger.filter(LogCategory.ALL).info(testMessage);
111         verifyLogMessage(null);
112         CategoryLogger.addLogCategory(LogCategory.ALL);
113         CategoryLogger.filter(LogCategory.ALL).info(testMessage);
114         verifyLogMessage(testMessage);
115         CategoryLogger.always().info(testMessage);
116         verifyLogMessage(testMessage);
117 
118         CategoryLogger.removeLogCategory(LogCategory.ALL);
119         CategoryLogger.filter(testLogCategory).when(false).info(testMessage);
120         verifyLogMessage(null);
121         CategoryLogger.addLogCategory(testLogCategory);
122         CategoryLogger.filter(testLogCategory).when(false).info(testMessage);
123         verifyLogMessage(null);
124         CategoryLogger.removeLogCategory(testLogCategory);
125         CategoryLogger.filter(testLogCategory).when(false).info(testMessage);
126         verifyLogMessage(null);
127         CategoryLogger.filter(LogCategory.ALL).when(false).info(testMessage);
128         verifyLogMessage(null);
129         CategoryLogger.addLogCategory(LogCategory.ALL);
130         CategoryLogger.filter(LogCategory.ALL).when(false).info(testMessage);
131         verifyLogMessage(null);
132         CategoryLogger.always().when(false).info(testMessage);
133         verifyLogMessage(null);
134 
135         CategoryLogger.removeLogCategory(LogCategory.ALL);
136         CategoryLogger.filter(testLogCategory).when(true).info(testMessage);
137         verifyLogMessage(null);
138         CategoryLogger.addLogCategory(testLogCategory);
139         CategoryLogger.filter(testLogCategory).when(true).info(testMessage);
140         verifyLogMessage(testMessage);
141         CategoryLogger.removeLogCategory(testLogCategory);
142         CategoryLogger.filter(testLogCategory).when(true).info(testMessage);
143         verifyLogMessage(null);
144         CategoryLogger.filter(LogCategory.ALL).when(true).info(testMessage);
145         verifyLogMessage(null);
146         CategoryLogger.addLogCategory(LogCategory.ALL);
147         CategoryLogger.filter(LogCategory.ALL).when(true).info(testMessage);
148         verifyLogMessage(testMessage);
149         CategoryLogger.always().when(true).info(testMessage);
150         verifyLogMessage(testMessage);
151 
152         // test when(...) with booleanSupplier
153         BooleanSupplier trueSupplier = new BooleanSupplier()
154         {
155             @Override
156             public boolean getAsBoolean()
157             {
158                 return true;
159             }
160         };
161         BooleanSupplier falseSupplier = new BooleanSupplier()
162         {
163             @Override
164             public boolean getAsBoolean()
165             {
166                 return false;
167             }
168         };
169         CategoryLogger.when(trueSupplier).info(testMessage);
170         verifyLogMessage(testMessage);
171         CategoryLogger.when(trueSupplier).when(true).info(testMessage);
172         verifyLogMessage(testMessage);
173         CategoryLogger.when(trueSupplier).when(trueSupplier).info(testMessage);
174         verifyLogMessage(testMessage);
175         CategoryLogger.when(trueSupplier).when(falseSupplier).when(trueSupplier).info(testMessage);
176         verifyLogMessage(null);
177         CategoryLogger.when(falseSupplier).info(testMessage);
178         verifyLogMessage(null);
179         CategoryLogger.when(trueSupplier).when(false).info(testMessage);
180         verifyLogMessage(null);
181         CategoryLogger.when(false).when(true).info(testMessage);
182         verifyLogMessage(null);
183         CategoryLogger.when(false).when(trueSupplier).info(testMessage);
184         verifyLogMessage(null);
185         CategoryLogger.when(false).when(falseSupplier).info(testMessage);
186         verifyLogMessage(null);
187 
188         CategoryLogger.removeWriter(this.stringWriter);
189         addConsoleWriter();
190     }
191 
192     /**
193      * Test varying the logging level for the AllLogLevel levels.
194      * @throws SecurityException when a logging method can not be found (should not happen)
195      * @throws NoSuchMethodException when a logging method can not be found (should not happen)
196      * @throws InvocationTargetException when calling a logging method through reflection fails (should not happen)
197      * @throws IllegalArgumentException when calling a logging method through reflection fails (should not happen)
198      * @throws IllegalAccessException when calling a logging method through reflection fails (should not happen)
199      */
200     @Test
201     public void testAllLogLevels() throws NoSuchMethodException, SecurityException, IllegalAccessException,
202             IllegalArgumentException, InvocationTargetException
203     {
204         CategoryLogger.addWriter(this.stringWriter);
205         CategoryLogger.setAllLogLevel(Level.DEBUG);
206         removeConsoleWriter();
207         String[] methodNames = new String[] {"trace", "debug", "info", "warn", "error"};
208         Level[] logLevels = new Level[] {Level.TRACE, Level.DEBUG, Level.INFO, Level.WARNING, Level.ERROR, Level.OFF};
209         for (int levelIndex = 0; levelIndex < logLevels.length; levelIndex++)
210         {
211             CategoryLogger.setAllLogLevel(logLevels[levelIndex]);
212             for (int methodIndex = 0; methodIndex < methodNames.length; methodIndex++)
213             {
214                 // String; no additional arguments
215                 String message = "test message";
216                 String methodName = methodNames[methodIndex];
217                 Method method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, String.class);
218                 method.invoke(CategoryLogger.always(), message);
219                 if (methodIndex < levelIndex)
220                 {
221                     verifyLogMessage(null);
222                 }
223                 else
224                 {
225                     verifyLogMessage(message);
226                 }
227                 method.invoke(CategoryLogger.when(false), message);
228                 verifyLogMessage(null);
229 
230                 // Object (no arguments - of course)
231                 method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Object.class);
232                 method.invoke(CategoryLogger.always(), message);
233                 if (methodIndex < levelIndex)
234                 {
235                     verifyLogMessage(null);
236                 }
237                 else
238                 {
239                     verifyLogMessage(message);
240                 }
241                 method.invoke(CategoryLogger.when(false), message);
242                 verifyLogMessage(null);
243 
244                 // Throwable
245                 String exceptionMessage = "ExceptionMessage";
246                 Exception exception = new Exception(exceptionMessage);
247                 method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Throwable.class);
248                 method.invoke(CategoryLogger.always(), exception);
249                 if (methodIndex < levelIndex)
250                 {
251                     verifyLogMessage(null);
252                 }
253                 else
254                 {
255                     verifyLogMessage(exceptionMessage);
256                 }
257                 method.invoke(CategoryLogger.when(false), exception);
258                 verifyLogMessage(null);
259 
260                 // Throwable with message
261                 String extraMessage = "Extra Message";
262                 method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Throwable.class, String.class);
263                 method.invoke(CategoryLogger.always(), exception, extraMessage);
264                 if (methodIndex < levelIndex)
265                 {
266                     verifyLogMessage(null);
267                 }
268                 else
269                 {
270                     assertTrue(this.stringWriter.getResult().contains(extraMessage));
271                     verifyLogMessage(exceptionMessage);
272                 }
273                 method.invoke(CategoryLogger.when(false), exception, extraMessage);
274                 verifyLogMessage(null);
275 
276                 // String, with arguments
277                 message = "test message arg1={}, arg2={}";
278                 int arg1 = 1;
279                 String arg2 = "2";
280                 String expectedMessage = message.replaceFirst("\\{\\}", String.valueOf(arg1)).replaceFirst("\\{\\}", arg2);
281                 method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, String.class, Object[].class);
282                 method.invoke(CategoryLogger.always(), message, new Object[] {arg1, arg2});
283                 if (methodIndex < levelIndex)
284                 {
285                     verifyLogMessage(null);
286                 }
287                 else
288                 {
289                     verifyLogMessage(expectedMessage);
290                 }
291                 method.invoke(CategoryLogger.when(false), message, new Object[] {arg1, arg2});
292                 verifyLogMessage(null);
293 
294                 // Throwable with message and arguments
295                 method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Throwable.class, String.class,
296                         Object[].class);
297                 method.invoke(CategoryLogger.always(), exception, message, new Object[] {arg1, arg2});
298                 if (methodIndex < levelIndex)
299                 {
300                     verifyLogMessage(null);
301                 }
302                 else
303                 {
304                     assertTrue(this.stringWriter.getResult().contains(exceptionMessage));
305                     verifyLogMessage(expectedMessage);
306                 }
307                 method.invoke(CategoryLogger.when(false), exception, message, new Object[] {arg1, arg2});
308                 verifyLogMessage(null);
309 
310             }
311         }
312         addConsoleWriter();
313         CategoryLogger.setAllLogLevel(Level.DEBUG);
314         CategoryLogger.removeWriter(this.stringWriter);
315     }
316 
317     /**
318      * Test varying the logging level per writer, when AllLogLevels is different. The way CategoryLogger has been set up, the
319      * Writer's log level should always take precedence of the default log level, independent on the relative ranking of the
320      * writer's log level and the default log level.
321      * @throws SecurityException when a logging method can not be found (should not happen)
322      * @throws NoSuchMethodException when a logging method can not be found (should not happen)
323      * @throws InvocationTargetException when calling a logging method through reflection fails (should not happen)
324      * @throws IllegalArgumentException when calling a logging method through reflection fails (should not happen)
325      * @throws IllegalAccessException when calling a logging method through reflection fails (should not happen)
326      */
327     @Test
328     public void testWriterLogLevels() throws NoSuchMethodException, SecurityException, IllegalAccessException,
329             IllegalArgumentException, InvocationTargetException
330     {
331         CategoryLogger.addWriter(this.stringWriter);
332         CategoryLogger.setAllLogLevel(Level.DEBUG);
333         removeConsoleWriter();
334         String[] methodNames = new String[] {"trace", "debug", "info", "warn", "error"};
335         Level[] logLevels = new Level[] {Level.TRACE, Level.DEBUG, Level.INFO, Level.WARNING, Level.ERROR, Level.OFF};
336         for (int allLevelIndex = 0; allLevelIndex < logLevels.length; allLevelIndex++)
337         {
338             for (int writerLevelIndex = 0; writerLevelIndex < logLevels.length; writerLevelIndex++)
339             {
340                 CategoryLogger.setAllLogLevel(logLevels[allLevelIndex]);
341                 CategoryLogger.setLogLevel(this.stringWriter, logLevels[writerLevelIndex]);
342                 for (int methodIndex = 0; methodIndex < methodNames.length; methodIndex++)
343                 {
344                     // String; no additional arguments
345                     String message = "test message";
346                     String methodName = methodNames[methodIndex];
347                     Method method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, String.class);
348                     method.invoke(CategoryLogger.always(), message);
349                     if (methodIndex < writerLevelIndex)
350                     {
351                         verifyLogMessage(null);
352                     }
353                     else
354                     {
355                         verifyLogMessage(message);
356                     }
357                     method.invoke(CategoryLogger.when(false), message);
358                     verifyLogMessage(null);
359 
360                     // Object (no arguments - of course)
361                     method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Object.class);
362                     method.invoke(CategoryLogger.always(), message);
363                     if (methodIndex < writerLevelIndex)
364                     {
365                         verifyLogMessage(null);
366                     }
367                     else
368                     {
369                         verifyLogMessage(message);
370                     }
371                     method.invoke(CategoryLogger.when(false), message);
372                     verifyLogMessage(null);
373 
374                     // Throwable
375                     String exceptionMessage = "ExceptionMessage";
376                     Exception exception = new Exception(exceptionMessage);
377                     method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Throwable.class);
378                     method.invoke(CategoryLogger.always(), exception);
379                     if (methodIndex < writerLevelIndex)
380                     {
381                         verifyLogMessage(null);
382                     }
383                     else
384                     {
385                         verifyLogMessage(exceptionMessage);
386                     }
387                     method.invoke(CategoryLogger.when(false), exception);
388                     verifyLogMessage(null);
389 
390                     // Throwable with message
391                     String extraMessage = "Extra Message";
392                     method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Throwable.class,
393                             String.class);
394                     method.invoke(CategoryLogger.always(), exception, extraMessage);
395                     if (methodIndex < writerLevelIndex)
396                     {
397                         verifyLogMessage(null);
398                     }
399                     else
400                     {
401                         assertTrue(this.stringWriter.getResult().contains(extraMessage));
402                         verifyLogMessage(exceptionMessage);
403                     }
404                     method.invoke(CategoryLogger.when(false), exception, extraMessage);
405                     verifyLogMessage(null);
406 
407                     // String, with arguments
408                     message = "test message arg1={}, arg2={}";
409                     int arg1 = 1;
410                     String arg2 = "2";
411                     String expectedMessage = message.replaceFirst("\\{\\}", String.valueOf(arg1)).replaceFirst("\\{\\}", arg2);
412                     method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, String.class,
413                             Object[].class);
414                     method.invoke(CategoryLogger.always(), message, new Object[] {arg1, arg2});
415                     if (methodIndex < writerLevelIndex)
416                     {
417                         verifyLogMessage(null);
418                     }
419                     else
420                     {
421                         verifyLogMessage(expectedMessage);
422                     }
423                     method.invoke(CategoryLogger.when(false), message, new Object[] {arg1, arg2});
424                     verifyLogMessage(null);
425 
426                     // Throwable with message and arguments
427                     method = CategoryLogger.DELEGATE_LOGGER.getClass().getDeclaredMethod(methodName, Throwable.class,
428                             String.class, Object[].class);
429                     method.invoke(CategoryLogger.always(), exception, message, new Object[] {arg1, arg2});
430                     if (methodIndex < writerLevelIndex)
431                     {
432                         verifyLogMessage(null);
433                     }
434                     else
435                     {
436                         assertTrue(this.stringWriter.getResult().contains(exceptionMessage));
437                         verifyLogMessage(expectedMessage);
438                     }
439                     method.invoke(CategoryLogger.when(false), exception, message, new Object[] {arg1, arg2});
440                     verifyLogMessage(null);
441 
442                 }
443             }
444         }
445         addConsoleWriter();
446         CategoryLogger.setAllLogLevel(Level.DEBUG);
447         CategoryLogger.removeWriter(this.stringWriter);
448     }
449 
450     /**
451      * Filter with multiple categories.
452      */
453     @Test
454     public void testFilterOnCategories()
455     {
456         removeConsoleWriter();
457         String message = "Test message";
458         CategoryLogger.setAllLogLevel(Level.DEBUG);
459         CategoryLogger.addWriter(this.stringWriter);
460         LogCategory one = new LogCategory("ONE");
461         LogCategory two = new LogCategory("TWO");
462         LogCategory three = new LogCategory("THREE");
463         Set<LogCategory> set0 = setOf();
464         Set<LogCategory> set1 = setOf(one);
465         Set<LogCategory> set12 = setOf(one, two);
466         Set<LogCategory> set123 = setOf(one, two, three);
467         Set<LogCategory> set23 = setOf(two, three);
468         Set<LogCategory> set3 = setOf(three);
469 
470         CategoryLogger.setLogCategories();
471         CategoryLogger.always().info(message);
472         verifyLogMessage(message);
473         CategoryLogger.filter().info(message);
474         verifyLogMessage(null);
475         CategoryLogger.filter(one).info(message);
476         verifyLogMessage(null);
477         CategoryLogger.filter(one, two).info(message);
478         verifyLogMessage(null);
479         CategoryLogger.filter(one, two, three).info(message);
480         verifyLogMessage(null);
481 
482         CategoryLogger.filter(set0).info(message);
483         verifyLogMessage(null);
484         CategoryLogger.filter(set1).info(message);
485         verifyLogMessage(null);
486         CategoryLogger.filter(set12).info(message);
487         verifyLogMessage(null);
488         CategoryLogger.filter(set123).info(message);
489         verifyLogMessage(null);
490 
491         CategoryLogger.setLogCategories(one);
492         CategoryLogger.always().info(message);
493         verifyLogMessage(message);
494         CategoryLogger.filter().info(message);
495         verifyLogMessage(null);
496         CategoryLogger.filter(one).info(message);
497         verifyLogMessage(message);
498         CategoryLogger.filter(one, two).info(message);
499         verifyLogMessage(message);
500         CategoryLogger.filter(one, two, three).info(message);
501         verifyLogMessage(message);
502         CategoryLogger.filter(two, three).info(message);
503         verifyLogMessage(null);
504         CategoryLogger.filter(three).info(message);
505         verifyLogMessage(null);
506 
507         CategoryLogger.filter(set0).info(message);
508         verifyLogMessage(null);
509         CategoryLogger.filter(set1).info(message);
510         verifyLogMessage(message);
511         CategoryLogger.filter(set12).info(message);
512         verifyLogMessage(message);
513         CategoryLogger.filter(set123).info(message);
514         verifyLogMessage(message);
515         CategoryLogger.filter(set23).info(message);
516         verifyLogMessage(null);
517         CategoryLogger.filter(set3).info(message);
518         verifyLogMessage(null);
519 
520         CategoryLogger.setLogCategories(one, two);
521         CategoryLogger.always().info(message);
522         verifyLogMessage(message);
523         CategoryLogger.filter().info(message);
524         verifyLogMessage(null);
525         CategoryLogger.filter(one).info(message);
526         verifyLogMessage(message);
527         CategoryLogger.filter(one, two).info(message);
528         verifyLogMessage(message);
529         CategoryLogger.filter(one, two, three).info(message);
530         verifyLogMessage(message);
531         CategoryLogger.filter(two, three).info(message);
532         verifyLogMessage(message);
533         CategoryLogger.filter(three).info(message);
534         verifyLogMessage(null);
535 
536         CategoryLogger.filter(set0).info(message);
537         verifyLogMessage(null);
538         CategoryLogger.filter(set1).info(message);
539         verifyLogMessage(message);
540         CategoryLogger.filter(set12).info(message);
541         verifyLogMessage(message);
542         CategoryLogger.filter(set123).info(message);
543         verifyLogMessage(message);
544         CategoryLogger.filter(set23).info(message);
545         verifyLogMessage(message);
546         CategoryLogger.filter(set3).info(message);
547         verifyLogMessage(null);
548 
549         CategoryLogger.setLogCategories(one, LogCategory.ALL);
550         CategoryLogger.always().info(message);
551         verifyLogMessage(message);
552         CategoryLogger.filter().info(message);
553         verifyLogMessage(message);
554         CategoryLogger.filter(one).info(message);
555         verifyLogMessage(message);
556         CategoryLogger.filter(one, two).info(message);
557         verifyLogMessage(message);
558         CategoryLogger.filter(one, two, three).info(message);
559         verifyLogMessage(message);
560         CategoryLogger.filter(two, three).info(message);
561         verifyLogMessage(message);
562         CategoryLogger.filter(three).info(message);
563         verifyLogMessage(message);
564 
565         CategoryLogger.filter(set0).info(message);
566         verifyLogMessage(message);
567         CategoryLogger.filter(set1).info(message);
568         verifyLogMessage(message);
569         CategoryLogger.filter(set12).info(message);
570         verifyLogMessage(message);
571         CategoryLogger.filter(set123).info(message);
572         verifyLogMessage(message);
573         CategoryLogger.filter(set23).info(message);
574         verifyLogMessage(message);
575         CategoryLogger.filter(set3).info(message);
576         verifyLogMessage(message);
577 
578         CategoryLogger.setLogCategories(LogCategory.ALL);
579         CategoryLogger.removeWriter(this.stringWriter);
580         addConsoleWriter();
581     }
582 
583     /**
584      * Test varying the default message format for all writers.
585      */
586     @Test
587     public void testAllLogMessageFormat()
588     {
589         CategoryLogger.addWriter(this.stringWriter);
590         removeConsoleWriter();
591 
592         CategoryLogger.setAllLogMessageFormat("");
593         CategoryLogger.always().info("Test message");
594         assertEquals("", this.stringWriter.getResult().trim());
595         this.stringWriter.clear();
596         CategoryLogger.always().error(new NullPointerException("NPE"));
597         assertEquals("", this.stringWriter.getResult().trim());
598         this.stringWriter.clear();
599 
600         CategoryLogger.setAllLogMessageFormat("Logger message:");
601         CategoryLogger.always().info("Test message");
602         assertEquals("Logger message:", this.stringWriter.getResult().trim());
603         this.stringWriter.clear();
604         CategoryLogger.always().error(new NullPointerException("NPE"));
605         assertEquals("Logger message:", this.stringWriter.getResult().trim());
606         this.stringWriter.clear();
607 
608         CategoryLogger.setAllLogMessageFormat("Logger message: {level}");
609         CategoryLogger.always().info("Test message");
610         assertEquals("Logger message: INFO", this.stringWriter.getResult().trim());
611         this.stringWriter.clear();
612         CategoryLogger.always().error(new NullPointerException("NPE"));
613         assertEquals("Logger message: ERROR", this.stringWriter.getResult().trim());
614         this.stringWriter.clear();
615 
616         CategoryLogger.setAllLogMessageFormat("Logger message: {message}");
617         CategoryLogger.always().info("Test message");
618         assertEquals("Logger message: Test message", this.stringWriter.getResult().trim());
619         this.stringWriter.clear();
620         CategoryLogger.always().error(new NullPointerException("NPE"));
621         assertTrue(this.stringWriter.getResult().contains("Logger message:"));
622         assertTrue(this.stringWriter.getResult().contains("NullPointerException"));
623         this.stringWriter.clear();
624 
625         CategoryLogger.setAllLogMessageFormat(CategoryLogger.DEFAULT_MESSAGE_FORMAT);
626         CategoryLogger.removeWriter(this.stringWriter);
627         addConsoleWriter();
628     }
629 
630     /**
631      * Test varying the message format for individual writers. The writer's message format always takes precedence over the
632      * default message format.
633      */
634     @Test
635     public void testWriterLogMessageFormat()
636     {
637         CategoryLogger.addWriter(this.stringWriter);
638         removeConsoleWriter();
639 
640         CategoryLogger.setAllLogMessageFormat("");
641         CategoryLogger.setLogMessageFormat(this.stringWriter, "");
642         CategoryLogger.always().info("Test message");
643         assertEquals("", this.stringWriter.getResult().trim());
644         this.stringWriter.clear();
645         CategoryLogger.always().error(new NullPointerException("NPE"));
646         assertEquals("", this.stringWriter.getResult().trim());
647         this.stringWriter.clear();
648 
649         CategoryLogger.setAllLogMessageFormat("xyz");
650         CategoryLogger.setLogMessageFormat(this.stringWriter, "Logger message:");
651         CategoryLogger.always().info("Test message");
652         assertEquals("Logger message:", this.stringWriter.getResult().trim());
653         this.stringWriter.clear();
654         CategoryLogger.always().error(new NullPointerException("NPE"));
655         assertEquals("Logger message:", this.stringWriter.getResult().trim());
656         this.stringWriter.clear();
657 
658         CategoryLogger.setAllLogMessageFormat(CategoryLogger.DEFAULT_MESSAGE_FORMAT);
659         CategoryLogger.setLogMessageFormat(this.stringWriter, "Logger message: {level}");
660         CategoryLogger.always().info("Test message");
661         assertEquals("Logger message: INFO", this.stringWriter.getResult().trim());
662         this.stringWriter.clear();
663         CategoryLogger.always().error(new NullPointerException("NPE"));
664         assertEquals("Logger message: ERROR", this.stringWriter.getResult().trim());
665         this.stringWriter.clear();
666 
667         CategoryLogger.setAllLogMessageFormat("");
668         CategoryLogger.setLogMessageFormat(this.stringWriter, "Logger message: {message}");
669         CategoryLogger.always().info("Test message");
670         assertEquals("Logger message: Test message", this.stringWriter.getResult().trim());
671         this.stringWriter.clear();
672         CategoryLogger.always().error(new NullPointerException("NPE"));
673         assertTrue(this.stringWriter.getResult().contains("Logger message:"));
674         assertTrue(this.stringWriter.getResult().contains("NullPointerException"));
675         this.stringWriter.clear();
676 
677         CategoryLogger.setAllLogMessageFormat(CategoryLogger.DEFAULT_MESSAGE_FORMAT);
678         CategoryLogger.removeWriter(this.stringWriter);
679         addConsoleWriter();
680     }
681 
682     /** ... */
683     protected static class StringWriter implements Writer
684     {
685         /** Last output. */
686         private String result = null;
687 
688         /** {@inheritDoc} */
689         @Override
690         public Set<LogEntryValue> getRequiredLogEntryValues()
691         {
692             return EnumSet.of(LogEntryValue.LEVEL, LogEntryValue.RENDERED_LOG_ENTRY);
693         }
694 
695         /** {@inheritDoc} */
696         @Override
697         public void init(final Configuration configuration) throws Exception
698         {
699             // Nothing to do
700         }
701 
702         /** {@inheritDoc} */
703         @Override
704         public void write(final LogEntry logEntry) throws Exception
705         {
706             this.result = logEntry.getRenderedLogEntry();
707         }
708 
709         /** {@inheritDoc} */
710         @Override
711         public void flush() throws Exception
712         {
713             // Nothing to do
714         }
715 
716         /** {@inheritDoc} */
717         @Override
718         public void close() throws Exception
719         {
720             // Nothing to do
721         }
722 
723         /**
724          * Return the last logged message.
725          * @return String; the last logged message
726          */
727         public String getResult()
728         {
729             return this.result;
730         }
731 
732         /**
733          * Nullify the last logged message (so we can distinguish a newly received message even when it is the empty string.
734          */
735         public void clear()
736         {
737             this.result = null;
738         }
739 
740     }
741 
742     /**
743      * For Java before java 9: return a set of the given members.
744      * @param <T> the set member type
745      * @param members the members to add
746      * @return the set with the members
747      */
748     @SuppressWarnings("unchecked")
749     private <T> Set<T> setOf(final T... members)
750     {
751         Set<T> result = new LinkedHashSet<T>();
752         for (T member : members)
753         {
754             result.add(member);
755         }
756         return result;
757     }
758 
759 }