add support for scripting junit test scenarios using sigil junit FELIX-2537
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@984419 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/sigil/gogo/junit/sigil.properties b/sigil/gogo/junit/sigil.properties
index 60c6a51..dfafcde 100644
--- a/sigil/gogo/junit/sigil.properties
+++ b/sigil/gogo/junit/sigil.properties
@@ -11,7 +11,6 @@
-imports: \
junit.framework, \
- org.apache.commons.cli, \
org.apache.felix.sigil.common.junit.server, \
org.apache.tools.ant, \
org.apache.tools.ant.taskdefs.optional.junit, \
diff --git a/sigil/gogo/junit/src/org/apache/felix/gogo/options/Option.java b/sigil/gogo/junit/src/org/apache/felix/gogo/options/Option.java
new file mode 100644
index 0000000..6b4a496
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/gogo/options/Option.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+package org.apache.felix.gogo.options;
+
+import java.util.List;
+
+public interface Option {
+ /**
+ * stop parsing on the first unknown option. This allows one parser to get its own options and
+ * then pass the remaining options to another parser.
+ *
+ * @param stopOnBadOption
+ */
+ Option setStopOnBadOption(boolean stopOnBadOption);
+
+ /**
+ * require options to precede args. Default is false, so options can appear between or after
+ * args.
+ *
+ * @param optionsFirst
+ */
+ Option setOptionsFirst(boolean optionsFirst);
+
+ /**
+ * parse arguments. If skipArgv0 is true, then parsing begins at arg1. This allows for commands
+ * where argv0 is the command name rather than a real argument.
+ *
+ * @param argv
+ * @param skipArg0
+ * @return
+ */
+ Option parse(List<? extends Object> argv, boolean skipArg0);
+
+ /**
+ * parse arguments.
+ *
+ * @see {@link #parse(List, boolean)
+
+ */
+ Option parse(List<? extends Object> argv);
+
+ /**
+ * parse arguments.
+ *
+ * @see {@link #parse(List, boolean)
+
+ */
+ Option parse(Object[] argv, boolean skipArg0);
+
+ /**
+ * parse arguments.
+ *
+ * @see {@link #parse(List, boolean)
+
+ */
+ Option parse(Object[] argv);
+
+ /**
+ * test whether specified option has been explicitly set.
+ *
+ * @param name
+ * @return
+ */
+ boolean isSet(String name);
+
+ /**
+ * get value of named option. If multiple options given, this method returns the last one. Use
+ * {@link #getList(String)} to get all values.
+ *
+ * @param name
+ * @return
+ * @throws IllegalArgumentException
+ * if value is not a String.
+ */
+ String get(String name);
+
+ /**
+ * get list of all values for named option.
+ *
+ * @param name
+ * @return empty list if option not given and no default specified.
+ * @throws IllegalArgumentException
+ * if all values are not Strings.
+ */
+ List<String> getList(String name);
+
+ /**
+ * get value of named option as an Object. If multiple options given, this method returns the
+ * last one. Use {@link #getObjectList(String)} to get all values.
+ *
+ * @param name
+ * @return
+ */
+ Object getObject(String name);
+
+ /**
+ * get list of all Object values for named option.
+ *
+ * @param name
+ * @return
+ */
+ List<Object> getObjectList(String name);
+
+ /**
+ * get value of named option as a Number.
+ *
+ * @param name
+ * @return
+ * @throws IllegalArgumentException
+ * if argument is not a Number.
+ */
+ int getNumber(String name);
+
+ /**
+ * get remaining non-options args as Strings.
+ *
+ * @return
+ * @throws IllegalArgumentException
+ * if args are not Strings.
+ */
+ List<String> args();
+
+ /**
+ * get remaining non-options args as Objects.
+ *
+ * @return
+ */
+ List<Object> argObjects();
+
+ /**
+ * print usage message to System.err.
+ */
+ void usage();
+
+ /**
+ * print specified usage error to System.err. You should explicitly throw the returned
+ * exception.
+ *
+ * @param error
+ * @return IllegalArgumentException
+ */
+ IllegalArgumentException usageError(String error);
+}
diff --git a/sigil/gogo/junit/src/org/apache/felix/gogo/options/Options.java b/sigil/gogo/junit/src/org/apache/felix/gogo/options/Options.java
new file mode 100644
index 0000000..e2fdba0
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/gogo/options/Options.java
@@ -0,0 +1,528 @@
+/*
+ * 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.
+ */
+package org.apache.felix.gogo.options;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Yet another GNU long options parser. This one is configured by parsing its Usage string.
+ */
+public class Options implements Option {
+ public static void main(String[] args) {
+ final String[] usage = {
+ "test - test Options usage",
+ " text before Usage: is displayed when usage() is called and no error has occurred.",
+ " so can be used as a simple help message.",
+ "",
+ "Usage: testOptions [OPTION]... PATTERN [FILES]...",
+ " Output control: arbitary non-option text can be included.",
+ " -? --help show help",
+ " -c --count=COUNT show COUNT lines",
+ " -h --no-filename suppress the prefixing filename on output",
+ " -q --quiet, --silent suppress all normal output",
+ " --binary-files=TYPE assume that binary files are TYPE",
+ " TYPE is 'binary', 'text', or 'without-match'",
+ " -I equivalent to --binary-files=without-match",
+ " -d --directories=ACTION how to handle directories (default=skip)",
+ " ACTION is 'read', 'recurse', or 'skip'",
+ " -D --devices=ACTION how to handle devices, FIFOs and sockets",
+ " ACTION is 'read' or 'skip'",
+ " -R, -r --recursive equivalent to --directories=recurse" };
+
+ Option opt = Options.compile(usage).parse(args);
+
+ if (opt.isSet("help")) {
+ opt.usage(); // includes text before Usage:
+ return;
+ }
+
+ if (opt.args().size() == 0)
+ throw opt.usageError("PATTERN not specified");
+
+ System.out.println(opt);
+ if (opt.isSet("count"))
+ System.out.println("count = " + opt.getNumber("count"));
+ System.out.println("--directories specified: " + opt.isSet("directories"));
+ System.out.println("directories=" + opt.get("directories"));
+ }
+
+ public static final String NL = System.getProperty("line.separator", "\n");
+
+ // Note: need to double \ within ""
+ private static final String regex = "(?x)\\s*" + "(?:-([^-]))?" + // 1: short-opt-1
+ "(?:,?\\s*-(\\w))?" + // 2: short-opt-2
+ "(?:,?\\s*--(\\w[\\w-]*)(=\\w+)?)?" + // 3: long-opt-1 and 4:arg-1
+ "(?:,?\\s*--(\\w[\\w-]*))?" + // 5: long-opt-2
+ ".*?(?:\\(default=(.*)\\))?\\s*"; // 6: default
+
+ private static final int GROUP_SHORT_OPT_1 = 1;
+ private static final int GROUP_SHORT_OPT_2 = 2;
+ private static final int GROUP_LONG_OPT_1 = 3;
+ private static final int GROUP_ARG_1 = 4;
+ private static final int GROUP_LONG_OPT_2 = 5;
+ private static final int GROUP_DEFAULT = 6;
+
+ private final Pattern parser = Pattern.compile(regex);
+ private final Pattern uname = Pattern.compile("^Usage:\\s+(\\w+)");
+
+ private final Map<String, Boolean> unmodifiableOptSet;
+ private final Map<String, Object> unmodifiableOptArg;
+ private final Map<String, Boolean> optSet = new HashMap<String, Boolean>();
+ private final Map<String, Object> optArg = new HashMap<String, Object>();
+
+ private final Map<String, String> optName = new HashMap<String, String>();
+ private final Map<String, String> optAlias = new HashMap<String, String>();
+ private final List<Object> xargs = new ArrayList<Object>();
+ private List<String> args = null;
+
+ private static final String UNKNOWN = "unknown";
+ private String usageName = UNKNOWN;
+ private int usageIndex = 0;
+
+ private final String[] spec;
+ private final String[] gspec;
+ private final String defOpts;
+ private final String[] defArgs;
+ private PrintStream errStream = System.err;
+ private String error = null;
+
+ private boolean optionsFirst = false;
+ private boolean stopOnBadOption = false;
+
+ public static Option compile(String[] optSpec) {
+ return new Options(optSpec, null, null);
+ }
+
+ public static Option compile(String optSpec) {
+ return compile(optSpec.split("\\n"));
+ }
+
+ public static Option compile(String[] optSpec, Option gopt) {
+ return new Options(optSpec, null, gopt);
+ }
+
+ public static Option compile(String[] optSpec, String[] gspec) {
+ return new Options(optSpec, gspec, null);
+ }
+
+ public Option setStopOnBadOption(boolean stopOnBadOption) {
+ this.stopOnBadOption = stopOnBadOption;
+ return this;
+ }
+
+ public Option setOptionsFirst(boolean optionsFirst) {
+ this.optionsFirst = optionsFirst;
+ return this;
+ }
+
+ public boolean isSet(String name) {
+ if (!optSet.containsKey(name))
+ throw new IllegalArgumentException("option not defined in spec: " + name);
+
+ return optSet.get(name);
+ }
+
+ public Object getObject(String name) {
+ if (!optArg.containsKey(name))
+ throw new IllegalArgumentException("option not defined with argument: " + name);
+
+ List<Object> list = getObjectList(name);
+
+ return list.isEmpty() ? "" : list.get(list.size() - 1);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<Object> getObjectList(String name) {
+ List<Object> list;
+ Object arg = optArg.get(name);
+
+ if ( arg == null ) {
+ throw new IllegalArgumentException("option not defined with argument: " + name);
+ }
+
+ if (arg instanceof String) { // default value
+ list = new ArrayList<Object>();
+ if (!"".equals(arg))
+ list.add(arg);
+ }
+ else {
+ list = (List<Object>) arg;
+ }
+
+ return list;
+ }
+
+ public List<String> getList(String name) {
+ ArrayList<String> list = new ArrayList<String>();
+ for (Object o : getObjectList(name)) {
+ try {
+ list.add((String) o);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("option not String: " + name);
+ }
+ }
+ return list;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void addArg(String name, Object value) {
+ List<Object> list;
+ Object arg = optArg.get(name);
+
+ if (arg instanceof String) { // default value
+ list = new ArrayList<Object>();
+ optArg.put(name, list);
+ }
+ else {
+ list = (List<Object>) arg;
+ }
+
+ list.add(value);
+ }
+
+ public String get(String name) {
+ try {
+ return (String) getObject(name);
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("option not String: " + name);
+ }
+ }
+
+ public int getNumber(String name) {
+ String number = get(name);
+ try {
+ if (number != null)
+ return Integer.parseInt(number);
+ return 0;
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("option '" + name + "' not Number: " + number);
+ }
+ }
+
+ public List<Object> argObjects() {
+ return xargs;
+ }
+
+ public List<String> args() {
+ if (args == null) {
+ args = new ArrayList<String>();
+ for (Object arg : xargs) {
+ args.add(arg == null ? "null" : arg.toString());
+ }
+ }
+ return args;
+ }
+
+ public void usage() {
+ StringBuilder buf = new StringBuilder();
+ int index = 0;
+
+ if (error != null) {
+ buf.append(error);
+ buf.append(NL);
+ index = usageIndex;
+ }
+
+ for (int i = index; i < spec.length; ++i) {
+ buf.append(spec[i]);
+ buf.append(NL);
+ }
+
+ String msg = buf.toString();
+
+ if (errStream != null) {
+ errStream.print(msg);
+ }
+ }
+
+ /**
+ * prints usage message and returns IllegalArgumentException, for you to throw.
+ */
+ public IllegalArgumentException usageError(String s) {
+ error = usageName + ": " + s;
+ usage();
+ return new IllegalArgumentException(error);
+ }
+
+ // internal constructor
+ private Options(String[] spec, String[] gspec, Option opt) {
+ this.gspec = gspec;
+ Options gopt = (Options) opt;
+
+ if (gspec == null && gopt == null) {
+ this.spec = spec;
+ }
+ else {
+ ArrayList<String> list = new ArrayList<String>();
+ list.addAll(Arrays.asList(spec));
+ list.addAll(Arrays.asList(gspec != null ? gspec : gopt.gspec));
+ this.spec = list.toArray(new String[0]);
+ }
+
+ Map<String, Boolean> myOptSet = new HashMap<String, Boolean>();
+ Map<String, Object> myOptArg = new HashMap<String, Object>();
+
+ parseSpec(myOptSet, myOptArg);
+
+ if (gopt != null) {
+ for (Entry<String, Boolean> e : gopt.optSet.entrySet()) {
+ if (e.getValue())
+ myOptSet.put(e.getKey(), true);
+ }
+
+ for (Entry<String, Object> e : gopt.optArg.entrySet()) {
+ if (!e.getValue().equals(""))
+ myOptArg.put(e.getKey(), e.getValue());
+ }
+
+ gopt.reset();
+ }
+
+ unmodifiableOptSet = Collections.unmodifiableMap(myOptSet);
+ unmodifiableOptArg = Collections.unmodifiableMap(myOptArg);
+
+ defOpts = System.getenv(usageName.toUpperCase() + "_OPTS");
+ defArgs = (defOpts != null) ? defOpts.split("\\s+") : new String[0];
+ }
+
+ /**
+ * parse option spec.
+ */
+ private void parseSpec(Map<String, Boolean> myOptSet, Map<String, Object> myOptArg) {
+ int index = 0;
+ for (String line : spec) {
+ Matcher m = parser.matcher(line);
+
+ if (m.matches()) {
+ final String opt = m.group(GROUP_LONG_OPT_1);
+ final String name = (opt != null) ? opt : m.group(GROUP_SHORT_OPT_1);
+
+ if (name != null) {
+ if (myOptSet.containsKey(name))
+ throw new IllegalArgumentException("duplicate option in spec: --" + name);
+ myOptSet.put(name, false);
+ }
+
+ String dflt = (m.group(GROUP_DEFAULT) != null) ? m.group(GROUP_DEFAULT) : "";
+ if (m.group(GROUP_ARG_1) != null)
+ myOptArg.put(opt, dflt);
+
+ String opt2 = m.group(GROUP_LONG_OPT_2);
+ if (opt2 != null) {
+ optAlias.put(opt2, opt);
+ myOptSet.put(opt2, false);
+ if (m.group(GROUP_ARG_1) != null)
+ myOptArg.put(opt2, "");
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ String sopt = m.group(i == 0 ? GROUP_SHORT_OPT_1 : GROUP_SHORT_OPT_2);
+ if (sopt != null) {
+ if (optName.containsKey(sopt))
+ throw new IllegalArgumentException("duplicate option in spec: -" + sopt);
+ optName.put(sopt, name);
+ }
+ }
+ }
+
+ if (usageName == UNKNOWN) {
+ Matcher u = uname.matcher(line);
+ if (u.find()) {
+ usageName = u.group(1);
+ usageIndex = index;
+ }
+ }
+
+ index++;
+ }
+ }
+
+ private void reset() {
+ optSet.clear();
+ optSet.putAll(unmodifiableOptSet);
+ optArg.clear();
+ optArg.putAll(unmodifiableOptArg);
+ xargs.clear();
+ args = null;
+ error = null;
+ }
+
+ public Option parse(Object[] argv) {
+ return parse(argv, false);
+ }
+
+ public Option parse(List<? extends Object> argv) {
+ return parse(argv, false);
+ }
+
+ public Option parse(Object[] argv, boolean skipArg0) {
+ if (null == argv)
+ throw new IllegalArgumentException("argv is null");
+
+ return parse(Arrays.asList(argv), skipArg0);
+ }
+
+ public Option parse(List<? extends Object> argv, boolean skipArg0) {
+ reset();
+ List<Object> args = new ArrayList<Object>();
+ args.addAll(Arrays.asList(defArgs));
+
+ for (Object arg : argv) {
+ if (skipArg0) {
+ skipArg0 = false;
+ usageName = arg.toString();
+ }
+ else {
+ args.add(arg);
+ }
+ }
+
+ String needArg = null;
+ String needOpt = null;
+ boolean endOpt = false;
+
+ for (Object oarg : args) {
+ String arg = oarg == null ? "null" : oarg.toString();
+
+ if (endOpt) {
+ xargs.add(oarg);
+ }
+ else if (needArg != null) {
+ addArg(needArg, oarg);
+ needArg = null;
+ needOpt = null;
+ }
+ else if (!arg.startsWith("-") || "-".equals(oarg)) {
+ if (optionsFirst)
+ endOpt = true;
+ xargs.add(oarg);
+ }
+ else {
+ if (arg.equals("--"))
+ endOpt = true;
+ else if (arg.startsWith("--")) {
+ int eq = arg.indexOf("=");
+ String value = (eq == -1) ? null : arg.substring(eq + 1);
+ String name = arg.substring(2, ((eq == -1) ? arg.length() : eq));
+ List<String> names = new ArrayList<String>();
+
+ if (optSet.containsKey(name)) {
+ names.add(name);
+ }
+ else {
+ for (String k : optSet.keySet()) {
+ if (k.startsWith(name))
+ names.add(k);
+ }
+ }
+
+ switch (names.size()) {
+ case 1:
+ name = names.get(0);
+ optSet.put(name, true);
+ if (optArg.containsKey(name)) {
+ if (value != null)
+ addArg(name, value);
+ else
+ needArg = name;
+ }
+ else if (value != null) {
+ throw usageError("option '--" + name + "' doesn't allow an argument");
+ }
+ break;
+
+ case 0:
+ if (stopOnBadOption) {
+ endOpt = true;
+ xargs.add(oarg);
+ break;
+ }
+ else
+ throw usageError("invalid option '--" + name + "'");
+
+ default:
+ throw usageError("option '--" + name + "' is ambiguous: " + names);
+ }
+ }
+ else {
+ int i = 0;
+ for (String c : arg.substring(1).split("")) {
+ if (i++ == 0)
+ continue;
+ if (optName.containsKey(c)) {
+ String name = optName.get(c);
+ optSet.put(name, true);
+ if (optArg.containsKey(name)) {
+ if (i < arg.length()) {
+ addArg(name, arg.substring(i));
+ }
+ else {
+ needOpt = c;
+ needArg = name;
+ }
+ break;
+ }
+ }
+ else {
+ if (stopOnBadOption) {
+ xargs.add("-" + c);
+ endOpt = true;
+ }
+ else
+ throw usageError("invalid option '" + c + "'");
+ }
+ }
+ }
+ }
+ }
+
+ if (needArg != null) {
+ String name = (needOpt != null) ? needOpt : "--" + needArg;
+ throw usageError("option '" + name + "' requires an argument");
+ }
+
+ // remove long option aliases
+ for (Entry<String, String> alias : optAlias.entrySet()) {
+ if (optSet.get(alias.getKey())) {
+ optSet.put(alias.getValue(), true);
+ if (optArg.containsKey(alias.getKey()))
+ optArg.put(alias.getValue(), optArg.get(alias.getKey()));
+ }
+ optSet.remove(alias.getKey());
+ optArg.remove(alias.getKey());
+ }
+
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return "isSet" + optSet + "\nArg" + optArg + "\nargs" + xargs;
+ }
+
+}
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
index cee4020..404b859 100644
--- 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
@@ -18,55 +18,66 @@
*/
package org.apache.felix.sigil.gogo.junit;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
import java.util.Hashtable;
-import java.util.Map;
+
+import junit.framework.Assert;
import org.apache.felix.sigil.common.junit.server.JUnitService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
import org.osgi.service.command.CommandProcessor;
import org.osgi.util.tracker.ServiceTracker;
+
public class Activator implements BundleActivator
{
- public void start(final BundleContext ctx) throws Exception
+ public void start( final BundleContext ctx ) throws Exception
{
- final Hashtable props = new Hashtable();
- props.put(CommandProcessor.COMMAND_SCOPE, "sigil");
- props.put(CommandProcessor.COMMAND_FUNCTION, new String[] { "junit" });
+ Hashtable<String, Object> props = new Hashtable<String, Object>();
+ props.put( CommandProcessor.COMMAND_SCOPE, "sigil" );
+ props.put( CommandProcessor.COMMAND_FUNCTION, new String[]
+ { "runTests", "listTests" } );
- ServiceTracker tracker = new ServiceTracker(ctx, JUnitService.class.getName(),
- null)
- {
- private Map<ServiceReference, ServiceRegistration> regs;
-
- @Override
- public Object addingService(ServiceReference reference)
- {
- JUnitService svc = (JUnitService) super.addingService(reference);
- ServiceRegistration reg = ctx.registerService(SigilJunit.class.getName(),
- new SigilJunit(svc), props);
- regs.put(reference, reg);
- return svc;
- }
-
- @Override
- public void removedService(ServiceReference reference, Object service)
- {
- ServiceRegistration reg = regs.remove(reference);
- reg.unregister();
- super.removedService(reference, service);
- }
-
- };
+ ServiceTracker tracker = new ServiceTracker( ctx, JUnitService.class.getName(), null );
tracker.open();
+
+ ctx.registerService( SigilJunitRunner.class.getName(), new SigilJunitRunner( tracker ), props );
+
+ props.put( CommandProcessor.COMMAND_FUNCTION, new String[]
+ { "newTest", "newTestSuite" } );
+ ctx.registerService( SigilTestAdapter.class.getName(), new SigilTestAdapter(), props );
+
+ props.put( CommandProcessor.COMMAND_SCOPE, "junit" );
+ props.put( CommandProcessor.COMMAND_FUNCTION, getAssertMethods() );
+ ctx.registerService( Assert.class.getName(), new Assert()
+ {
+ }, props );
}
- public void stop(BundleContext ctx) throws Exception
+
+ /**
+ * @return
+ */
+ private String[] getAssertMethods()
+ {
+ ArrayList<String> list = new ArrayList<String>();
+ for ( Method m : Assert.class.getDeclaredMethods() )
+ {
+ if ( Modifier.isPublic( m.getModifiers() ) ) {
+ list.add( m.getName() );
+ }
+ }
+ return list.toArray( new String[list.size()] );
+ }
+
+
+ public void stop( BundleContext ctx ) throws Exception
{
}
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
deleted file mode 100644
index f13839e..0000000
--- a/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunit.java
+++ /dev/null
@@ -1,209 +0,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.
- */
-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.common.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 final JUnitService service;
-
- public SigilJunit(JUnitService service)
- {
- this.service = service;
- }
-
- public boolean 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();
- }
- return true;
- }
- 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();
- }
- return runTests(cargs, quiet, dir);
- }
- }
-
- private boolean 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();
-
- return failures + errors == 0;
- }
-
- 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);
- }
- }
-}
diff --git a/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunitRunner.java b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunitRunner.java
new file mode 100644
index 0000000..50f3d4f
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilJunitRunner.java
@@ -0,0 +1,299 @@
+/*
+ * 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.
+ */
+package org.apache.felix.sigil.gogo.junit;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.felix.gogo.options.Option;
+import org.apache.felix.gogo.options.Options;
+import org.apache.felix.sigil.common.junit.server.JUnitService;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
+import org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class SigilJunitRunner
+{
+ private ServiceTracker tracker;
+
+ public SigilJunitRunner(ServiceTracker tracker)
+ {
+ this.tracker = tracker;
+ }
+
+ public boolean runTests(Object[] args) throws IOException
+ {
+ final String[] usage = {
+ "runTests - run unit tests",
+ "Usage: runTests [OPTION]... [TESTS]...",
+ " -? --help show help",
+ " -d --directory=DIR Write test results to specified directory",
+ " -q --quiet Do not output test results to console"};
+
+ Option opts = Options.compile( usage ).parse( args );
+
+ boolean quiet = opts.isSet( "quiet" );
+ String d = opts.isSet( "directory" ) ? opts.get( "directory" ) : null;
+ File dir = null;
+ if (d != null)
+ {
+ dir = new File(d);
+ dir.mkdirs();
+ if (!quiet) {
+ System.out.println("Writing results to " + dir.getAbsolutePath());
+ System.out.flush();
+ }
+ }
+
+ List<Object> tests = opts.argObjects();
+
+ return runTests(tests, quiet, dir);
+ }
+
+ public void listTests() {
+ JUnitService service = ( JUnitService ) tracker.getService();
+
+ if ( service == null ) {
+ throw new IllegalStateException(JUnitService.class.getName() + " not found");
+ }
+
+ for (String t : service.getTests())
+ {
+ System.out.println("\t" + t);
+ System.out.flush();
+ }
+ }
+
+ private boolean runTests(List<Object> tests, boolean quiet, File dir) throws IOException
+ {
+ int count = 0;
+ int failures = 0;
+ int errors = 0;
+
+ TestSuite[] suites = buildTestSuites(tests);
+
+ if (suites.length > 0) {
+ // redirect io to capture test output - broken due to gogo bug
+ PrintStream oldOut = System.out;
+ PrintStream oldErr = System.err;
+ ByteArrayOutputStream tempOut = new ByteArrayOutputStream();
+ ByteArrayOutputStream tempErr = new ByteArrayOutputStream();
+
+ System.setOut( new PrintStream( tempOut, false ) );
+ System.setErr( new PrintStream( tempErr, false ) );
+
+ try {
+ for (TestSuite test : suites)
+ {
+ TestResult result = new TestResult();
+
+ runTests(test, result, quiet, dir, tempOut, tempErr);
+
+ tempOut.reset();
+ tempErr.reset();
+ count += result.runCount();
+ failures += result.failureCount();
+ errors += result.errorCount();
+ }
+ }
+ finally {
+ System.setOut( oldOut );
+ System.setErr( oldErr );
+ }
+ }
+
+ System.out.println("Ran " + count + " tests. " + failures + " failures " + errors
+ + " errors.");
+ System.out.flush();
+
+ return failures + errors == 0;
+ }
+
+ /**
+ * @param tests
+ * @return
+ */
+ private TestSuite[] buildTestSuites( List<Object> tests )
+ {
+ ArrayList<TestSuite> suites = new ArrayList<TestSuite>(tests.size());
+
+ for (Object o : tests) {
+ TestSuite[] s = coerceTest(o);
+ if (s.length == 0)
+ {
+ System.err.println("No tests found for " + o);
+ }
+ else
+ {
+ for (TestSuite t : s) {
+ suites.add(t);
+ }
+ }
+ }
+
+ return suites.toArray(new TestSuite[suites.size()]);
+ }
+
+ /**
+ * @param tempOut
+ * @param tempErr
+ * @throws IOException
+ */
+ private void runTests( TestSuite test, TestResult result, boolean quiet, File dir, ByteArrayOutputStream tempOut, ByteArrayOutputStream tempErr ) throws IOException
+ {
+ if (!quiet)
+ {
+ result.addListener(new PrintListener());
+ }
+
+ JUnitTest antTest = null;
+ FileOutputStream fout = null;
+ XMLJUnitResultFormatter formatter = null;
+
+ if (dir != null)
+ {
+ antTest = new JUnitTest(test.getName(), 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);
+
+ System.out.flush();
+ System.err.flush();
+
+ if ( dir != null ) {
+ formatter.setSystemOutput( tempOut.toString() );
+ formatter.setSystemError( tempErr.toString() );
+
+ antTest.setCounts(result.runCount(), result.failureCount(),
+ result.errorCount());
+
+ formatter.endTestSuite(antTest);
+
+ fout.flush();
+ fout.close();
+ }
+ }
+
+ /**
+ * @param o
+ * @return
+ */
+ private TestSuite[] coerceTest( Object o )
+ {
+ if ( o instanceof TestCase ) {
+ TestCase t = ( TestCase ) o;
+ TestSuite suite = new TestSuite(t.getName());
+ suite.addTest(t);
+ return new TestSuite[] { suite };
+ }
+ else if (o instanceof TestSuite ) {
+ return new TestSuite[] { ( TestSuite ) o };
+ }
+ else if (o instanceof String) {
+ return findTests(( String ) o);
+ }
+ else {
+ throw new IllegalArgumentException("Unexpected test type " + o.getClass().getName() );
+ }
+ }
+
+ private TestSuite[] findTests(String t)
+ {
+ JUnitService service = ( JUnitService ) tracker.getService();
+
+ if ( service == null ) {
+ throw new IllegalStateException(JUnitService.class.getName() + " not found");
+ }
+
+ 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);
+ }
+ }
+}
diff --git a/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilTestAdapter.java b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilTestAdapter.java
new file mode 100644
index 0000000..8137759
--- /dev/null
+++ b/sigil/gogo/junit/src/org/apache/felix/sigil/gogo/junit/SigilTestAdapter.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+package org.apache.felix.sigil.gogo.junit;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.osgi.service.command.CommandSession;
+import org.osgi.service.command.Function;
+
+
+public class SigilTestAdapter
+{
+ public TestCase newTest( final CommandSession session, final String name, final Function f, final Object... args )
+ {
+ return new TestCase( name )
+ {
+ public int countTestCases()
+ {
+ return 1;
+ }
+
+
+ public void run( TestResult result )
+ {
+ try
+ {
+ f.execute( session, Arrays.asList( args ) );
+ }
+ catch ( InvocationTargetException e )
+ {
+ Throwable c = e.getCause();
+ if ( c instanceof AssertionFailedError )
+ {
+ result.addFailure( this, ( AssertionFailedError ) c );
+ }
+ else
+ {
+ result.addError( this, c );
+ }
+ }
+ catch ( AssertionFailedError e )
+ {
+ result.addFailure( this, e );
+ }
+ catch ( Throwable t )
+ {
+ result.addError( this, t );
+ }
+ }
+ };
+ }
+
+
+ public TestSuite newTestSuite( String name, Test... tests )
+ {
+ TestSuite suite = new TestSuite( name );
+ for ( Test t : tests )
+ {
+ suite.addTest( t );
+ }
+ return suite;
+ }
+}