You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by db...@apache.org on 2011/06/12 15:58:07 UTC

svn commit: r1134928 - in /felix/trunk/gogo/runtime/src: main/java/org/apache/felix/gogo/runtime/ test/java/org/apache/felix/gogo/runtime/

Author: dbaum
Date: Sun Jun 12 13:58:07 2011
New Revision: 1134928

URL: http://svn.apache.org/viewvc?rev=1134928&view=rev
Log:
fix Felix-2894 - Gogo does not handles options but not parameters
also added new testcase testParameter1() in TestCoercsion.java to specifically
test this situation.

fixed FELIX-2927 coercion mechanism invokes foo(String) instead of foo(int) - even with explicit int argument, as this was releated to the refactoring of Refelctive.java


Added:
    felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java
Modified:
    felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java
    felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProxy.java
    felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java
    felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java

Modified: felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java?rev=1134928&r1=1134927&r2=1134928&view=diff
==============================================================================
--- felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java (original)
+++ felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Closure.java Sun Jun 12 13:58:07 2011
@@ -249,7 +249,15 @@ public class Closure implements Function
         }
         else
         {
-            v = s;
+            try
+            {
+                v = s;
+                v = Double.parseDouble(s);    // if it parses as double
+                v = Long.parseLong(s);        // see whether it is integral
+            }
+            catch (NumberFormatException e)
+            {
+            }
         }
         return v;
     }
@@ -304,7 +312,7 @@ public class Closure implements Function
     {
         Object echo = session.get("echo");
         String xtrace = null;
-        
+
         if (echo != null && !"false".equals(echo.toString()))
         {
             // set -x execution trace
@@ -491,7 +499,7 @@ public class Closure implements Function
             {
                 if (".".equals(arg))
                 {
-                    target = Reflective.method(session, target,
+                    target = Reflective.invoke(session, target,
                         args.remove(0).toString(), args);
                     args.clear();
                 }
@@ -506,7 +514,7 @@ public class Closure implements Function
                 return target;
             }
 
-            return Reflective.method(session, target, args.remove(0).toString(), args);
+            return Reflective.invoke(session, target, args.remove(0).toString(), args);
         }
         else if (cmd.getClass().isArray() && values.size() == 1)
         {
@@ -516,7 +524,7 @@ public class Closure implements Function
         }
         else
         {
-            return Reflective.method(session, cmd, values.remove(0).toString(), values);
+            return Reflective.invoke(session, cmd, values.remove(0).toString(), values);
         }
     }
 

Modified: felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProxy.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProxy.java?rev=1134928&r1=1134927&r2=1134928&view=diff
==============================================================================
--- felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProxy.java (original)
+++ felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/CommandProxy.java Sun Jun 12 13:58:07 2011
@@ -79,7 +79,7 @@ public class CommandProxy implements Fun
             }
             else
             {
-                return Reflective.method(session, tgt, function, arguments);
+                return Reflective.invoke(session, tgt, function, arguments);
             }
         }
         finally
@@ -87,4 +87,4 @@ public class CommandProxy implements Fun
             ungetTarget();
         }
     }
-}
\ No newline at end of file
+}

Modified: felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java?rev=1134928&r1=1134927&r2=1134928&view=diff
==============================================================================
--- felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java (original)
+++ felix/trunk/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Reflective.java Sun Jun 12 13:58:07 2011
@@ -25,7 +25,6 @@ import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
@@ -46,9 +45,18 @@ public final class Reflective
                 "finally", "long", "strictfp", "volatile", "const", "float", "native",
                 "super", "while" }));
 
-    public static Object method(CommandSession session, Object target, String name,
-        List<Object> args) throws IllegalArgumentException, IllegalAccessException,
-        InvocationTargetException, Exception
+    /**
+     * invokes the named method on the given target using the supplied args,
+     * which are converted if necessary.
+     * @param session
+     * @param target
+     * @param name
+     * @param args
+     * @return the result of the invoked method
+     * @throws Exception
+     */
+    public static Object invoke(CommandSession session, Object target, String name,
+        List<Object> args) throws Exception
     {
         Method[] methods = target.getClass().getMethods();
         name = name.toLowerCase();
@@ -79,7 +87,7 @@ public final class Reflective
 
         Method bestMethod = null;
         Object[] bestArgs = null;
-        int match = -1;
+        int lowestMatch = Integer.MAX_VALUE;
         ArrayList<Class<?>[]> possibleTypes = new ArrayList<Class<?>[]>();
 
         for (Method m : methods)
@@ -98,38 +106,25 @@ public final class Reflective
                     xargs.add(0, name);
                 }
 
-                // Check if the command takes a session
-                if ((types.length > 0) && types[0].isInterface()
-                    && types[0].isAssignableFrom(session.getClass()))
-                {
-                    xargs.add(0, session);
-                }
-
                 Object[] parms = new Object[types.length];
-                int local = coerce(session, target, m, types, parms, xargs);
+                int match = coerce(session, target, m, types, parms, xargs);
 
-                // FELIX-2894 xargs can contain parameters thus the size
-		// does not match the available slots. I think someone
-		// copied the xargs list in coerce but that left xargs
-		// having an incorrect length
- 
-                if (/*(local >= xargs.size()) && */(local >= types.length))
+                if (match < 0)
+                {
+                    // coerce failed
+                    possibleTypes.add(types);
+                }
+                else
                 {
-                    boolean exact = ((local == xargs.size()) && (local == types.length));
-                    if (exact || (local > match))
+                    if (match < lowestMatch)
                     {
+                        lowestMatch = match;
                         bestMethod = m;
                         bestArgs = parms;
-                        match = local;
                     }
-                    if (exact)
-                    {
-                        break;
-                    }
-                }
-                else
-                {
-                    possibleTypes.add(types);
+
+                    if (match == 0)
+                        break; // can't get better score
                 }
             }
         }
@@ -186,6 +181,62 @@ public final class Reflective
     }
 
     /**
+     * transform name/value parameters into ordered argument list.
+     * params: --param2, value2, --flag1, arg3
+     * args: true, value2, arg3
+     * @param method
+     * @param params
+     * @return new ordered list of args.
+     */
+    private static List<Object> transformParameters(Method method, List<Object> in)
+    {
+        Annotation[][] pas = method.getParameterAnnotations();
+        ArrayList<Object> out = new ArrayList<Object>();
+        ArrayList<Object> parms = new ArrayList<Object>(in);
+
+        for (Annotation as[] : pas)
+        {
+            for (Annotation a : as)
+            {
+                if (a instanceof Parameter)
+                {
+                    int i = -1;
+                    Parameter p = (Parameter) a;
+                    for (String name : p.names())
+                    {
+                        i = parms.indexOf(name);
+                        if (i >= 0)
+                            break;
+                    }
+
+                    if (i >= 0)
+                    {
+                        // parameter present
+                        parms.remove(i);
+                        Object value = p.presentValue();
+                        if (Parameter.UNSPECIFIED.equals(value))
+                        {
+                            if (i >= parms.size())
+                                return null; // missing parameter, so try other methods
+                            value = parms.remove(i);
+                        }
+                        out.add(value);
+                    }
+                    else
+                    {
+                        out.add(p.absentValue());
+                    }
+
+                }
+            }
+        }
+
+        out.addAll(parms);
+
+        return out;
+    }
+
+    /**
      * Complex routein to convert the arguments given from the command line to
      * the arguments of the method call. First, an attempt is made to convert
      * each argument. If this fails, a check is made to see if varargs can be
@@ -197,154 +248,106 @@ public final class Reflective
      * @param types
      * @param out
      * @param in
-     * @return
-     * @throws Exception
+     * @return -1 if arguments can't be coerced; 0 if no coercion was necessary; > 0 if coercion was needed.
      */
-    @SuppressWarnings("unchecked")
     private static int coerce(CommandSession session, Object target, Method m,
-        Class<?> types[], Object out[], List<Object> in) throws Exception
+        Class<?> types[], Object out[], List<Object> in)
     {
-        Annotation[][] pas = m.getParameterAnnotations();
-
-        int start = 0;
-        for (int argIndex = 0; argIndex < pas.length; argIndex++)
+        in = transformParameters(m, in);
+        if (in == null)
         {
-            Annotation as[] = pas[argIndex];
-            for (int a = 0; a < as.length; a++)
-            {
-                if (as[a] instanceof Parameter)
-                {
-                    Parameter o = (Parameter) as[a];
-                    out[argIndex] = coerce(session, target, types[argIndex],
-                        o.absentValue());
-                    start = argIndex + 1;
-                }
-            }
+            // missing parameter argument?
+            return -1;
         }
 
-        in = new ArrayList(in);
-        for (Iterator<Object> itArgs = in.iterator(); itArgs.hasNext();)
+        int[] convert = { 0 };
+
+        // Check if the command takes a session
+        if ((types.length > 0) && types[0].isInterface()
+            && types[0].isAssignableFrom(session.getClass()))
         {
-            Object item = itArgs.next();
-            if (item instanceof String)
-            {
-                if (((String) item).startsWith("-"))
-                {
-                    for (int argIndex = 0; argIndex < pas.length; argIndex++)
-                    {
-                        Annotation as[] = pas[argIndex];
-                        for (int a = 0; a < as.length; a++)
-                        {
-                            if (as[a] instanceof Parameter)
-                            {
-                                Parameter param = (Parameter) as[a];
-                                for (String name : param.names())
-                                {
-                                    if (name.equals(item))
-                                    {
-					// FELIX-2984 annotations never return null, the Parameter annotation
-					// returns UNSPECIFIED
-                                        if (param.presentValue() == null || param.presentValue().equals(Parameter.UNSPECIFIED))
-                                        {
-                                            itArgs.remove(); // parameter name
-                                            assert itArgs.hasNext();
-                                            Object value = itArgs.next(); // the value
-                                            itArgs.remove(); // remove it
-                                            out[argIndex] = coerce(session, target,
-                                                types[argIndex], value);
-                                        }
-                                        else if (param.presentValue() != null)
-                                        {
-                                            itArgs.remove();
-                                            out[argIndex] = coerce(session, target,
-                                                types[argIndex], param.presentValue());
-                                        }
-                                        break;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+            in.add(0, session);
         }
 
-        int i = start;
+        int i = 0;
         while (i < out.length)
         {
             out[i] = null;
-            try
+
+            // Try to convert one argument
+            if (in.size() == 0)
+            {
+                out[i] = NO_MATCH;
+            }
+            else
             {
-                // Try to convert one argument
-                if (in.size() == 0)
+                out[i] = coerce(session, types[i], in.get(0), convert);
+
+                if (out[i] == null && types[i].isArray() && in.size() > 0)
                 {
+                    // don't coerce null to array FELIX-2432
                     out[i] = NO_MATCH;
                 }
-                else
+
+                if (out[i] != NO_MATCH)
                 {
-                    out[i] = coerce(session, target, types[i], in.get(0));
-                    
-                    if (out[i] == null && types[i].isArray() && in.size() > 0)
-                    {
-                        // don't coerce null to array FELIX-2432
-                        out[i] = NO_MATCH;
-                    }
-                    
-                    if (out[i] != NO_MATCH)
-                    {
-                        in.remove(0);
-                    }
+                    in.remove(0);
                 }
+            }
 
-                if (out[i] == NO_MATCH)
+            if (out[i] == NO_MATCH)
+            {
+                // No match, check for varargs
+                if (types[i].isArray() && (i == types.length - 1))
                 {
-                    // Failed
-                    // No match, check for varargs
-                    if (types[i].isArray() && (i == types.length - 1))
+                    // Try to parse the remaining arguments in an array
+                    Class<?> ctype = types[i].getComponentType();
+                    int asize = in.size();
+                    Object array = Array.newInstance(ctype, asize);
+                    int n = i;
+                    while (in.size() > 0)
                     {
-                        // Try to parse the remaining arguments in an array
-                        Class<?> component = types[i].getComponentType();
-                        Object components = Array.newInstance(component, in.size());
-                        int n = i;
-                        while (in.size() > 0)
+                        Object t = coerce(session, ctype, in.remove(0), convert);
+                        if (t == NO_MATCH)
                         {
-                            Object t = coerce(session, target, component, in.remove(0));
-                            if (t == NO_MATCH)
-                            {
-                                return -1;
-                            }
-                            Array.set(components, i - n, t);
-                            i++;
+                            return -1;
                         }
-                        out[n] = components;
-                        // Is last element, so we will quite hereafter
-                        // return n;
-                        if (in.size() == 0)
-                        {
-                            ++i;
-                        }
-                        return i; // derek - return number of args converted
+                        Array.set(array, i - n, t);
+                        i++;
                     }
-                    return -1;
-                }
-                i++;
-            }
-            catch (Exception e)
-            {
-                System.err.println("Reflective:" + e);
-                e.printStackTrace();
+                    out[n] = array;
 
-                // should get rid of those exceptions, but requires
-                // reg ex matching to see if it throws an exception.
-                // dont know what is better
+                    /*
+                     * 1. prefer f() to f(T[]) with empty array
+                     * 2. prefer f(T) to f(T[1])
+                     * 3. prefer f(T) to f(Object[1]) even if there is a conversion cost for T
+                     * 
+                     * 1 & 2 require to add 1 to conversion cost, but 3 also needs to match
+                     * the conversion cost for T.
+                     */
+                    return convert[0] + 1 + (asize * 2);
+                }
                 return -1;
             }
+            i++;
         }
-        return i;
+
+        if (in.isEmpty())
+            return convert[0];
+        return -1;
     }
 
-    private static Object coerce(CommandSession session, Object target, Class<?> type,
-        Object arg) throws Exception
+    /**
+     * converts given argument to specified type and increments convert[0] if any conversion was needed.
+     * @param session
+     * @param type
+     * @param arg
+     * @param convert convert[0] is incremented according to the conversion needed,
+     * to allow the "best" conversion to be determined.
+     * @return converted arg or NO_MATCH if no conversion possible.
+     */
+    private static Object coerce(CommandSession session, Class<?> type, Object arg,
+        int[] convert)
     {
         if (arg == null)
         {
@@ -356,6 +359,33 @@ public final class Reflective
             return arg;
         }
 
+        if (type.isArray())
+        {
+            return NO_MATCH;
+        }
+
+        if (type.isPrimitive() && arg instanceof Long)
+        {
+            // no-cost conversions between integer types
+            Number num = (Number) arg;
+
+            if (type == short.class)
+            {
+                return num.shortValue();
+            }
+            if (type == int.class)
+            {
+                return num.intValue();
+            }
+            if (type == long.class)
+            {
+                return num.longValue();
+            }
+        }
+
+        // all following conversions cost 2 points
+        convert[0] += 2;
+
         Object converted = session.convert(type, arg);
         if (converted != null)
         {
@@ -363,95 +393,68 @@ public final class Reflective
         }
 
         String string = arg.toString();
+
         if (type.isAssignableFrom(String.class))
         {
             return string;
         }
 
-        if (type.isArray())
+        if (type.isPrimitive())
         {
-            // Must handle array types
-            return NO_MATCH;
-        }
-        else
-        {
-            if (!type.isPrimitive())
-            {
-                try
-                {
-                    return type.getConstructor(String.class).newInstance(string);
-                }
-                catch (Exception e)
-                {
-                    return NO_MATCH;
-                }
-            }
+            type = primitiveToObject(type);
         }
 
         try
         {
-            if (type == boolean.class)
-            {
-                return new Boolean(string);
-            }
-            else
-            {
-                if (type == byte.class)
-                {
-                    return new Byte(string);
-                }
-                else
-                {
-                    if (type == char.class)
-                    {
-                        if (string.length() == 1)
-                        {
-                            return string.charAt(0);
-                        }
-                    }
-                    else
-                    {
-                        if (type == short.class)
-                        {
-                            return new Short(string);
-                        }
-                        else
-                        {
-                            if (type == int.class)
-                            {
-                                return new Integer(string);
-                            }
-                            else
-                            {
-                                if (type == float.class)
-                                {
-                                    return new Float(string);
-                                }
-                                else
-                                {
-                                    if (type == double.class)
-                                    {
-                                        return new Double(string);
-                                    }
-                                    else
-                                    {
-                                        if (type == long.class)
-                                        {
-                                            return new Long(string);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+            return type.getConstructor(String.class).newInstance(string);
+        }
+        catch (Exception e)
+        {
         }
-        catch (NumberFormatException e)
+
+        if (type == Character.class && string.length() == 1)
         {
+            return string.charAt(0);
         }
 
         return NO_MATCH;
     }
 
+    private static Class<?> primitiveToObject(Class<?> type)
+    {
+        if (type == boolean.class)
+        {
+            return Boolean.class;
+        }
+        if (type == byte.class)
+        {
+            return Byte.class;
+        }
+        if (type == char.class)
+        {
+            return Character.class;
+        }
+        if (type == short.class)
+        {
+            return Short.class;
+        }
+        if (type == int.class)
+        {
+            return Integer.class;
+        }
+        if (type == float.class)
+        {
+            return Float.class;
+        }
+        if (type == double.class)
+        {
+            return Double.class;
+        }
+        if (type == long.class)
+        {
+            return Long.class;
+        }
+        return null;
+    }
+
 }

Added: felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java?rev=1134928&view=auto
==============================================================================
--- felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java (added)
+++ felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestCoercion.java Sun Jun 12 13:58:07 2011
@@ -0,0 +1,207 @@
+/*
+ * 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.runtime;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.service.command.CommandSession;
+import org.apache.felix.service.command.Descriptor;
+import org.apache.felix.service.command.Parameter;
+
+public class TestCoercion extends TestCase
+{
+    public boolean fBool(boolean t)
+    {
+        return t;
+    }
+
+    public double fDouble(double x)
+    {
+        return x;
+    }
+
+    public int fInt(int x)
+    {
+        return x;
+    }
+
+    public long fLong(long x)
+    {
+        return x;
+    }
+
+    // the presence of this method checks that it is not invoked instead of fInt(int)
+    public String fInt(Object[] x)
+    {
+        return "array";
+    }
+
+    public String fString(String s)
+    {
+        return s;
+    }
+
+    public void testSimpleTypes() throws Exception
+    {
+        Context c = new Context();
+        c.addCommand("fBool", this);
+        c.addCommand("fDouble", this);
+        c.addCommand("fInt", this);
+        c.addCommand("fLong", this);
+        c.addCommand("fString", this);
+
+        assertEquals("fBool true", true, c.execute("fBool true"));
+        assertEquals("fBool 'false'", false, c.execute("fBool 'false'"));
+        
+        assertEquals("fDouble 11", 11.0, c.execute("fDouble 11"));
+        assertEquals("fDouble '11'", 11.0, c.execute("fDouble '11'"));
+        
+        assertEquals("fInt 22", 22, c.execute("fInt 22"));
+        assertEquals("fInt '23'", 23, c.execute("fInt '23'"));
+        assertEquals("fInt 1 2", "array", c.execute("fInt 1 2"));
+        
+        assertEquals("fLong 33", 33L, c.execute("fLong 33"));
+        assertEquals("fLong '34'", 34L, c.execute("fLong '34'"));
+        
+        assertEquals("fString wibble", "wibble", c.execute("fString wibble"));
+        assertEquals("fString 'wibble'", "wibble", c.execute("fString 'wibble'"));
+
+        try
+        {
+            Object r = c.execute("fString ");
+            fail("too few args: expected IllegalArgumentException, got: " + r);
+        }
+        catch (IllegalArgumentException e)
+        {
+        }
+
+        try
+        {
+            Object r = c.execute("fString a b");
+            fail("too many args: expected IllegalArgumentException, got: " + r);
+        }
+        catch (IllegalArgumentException e)
+        {
+        }
+
+        try
+        {
+            Object r = c.execute("fLong string");
+            fail("wrong arg type: expected IllegalArgumentException, got: " + r);
+        }
+        catch (IllegalArgumentException e)
+        {
+        }
+    }
+
+    public String bundles(Long id)
+    {
+        return "long";
+    }
+
+    public String bundles(String loc)
+    {
+        return "string";
+    }
+
+    public void testBestCoercion() throws Exception
+    {
+        Context c = new Context();
+        c.addCommand("bundles", this);
+
+        assertEquals("bundles myloc", "string", c.execute("bundles myloc"));
+        assertEquals("bundles 1", "long", c.execute("bundles 1"));
+        assertEquals("bundles '1'", "string", c.execute("bundles '1'"));
+    }
+
+    @Descriptor("list all installed bundles")
+    public String p0(
+        @Descriptor("show location") @Parameter(names = { "-l", "--location" }, presentValue = "true", absentValue = "false") boolean showLoc,
+        @Descriptor("show symbolic name") @Parameter(names = { "-s", "--symbolicname" }, presentValue = "true", absentValue = "false") boolean showSymbolic)
+    {
+        return showLoc + ":" + showSymbolic;
+    }
+
+    // function with session and parameter
+    public boolean p01(
+        CommandSession session,
+        @Parameter(names = { "-f", "--flag" }, presentValue = "true", absentValue = "false") boolean flag)
+    {
+        assertNotNull("session must not be null", session);
+        return flag;
+    }
+
+    public void testParameter0() throws Exception
+    {
+        Context c = new Context();
+        c.addCommand("p0", this);
+        c.addCommand("p01", this);
+
+        assertEquals("p0", "false:false", c.execute("p0"));
+        assertEquals("p0 -l", "true:false", c.execute("p0 -l"));
+        assertEquals("p0 --location", "true:false", c.execute("p0 --location"));
+        assertEquals("p0 -l -s", "true:true", c.execute("p0 -l -s"));
+        assertEquals("p0 -s -l", "true:true", c.execute("p0 -s -l"));
+        try
+        {
+            Object r = c.execute("p0 wibble");
+            fail("too many args: expected IllegalArgumentException, got: " + r);
+        }
+        catch (IllegalArgumentException e)
+        {
+        }
+        assertEquals("p01 -f", true, c.execute("p01 -f"));
+    }
+
+    public String p1(
+        @Parameter(names = { "-p", "--parameter" }, absentValue = "absent") String parm1)
+    {
+        return parm1;
+    }
+
+    public void testParameter1() throws Exception
+    {
+        Context c = new Context();
+        c.addCommand("p1", this);
+
+        assertEquals("no parameter", "absent", c.execute("p1"));
+
+        // FELIX-2894
+        assertEquals("correct parameter", "wibble", c.execute("p1 -p wibble"));
+
+        try
+        {
+            Object r = c.execute("p1 -p");
+            fail("missing parameter: expected IllegalArgumentException, got: " + r);
+        }
+        catch (IllegalArgumentException e)
+        {
+        }
+
+        try
+        {
+            Object r = c.execute("p1 -X");
+            fail("wrong parameter: expected IllegalArgumentException, got: " + r);
+        }
+        catch (IllegalArgumentException e)
+        {
+        }
+    }
+
+}

Modified: felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java
URL: http://svn.apache.org/viewvc/felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java?rev=1134928&r1=1134927&r2=1134928&view=diff
==============================================================================
--- felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java (original)
+++ felix/trunk/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestParser.java Sun Jun 12 13:58:07 2011
@@ -167,7 +167,7 @@ public class TestParser extends TestCase
         assertEquals("http://www.aqute.biz?com=2&biz=1",
             c.execute("['http://www.aqute.biz?com=2&biz=1'] get 0"));
         assertEquals("{a=2, b=3}", c.execute("[a=2 b=3]").toString());
-        assertEquals("3", c.execute("[a=2 b=3] get b"));
+        assertEquals(3L, c.execute("[a=2 b=3] get b"));
         assertEquals("[3, 4]", c.execute("[1 2 [3 4] 5 6] get 2").toString());
         assertEquals(5, c.execute("[1 2 [3 4] 5 6] size"));
     }