- fixed TestNG console help
- logger prints out only the class name (excluding the package)
diff --git a/src/main/org/testng/TestNGCommandLineArgs.java b/src/main/org/testng/TestNGCommandLineArgs.java
index f90cf88..8328936 100644
--- a/src/main/org/testng/TestNGCommandLineArgs.java
+++ b/src/main/org/testng/TestNGCommandLineArgs.java
@@ -686,7 +686,7 @@
}
else {
System.out.println("[" + ANNOTATIONS_COMMAND_OPT + " " + AnnotationTypeEnum.JAVADOC.getName() + " or "
- + AnnotationTypeEnum.JAVADOC.getName() + "]");
+ + AnnotationTypeEnum.JDK.getName() + "]");
System.out.println("\t\tSpecifies the default annotation type to be used in suites when none is explicitly");
System.out.println("\t\tspecified. This version of TestNG (15) supports both \""
+ AnnotationTypeEnum.JAVADOC.getName() + "\" and \"" + AnnotationTypeEnum.JDK.getName() + "\" annotation types.");
diff --git a/src/main/org/testng/log4testng/Logger.java b/src/main/org/testng/log4testng/Logger.java
index 10cd501..8fa55f1 100644
--- a/src/main/org/testng/log4testng/Logger.java
+++ b/src/main/org/testng/log4testng/Logger.java
@@ -1,729 +1,724 @@
-package org.testng.log4testng;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Map.Entry;
-
-import org.testng.Assert;
-
-/**
- * TestNG support logging via a custom logging framework similar to
- * <a href="http://logging.apache.org/log4j"> Log4j</a>. To control logging, add a
- * resource named "log4testng.properties" to your classpath. The logging levels are
- * TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
- * The Logging framework has the following characteristics:
- *
- * <ul>
- * <li>All logging is done using System.out (for levels < ERROR) or System.err. There
- * is no way to specify Appenders.</li>
- * <li>There is no way to control logging programmatically.</li>
- * <li>The log4testng.properties resource is searched in the classpath on the first
- * call to the logging API. If it is not present, logging defaults to the WARN
- * level.</li>
- * </ul>
- *
- * The property file contains lines in the following format:
- *
- * <pre><code>
- * # log4testng will log its own behavior (generally used for debugging this package only).
- * log4testng.debug=true
- *
- * # Specifies the root Loggers logging level. Will log DEBUG level and above
- * log4testng.rootLogger=DEBUG
- *
- * # The org.testng.reporters.EmailableReporter Logger will log TRACE level and above
- * log4testng.logger.org.testng.reporters.EmailableReporter=TRACE
- *
- * # All Logger in packages below org.testng will log WARN level and above
- * log4testng.logger.org.testng=WARN
- * </code></pre>
- *
- * In your source files you will typically instantiate and use loggers this ways:
- * <pre><code>
- * import org.testng.log4testng.Logger;
- *
- * class ThisClass {
- * private static final Logger LOGGER = Logger.getLogger(ThisClass.class);
- *
- * ...
- * LOGGER.debug("entering myMethod()");
- * ...
- * LOGGER.warn("unknown file: " + filename);
- * ...
- * LOGGER.error("Unexpected error", exception);
- * </code></pre>
- */
-public class Logger {
-
- // Attribute an hierarchical integer value to all levels.
- private static int i = 0;
- private static final int TRACE = i++;
- private static final int DEBUG = i++;
- private static final int INFO = i++;
- private static final int WARN = i++;
- private static final int ERROR = i++;
- private static final int FATAL = i++;
- private static final int LEVEL_COUNT = i;
-
- /** Standard prefix of all property names in log4testng.properties. */
- private static final String PREFIX = "log4testng.";
-
- /** Standard prefix of all logger names in log4testng.properties. */
- private static final String LOGGER_PREFIX = PREFIX + "logger.";
-
- /** Root logger name in log4testng.properties. */
- private static final String ROOT_LOGGER = PREFIX + "rootLogger";
-
- /** Debug property name in log4testng.properties. */
- private static final String DEBUG_PROPERTY = PREFIX + "debug";
-
- /** The standard error stream (this is allways System.err except for unit tests) */
- private static PrintStream err = System.err;
-
- /** The standard output stream (this is allways System.out except for unit tests) */
- private static PrintStream out = System.out;
-
- /** An ordered list of level names. */
- private static final String[] levelNames = new String[LEVEL_COUNT];
- static {
- levelNames[TRACE] = "TRACE";
- levelNames[DEBUG] = "DEBUG";
- levelNames[INFO] = "INFO" ;
- levelNames[WARN] = "WARN" ;
- levelNames[ERROR] = "ERROR";
- levelNames[FATAL] = "FATAL";
- }
-
- /** A map from level name to level integer index (TRACE->0, DEBUG->1 ...) */
- private static final Map<String,Integer> levelMap = new HashMap<String,Integer>();
- static {
- for(i = 0; i < LEVEL_COUNT; ++i) {
- levelMap.put(levelNames[i], new Integer(i));
- }
- }
-
- /** true if the Logging system has been initialized. */
- private static boolean initialized;
-
- /** Map from Logger names to level index (as specified in log4testng.properties) */
- private static final Map<String, Integer> loggerLevels = new HashMap<String, Integer>();
-
- /** Map of all known loggers. */
- private static final Map<Class, Logger> loggers = new HashMap<Class, Logger>();
-
- /** The logging level of the root logger (defaults to warn). */
- private static int rootLoggerLevel = WARN;
-
- /** Should log4testng log what it is doing (defaults to false). */
- private static boolean debug = false;
-
- /** The logger's level */
- private final int level;
-
- /** The logger's name. */
- private final Class klass;
-
- /**
- * Retrieve a logger named according to the value of the pClass.getName()
- * parameter. If the named logger already exists, then the existing instance
- * will be returned. Otherwise, a new instance is created. By default, loggers
- * do not have a set level but inherit it from their nearest ancestor with
- * a set level.
- *
- * @param pClass The class' logger to retrieve.
- * @return a logger named according to the value of the pClass.getName().
- */
- public static synchronized Logger getLogger(Class pClass) {
- initialize();
- Logger logger = loggers.get(pClass);
- if (logger != null) {
- return logger;
- }
- int level = getLevel(pClass);
- logger = new Logger(pClass, level);
- loggers.put(pClass, logger);
- return logger;
- }
-
- /**
- * Check whether this logger is enabled for the TRACE Level.
- * @return true if this logger is enabled for level TRACE, false otherwise.
- */
- public boolean isTraceEnabled() {
- return isLevelEnabled(TRACE);
- }
-
- /**
- * Log a message object with the TRACE level. This method first checks if this
- * logger is TRACE enabled. If this logger is TRACE enabled, then it converts
- * the message object (passed as parameter) to a string by invoking toString().
- * WARNING Note that passing a Throwable to this method will print the name of
- * the Throwable but no stack trace. To print a stack trace use the
- * trace(Object, Throwable) form instead.
- * @param message the message object to log.
- */
- public void trace(Object message) {
- log(TRACE, message, null);
- }
-
- /**
- * Log a message object with the TRACE level including the stack trace of the
- * Throwable t passed as parameter.
- * See Logger.trace(Object) form for more detailed information.
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- public void trace(Object message, Throwable t) {
- log(TRACE, message, t);
- }
-
- /**
- * Check whether this logger is enabled for the DEBUG Level.
- * @return true if this logger is enabled for level DEBUG, false otherwise.
- */
- public boolean isDebugEnabled() {
- return isLevelEnabled(DEBUG);
- }
-
- /**
- * Log a message object with the DEBUG level.
- * See Logger.trace(Object) form for more detailed information.
- * @param message the message object to log.
- */
- public void debug(Object message) {
- log(DEBUG, message, null);
- }
-
- /**
- * Log a message object with the DEBUG level including the stack trace of the
- * Throwable t passed as parameter.
- * See Logger.trace(Object, Throwable) form for more detailed information.
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- public void debug(Object message, Throwable t) {
- log(DEBUG, message, t);
- }
-
-
- /**
- * Check whether this logger is enabled for the INFO Level.
- * @return true if this logger is enabled for level INFO, false otherwise.
- */
- public boolean isInfoEnabled() {
- return isLevelEnabled(INFO);
- }
- /**
- * Log a message object with the INFO level.
- * See Logger.trace(Object) form for more detailed information.
- * @param message the message object to log.
- */
- public void info(Object message) {
- log(INFO, message, null);
- }
- /**
- * Log a message object with the WARN level including the stack trace of the
- * Throwable t passed as parameter.
- * See Logger.trace(Object, Throwable) form for more detailed information.
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- public void info(Object message, Throwable t) {
- log(INFO, message, t);
- }
- /**
- * Log a message object with the WARN level.
- * See Logger.trace(Object) form for more detailed information.
- * @param message the message object to log.
- */
- public void warn(Object message) {
- log(WARN, message, null);
- }
- /**
- * Log a message object with the ERROR level including the stack trace of the
- * Throwable t passed as parameter.
- * See Logger.trace(Object, Throwable) form for more detailed information.
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- public void warn(Object message, Throwable t) {
- log(WARN, message, t);
- }
- /**
- * Log a message object with the ERROR level.
- * See Logger.trace(Object) form for more detailed information.
- * @param message the message object to log.
- */
- public void error(Object message) {
- log(ERROR, message, null);
- }
- /**
- * Log a message object with the DEBUG level including the stack trace of the
- * Throwable t passed as parameter.
- * See Logger.trace(Object, Throwable) form for more detailed information.
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- public void error(Object message, Throwable t) {
- log(ERROR, message, t);
- }
- /**
- * Log a message object with the FATAL level.
- * See Logger.trace(Object) form for more detailed information.
- * @param message the message object to log.
- */
- public void fatal(Object message) {
- log(FATAL, message, null);
- }
- /**
- * Log a message object with the FATAL level including the stack trace of the
- * Throwable t passed as parameter.
- * See Logger.trace(Object, Throwable) form for more detailed information.
- * @param message the message object to log.
- * @param t the exception to log, including its stack trace.
- */
- public void fatal(Object message, Throwable t) {
- log(FATAL, message, t);
- }
-
- private Logger(Class pClass, int pLevel) {
- level = pLevel;
- klass = pClass;
- }
-
- private static synchronized void initialize() {
- if (initialized) {
- return;
- }
-
- // We flag as initialized right away because if anything goes wrong
- // We still consider it initialized. TODO Is this OK?
- initialized = true;
-
- InputStream is = Thread.currentThread().getContextClassLoader()
- .getResourceAsStream("log4testng.properties");
- if (is == null) {
- return;
- }
- Properties properties = new Properties();
- try {
- properties.load(is);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- checkProperties(properties);
- }
-
- private static void checkProperties(Properties pProperties)
- {
- {
- // See if we want to debug log4testng
- String debugStr = pProperties.getProperty(DEBUG_PROPERTY);
- if (debugStr != null)
- {
- if (debugStr.equalsIgnoreCase("true"))
- {
- debug = true;
- }
- else if (debugStr.equalsIgnoreCase("false"))
- {
- debug = false;
- }
- else
- {
- throw new IllegalArgumentException("Unknown " + DEBUG_PROPERTY
- + " value " + debugStr);
- }
- }
- loglog4testng("log4testng.debug set to " + debug);
- }
- {
- // Set the value of the root logger (if any).
- String rootLevelStr = pProperties.getProperty(ROOT_LOGGER);
- if (rootLevelStr != null)
- {
- Integer ilevel = levelMap.get(rootLevelStr.toUpperCase());
- if (ilevel == null) {
- throw new IllegalArgumentException("Unknown level for log4testng.rootLogger "
- + rootLevelStr + " in log4testng.properties");
- }
- rootLoggerLevel = ilevel.intValue();
- loglog4testng("Root level logger set to " + rootLevelStr + " level.");
- }
- }
-
- Iterator it = pProperties.entrySet().iterator();
- while(it.hasNext())
- {
- Map.Entry entry = (Entry) it.next();
- String logger = (String) entry.getKey();
- String level = (String) entry.getValue();
-
- if (!logger.startsWith(PREFIX))
- {
- throw new IllegalArgumentException("Illegal property value: " + logger);
- }
- if(logger.equals(DEBUG_PROPERTY))
- {
- // Already handled
- }
- else if(logger.equals(ROOT_LOGGER))
- {
- // Already handled
- }
- else
- {
- if (!logger.startsWith(LOGGER_PREFIX))
- {
- throw new IllegalArgumentException("Illegal property value: " + logger);
- }
-
- Integer ilevel = levelMap.get(level.toUpperCase());
- if (ilevel == null) {
- throw new IllegalArgumentException("Unknown level " + level + " for logger " + logger
- + " in log4testng.properties");
- }
-
- loggerLevels.put(logger.substring(LOGGER_PREFIX.length()), ilevel);
- loglog4testng("logger " + logger + " set to " + ilevel + " level.");
- }
- }
- }
-
- /**
- * Returns the level associated to the current class. The level is obtain by searching
- * for a logger in the "testng-logging.properties" resource. For example, if class is
- * "org.testng.TestNG" the the following loggers are searched in this order:
- * <ol>
- * <li>"org.testng.TestNG"</li>
- * <li>"org.testng"</li>
- * <li>"org"</li>
- * <li>The root level</li>
- * </ol>
- *
- * @param pClass the class name used for logger name.
- * @return the level associated to the current class.
- */
- private static int getLevel(Class pClass) {
- String name = pClass.getName();
- loglog4testng("Getting level for logger " + name);
- while (true) {
- Integer level = loggerLevels.get(name);
- if (level != null) {
- loglog4testng("Found level " + level + " for logger " + name);
- return level.intValue();
- }
- int dot = name.lastIndexOf('.');
- if (dot != -1) {
- loglog4testng("Found level " + rootLoggerLevel + " for root logger");
- // Logger name not found. Defaults to root logger level.
- return rootLoggerLevel;
- }
- name = name.substring(0, dot);
- }
- }
-
- private boolean isLevelEnabled(int pLevel) {
- return level <= pLevel;
- }
-
- private void log(int pLevel, Object pMessage, Throwable pT) {
- if (isLevelEnabled(pLevel)) {
- PrintStream ps = pLevel >= ERROR ? err : out;
- ps.println("[" + klass.getName() + "] [" + levelNames[pLevel] + "] " + pMessage);
- if (pT != null) {
- pT.printStackTrace(ps);
- }
- }
- }
-
- /**
- * Logs the message to System.out of debug is on.
- * @param pmessage the message to log to the console
- */
- private static void loglog4testng(String pmessage)
- {
- if (debug)
- {
- out.println("[log4testng] [debug] " + pmessage);
- }
- }
-
-
- /**
- * This method is for debugging purpose only.
- *
- * @param pProperties a properties bundle initialised as log4testng
- * property file would be.
- * @param pOut the standard output stream to be used for logging.
- * @param pErr the standard error stream to be used for logging.
- */
- private static synchronized void testInitialize(Properties pProperties, PrintStream pOut, PrintStream pErr) {
- initialized = true;
- loggers.clear();
- rootLoggerLevel = WARN;
- debug = false;
- out = pOut;
- err = pErr;
- checkProperties(pProperties);
- }
-
- /**
- * Makes sure the default debug value is false.
- */
- private static void testDebugDefault()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.rootLogger", "WARN");
- testInitialize(props, out2, err2);
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- }
-
- /**
- * Makes sure the debug value can be turned on and actualls logs something.
- */
- private static void testDebugOn()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.debug", "true");
- props.put("log4testng.rootLogger", "WARN");
- testInitialize(props, out2, err2);
- Assert.assertTrue(out1.toString().startsWith("[log4testng][debug]"));
- Assert.assertEquals(err1.toString(), "");
- }
-
- /**
- * Makes sure the debug value can be turned off and logs nothing.
- */
- private static void testDebugOff()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.debug", "false");
- props.put("log4testng.rootLogger", "WARN");
- testInitialize(props, out2, err2);
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- }
-
- /**
- * Makes sure an illegal debug value throws an exception.
- */
- private static void testDebugError()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.debug", "unknown");
- props.put("log4testng.rootLogger", "WARN");
- try
- {
- testInitialize(props, out2, err2);
- throw new RuntimeException("failure");
- }
- catch(IllegalArgumentException pEx)
- {
- // Normal case
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- }
- }
-
- /**
- * Tests that the root logger's default level is WARN and that loggers do not
- * log bellow this level and do log in the correct stream for levels equal to
- * and above WARN.
- */
- private static void testRootLoggerDefault()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- testInitialize(props, out2, err2);
-
- Logger strLogger = Logger.getLogger(String.class);
- strLogger.trace("trace should not appear");
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- strLogger.debug("debug should not appear");
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- strLogger.info("info should not appear");
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- strLogger.warn("warn should appear");
- int outlength = out1.toString().length();
- Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [WARN] warn should appear"));
- Assert.assertEquals(err1.toString(), "");
- strLogger.error("error should appear");
- Assert.assertEquals(out1.toString().length(), outlength);
- Assert.assertTrue(err1.toString().startsWith("[java.lang.String] [ERROR] error should appear"));
- strLogger.fatal("fatal should appear");
- Assert.assertEquals(out1.toString().length(), outlength);
- Assert.assertTrue(err1.toString().contains("[java.lang.String] [FATAL] fatal should appear"));
- }
-
- /**
- * Test setting the root logger level
- */
- private static void testRootLoggerSet()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.rootLogger", "DEBUG");
- testInitialize(props, out2, err2);
-
- Logger strLogger = Logger.getLogger(String.class);
- strLogger.trace("trace should appear");
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- strLogger.debug("debug should appear");
- Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
- Assert.assertEquals(err1.toString(), "");
- }
-
- /**
- * Test setting the root logger to an illegal level value throws an exception.
- */
- private static void testRootLoggerSetError()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.rootLogger", "unknown");
- try
- {
- testInitialize(props, out2, err2);
- throw new RuntimeException("failure");
- }
- catch(IllegalArgumentException pEx)
- {
- // Normal case
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- }
- }
-
- /**
- * Test setting a user logger level
- */
- private static void testUserLoggerSet()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.logger.java.lang.String", "DEBUG");
- testInitialize(props, out2, err2);
-
- Logger strLogger = Logger.getLogger(String.class);
- strLogger.trace("trace should not appear");
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- strLogger.debug("debug should appear");
- int outLength = out1.toString().length();
- Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
- Assert.assertEquals(err1.toString(), "");
-
- Logger classLogger = Logger.getLogger(Class.class);
- classLogger.debug("debug should not appear");
- Assert.assertEquals(out1.toString().length(), outLength);
- Assert.assertEquals(err1.toString(), "");
- classLogger.warn("warn should appear");
- Assert.assertTrue(out1.toString().contains("[java.lang.Class] [WARN] warn should appear"));
- Assert.assertEquals(err1.toString(), "");
- }
-
- /**
- * Test setting a user logger to an illegal level value throws an exception
- */
- private static void testUserLoggerSetError()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.logger.java.lang.String", "unknown");
- try
- {
- testInitialize(props, out2, err2);
- throw new RuntimeException("failure");
- }
- catch(IllegalArgumentException pEx)
- {
- // Normal case
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- }
- }
-
- /**
- * Tests setting a partial logger name (a hierarchy scope)
- */
- private static void testUserLoggerSetHierarchy()
- {
- Properties props = new Properties();
- ByteArrayOutputStream out1 = new ByteArrayOutputStream();
- ByteArrayOutputStream err1 = new ByteArrayOutputStream();
- PrintStream out2 = new PrintStream(out1);
- PrintStream err2 = new PrintStream(err1);
- props.put("log4testng.logger.java.lang", "DEBUG");
- testInitialize(props, out2, err2);
-
- Logger strLogger = Logger.getLogger(String.class);
- strLogger.trace("trace should not appear");
- Assert.assertEquals(out1.toString(), "");
- Assert.assertEquals(err1.toString(), "");
- strLogger.debug("debug should appear");
- Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
- Assert.assertEquals(err1.toString(), "");
- }
-
- /**
- * Run all tests. (very crusty ...)
- * @param pArgs not used
- */
- public static void main(String[] pArgs)
- {
- testDebugDefault();
- testDebugOn();
- testDebugOff();
- testDebugError();
- testRootLoggerDefault();
- testRootLoggerSet();
- testRootLoggerSetError();
- testUserLoggerSet();
- testUserLoggerSetError();
- testUserLoggerSetHierarchy();
- }
-}
+package org.testng.log4testng;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.testng.Assert;
+
+/**
+ * TestNG support logging via a custom logging framework similar to
+ * <a href="http://logging.apache.org/log4j"> Log4j</a>. To control logging, add a
+ * resource named "log4testng.properties" to your classpath. The logging levels are
+ * TRACE, DEBUG, INFO, WARN, ERROR and FATAL.
+ * The Logging framework has the following characteristics:
+ *
+ * <ul>
+ * <li>All logging is done using System.out (for levels < ERROR) or System.err. There
+ * is no way to specify Appenders.</li>
+ * <li>There is no way to control logging programmatically.</li>
+ * <li>The log4testng.properties resource is searched in the classpath on the first
+ * call to the logging API. If it is not present, logging defaults to the WARN
+ * level.</li>
+ * </ul>
+ *
+ * The property file contains lines in the following format:
+ *
+ * <pre><code>
+ * # log4testng will log its own behavior (generally used for debugging this package only).
+ * log4testng.debug=true
+ *
+ * # Specifies the root Loggers logging level. Will log DEBUG level and above
+ * log4testng.rootLogger=DEBUG
+ *
+ * # The org.testng.reporters.EmailableReporter Logger will log TRACE level and above
+ * log4testng.logger.org.testng.reporters.EmailableReporter=TRACE
+ *
+ * # All Logger in packages below org.testng will log WARN level and above
+ * log4testng.logger.org.testng=WARN
+ * </code></pre>
+ *
+ * In your source files you will typically instantiate and use loggers this ways:
+ * <pre><code>
+ * import org.testng.log4testng.Logger;
+ *
+ * class ThisClass {
+ * private static final Logger LOGGER = Logger.getLogger(ThisClass.class);
+ *
+ * ...
+ * LOGGER.debug("entering myMethod()");
+ * ...
+ * LOGGER.warn("unknown file: " + filename);
+ * ...
+ * LOGGER.error("Unexpected error", exception);
+ * </code></pre>
+ */
+public class Logger {
+
+ // Attribute an hierarchical integer value to all levels.
+ private static int i= 0;
+ private static final int TRACE= i++;
+ private static final int DEBUG= i++;
+ private static final int INFO= i++;
+ private static final int WARN= i++;
+ private static final int ERROR= i++;
+ private static final int FATAL= i++;
+ private static final int LEVEL_COUNT= i;
+
+ /** Standard prefix of all property names in log4testng.properties. */
+ private static final String PREFIX= "log4testng.";
+
+ /** Standard prefix of all logger names in log4testng.properties. */
+ private static final String LOGGER_PREFIX= PREFIX + "logger.";
+
+ /** Root logger name in log4testng.properties. */
+ private static final String ROOT_LOGGER= PREFIX + "rootLogger";
+
+ /** Debug property name in log4testng.properties. */
+ private static final String DEBUG_PROPERTY= PREFIX + "debug";
+
+ /** The standard error stream (this is allways System.err except for unit tests) */
+ private static PrintStream err= System.err;
+
+ /** The standard output stream (this is allways System.out except for unit tests) */
+ private static PrintStream out= System.out;
+
+ /** An ordered list of level names. */
+ private static final String[] levelNames= new String[LEVEL_COUNT];
+
+ static {
+ levelNames[TRACE]= "TRACE";
+ levelNames[DEBUG]= "DEBUG";
+ levelNames[INFO]= "INFO";
+ levelNames[WARN]= "WARN";
+ levelNames[ERROR]= "ERROR";
+ levelNames[FATAL]= "FATAL";
+ }
+
+ /** A map from level name to level integer index (TRACE->0, DEBUG->1 ...) */
+ private static final Map<String, Integer> levelMap= new HashMap<String, Integer>();
+
+ static {
+ for(i= 0; i < LEVEL_COUNT; ++i) {
+ levelMap.put(levelNames[i], new Integer(i));
+ }
+ }
+
+ /** true if the Logging system has been initialized. */
+ private static boolean initialized;
+
+ /** Map from Logger names to level index (as specified in log4testng.properties) */
+ private static final Map<String, Integer> loggerLevels= new HashMap<String, Integer>();
+
+ /** Map of all known loggers. */
+ private static final Map<Class, Logger> loggers= new HashMap<Class, Logger>();
+
+ /** The logging level of the root logger (defaults to warn). */
+ private static int rootLoggerLevel= WARN;
+
+ /** Should log4testng log what it is doing (defaults to false). */
+ private static boolean debug= false;
+
+ /** The logger's level */
+ private final int level;
+
+ /** The logger's name. */
+ private final Class klass;
+ private final String m_className;
+
+ /**
+ * Retrieve a logger named according to the value of the pClass.getName()
+ * parameter. If the named logger already exists, then the existing instance
+ * will be returned. Otherwise, a new instance is created. By default, loggers
+ * do not have a set level but inherit it from their nearest ancestor with
+ * a set level.
+ *
+ * @param pClass The class' logger to retrieve.
+ * @return a logger named according to the value of the pClass.getName().
+ */
+ public static synchronized Logger getLogger(Class pClass) {
+ initialize();
+ Logger logger= loggers.get(pClass);
+ if(logger != null) {
+ return logger;
+ }
+ int level= getLevel(pClass);
+ logger= new Logger(pClass, level);
+ loggers.put(pClass, logger);
+
+ return logger;
+ }
+
+ /**
+ * Check whether this logger is enabled for the TRACE Level.
+ * @return true if this logger is enabled for level TRACE, false otherwise.
+ */
+ public boolean isTraceEnabled() {
+ return isLevelEnabled(TRACE);
+ }
+
+ /**
+ * Log a message object with the TRACE level. This method first checks if this
+ * logger is TRACE enabled. If this logger is TRACE enabled, then it converts
+ * the message object (passed as parameter) to a string by invoking toString().
+ * WARNING Note that passing a Throwable to this method will print the name of
+ * the Throwable but no stack trace. To print a stack trace use the
+ * trace(Object, Throwable) form instead.
+ * @param message the message object to log.
+ */
+ public void trace(Object message) {
+ log(TRACE, message, null);
+ }
+
+ /**
+ * Log a message object with the TRACE level including the stack trace of the
+ * Throwable t passed as parameter.
+ * See Logger.trace(Object) form for more detailed information.
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ public void trace(Object message, Throwable t) {
+ log(TRACE, message, t);
+ }
+
+ /**
+ * Check whether this logger is enabled for the DEBUG Level.
+ * @return true if this logger is enabled for level DEBUG, false otherwise.
+ */
+ public boolean isDebugEnabled() {
+ return isLevelEnabled(DEBUG);
+ }
+
+ /**
+ * Log a message object with the DEBUG level.
+ * See Logger.trace(Object) form for more detailed information.
+ * @param message the message object to log.
+ */
+ public void debug(Object message) {
+ log(DEBUG, message, null);
+ }
+
+ /**
+ * Log a message object with the DEBUG level including the stack trace of the
+ * Throwable t passed as parameter.
+ * See Logger.trace(Object, Throwable) form for more detailed information.
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ public void debug(Object message, Throwable t) {
+ log(DEBUG, message, t);
+ }
+
+ /**
+ * Check whether this logger is enabled for the INFO Level.
+ * @return true if this logger is enabled for level INFO, false otherwise.
+ */
+ public boolean isInfoEnabled() {
+ return isLevelEnabled(INFO);
+ }
+
+ /**
+ * Log a message object with the INFO level.
+ * See Logger.trace(Object) form for more detailed information.
+ * @param message the message object to log.
+ */
+ public void info(Object message) {
+ log(INFO, message, null);
+ }
+
+ /**
+ * Log a message object with the WARN level including the stack trace of the
+ * Throwable t passed as parameter.
+ * See Logger.trace(Object, Throwable) form for more detailed information.
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ public void info(Object message, Throwable t) {
+ log(INFO, message, t);
+ }
+
+ /**
+ * Log a message object with the WARN level.
+ * See Logger.trace(Object) form for more detailed information.
+ * @param message the message object to log.
+ */
+ public void warn(Object message) {
+ log(WARN, message, null);
+ }
+
+ /**
+ * Log a message object with the ERROR level including the stack trace of the
+ * Throwable t passed as parameter.
+ * See Logger.trace(Object, Throwable) form for more detailed information.
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ public void warn(Object message, Throwable t) {
+ log(WARN, message, t);
+ }
+
+ /**
+ * Log a message object with the ERROR level.
+ * See Logger.trace(Object) form for more detailed information.
+ * @param message the message object to log.
+ */
+ public void error(Object message) {
+ log(ERROR, message, null);
+ }
+
+ /**
+ * Log a message object with the DEBUG level including the stack trace of the
+ * Throwable t passed as parameter.
+ * See Logger.trace(Object, Throwable) form for more detailed information.
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ public void error(Object message, Throwable t) {
+ log(ERROR, message, t);
+ }
+
+ /**
+ * Log a message object with the FATAL level.
+ * See Logger.trace(Object) form for more detailed information.
+ * @param message the message object to log.
+ */
+ public void fatal(Object message) {
+ log(FATAL, message, null);
+ }
+
+ /**
+ * Log a message object with the FATAL level including the stack trace of the
+ * Throwable t passed as parameter.
+ * See Logger.trace(Object, Throwable) form for more detailed information.
+ * @param message the message object to log.
+ * @param t the exception to log, including its stack trace.
+ */
+ public void fatal(Object message, Throwable t) {
+ log(FATAL, message, t);
+ }
+
+ private Logger(Class pClass, int pLevel) {
+ level= pLevel;
+ klass= pClass;
+ m_className= pClass.getName().substring(pClass.getName().lastIndexOf('.') + 1);
+ }
+
+ private static synchronized void initialize() {
+ if(initialized) {
+ return;
+ }
+
+ // We flag as initialized right away because if anything goes wrong
+ // We still consider it initialized. TODO Is this OK?
+ initialized= true;
+
+ InputStream is= Thread.currentThread().getContextClassLoader().getResourceAsStream("log4testng.properties");
+ if(is == null) {
+ return;
+ }
+ Properties properties= new Properties();
+ try {
+ properties.load(is);
+ }
+ catch(IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ checkProperties(properties);
+ }
+
+ private static void checkProperties(Properties pProperties) {
+ {
+ // See if we want to debug log4testng
+ String debugStr= pProperties.getProperty(DEBUG_PROPERTY);
+ if(debugStr != null) {
+ if(debugStr.equalsIgnoreCase("true")) {
+ debug= true;
+ }
+ else if(debugStr.equalsIgnoreCase("false")) {
+ debug= false;
+ }
+ else {
+ throw new IllegalArgumentException("Unknown " + DEBUG_PROPERTY
+ + " value " + debugStr);
+ }
+ }
+ loglog4testng("log4testng.debug set to " + debug);
+ }
+
+ {
+ // Set the value of the root logger (if any).
+ String rootLevelStr= pProperties.getProperty(ROOT_LOGGER);
+ if(rootLevelStr != null) {
+ Integer ilevel= levelMap.get(rootLevelStr.toUpperCase());
+ if(ilevel == null) {
+ throw new IllegalArgumentException("Unknown level for log4testng.rootLogger "
+ + rootLevelStr + " in log4testng.properties");
+ }
+ rootLoggerLevel= ilevel.intValue();
+ loglog4testng("Root level logger set to " + rootLevelStr + " level.");
+ }
+ }
+
+ Iterator it= pProperties.entrySet().iterator();
+ while(it.hasNext()) {
+ Map.Entry entry= (Entry) it.next();
+ String logger= (String) entry.getKey();
+ String level= (String) entry.getValue();
+
+ if(!logger.startsWith(PREFIX)) {
+ throw new IllegalArgumentException("Illegal property value: " + logger);
+ }
+ if(logger.equals(DEBUG_PROPERTY)) {
+ // Already handled
+ }
+ else if(logger.equals(ROOT_LOGGER)) {
+ // Already handled
+ }
+ else {
+ if(!logger.startsWith(LOGGER_PREFIX)) {
+ throw new IllegalArgumentException("Illegal property value: " + logger);
+ }
+
+ Integer ilevel= levelMap.get(level.toUpperCase());
+ if(ilevel == null) {
+ throw new IllegalArgumentException("Unknown level " + level + " for logger " + logger
+ + " in log4testng.properties");
+ }
+
+ loggerLevels.put(logger.substring(LOGGER_PREFIX.length()), ilevel);
+ loglog4testng("logger " + logger + " set to " + ilevel + " level.");
+ }
+ }
+ }
+
+ /**
+ * Returns the level associated to the current class. The level is obtain by searching
+ * for a logger in the "testng-logging.properties" resource. For example, if class is
+ * "org.testng.TestNG" the the following loggers are searched in this order:
+ * <ol>
+ * <li>"org.testng.TestNG"</li>
+ * <li>"org.testng"</li>
+ * <li>"org"</li>
+ * <li>The root level</li>
+ * </ol>
+ *
+ * @param pClass the class name used for logger name.
+ * @return the level associated to the current class.
+ */
+ private static int getLevel(Class pClass) {
+ String name= pClass.getName();
+ loglog4testng("Getting level for logger " + name);
+ while(true) {
+ Integer level= loggerLevels.get(name);
+ if(level != null) {
+ loglog4testng("Found level " + level + " for logger " + name);
+
+ return level.intValue();
+ }
+ int dot= name.lastIndexOf('.');
+ if(dot != -1) {
+ loglog4testng("Found level " + rootLoggerLevel + " for root logger");
+
+ // Logger name not found. Defaults to root logger level.
+ return rootLoggerLevel;
+ }
+ name= name.substring(0, dot);
+ }
+ }
+
+ private boolean isLevelEnabled(int pLevel) {
+ return level <= pLevel;
+ }
+
+ private void log(int pLevel, Object pMessage, Throwable pT) {
+ if(isLevelEnabled(pLevel)) {
+ PrintStream ps= (pLevel >= ERROR) ? err : out;
+ if(null != pT) {
+ synchronized(ps) {
+ ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage);
+ pT.printStackTrace(ps);
+ }
+ }
+ else {
+ ps.println("[" + m_className + "] [" + levelNames[pLevel] + "] " + pMessage);
+ }
+ }
+ }
+
+ /**
+ * Logs the message to System.out of debug is on.
+ * @param pmessage the message to log to the console
+ */
+ private static void loglog4testng(String pmessage) {
+ if(debug) {
+ out.println("[log4testng] [debug] " + pmessage);
+ }
+ }
+
+ /**
+ * This method is for debugging purpose only.
+ *
+ * @param pProperties a properties bundle initialised as log4testng
+ * property file would be.
+ * @param pOut the standard output stream to be used for logging.
+ * @param pErr the standard error stream to be used for logging.
+ */
+ private static synchronized void testInitialize(Properties pProperties,
+ PrintStream pOut,
+ PrintStream pErr) {
+ initialized= true;
+ loggers.clear();
+ rootLoggerLevel= WARN;
+ debug= false;
+ out= pOut;
+ err= pErr;
+ checkProperties(pProperties);
+ }
+
+ /**
+ * Makes sure the default debug value is false.
+ */
+ private static void testDebugDefault() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.rootLogger", "WARN");
+ testInitialize(props, out2, err2);
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ }
+
+ /**
+ * Makes sure the debug value can be turned on and actualls logs something.
+ */
+ private static void testDebugOn() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.debug", "true");
+ props.put("log4testng.rootLogger", "WARN");
+ testInitialize(props, out2, err2);
+ Assert.assertTrue(out1.toString().startsWith("[log4testng][debug]"));
+ Assert.assertEquals(err1.toString(), "");
+ }
+
+ /**
+ * Makes sure the debug value can be turned off and logs nothing.
+ */
+ private static void testDebugOff() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.debug", "false");
+ props.put("log4testng.rootLogger", "WARN");
+ testInitialize(props, out2, err2);
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ }
+
+ /**
+ * Makes sure an illegal debug value throws an exception.
+ */
+ private static void testDebugError() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.debug", "unknown");
+ props.put("log4testng.rootLogger", "WARN");
+ try {
+ testInitialize(props, out2, err2);
+ throw new RuntimeException("failure");
+ }
+ catch(IllegalArgumentException pEx) {
+
+ // Normal case
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ }
+ }
+
+ /**
+ * Tests that the root logger's default level is WARN and that loggers do not
+ * log bellow this level and do log in the correct stream for levels equal to
+ * and above WARN.
+ */
+ private static void testRootLoggerDefault() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ testInitialize(props, out2, err2);
+
+ Logger strLogger= Logger.getLogger(String.class);
+ strLogger.trace("trace should not appear");
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.debug("debug should not appear");
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.info("info should not appear");
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.warn("warn should appear");
+ int outlength= out1.toString().length();
+ Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [WARN] warn should appear"));
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.error("error should appear");
+ Assert.assertEquals(out1.toString().length(), outlength);
+ Assert.assertTrue(err1.toString().startsWith("[java.lang.String] [ERROR] error should appear"));
+ strLogger.fatal("fatal should appear");
+ Assert.assertEquals(out1.toString().length(), outlength);
+ Assert.assertTrue(err1.toString().contains("[java.lang.String] [FATAL] fatal should appear"));
+ }
+
+ /**
+ * Test setting the root logger level
+ */
+ private static void testRootLoggerSet() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.rootLogger", "DEBUG");
+ testInitialize(props, out2, err2);
+
+ Logger strLogger= Logger.getLogger(String.class);
+ strLogger.trace("trace should appear");
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.debug("debug should appear");
+ Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
+ Assert.assertEquals(err1.toString(), "");
+ }
+
+ /**
+ * Test setting the root logger to an illegal level value throws an exception.
+ */
+ private static void testRootLoggerSetError() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.rootLogger", "unknown");
+ try {
+ testInitialize(props, out2, err2);
+ throw new RuntimeException("failure");
+ }
+ catch(IllegalArgumentException pEx) {
+
+ // Normal case
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ }
+ }
+
+ /**
+ * Test setting a user logger level
+ */
+ private static void testUserLoggerSet() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.logger.java.lang.String", "DEBUG");
+ testInitialize(props, out2, err2);
+
+ Logger strLogger= Logger.getLogger(String.class);
+ strLogger.trace("trace should not appear");
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.debug("debug should appear");
+ int outLength= out1.toString().length();
+ Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
+ Assert.assertEquals(err1.toString(), "");
+
+ Logger classLogger= Logger.getLogger(Class.class);
+ classLogger.debug("debug should not appear");
+ Assert.assertEquals(out1.toString().length(), outLength);
+ Assert.assertEquals(err1.toString(), "");
+ classLogger.warn("warn should appear");
+ Assert.assertTrue(out1.toString().contains("[java.lang.Class] [WARN] warn should appear"));
+ Assert.assertEquals(err1.toString(), "");
+ }
+
+ /**
+ * Test setting a user logger to an illegal level value throws an exception
+ */
+ private static void testUserLoggerSetError() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.logger.java.lang.String", "unknown");
+ try {
+ testInitialize(props, out2, err2);
+ throw new RuntimeException("failure");
+ }
+ catch(IllegalArgumentException pEx) {
+
+ // Normal case
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ }
+ }
+
+ /**
+ * Tests setting a partial logger name (a hierarchy scope)
+ */
+ private static void testUserLoggerSetHierarchy() {
+ Properties props= new Properties();
+ ByteArrayOutputStream out1= new ByteArrayOutputStream();
+ ByteArrayOutputStream err1= new ByteArrayOutputStream();
+ PrintStream out2= new PrintStream(out1);
+ PrintStream err2= new PrintStream(err1);
+ props.put("log4testng.logger.java.lang", "DEBUG");
+ testInitialize(props, out2, err2);
+
+ Logger strLogger= Logger.getLogger(String.class);
+ strLogger.trace("trace should not appear");
+ Assert.assertEquals(out1.toString(), "");
+ Assert.assertEquals(err1.toString(), "");
+ strLogger.debug("debug should appear");
+ Assert.assertTrue(out1.toString().startsWith("[java.lang.String] [DEBUG] debug should appear"));
+ Assert.assertEquals(err1.toString(), "");
+ }
+
+ /**
+ * Run all tests. (very crusty ...)
+ * @param pArgs not used
+ */
+ public static void main(String[] pArgs) {
+ testDebugDefault();
+ testDebugOn();
+ testDebugOff();
+ testDebugError();
+ testRootLoggerDefault();
+ testRootLoggerSet();
+ testRootLoggerSetError();
+ testUserLoggerSet();
+ testUserLoggerSetError();
+ testUserLoggerSetHierarchy();
+ }
+}