add gogo cli for junit testing (FELIX-1358)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@906437 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/bldcommon/ivysettings.xml b/sigil/bldcommon/ivysettings.xml
index 7704355..760115c 100644
--- a/sigil/bldcommon/ivysettings.xml
+++ b/sigil/bldcommon/ivysettings.xml
@@ -91,6 +91,7 @@
     <module organisation="org.eclipse2" resolver="eclipse2"/>
     <module organisation="org.apache" name="felix\.sigil.*" matcher="regexp" resolver="default"/>
     <module organisation="org.apache" resolver="apache"/>
+    <module organisation="org.apache.ant" resolver="apache"/>
     <module organisation="biz.aQute" resolver="aQute"/>
     <module organisation="org.codehaus.groovy" resolver="apache" />
   </modules>
diff --git a/sigil/gogo/build.xml b/sigil/gogo/build.xml
new file mode 100644
index 0000000..e8b2dd0
--- /dev/null
+++ b/sigil/gogo/build.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+<project name="gogo" default="build-list">
+  <import file="../bldcommon/common.xml"/>
+</project>
diff --git a/sigil/gogo/junit/.classpath b/sigil/gogo/junit/.classpath
new file mode 100644
index 0000000..0b3e710
--- /dev/null
+++ b/sigil/gogo/junit/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.apache.felix.sigil.classpathContainer"/>
+	<classpathentry kind="lib" path="lib/ant-junit-1.7.1.jar"/>
+	<classpathentry kind="output" path="build/classes"/>
+</classpath>
diff --git a/sigil/gogo/junit/.project b/sigil/gogo/junit/.project
new file mode 100644
index 0000000..83e5136
--- /dev/null
+++ b/sigil/gogo/junit/.project
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.felix.sigil.gogo.junit</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.apache.felix.sigil.eclipse.core.sigilBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.apache.felix.sigil.sigilnature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/sigil/gogo/junit/build.xml b/sigil/gogo/junit/build.xml
new file mode 100644
index 0000000..1abba77
--- /dev/null
+++ b/sigil/gogo/junit/build.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+<project name="gogo.junit" default="build"
+  xmlns:ivy="antlib:org.apache.ivy.ant">
+  <import file="../build.xml"/>
+  <target name="init">
+  	<ivy:retrieve inline="true" organisation="org.apache.ant" module="ant-junit" revision="1.7.1" transitive="false" />
+  </target>
+</project>
diff --git a/sigil/gogo/junit/ivy.xml b/sigil/gogo/junit/ivy.xml
new file mode 100644
index 0000000..1dfa96b
--- /dev/null
+++ b/sigil/gogo/junit/ivy.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+<ivy-module version="1.0">
+  <info 
+       organisation="org.apache"
+       module="felix.sigil.gogo.junit"
+       status="integration"/>
+  <publications>
+    <artifact name="org.apache.felix.sigil.gogo.junit" />
+  </publications>
+  
+  <dependencies>
+    <dependency org="org.apache" name="ant" rev="1.7.1">
+      <artifact name="ant-junit" type="jar" />
+    </dependency>
+  </dependencies> 
+</ivy-module>
diff --git a/sigil/gogo/junit/sigil.properties b/sigil/gogo/junit/sigil.properties
new file mode 100644
index 0000000..babc576
--- /dev/null
+++ b/sigil/gogo/junit/sigil.properties
@@ -0,0 +1,19 @@
+
+# sigil project file, saved by plugin.
+
+version: 0.0.0
+
+-bundles: \
+	org.apache.felix.sigil.gogo.junit, \
+
+-sourcedirs: \
+	src, \
+
+-imports: \
+	junit.framework;version=4.4.0, \
+	org.apache.commons.cli;version=1.2.0, \
+	org.apache.felix.sigil.junit.server;version=0.9.0, \
+	org.apache.tools.ant;version=1.7.0, \
+	org.osgi.framework;version=1.5.0, \
+
+# end
diff --git a/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/Activator.java b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/Activator.java
new file mode 100644
index 0000000..905e9ce
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/Activator.java
@@ -0,0 +1,17 @@
+package org.apache.felix.sigil.gogo.junit;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class Activator implements BundleActivator
+{
+
+    public void start( BundleContext ctx ) throws Exception
+    {
+    }
+
+    public void stop( BundleContext ctx ) throws Exception
+    {
+    }
+
+}
diff --git a/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/PrintListener.java b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/PrintListener.java
new file mode 100644
index 0000000..162bfcf
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/PrintListener.java
@@ -0,0 +1,33 @@
+package org.apache.felix.sigil.gogo.junit;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+
+public class PrintListener implements TestListener {
+
+    public PrintListener() {
+    }
+
+    public void startTest(Test test) {
+        System.out.println( "Start " + test );
+        System.out.flush();
+    }
+
+    public void endTest(Test test) {
+        System.out.println( "End " + test );
+        System.out.flush();
+    }
+
+
+    public void addError(Test test, Throwable t) {
+        System.out.println( "Error " + test );
+        t.printStackTrace(System.out);
+        System.out.flush();
+    }
+
+    public void addFailure(Test test, AssertionFailedError error) {
+        System.out.println( "Failure " + test + ": " + error.getMessage() );
+        System.out.flush();
+    }
+}
diff --git a/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunit.java b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunit.java
new file mode 100644
index 0000000..dd3df5f
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunit.java
@@ -0,0 +1,156 @@
+package org.apache.felix.sigil.gogo.junit;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.regex.Pattern;
+
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
+import org.apache.felix.sigil.junit.server.JUnitService;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
+import org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter;
+
+public class SigilJunit
+{
+    private static final Options OPTIONS;
+    
+    static {
+        OPTIONS = new Options();
+        OPTIONS.addOption("d", "dir", true, "Directory to write ant test results to");
+        OPTIONS.addOption("q", "quiet", false, "Run tests quietly, i.e. don't print steps to console" );
+    }
+    
+    private JUnitService service;
+
+    public void junit(String[] args) throws IOException, ParseException {
+        Parser p = new GnuParser();
+        CommandLine cmd = p.parse(OPTIONS, args);
+        String[] cargs = cmd.getArgs();
+        if ( cargs.length == 0 ) {
+            for ( String t : service.getTests() ) {
+                System.out.println( "\t" + t );
+                System.out.flush();
+            }
+        }
+        else {
+            boolean quiet = cmd.hasOption( 'q' );
+            String d = cmd.getOptionValue('d');
+            File dir = null;
+            if ( d != null ) {
+                dir = new File(d);
+                dir.mkdirs();
+                System.out.println( "Writing results to " + dir.getAbsolutePath() );
+                System.out.flush();
+            }
+            runTests( cargs, quiet, dir );
+        }
+    }
+    
+    private void runTests(String[] args, boolean quiet, File dir) throws IOException {
+        int count = 0;
+        int failures = 0;
+        int errors = 0;
+        for ( String t : args ) {
+            TestSuite[] tests = findTests( t );
+            if ( tests.length == 0 ) {
+                System.err.println( "No tests found for " + t );
+            }
+            else {
+                for ( TestSuite test : tests ) {
+                    TestResult result = new TestResult();
+                    if ( !quiet ) {
+                        result.addListener( new PrintListener());
+                    }
+                    
+                    JUnitTest antTest = null;
+                    FileOutputStream fout = null;
+                    XMLJUnitResultFormatter formatter = null;
+                    
+                    if ( dir != null ) {
+                        antTest = new JUnitTest(t, false, false, true);
+        
+                        formatter = new XMLJUnitResultFormatter();
+                        formatter.startTestSuite(antTest);
+        
+                        String name = "TEST-" + test.getName() + ".xml";
+                        
+                        File f = new File( dir, name );
+                        fout = new FileOutputStream( f );
+                        formatter.setOutput(fout);
+                        result.addListener(formatter);
+                    }
+                    
+                    test.run(result);
+                    
+                    if ( dir != null ) {
+                        antTest.setCounts(result.runCount(), result.failureCount(), result.errorCount());
+                        formatter.endTestSuite(antTest);
+                        fout.flush();
+                        fout.close();
+                    }
+                    count += result.runCount();
+                    failures += result.failureCount();
+                    errors += result.errorCount();
+                }
+            }
+        }
+        
+        System.out.println( "Ran " + count + " tests. " + failures + " failures " + errors + " errors." );
+        System.out.flush();
+    }
+
+    private TestSuite[] findTests(String t) {
+        if ( t.contains("*" ) ) {
+            Pattern p = compile(t);
+            LinkedList<TestSuite> tests = new LinkedList<TestSuite>();
+            for ( String n : service.getTests() ) {
+                if ( p.matcher(n).matches() ) {
+                    tests.add( service.createTest(n) );
+                }
+            }
+            return tests.toArray( new TestSuite[tests.size()] );
+        }
+        else {
+            TestSuite test = service.createTest(t);
+            return test == null ? new TestSuite[0] : new TestSuite[] { test };
+        }
+    }
+
+    public static final Pattern compile(String glob) {
+        char[] chars = glob.toCharArray();
+        if ( chars.length > 0 ) {
+            StringBuilder builder = new StringBuilder(chars.length + 5);
+    
+            builder.append('^');
+            
+            for (char c : chars) {
+                switch ( c ) {
+                case '*':
+                    builder.append(".*");
+                    break;
+                case '.':
+                    builder.append("\\.");
+                    break;
+                case '$':
+                    builder.append( "\\$" );
+                    break;
+                default:
+                    builder.append( c );
+                }
+            }
+    
+            return Pattern.compile(builder.toString());
+        }
+        else {
+            return Pattern.compile(glob);
+        }
+    }    
+}