Bug 42094: Adding tests (currently failing) and web content

git-svn-id: https://svn.apache.org/repos/asf/logging/sandbox/log4j/component@530637 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 24ef261..b5bec10 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,12 +22,15 @@
   <artifactId>apache-log4j-component</artifactId>
   <packaging>jar</packaging>
   <version>0.1-SNAPSHOT</version>
-  <name>apache-log4j-component</name>
-  <description>log4j 1.3 component framework</description>
-  <url>http://logging.apache.org</url>
+  <name>Component</name>
+  <description>This companion emulates the log4j 1.3 Component Framework to
+  simplify the back-porting of code that made use of its services.  It does
+  not provide any immediately useful functionality to log4j by itself,
+  but is used by Receivers and Chainsaw.</description>
+  <url>http://logging.apache.org/log4j/companions/component</url>
   <issueManagement>
     <system>Bugzilla</system>
-    <url>http://issues.apache.org/bugzilla</url>
+    <url>http://issues.apache.org/bugzilla/</url>
   </issueManagement>
 <mailingLists>
 	<mailingList>
@@ -53,6 +56,14 @@
 		</otherArchives>
 	</mailingList>
 </mailingLists>
+<developers>
+    <developer>
+    	<id>carnold</id>
+    	<name>Curt Arnold</name>
+    	<email>carnold@apache.org</email>
+    	<timezone>-6</timezone>
+    </developer>
+ </developers>
 <licenses>
 	<license>
 		<name>Apache License, Version 2.0</name>
@@ -88,6 +99,19 @@
             <target>1.3</target>
         </configuration>
       </plugin>
+	<!-- clean stray cobertura.ser -->
+  <plugin> 
+   <groupId>org.codehaus.mojo</groupId> 
+   <artifactId>cobertura-maven-plugin</artifactId> 
+   <executions> 
+    <execution> 
+     <id>clean</id> 
+     <goals> 
+      <goal>clean</goal> 
+     </goals> 
+    </execution> 
+   </executions> 
+  </plugin> 
     </plugins>
 </build>
   <dependencies>
@@ -122,7 +146,35 @@
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>jxr-maven-plugin</artifactId>
       </plugin>
+ 	<plugin> 
+    	<groupId>org.apache.maven.plugins</groupId> 
+    	<artifactId>maven-surefire-report-plugin</artifactId>    
+    </plugin> 
+	  <!-- plugin> 
+ 		<groupId>org.codehaus.mojo</groupId> 
+ 		<artifactId>cobertura-maven-plugin</artifactId> 
+	  </plugin -->   
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-changes-plugin</artifactId>
+      	<reportSets>
+          <reportSet>
+            <reports>
+              <report>changes-report</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+        <configuration>
+        	<issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
+        </configuration>
+      </plugin>      
     </plugins>
   </reporting>
+ <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/home/carnold/public_html/log4j/companions/component</url>
+    </site>
+  </distributionManagement> 
   
 </project>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
new file mode 100644
index 0000000..8830e38
--- /dev/null
+++ b/src/changes/changes.xml
Binary files differ
diff --git a/src/site/resources/css/site.css b/src/site/resources/css/site.css
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/site/resources/css/site.css
@@ -0,0 +1 @@
+
diff --git a/src/site/resources/images/logo.jpg b/src/site/resources/images/logo.jpg
new file mode 100644
index 0000000..5b6ede8
--- /dev/null
+++ b/src/site/resources/images/logo.jpg
Binary files differ
diff --git a/src/site/resources/images/ls-logo.jpg b/src/site/resources/images/ls-logo.jpg
new file mode 100755
index 0000000..611c5c3
--- /dev/null
+++ b/src/site/resources/images/ls-logo.jpg
Binary files differ
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..04ef9fa
--- /dev/null
+++ b/src/site/site.xml
Binary files differ
diff --git a/src/test/java/org/apache/log4j/plugins/PluginTestCase.java b/src/test/java/org/apache/log4j/plugins/PluginTestCase.java
new file mode 100644
index 0000000..b76cd70
--- /dev/null
+++ b/src/test/java/org/apache/log4j/plugins/PluginTestCase.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.plugins;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Hierarchy;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.SimpleLayout;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.spi.RootLogger;
+import org.apache.log4j.util.Compare;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import java.io.File;
+import java.io.IOException;
+
+import java.util.HashMap;
+import org.apache.log4j.LoggerRepositoryExImpl;
+
+
+public class PluginTestCase extends TestCase {
+
+    static String FILE = "output/plugins.PluginTestCase";
+    static String WITNESS = "witness/plugins.PluginTestCase";
+    private static boolean verbosePluginOutput = true;
+    private static HashMap repositoryMap = new HashMap();
+
+    PluginRegistry pluginRegistry;
+
+    public void setUp() {
+        pluginRegistry = new LoggerRepositoryExImpl(
+                LogManager.getLoggerRepository()).getPluginRegistry();
+
+        // delete the output file if they happen to exist
+        new File(getOutputFile("test1")).delete();
+    }
+
+    private String getOutputFile(String caseName) {
+
+        return FILE + "." + caseName + ".txt";
+    }
+
+    private String getWitnessFile(String caseName) {
+
+        return WITNESS + "." + caseName + ".txt";
+    }
+
+    private void setupAppender(String caseName) throws IOException {
+
+        Logger root = Logger.getRootLogger();
+        root.removeAllAppenders();
+
+        // set up appender
+        FileAppender appender = new FileAppender(new SimpleLayout(),
+                getOutputFile(caseName), false);
+
+        //FileAppender appender = new FileAppender(new PatternLayout("%c{1}: %m%n"),
+        //  getOutputFile(caseName), false);
+        root.addAppender(appender);
+        root.setLevel(Level.DEBUG);
+    }
+    
+    
+
+    public PluginTestCase(final String testName) {
+        super(testName);
+    }
+
+    public void test1() throws Exception {
+
+        String testName = "test1";
+        Logger logger = Logger.getLogger(testName);
+
+        setupAppender(testName);
+
+        PluginTester plugin1 = new PluginTester1("plugin1", 1);
+        PluginTester plugin2 = new PluginTester1("plugin1", 2);
+        PluginTester plugin3 = new PluginTester2("plugin1", 3);
+        PluginTester plugin4 = new PluginTester2("plugin2", 4);
+        PluginTester retPlugin;
+
+        repositoryMap.clear();
+        repositoryMap.put(LogManager.getLoggerRepository(),
+            "default repository");
+
+        // test basic starting/stopping
+        logger.info("test 1.1 - basic starting/stopping");
+        logger.info("starting " + plugin1.getIdentifier());
+        pluginRegistry.addPlugin(plugin1);
+        logger.info("stopping " + plugin1.getIdentifier() +
+            " using plugin object");
+        pluginRegistry.stopPlugin(plugin1.getName());
+
+        // test restarting and starting when already started
+        logger.info("test 1.2 - restarting and starting when already started");
+        logger.info("restarting " + plugin1.getIdentifier());
+        pluginRegistry.addPlugin(plugin1);
+        logger.info("restarting " + plugin1.getIdentifier() + " again");
+        pluginRegistry.addPlugin(plugin1);
+
+        // test stopping and stopping when already stopped
+        logger.info("test 1.3- stopping and stopping when already stopped");
+        logger.info("stopping " + plugin1.getIdentifier());
+        pluginRegistry.stopPlugin(plugin1.getName());
+        logger.info("stopping " + plugin1.getIdentifier() + " again");
+        pluginRegistry.stopPlugin(plugin1.getName());
+
+        logger.info("test 1.4 - restarting then stopping by plugin name");
+        logger.info("starting " + plugin1.getIdentifier());
+        pluginRegistry.addPlugin(plugin1);
+        logger.info("stopping " + plugin1.getIdentifier() +
+            " using plugin name");
+        pluginRegistry.stopPlugin(plugin1.getName());
+
+//        // test starting of an "equal" plugin
+//        logger.info("test 1.5 - starting of an \"equal\" plugin");
+//        logger.info("starting " + plugin1.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin1);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("starting " + plugin2.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin2);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("stopping " + retPlugin.getIdentifier());
+//        pluginRegistry.stopPlugin(retPlugin.getName());
+//
+//        // test starting an "equal" plugin after original stopped
+//        logger.info(
+//            "test 1.6 - starting an \"equal\" plugin after original stopped");
+//        logger.info("starting " + plugin2.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin2);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("stopping " + retPlugin.getIdentifier());
+//        pluginRegistry.stopPlugin(retPlugin.getName());
+//
+//        // test starting of an "unequal" plugin with same name
+//        logger.info(
+//            "test 1.7 - starting of an \"unequal\" plugin with same name");
+//        logger.info("starting " + plugin1.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin1);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("starting " + plugin3.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin3);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("stopping " + retPlugin.getIdentifier());
+//        pluginRegistry.stopPlugin(retPlugin.getName());
+//
+//        // test starting of multiple plugins and stopAll
+//        logger.info("test 1.8 - starting of multiple plugins and stopAll");
+//        logger.info("starting " + plugin1.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin1);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("starting " + plugin4.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin4);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        verbosePluginOutput = false;
+//        logger.info("stopping all plugins");
+//        pluginRegistry.stopAllPlugins();
+//        verbosePluginOutput = true;
+//        logger.info(plugin1.getIdentifier() + " is " +
+//            (plugin1.isActive() ? "active" : "inactive"));
+//        logger.info(plugin4.getIdentifier() + " is " +
+//            (plugin4.isActive() ? "active" : "inactive"));
+//        logger.info("stopping all plugins again");
+//        pluginRegistry.stopAllPlugins();
+//
+//        // test starting of multiple plugins and stopAll
+//        logger.info(
+//            "test 1.9 - starting of multiple plugins, stopping, and stopAll");
+//        logger.info("starting " + plugin1.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin1);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+//        logger.info("starting " + plugin4.getIdentifier());
+//        retPlugin = (PluginTester) pluginRegistry.startPlugin(plugin4);
+//        logger.info("returned plugin is " + retPlugin.getIdentifier());
+        logger.info("stopping " + plugin1.getIdentifier() +
+            " using plugin object");
+        pluginRegistry.stopPlugin(plugin1.getName());
+        verbosePluginOutput = false;
+        logger.info("stopping all plugins");
+        pluginRegistry.stopAllPlugins();
+        verbosePluginOutput = true;
+        logger.info(plugin1.getIdentifier() + " is " +
+            (plugin1.isActive() ? "active" : "inactive"));
+        logger.info(plugin4.getIdentifier() + " is " +
+            (plugin4.isActive() ? "active" : "inactive"));
+        logger.info("stopping all plugins again");
+        pluginRegistry.stopAllPlugins();
+
+        assertTrue(Compare.compare(getOutputFile(testName),
+                getWitnessFile(testName)));
+    }
+
+    public void testPluginListeners() {
+
+        Plugin p = new PluginTester1("MyNewPlugin", 1);
+        PluginListenerLatch l = new PluginListenerLatch();
+        pluginRegistry.stopAllPlugins();
+        pluginRegistry.addPluginListener(l);
+        pluginRegistry.addPlugin(p);
+
+        PluginEvent e = l.LastEvent;
+
+        assertTrue("PluginListener should have been notified of start",
+            l.StartLatch);
+        assertTrue("PluginListener stop latch should not be activated",
+            !l.StopLatch);
+        assertTrue("PluginListener should be given reference to Plugin",
+            e.getPlugin() == p);
+
+        l.reset();
+        pluginRegistry.stopAllPlugins();
+        assertTrue("PluginListener should have been notified of stop",
+            l.StopLatch);
+        assertTrue("PluginListener should not have been notified of start",
+            !l.StartLatch);
+        assertTrue("PluginListener should be given reference to Plugin",
+            l.LastEvent.getPlugin() == p);
+        assertTrue(
+            "PluginListener should have received a distinct event object",
+            l.LastEvent != e);
+    }
+
+
+    public void testPropertyChangeListeners() {
+
+        Plugin plugin = new PluginTester1("PluginTest1", 1);
+
+        final PropertyChangeListenerLatch l = new PropertyChangeListenerLatch();
+        plugin.addPropertyChangeListener(l);
+
+        /**
+         * Test the basic properties and ensure they get latched by notification
+         */
+        plugin.setName("NewName");
+        assertTrue("PropertyChange latch should have been detected",
+            l.isLatched());
+        assertTrue("Old value unexpected: '" + l.getLastEvent().getOldValue() +
+            "'", l.getLastEvent().getOldValue().equals("PluginTest1"));
+        assertTrue("New value unexpected: '" + l.getLastEvent().getNewValue() +
+            "'", l.getLastEvent().getNewValue().equals("NewName"));
+
+        l.reset();
+
+        plugin.removePropertyChangeListener(l);
+        plugin.setName("SecondNewName");
+
+        assertTrue("Should not have been notified/latched", !l.isLatched());
+
+        l.reset();
+
+        /**
+         * Test when only listening for specific property
+         */
+        plugin.addPropertyChangeListener("name", l);
+
+        plugin.setName("NewName2");
+        assertTrue("PropertyChange latch should have been detected",
+            l.isLatched());
+        assertTrue("Old value unexpected: '" + l.getLastEvent().getOldValue() +
+            "'", l.getLastEvent().getOldValue().equals("SecondNewName"));
+        assertTrue("New value unexpected: '" + l.getLastEvent().getNewValue() +
+            "'", l.getLastEvent().getNewValue().equals("NewName2"));
+
+        plugin.removePropertyChangeListener("name", l);
+
+        l.reset();
+
+        /**
+         * setup some assertions before continuing testing to make sure the test code isn't broken
+         */
+        assertTrue("Plugin should not be active just yet", !plugin.isActive());
+        assertTrue("Latch should not be latched", !l.isLatched());
+
+        plugin.addPropertyChangeListener("active", l);
+
+        pluginRegistry.addPlugin(plugin);
+        assertTrue(
+            "Should have been notified of activation when pluginRegistry.start(plugin)",
+            l.isLatched());
+        assertTrue("Active old value should have been false",
+            l.getLastEvent().getOldValue().equals(Boolean.FALSE));
+        assertTrue("Active New value should have been true",
+            l.getLastEvent().getNewValue().equals(Boolean.TRUE));
+
+        pluginRegistry.stopAllPlugins();
+        l.reset();
+        assertTrue("Latch should have been reset", !l.isLatched());
+
+        /**
+         * start afresh
+         */
+        plugin = new PluginTester1("LoggerRepositoryProperty", 2);
+
+        LoggerRepository oldValue = plugin.getLoggerRepository();
+        plugin.addPropertyChangeListener("loggerRepository", l);
+
+        LoggerRepository rep = new Hierarchy(new RootLogger(Level.DEBUG));
+        plugin.setLoggerRepository(rep);
+
+        assertTrue("Should be notified of LoggerRepository property change",
+            l.isLatched());
+        assertTrue("LoggerRepository Old value mismatch",
+            l.getLastEvent().getOldValue() == oldValue);
+        assertTrue("LoggerRepository New vale mismatch",
+            l.getLastEvent().getNewValue() == rep);
+    }
+
+    
+
+    private static class PluginListenerLatch implements PluginListener {
+
+        private boolean StartLatch;
+        private boolean StopLatch;
+        private PluginEvent LastEvent;
+
+        /* (non-Javadoc)
+         * @see org.apache.log4j.plugins.PluginListener#pluginStarted(org.apache.log4j.plugins.PluginEvent)
+         */
+        public void pluginStarted(PluginEvent e) {
+            StartLatch = true;
+            LastEvent = e;
+        }
+
+        /* (non-Javadoc)
+         * @see org.apache.log4j.plugins.PluginListener#pluginStopped(org.apache.log4j.plugins.PluginEvent)
+         */
+        public void pluginStopped(PluginEvent e) {
+            StopLatch = true;
+            LastEvent = e;
+        }
+
+        void reset() {
+            StartLatch = false;
+            StopLatch = false;
+            LastEvent = null;
+        }
+    }
+
+    private static class PropertyChangeListenerLatch
+        implements PropertyChangeListener {
+
+        boolean latch = false;
+        PropertyChangeEvent lastEvent = null;
+
+        /* (non-Javadoc)
+         * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
+         */
+        public void propertyChange(PropertyChangeEvent evt) {
+            latch = true;
+            lastEvent = evt;
+        }
+
+        boolean isLatched() {
+
+            return latch;
+        }
+
+        void reset() {
+            latch = false;
+            lastEvent = null;
+        }
+
+        PropertyChangeEvent getLastEvent() {
+
+            return lastEvent;
+        }
+    }
+
+    /**
+      Class to test the Plugin and PluginRegistry functionality. */
+    private static class PluginTester extends PluginSkeleton {
+
+        protected Logger logger;
+        private boolean active = false;
+        public int id;
+
+        public synchronized boolean isActive() {
+            logger.debug(this.getIdentifier() + " is " +
+                (active ? "active" : "inactive"));
+
+            return active;
+        }
+
+        private synchronized boolean setActive(boolean _active) {
+
+            boolean oldValue = active;
+
+            if (active != _active) {
+                active = _active;
+                firePropertyChange("active", oldValue, active);
+
+                return true;
+            } else {
+
+                return false;
+            }
+        }
+
+        public String getIdentifier() {
+
+            if (verbosePluginOutput) {
+
+                return this.getName() + "-id" + id;
+            } else {
+
+                return "plugin in " +
+                repositoryMap.get(this.getLoggerRepository());
+            }
+        }
+
+        public void activateOptions() {
+
+            if (setActive(true)) {
+                logger.debug(this.getIdentifier() + " activated");
+            } else {
+                logger.debug(this.getIdentifier() + " already activated");
+            }
+        }
+
+        public void shutdown() {
+
+            if (setActive(false)) {
+                logger.debug(this.getIdentifier() + " shutdown");
+            } else {
+                logger.debug(this.getIdentifier() + " already shutdown");
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see org.apache.log4j.plugins.Plugin#isEquivalent(org.apache.log4j.plugins.Plugin)
+         */
+        public boolean isEquivalent(Plugin testPlugin) {
+
+            boolean equiv = super.isEquivalent(testPlugin);
+
+            if (equiv) {
+                logger.debug("plugin equal");
+            } else if (!(testPlugin.getClass() == this.getClass())) {
+                logger.debug(
+                    "plugin not equal, different class: " +
+                    this.getClass().getName() + " != " +
+                    testPlugin.getClass().getName());
+
+            } else if (!this.getName().equals(testPlugin.getName())) {
+                logger.debug(
+                    "plugin not equal, different name: " + this.getName() +
+                    " != " + testPlugin.getName());
+
+            } else if (!this.getLoggerRepository().equals(
+                        testPlugin.getLoggerRepository())) {
+                logger.debug(
+                    "plugin not equal, different repository: " +
+"");//                    repositoryMap.get(this.getLoggerRepository()) + " != " +
+//                    repositoryMap.get(testPlugin.getLoggerRepository()));
+            }
+
+            return equiv;
+        }
+    }
+
+    /**
+      Class to test the Plugin and PluginRegistry functionality. */
+    private static class PluginTester1 extends PluginTester {
+        public PluginTester1(String _name, int _id) {
+            logger = Logger.getLogger(this.getClass());
+            setName(_name);
+            id = _id;
+        }
+    }
+
+    /**
+      Class to test the Plugin and PluginRegistry functionality. */
+    private static class PluginTester2 extends PluginTester {
+        public PluginTester2(String _name, int _id) {
+            logger = Logger.getLogger(this.getClass());
+            setName(_name);
+            id = _id;
+        }
+    }
+
+}
diff --git a/src/test/java/org/apache/log4j/util/Compare.java b/src/test/java/org/apache/log4j/util/Compare.java
new file mode 100644
index 0000000..a67576d
--- /dev/null
+++ b/src/test/java/org/apache/log4j/util/Compare.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.util;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.zip.GZIPInputStream;
+import java.io.*;
+
+
+public class Compare {
+  static final int B1_NULL = -1;
+  static final int B2_NULL = -2;
+
+  public static boolean compare(String file1, String file2)
+    throws IOException {
+    BufferedReader in1 = new BufferedReader(new FileReader(file1));
+    InputStream is = Compare.class.getResourceAsStream("/" + file2);
+    if (is == null) {
+        is = new FileInputStream(file2);
+    }
+    BufferedReader in2 = new BufferedReader(new InputStreamReader(is));
+    try {
+      return compare(file1, file2, in1, in2);
+    } finally {
+      in1.close();
+      in2.close();
+    }
+  }
+    
+ public static boolean compare(String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+    String s1;
+    int lineCounter = 0;
+
+    while ((s1 = in1.readLine()) != null) {
+      lineCounter++;
+
+      String s2 = in2.readLine();
+
+      if (!s1.equals(s2)) {
+        System.out.println(
+          "Files [" + file1 + "] and [" + file2 + "] differ on line "
+          + lineCounter);
+        System.out.println("One reads:  [" + s1 + "].");
+        System.out.println("Other reads:[" + s2 + "].");
+        outputFile(file1);
+        outputFile(file2);
+
+        return false;
+      }
+    }
+
+    // the second file is longer
+    if (in2.read() != -1) {
+      System.out.println(
+        "File [" + file2 + "] longer than file [" + file1 + "].");
+      outputFile(file1);
+      outputFile(file2);
+
+      return false;
+    }
+
+    return true;
+  }
+
+  /** 
+   * 
+   * Prints file on the console.
+   *
+   */
+  private static void outputFile(String file)
+    throws FileNotFoundException, IOException {
+    BufferedReader in1 = new BufferedReader(new FileReader(file));
+
+    String s1;
+    int lineCounter = 0;
+    System.out.println("--------------------------------");
+    System.out.println("Contents of " + file + ":");
+
+    while ((s1 = in1.readLine()) != null) {
+      lineCounter++;
+      System.out.print(lineCounter);
+
+      if (lineCounter < 10) {
+        System.out.print("   : ");
+      } else if (lineCounter < 100) {
+        System.out.print("  : ");
+      } else if (lineCounter < 1000) {
+        System.out.print(" : ");
+      } else {
+        System.out.print(": ");
+      }
+
+      System.out.println(s1);
+    }
+    in1.close();
+  }
+  
+    public static boolean gzCompare(String file1, String file2)
+      throws FileNotFoundException, IOException {
+      BufferedReader in1 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file1))));      
+      BufferedReader in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(file2))));
+      try {
+        return gzCompare(file1, file2, in1, in2);
+      } finally {
+        in1.close();
+        in2.close();
+      }
+    }
+      
+    public static boolean gzCompare(String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+      String s1;
+      int lineCounter = 0;
+
+      while ((s1 = in1.readLine()) != null) {
+        lineCounter++;
+
+        String s2 = in2.readLine();
+
+        if (!s1.equals(s2)) {
+          System.out.println(
+            "Files [" + file1 + "] and [" + file2 + "] differ on line "
+            + lineCounter);
+          System.out.println("One reads:  [" + s1 + "].");
+          System.out.println("Other reads:[" + s2 + "].");
+          outputFile(file1);
+          outputFile(file2);
+
+          return false;
+        }
+      }
+
+      // the second file is longer
+      if (in2.read() != -1) {
+        System.out.println(
+          "File [" + file2 + "] longer than file [" + file1 + "].");
+        outputFile(file1);
+        outputFile(file2);
+
+        return false;
+      }
+
+      return true;
+    }
+}
diff --git a/src/test/resources/witness/plugins.PluginTestCase.test1.txt b/src/test/resources/witness/plugins.PluginTestCase.test1.txt
new file mode 100644
index 0000000..4e30c14
--- /dev/null
+++ b/src/test/resources/witness/plugins.PluginTestCase.test1.txt
@@ -0,0 +1,89 @@
+INFO - test 1.1 - basic starting/stopping
+INFO - starting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - stopping plugin1-id1 using plugin object
+DEBUG - plugin1-id1 shutdown
+INFO - test 1.2 - restarting and starting when already started
+INFO - restarting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - restarting plugin1-id1 again
+DEBUG - plugin1-id1 is active
+INFO - test 1.3- stopping and stopping when already stopped
+INFO - stopping plugin1-id1
+DEBUG - plugin1-id1 shutdown
+INFO - stopping plugin1-id1 again
+INFO - test 1.4 - restarting then stopping by plugin name
+INFO - starting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - stopping plugin1-id1 using plugin name
+DEBUG - plugin1-id1 shutdown
+INFO - test 1.5 - starting of an "equal" plugin
+INFO - starting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - returned plugin is plugin1-id1
+INFO - starting plugin1-id2
+DEBUG - plugin1-id2 is inactive
+DEBUG - plugin equal
+DEBUG - plugin1-id1 is active
+INFO - returned plugin is plugin1-id1
+INFO - stopping plugin1-id1
+DEBUG - plugin1-id1 shutdown
+INFO - test 1.6 - starting an "equal" plugin after original stopped
+INFO - starting plugin1-id2
+DEBUG - plugin1-id2 is inactive
+DEBUG - plugin1-id2 activated
+INFO - returned plugin is plugin1-id2
+INFO - stopping plugin1-id2
+DEBUG - plugin1-id2 shutdown
+INFO - test 1.7 - starting of an "unequal" plugin with same name
+INFO - starting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - returned plugin is plugin1-id1
+INFO - starting plugin1-id3
+DEBUG - plugin1-id3 is inactive
+DEBUG - plugin not equal, different class: org.apache.log4j.plugins.PluginTestCase$PluginTester1 != org.apache.log4j.plugins.PluginTestCase$PluginTester2
+DEBUG - plugin1-id1 shutdown
+DEBUG - plugin1-id3 activated
+INFO - returned plugin is plugin1-id3
+INFO - stopping plugin1-id3
+DEBUG - plugin1-id3 shutdown
+INFO - test 1.8 - starting of multiple plugins and stopAll
+INFO - starting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - returned plugin is plugin1-id1
+INFO - starting plugin2-id4
+DEBUG - plugin2-id4 is inactive
+DEBUG - plugin2-id4 activated
+INFO - returned plugin is plugin2-id4
+INFO - stopping all plugins
+DEBUG - plugin in default repository shutdown
+DEBUG - plugin in default repository shutdown
+DEBUG - plugin1-id1 is inactive
+INFO - plugin1-id1 is inactive
+DEBUG - plugin2-id4 is inactive
+INFO - plugin2-id4 is inactive
+INFO - stopping all plugins again
+INFO - test 1.9 - starting of multiple plugins, stopping, and stopAll
+INFO - starting plugin1-id1
+DEBUG - plugin1-id1 is inactive
+DEBUG - plugin1-id1 activated
+INFO - returned plugin is plugin1-id1
+INFO - starting plugin2-id4
+DEBUG - plugin2-id4 is inactive
+DEBUG - plugin2-id4 activated
+INFO - returned plugin is plugin2-id4
+INFO - stopping plugin1-id1 using plugin object
+DEBUG - plugin1-id1 shutdown
+INFO - stopping all plugins
+DEBUG - plugin in default repository shutdown
+DEBUG - plugin1-id1 is inactive
+INFO - plugin1-id1 is inactive
+DEBUG - plugin2-id4 is inactive
+INFO - plugin2-id4 is inactive
+INFO - stopping all plugins again