• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.testng.log4testng;
2 
3 
4 import java.io.ByteArrayOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.PrintStream;
8 import java.util.Iterator;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.Properties;
12 
13 import org.testng.Assert;
14 import org.testng.collections.Maps;
15 
16 /**
17  * TestNG support logging via a custom logging framework similar to
18  * <a href="http://logging.apache.org/log4j"> Log4j</a>. To control logging, add a
19  * resource named "log4testng.properties" to your classpath. The logging levels are
20  * TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
21  * The Logging framework has the following characteristics:
22  *
23  * <ul>
24  * <li>All logging is done using System.out (for levels &lt; ERROR) or System.err. There
25  * is no way to specify Appenders.</li>
26  * <li>There is no way to control logging programmatically.</li>
27  * <li>The log4testng.properties resource is searched in the classpath on the first
28  * call to the logging API. If it is not present, logging defaults to the WARN
29  * level.</li>
30  * </ul>
31  *
32  * The property file contains lines in the following format:
33  *
34  * <pre><code>
35  * # log4testng will log its own behavior (generally used for debugging this package only).
36  * log4testng.debug=true
37  *
38  * # Specifies the root Loggers logging level. Will log DEBUG level and above
39  * log4testng.rootLogger=DEBUG
40  *
41  * # The org.testng.reporters.EmailableReporter Logger will log TRACE level and above
42  * log4testng.logger.org.testng.reporters.EmailableReporter=TRACE
43  *
44  * # All Logger in packages below org.testng will log WARN level and above
45  * log4testng.logger.org.testng=WARN
46  * </code></pre>
47  *
48  * In your source files you will typically instantiate and use loggers this ways:
49  * <pre><code>
50  * import org.testng.log4testng.Logger;
51  *
52  * class ThisClass {
53  *     private static final Logger LOGGER = Logger.getLogger(ThisClass.class);
54  *
55  *     ...
56  *     LOGGER.debug("entering myMethod()");
57  *     ...
58  *     LOGGER.warn("unknown file: " + filename);
59  *     ...
60  *     LOGGER.error("Unexpected error", exception);
61  * </code></pre>
62  */
63 public class Logger {
64 
65   // Attribute an hierarchical integer value to all levels.
66   private static int i= 0;
67   private static final int TRACE= i++;
68   private static final int DEBUG= i++;
69   private static final int INFO= i++;
70   private static final int WARN= i++;
71   private static final int ERROR= i++;
72   private static final int FATAL= i++;
73   private static final int LEVEL_COUNT= i;
74 
75   /** Standard prefix of all property names in log4testng.properties. */
76   private static final String PREFIX= "log4testng.";
77 
78   /** Standard prefix of all logger names in log4testng.properties. */
79   private static final String LOGGER_PREFIX= PREFIX + "logger.";
80 
81   /** Root logger name in log4testng.properties. */
82   private static final String ROOT_LOGGER= PREFIX + "rootLogger";
83 
84   /** Debug property name in log4testng.properties. */
85   private static final String DEBUG_PROPERTY= PREFIX + "debug";
86 
87   /** The standard error stream (this is allways System.err except for unit tests) */
88   private static PrintStream err= System.err;
89 
90   /** The standard output stream (this is allways System.out except for unit tests) */
91   private static PrintStream out= System.out;
92 
93   /** An ordered list of level names. */
94   private static final String[] levelNames= new String[LEVEL_COUNT];
95 
96   static {
97     levelNames[TRACE]= "TRACE";
98     levelNames[DEBUG]= "DEBUG";
99     levelNames[INFO] = "INFO";
100     levelNames[WARN] = "WARN";
101     levelNames[ERROR] = "ERROR";
102     levelNames[FATAL] = "FATAL";
103   }
104 
105   /** A map from level name to level integer index (TRACE->0, DEBUG->1 ...) */
106   private static final Map<String, Integer> levelMap= Maps.newHashMap();
107 
108   static {
109     for(i= 0; i < LEVEL_COUNT; ++i) {
levelMap.put(levelNames[i], i)110       levelMap.put(levelNames[i], i);
111     }
112   }
113 
114   /** true if the Logging system has been initialized. */
115   private static boolean initialized;
116 
117   /** Map from Logger names to level index (as specified in log4testng.properties) */
118   private static final Map<String, Integer> loggerLevels = Maps.newHashMap();
119 
120   /** Map of all known loggers. */
121   private static final Map<Class, Logger> loggers = Maps.newHashMap();
122 
123   /** The logging level of the root logger (defaults to warn). */
124   private static int rootLoggerLevel= WARN;
125 
126   /** Should log4testng log what it is doing (defaults to false). */
127   private static boolean debug= false;
128 
129   /** The logger's level */
130   private final int level;
131 
132   /** The logger's name. */
133   private final Class klass;
134   private final String m_className;
135 
136   /**
137    * Retrieve a logger named according to the value of the pClass.getName()
138    * parameter. If the named logger already exists, then the existing instance
139    * will be returned. Otherwise, a new instance is created. By default, loggers
140    * do not have a set level but inherit it from their nearest ancestor with
141    * a set level.
142    *
143    * @param pClass The class' logger to retrieve.
144    * @return a logger named according to the value of the pClass.getName().
145    */
getLogger(Class pClass)146   public static synchronized Logger getLogger(Class pClass) {
147     initialize();
148     Logger logger= loggers.get(pClass);
149     if(logger != null) {
150       return logger;
151     }
152     int level= getLevel(pClass);
153     logger= new Logger(pClass, level);
154     loggers.put(pClass, logger);
155 
156     return logger;
157   }
158 
159   /**
160    * Check whether this logger is enabled for the TRACE Level.
161    * @return true if this logger is enabled for level TRACE, false otherwise.
162    */
isTraceEnabled()163   public boolean isTraceEnabled() {
164     return isLevelEnabled(TRACE);
165   }
166 
167   /**
168    * Log a message object with the TRACE level. This method first checks if this
169    * logger is TRACE enabled. If this logger is TRACE enabled, then it converts
170    * the message object (passed as parameter) to a string by invoking toString().
171    * WARNING Note that passing a Throwable to this method will print the name of
172    * the Throwable but no stack trace. To print a stack trace use the
173    * trace(Object, Throwable) form instead.
174    * @param message the message object to log.
175    */
trace(Object message)176   public void trace(Object message) {
177     log(TRACE, message, null);
178   }
179 
180   /**
181    * Log a message object with the TRACE level including the stack trace of the
182    * Throwable t passed as parameter.
183    * See Logger.trace(Object) form for more detailed information.
184    * @param message the message object to log.
185    * @param t the exception to log, including its stack trace.
186    */
trace(Object message, Throwable t)187   public void trace(Object message, Throwable t) {
188     log(TRACE, message, t);
189   }
190 
191   /**
192    * Check whether this logger is enabled for the DEBUG Level.
193    * @return true if this logger is enabled for level DEBUG, false otherwise.
194    */
isDebugEnabled()195   public boolean isDebugEnabled() {
196     return isLevelEnabled(DEBUG);
197   }
198 
199   /**
200    * Log a message object with the DEBUG level.
201    * See Logger.trace(Object) form for more detailed information.
202    * @param message the message object to log.
203    */
debug(Object message)204   public void debug(Object message) {
205     log(DEBUG, message, null);
206   }
207 
208   /**
209    * Log a message object with the DEBUG level including the stack trace of the
210    * Throwable t passed as parameter.
211    * See Logger.trace(Object, Throwable) form for more detailed information.
212    * @param message the message object to log.
213    * @param t the exception to log, including its stack trace.
214    */
debug(Object message, Throwable t)215   public void debug(Object message, Throwable t) {
216     log(DEBUG, message, t);
217   }
218 
219   /**
220    * Check whether this logger is enabled for the INFO Level.
221    * @return true if this logger is enabled for level INFO, false otherwise.
222    */
isInfoEnabled()223   public boolean isInfoEnabled() {
224     return isLevelEnabled(INFO);
225   }
226 
227   /**
228    * Log a message object with the INFO level.
229    * See Logger.trace(Object) form for more detailed information.
230    * @param message the message object to log.
231    */
info(Object message)232   public void info(Object message) {
233     log(INFO, message, null);
234   }
235 
236   /**
237    * Log a message object with the WARN level including the stack trace of the
238    * Throwable t passed as parameter.
239    * See Logger.trace(Object, Throwable) form for more detailed information.
240    * @param message the message object to log.
241    * @param t the exception to log, including its stack trace.
242    */
info(Object message, Throwable t)243   public void info(Object message, Throwable t) {
244     log(INFO, message, t);
245   }
246 
247   /**
248    * Log a message object with the WARN level.
249    * See Logger.trace(Object) form for more detailed information.
250    * @param message the message object to log.
251    */
warn(Object message)252   public void warn(Object message) {
253     log(WARN, message, null);
254   }
255 
256   /**
257    * Log a message object with the ERROR level including the stack trace of the
258    * Throwable t passed as parameter.
259    * See Logger.trace(Object, Throwable) form for more detailed information.
260    * @param message the message object to log.
261    * @param t the exception to log, including its stack trace.
262    */
warn(Object message, Throwable t)263   public void warn(Object message, Throwable t) {
264     log(WARN, message, t);
265   }
266 
267   /**
268    * Log a message object with the ERROR level.
269    * See Logger.trace(Object) form for more detailed information.
270    * @param message the message object to log.
271    */
error(Object message)272   public void error(Object message) {
273     log(ERROR, message, null);
274   }
275 
276   /**
277    * Log a message object with the DEBUG level including the stack trace of the
278    * Throwable t passed as parameter.
279    * See Logger.trace(Object, Throwable) form for more detailed information.
280    * @param message the message object to log.
281    * @param t the exception to log, including its stack trace.
282    */
error(Object message, Throwable t)283   public void error(Object message, Throwable t) {
284     log(ERROR, message, t);
285   }
286 
287   /**
288    * Log a message object with the FATAL level.
289    * See Logger.trace(Object) form for more detailed information.
290    * @param message the message object to log.
291    */
fatal(Object message)292   public void fatal(Object message) {
293     log(FATAL, message, null);
294   }
295 
296   /**
297    * Log a message object with the FATAL level including the stack trace of the
298    * Throwable t passed as parameter.
299    * See Logger.trace(Object, Throwable) form for more detailed information.
300    * @param message the message object to log.
301    * @param t the exception to log, including its stack trace.
302    */
fatal(Object message, Throwable t)303   public void fatal(Object message, Throwable t) {
304     log(FATAL, message, t);
305   }
306 
Logger(Class pClass, int pLevel)307   private Logger(Class pClass, int pLevel) {
308     level= pLevel;
309     klass= pClass;
310     m_className= pClass.getName().substring(pClass.getName().lastIndexOf('.') + 1);
311   }
312 
initialize()313   private static synchronized void initialize() {
314     if(initialized) {
315       return;
316     }
317 
318     // We flag as initialized right away because if anything goes wrong
319     // We still consider it initialized. TODO Is this OK?
320     initialized= true;
321 
322     InputStream is= Thread.currentThread().getContextClassLoader().getResourceAsStream("log4testng.properties");
323     if(is == null) {
324       return;
325     }
326     Properties properties= new Properties();
327     try {
328       properties.load(is);
329     }
330     catch(IOException e) {
331       throw new RuntimeException(e);
332     }
333 
334     checkProperties(properties);
335   }
336 
checkProperties(Properties pProperties)337   private static void checkProperties(Properties pProperties) {
338     {
339       // See if we want to debug log4testng
340       String debugStr= pProperties.getProperty(DEBUG_PROPERTY);
341       if(debugStr != null) {
342         if(debugStr.equalsIgnoreCase("true")) {
343           debug= true;
344         }
345         else if(debugStr.equalsIgnoreCase("false")) {
346           debug= false;
347         }
348         else {
349           throw new IllegalArgumentException("Unknown " + DEBUG_PROPERTY
350                                              + " value " + debugStr);
351         }
352       }
353       loglog4testng("log4testng.debug set to " + debug);
354     }
355 
356     {
357       // Set the value of the root logger (if any).
358       String rootLevelStr= pProperties.getProperty(ROOT_LOGGER);
359       if(rootLevelStr != null) {
360         Integer ilevel= levelMap.get(rootLevelStr.toUpperCase());
361         if(ilevel == null) {
362           throw new IllegalArgumentException("Unknown level for log4testng.rootLogger "
363                                              + rootLevelStr + " in log4testng.properties");
364         }
365         rootLoggerLevel= ilevel;
366         loglog4testng("Root level logger set to " + rootLevelStr + " level.");
367       }
368     }
369 
370     Iterator it= pProperties.entrySet().iterator();
371     while(it.hasNext()) {
372       Map.Entry entry= (Entry) it.next();
373       String logger= (String) entry.getKey();
374       String level= (String) entry.getValue();
375 
376       if(!logger.startsWith(PREFIX)) {
377         throw new IllegalArgumentException("Illegal property value: " + logger);
378       }
379       if(logger.equals(DEBUG_PROPERTY)) {
380         // Already handled
381       }
382       else if(logger.equals(ROOT_LOGGER)) {
383         // Already handled
384       }
385       else {
386         if(!logger.startsWith(LOGGER_PREFIX)) {
387           throw new IllegalArgumentException("Illegal property value: " + logger);
388         }
389 
390         Integer ilevel= levelMap.get(level.toUpperCase());
391         if(ilevel == null) {
392           throw new IllegalArgumentException("Unknown level " + level + " for logger " + logger
393                                              + " in log4testng.properties");
394         }
395 
396         loggerLevels.put(logger.substring(LOGGER_PREFIX.length()), ilevel);
397         loglog4testng("logger " + logger + " set to " + ilevel + " level.");
398       }
399     }
400   }
401 
402   /**
403    * Returns the level associated to the current class. The level is obtain by searching
404    * for a logger in the "testng-logging.properties" resource. For example, if class is
405    * "org.testng.TestNG" the the following loggers are searched in this order:
406    * <ol>
407    * <li>"org.testng.TestNG"</li>
408    * <li>"org.testng"</li>
409    * <li>"org"</li>
410    * <li>The root level</li>
411    * </ol>
412    *
413    * @param pClass the class name used for logger name.
414    * @return the level associated to the current class.
415    */
getLevel(Class pClass)416   private static int getLevel(Class pClass) {
417     String name= pClass.getName();
418     loglog4testng("Getting level for logger " + name);
419     while(true) {
420       Integer level= loggerLevels.get(name);
421       if(level != null) {
422         loglog4testng("Found level " + level + " for logger " + name);
423 
424         return level;
425       }
426       int dot= name.lastIndexOf('.');
427       if(dot == -1) {
428         loglog4testng("Found level " + rootLoggerLevel + " for root logger");
429 
430         // Logger name not found. Defaults to root logger level.
431         return rootLoggerLevel;
432       }
433       name= name.substring(0, dot);
434     }
435   }
436 
isLevelEnabled(int pLevel)437   private boolean isLevelEnabled(int pLevel) {
438     return level <= pLevel;
439   }
440 
log(int pLevel, Object pMessage, Throwable pT)441   private void log(int pLevel, Object pMessage, Throwable pT) {
442     if(isLevelEnabled(pLevel)) {
443       PrintStream ps= (pLevel >= ERROR) ? err : out;
444       if(null != pT) {
445         synchronized(ps) {
446           ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage);
447           pT.printStackTrace(ps);
448         }
449       }
450       else {
451         ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage);
452       }
453     }
454   }
455 
456   /**
457    * Logs the message to System.out of debug is on.
458    * @param pmessage the message to log to the console
459    */
loglog4testng(String pmessage)460   private static void loglog4testng(String pmessage) {
461     if(debug) {
462       out.println("[log4testng] [debug] " + pmessage);
463     }
464   }
465 
466   /**
467    * This method is for debugging purpose only.
468    *
469    * @param pProperties a properties bundle initialised as log4testng
470    * property file would be.
471    * @param pOut the standard output stream to be used for logging.
472    * @param pErr the standard error stream to be used for logging.
473    */
testInitialize(Properties pProperties, PrintStream pOut, PrintStream pErr)474   private static synchronized void testInitialize(Properties pProperties,
475                                                   PrintStream pOut,
476                                                   PrintStream pErr) {
477     initialized= true;
478     loggers.clear();
479     rootLoggerLevel= WARN;
480     debug= false;
481     out= pOut;
482     err= pErr;
483     checkProperties(pProperties);
484   }
485 
486   /**
487    * Makes sure the default debug value is false.
488    */
testDebugDefault()489   private static void testDebugDefault() {
490     Properties props= new Properties();
491     ByteArrayOutputStream out1= new ByteArrayOutputStream();
492     ByteArrayOutputStream err1= new ByteArrayOutputStream();
493     PrintStream out2= new PrintStream(out1);
494     PrintStream err2= new PrintStream(err1);
495     props.put("log4testng.rootLogger", "WARN");
496     testInitialize(props, out2, err2);
497     Assert.assertEquals(out1.toString(), "");
498     Assert.assertEquals(err1.toString(), "");
499   }
500 
501   /**
502    * Makes sure the debug value can be turned on and actualls logs something.
503    */
testDebugOn()504   private static void testDebugOn() {
505     Properties props= new Properties();
506     ByteArrayOutputStream out1= new ByteArrayOutputStream();
507     ByteArrayOutputStream err1= new ByteArrayOutputStream();
508     PrintStream out2= new PrintStream(out1);
509     PrintStream err2= new PrintStream(err1);
510     props.put("log4testng.debug", "true");
511     props.put("log4testng.rootLogger", "WARN");
512     testInitialize(props, out2, err2);
513     Assert.assertTrue(out1.toString().startsWith("[log4testng][debug]"));
514     Assert.assertEquals(err1.toString(), "");
515   }
516 
517   /**
518    * Makes sure the debug value can be turned off and logs nothing.
519    */
testDebugOff()520   private static void testDebugOff() {
521     Properties props= new Properties();
522     ByteArrayOutputStream out1= new ByteArrayOutputStream();
523     ByteArrayOutputStream err1= new ByteArrayOutputStream();
524     PrintStream out2= new PrintStream(out1);
525     PrintStream err2= new PrintStream(err1);
526     props.put("log4testng.debug", "false");
527     props.put("log4testng.rootLogger", "WARN");
528     testInitialize(props, out2, err2);
529     Assert.assertEquals(out1.toString(), "");
530     Assert.assertEquals(err1.toString(), "");
531   }
532 
533   /**
534    * Makes sure an illegal debug value throws an exception.
535    */
testDebugError()536   private static void testDebugError() {
537     Properties props= new Properties();
538     ByteArrayOutputStream out1= new ByteArrayOutputStream();
539     ByteArrayOutputStream err1= new ByteArrayOutputStream();
540     PrintStream out2= new PrintStream(out1);
541     PrintStream err2= new PrintStream(err1);
542     props.put("log4testng.debug", "unknown");
543     props.put("log4testng.rootLogger", "WARN");
544     try {
545       testInitialize(props, out2, err2);
546       throw new RuntimeException("failure");
547     }
548     catch(IllegalArgumentException pEx) {
549 
550       // Normal case
551       Assert.assertEquals(out1.toString(), "");
552       Assert.assertEquals(err1.toString(), "");
553     }
554   }
555 
556   /**
557    * Tests that the root logger's default level is WARN and that loggers do not
558    * log bellow this level and do log in the correct stream for levels equal to
559    * and above WARN.
560    */
testRootLoggerDefault()561   private static void testRootLoggerDefault() {
562     Properties props= new Properties();
563     ByteArrayOutputStream out1= new ByteArrayOutputStream();
564     ByteArrayOutputStream err1= new ByteArrayOutputStream();
565     PrintStream out2= new PrintStream(out1);
566     PrintStream err2= new PrintStream(err1);
567     testInitialize(props, out2, err2);
568 
569     Logger strLogger= Logger.getLogger(String.class);
570     strLogger.trace("trace should not appear");
571     Assert.assertEquals(out1.toString(), "");
572     Assert.assertEquals(err1.toString(), "");
573     strLogger.debug("debug should not appear");
574     Assert.assertEquals(out1.toString(), "");
575     Assert.assertEquals(err1.toString(), "");
576     strLogger.info("info should not appear");
577     Assert.assertEquals(out1.toString(), "");
578     Assert.assertEquals(err1.toString(), "");
579     strLogger.warn("warn should appear");
580     int outlength= out1.toString().length();
581     Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [WARN] warn should appear"));
582     Assert.assertEquals(err1.toString(), "");
583     strLogger.error("error should appear");
584     Assert.assertEquals(out1.toString().length(), outlength);
585     Assert.assertTrue(err1.toString().startsWith("[java.lang.String] [ERROR] error should appear"));
586     strLogger.fatal("fatal should appear");
587     Assert.assertEquals(out1.toString().length(), outlength);
588     Assert.assertTrue(err1.toString().contains("[java.lang.String] [FATAL] fatal should appear"));
589   }
590 
591   /**
592    * Test setting the root logger level
593    */
testRootLoggerSet()594   private static void testRootLoggerSet() {
595     Properties props= new Properties();
596     ByteArrayOutputStream out1= new ByteArrayOutputStream();
597     ByteArrayOutputStream err1= new ByteArrayOutputStream();
598     PrintStream out2= new PrintStream(out1);
599     PrintStream err2= new PrintStream(err1);
600     props.put("log4testng.rootLogger", "DEBUG");
601     testInitialize(props, out2, err2);
602 
603     Logger strLogger= Logger.getLogger(String.class);
604     strLogger.trace("trace should appear");
605     Assert.assertEquals(out1.toString(), "");
606     Assert.assertEquals(err1.toString(), "");
607     strLogger.debug("debug should appear");
608     Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
609     Assert.assertEquals(err1.toString(), "");
610   }
611 
612   /**
613    * Test setting the root logger to an illegal level value throws an exception.
614    */
testRootLoggerSetError()615   private static void testRootLoggerSetError() {
616     Properties props= new Properties();
617     ByteArrayOutputStream out1= new ByteArrayOutputStream();
618     ByteArrayOutputStream err1= new ByteArrayOutputStream();
619     PrintStream out2= new PrintStream(out1);
620     PrintStream err2= new PrintStream(err1);
621     props.put("log4testng.rootLogger", "unknown");
622     try {
623       testInitialize(props, out2, err2);
624       throw new RuntimeException("failure");
625     }
626     catch(IllegalArgumentException pEx) {
627 
628       // Normal case
629       Assert.assertEquals(out1.toString(), "");
630       Assert.assertEquals(err1.toString(), "");
631     }
632   }
633 
634   /**
635    * Test setting a user logger level
636    */
testUserLoggerSet()637   private static void testUserLoggerSet() {
638     Properties props= new Properties();
639     ByteArrayOutputStream out1= new ByteArrayOutputStream();
640     ByteArrayOutputStream err1= new ByteArrayOutputStream();
641     PrintStream out2= new PrintStream(out1);
642     PrintStream err2= new PrintStream(err1);
643     props.put("log4testng.logger.java.lang.String", "DEBUG");
644     testInitialize(props, out2, err2);
645 
646     Logger strLogger= Logger.getLogger(String.class);
647     strLogger.trace("trace should not appear");
648     Assert.assertEquals(out1.toString(), "");
649     Assert.assertEquals(err1.toString(), "");
650     strLogger.debug("debug should appear");
651     int outLength= out1.toString().length();
652     Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
653     Assert.assertEquals(err1.toString(), "");
654 
655     Logger classLogger= Logger.getLogger(Class.class);
656     classLogger.debug("debug should not appear");
657     Assert.assertEquals(out1.toString().length(), outLength);
658     Assert.assertEquals(err1.toString(), "");
659     classLogger.warn("warn should appear");
660     Assert.assertTrue(out1.toString().contains("[java.lang.Class] [WARN] warn should appear"));
661     Assert.assertEquals(err1.toString(), "");
662   }
663 
664   /**
665    * Test setting a user logger to an illegal level value throws an exception
666    */
testUserLoggerSetError()667   private static void testUserLoggerSetError() {
668     Properties props= new Properties();
669     ByteArrayOutputStream out1= new ByteArrayOutputStream();
670     ByteArrayOutputStream err1= new ByteArrayOutputStream();
671     PrintStream out2= new PrintStream(out1);
672     PrintStream err2= new PrintStream(err1);
673     props.put("log4testng.logger.java.lang.String", "unknown");
674     try {
675       testInitialize(props, out2, err2);
676       throw new RuntimeException("failure");
677     }
678     catch(IllegalArgumentException pEx) {
679 
680       // Normal case
681       Assert.assertEquals(out1.toString(), "");
682       Assert.assertEquals(err1.toString(), "");
683     }
684   }
685 
686   /**
687    * Tests setting a partial logger name (a hierarchy scope)
688    */
testUserLoggerSetHierarchy()689   private static void testUserLoggerSetHierarchy() {
690     Properties props= new Properties();
691     ByteArrayOutputStream out1= new ByteArrayOutputStream();
692     ByteArrayOutputStream err1= new ByteArrayOutputStream();
693     PrintStream out2= new PrintStream(out1);
694     PrintStream err2= new PrintStream(err1);
695     props.put("log4testng.logger.java.lang", "DEBUG");
696     testInitialize(props, out2, err2);
697 
698     Logger strLogger= Logger.getLogger(String.class);
699     strLogger.trace("trace should not appear");
700     Assert.assertEquals(out1.toString(), "");
701     Assert.assertEquals(err1.toString(), "");
702     strLogger.debug("debug should appear");
703     Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
704     Assert.assertEquals(err1.toString(), "");
705   }
706 
707   /**
708    * Run all tests. (very crusty ...)
709    * @param pArgs not used
710    */
main(String[] pArgs)711   public static void main(String[] pArgs) {
712     testDebugDefault();
713     testDebugOn();
714     testDebugOff();
715     testDebugError();
716     testRootLoggerDefault();
717     testRootLoggerSet();
718     testRootLoggerSetError();
719     testUserLoggerSet();
720     testUserLoggerSetError();
721     testUserLoggerSetHierarchy();
722   }
723 }
724