/* * Copyright (C) 2010 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.crsh.cli.impl.matcher; import junit.framework.TestCase; import org.crsh.cli.impl.CLIException; import org.crsh.cli.descriptor.CommandDescriptor; import org.crsh.cli.impl.SyntaxException; import org.crsh.cli.Argument; import org.crsh.cli.Command; import org.crsh.cli.Option; import org.crsh.cli.Required; import org.crsh.cli.impl.invocation.InvocationMatch; import org.crsh.cli.impl.lang.CommandFactory; import org.crsh.cli.impl.invocation.InvocationMatcher; import org.crsh.cli.impl.lang.Instance; import org.crsh.cli.impl.lang.Util; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; /** * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> * @version $Revision$ */ public class MatcherTestCase extends TestCase { public void testRequiredClassOption() throws Exception { class A implements Runnable{ @Option(names = "o") @Required String s; public void run() {} } CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); A a = new A(); analyzer.parse("-o foo").invoke(Util.wrap(a)); assertEquals("foo", a.s); try { a = new A(); analyzer.parse("").invoke(Util.wrap(a)); fail(); } catch (SyntaxException e) { } } public void testOptionalClassOption() throws Exception { class A implements Runnable { @Option(names = "o") String s; public void run() {} } CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); A a = new A(); analyzer.parse("-o foo").invoke(Util.wrap(a)); assertEquals("foo", a.s); a = new A(); analyzer.parse("").invoke(Util.wrap(a)); assertEquals(null, a.s); } public void testPrimitiveClassArgument() throws Exception { class A implements Runnable { @Argument int i; public void run() {} } CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); A a = new A(); analyzer.parse("5").invoke(Util.wrap(a)); assertEquals(5, a.i); a = new A(); analyzer.parse("5 6").invoke(Util.wrap(a)); assertEquals(5, a.i); a = new A(); a.i = -3; try { analyzer.parse("").invoke(Util.wrap(a)); fail(); } catch (SyntaxException e) { } assertEquals(-3, a.i); } public static class PMA { int i; @Command public void m(@Argument int i) { this.i = i; } } public void testPrimitiveMethodArgument() throws Exception { CommandDescriptor<Instance<PMA>> desc = CommandFactory.DEFAULT.create(PMA.class); InvocationMatcher<Instance<PMA>> analyzer = desc.matcher(); PMA a = new PMA(); analyzer.parse("m 5").invoke(Util.wrap(a)); assertEquals(5, a.i); a = new PMA(); analyzer.parse("m 5 6").invoke(Util.wrap(a)); assertEquals(5, a.i); a = new PMA(); try { analyzer.parse("m").invoke(Util.wrap(a)); fail(); } catch (SyntaxException e) { } } public void testOptionalClassArgument() throws Exception { class A implements Runnable { @Argument String s; public void run() {} } CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); A a = new A(); analyzer.parse("foo").invoke(Util.wrap(a)); assertEquals("foo", a.s); a = new A(); analyzer.parse("foo bar").invoke(Util.wrap(a)); assertEquals("foo", a.s); a = new A(); analyzer.parse("").invoke(Util.wrap(a)); assertEquals(null, a.s); } public static class BC1 { List<String> s; @Command public void main(@Argument List<String> s) { this.s = s; } } public static class BC2 implements Runnable { @Argument List<String> s; public void run() {} } public void testOptionalArgumentList() throws Exception { abstract class Tester { abstract List<String> invoke(String line) throws Exception ; } Tester t1 = new Tester() { CommandDescriptor<Instance<BC1>> desc1 = CommandFactory.DEFAULT.create(BC1.class); @Override List<String> invoke(String line) throws Exception { BC1 object = new BC1(); desc1.matcher().parse(line).invoke(Util.wrap(object)); return object.s; } }; Tester t2 = new Tester() { CommandDescriptor<Instance<BC2>> desc2 = CommandFactory.DEFAULT.create(BC2.class); @Override List<String> invoke(String line) throws Exception { BC2 object = new BC2(); desc2.matcher().parse(line).invoke(Util.wrap(object)); return object.s; } }; for (Tester s : Arrays.asList(t1, t2)) { assertEquals(null, s.invoke("")); assertEquals(Arrays.asList("foo"), s.invoke("foo")); assertEquals(Arrays.asList("foo", "bar"), s.invoke("foo bar")); assertEquals(Arrays.asList("foo"), s.invoke("foo ")); } } public class OptionSyntaxException { @Option(names = "o") int option; @Command public void main() { } } public void testOptionSyntaxException() throws Exception { CommandDescriptor<Instance<OptionSyntaxException>> desc = CommandFactory.DEFAULT.create(OptionSyntaxException.class); InvocationMatcher<Instance<OptionSyntaxException>> analyzer = desc.matcher(); OptionSyntaxException cmd = new OptionSyntaxException(); // try { analyzer.parse("-o").invoke(Util.wrap(cmd)); fail(); } catch (SyntaxException ignore) { } // try { analyzer.parse("-o 0 -o 1").invoke(Util.wrap(cmd)); fail(); } catch (SyntaxException ignore) { } // try { analyzer.parse("-o a").invoke(Util.wrap(cmd)); fail(); } catch (SyntaxException ignore) { } // analyzer.parse("-o 45").invoke(Util.wrap(cmd)); assertEquals(45, cmd.option); } public void testRequiredArgumentList() throws Exception { class A implements Runnable { @Argument @Required List<String> s; public void run() {} } CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); A a = new A(); try { analyzer.parse("").invoke(Util.wrap(a)); fail(); } catch (SyntaxException expected) { } a = new A(); analyzer.parse("foo").invoke(Util.wrap(a)); assertEquals(Arrays.asList("foo"), a.s); a = new A(); analyzer.parse("foo bar").invoke(Util.wrap(a)); assertEquals(Arrays.asList("foo", "bar"), a.s); } public static class A { @Option(names = "s") String s; @Command public void m(@Option(names = "o") String o, @Argument String a) { this.o = o; this.a = a; } String o; String a; @Command public void dummy() {} } public void testMethodInvocation() throws Exception { CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); // A a = new A(); analyzer.parse("-s foo m -o bar juu").invoke(Util.wrap(a)); assertEquals("foo", a.s); assertEquals("bar", a.o); assertEquals("juu", a.a); // a = new A(); analyzer.parse("m -o bar juu").invoke(Util.wrap(a)); assertEquals(null, a.s); assertEquals("bar", a.o); assertEquals("juu", a.a); // a = new A(); analyzer.parse("m juu").invoke(Util.wrap(a)); assertEquals(null, a.s); assertEquals(null, a.o); assertEquals("juu", a.a); // a = new A(); analyzer.parse("m -o bar").invoke(Util.wrap(a)); assertEquals(null, a.s); assertEquals("bar", a.o); assertEquals(null, a.a); a = new A(); analyzer.parse("m").invoke(Util.wrap(a)); assertEquals(null, a.s); assertEquals(null, a.o); assertEquals(null, a.a); } public static class B { int count; @Command public void main() { count++; } } public void testMainMethodInvocation() throws Exception { CommandDescriptor<Instance<B>> desc = CommandFactory.DEFAULT.create(B.class); // B b = new B(); desc.matcher().parse("").invoke(Util.wrap(b)); assertEquals(1, b.count); b = new B(); desc.matcher().arguments(Collections.emptyList()).invoke(Util.wrap(b)); assertEquals(1, b.count); } public static class C { Locale locale; @Command public void main(Locale locale) { this.locale = locale; } } public void testInvocationAttributeInjection() throws Exception { CommandDescriptor<Instance<C>> desc = CommandFactory.DEFAULT.create(C.class); InvocationMatcher<Instance<C>> analyzer = desc.matcher(); // final C c = new C(); Instance<C> context = new Instance<C>() { @Override public C get() { return c; } public <T> T resolve(Class<T> type) { if (type.equals(Locale.class)) { return type.cast(Locale.FRENCH); } else { return null; } } }; analyzer.parse("").invoke(context); assertEquals(Locale.FRENCH, c.locale); } public static class D { private Integer i; @Command public void a(@Option(names = "o") Integer i) { this.i = i; } @Command public void b(@Option(names = "o") int i) { this.i = i; } } public void testInvocationTypeConversionInjection() throws Exception { CommandDescriptor<Instance<D>> desc = CommandFactory.DEFAULT.create(D.class); // D d = new D(); desc.matcher().parse("a -o 5").invoke(Util.wrap(d)); assertEquals((Integer)5, d.i); // d = new D(); desc.matcher().parse("b -o 5").invoke(Util.wrap(d)); assertEquals((Integer)5, d.i); } public static class E { private String i; @Command public void a(@Option(names = "o", unquote = false) String i) { this.i = i; } } public void testQuoted() throws Exception { CommandDescriptor<Instance<E>> desc = CommandFactory.DEFAULT.create(E.class); // E e = new E(); desc.matcher().parse("a -o a").invoke(Util.wrap(e)); assertEquals("a", e.i); // e = new E(); desc.matcher().parse("a -o \"a\"").invoke(Util.wrap(e)); assertEquals("\"a\"", e.i); } public static class F { List<String> s; @Command public void foo(@Option(names = "o") List<String> s) { this.s = s; } } public void testOptionList() throws Exception { CommandDescriptor<Instance<F>> desc = CommandFactory.DEFAULT.create(F.class); // F f = new F(); desc.matcher().parse("foo -o a").invoke(Util.wrap(f)); assertEquals(Arrays.asList("a"), f.s); f = new F(); desc.matcher().subordinate("foo").option("o", Collections.singletonList("a")).arguments(Collections.emptyList()).invoke(Util.wrap(f)); assertEquals(Arrays.asList("a"), f.s); // f = new F(); desc.matcher().parse("foo -o a -o b").invoke(Util.wrap(f)); assertEquals(Arrays.asList("a", "b"), f.s); f = new F(); desc.matcher().subordinate("foo").option("o", Arrays.asList("a", "b")).arguments(Collections.emptyList()).invoke(Util.wrap(f)); assertEquals(Arrays.asList("a", "b"), f.s); } public static class G { Custom o; @Command public void foo(@Option(names = "o") Custom o) { this.o = o; } } public void testValue() throws Exception { // CommandDescriptor<Instance<G>> desc = new CommandFactory(MatcherTestCase.class.getClassLoader()).create(G.class); // G g = new G(); desc.matcher().parse("foo -o a").invoke(Util.wrap(g)); assertEquals(new Custom("a"), g.o); g = new G(); desc.matcher().subordinate("foo").option("o", Collections.singletonList("a")).arguments(Collections.emptyList()).invoke(Util.wrap(g)); assertEquals(new Custom("a"), g.o); } public static class H { @Command public void foo() throws Exception { throw new Exception("fooexception"); } } public void testException() throws Exception { CommandDescriptor<Instance<H>> desc = CommandFactory.DEFAULT.create(H.class); // H h = new H(); InvocationMatch<Instance<H>> matcher = desc.matcher().parse("foo"); try { matcher.invoke(Util.wrap(h)); fail(); } catch (CLIException e) { assertEquals(Exception.class, e.getCause().getClass()); assertEquals("fooexception", e.getCause().getMessage()); } } public static class I { @Command public void foo() { throw new RuntimeException("fooruntimeexception"); } } public void testRuntimeException() throws Exception { CommandDescriptor<Instance<I>> desc = CommandFactory.DEFAULT.create(I.class); // I i = new I(); InvocationMatch<Instance<I>> matcher = desc.matcher().parse("foo"); try { matcher.invoke(Util.wrap(i)); fail(); } catch (CLIException e) { assertEquals(RuntimeException.class, e.getCause().getClass()); assertEquals("fooruntimeexception", e.getCause().getMessage()); } } public static class J { @Command public void foo() { throw new Error("fooerror"); } } public void testError() throws Exception { CommandDescriptor<Instance<J>> desc = CommandFactory.DEFAULT.create(J.class); // J j = new J(); InvocationMatch<Instance<J>> matcher = desc.matcher().parse("foo"); try { matcher.invoke(Util.wrap(j)); fail(); } catch (Error e) { assertEquals("fooerror", e.getMessage()); } } public static class K { @Option(names = "o") String opt; @Command public void cmd() {} } public void testSpecifyClassOptionBeforeSubordinate() throws Exception { CommandDescriptor<Instance<K>> desc = CommandFactory.DEFAULT.create(K.class); K k = new K(); desc.matcher().parse("-o foo cmd").invoke(Util.wrap(k)); assertEquals("foo", k.opt); k = new K(); desc.matcher().option("o", Collections.singletonList("foo")).subordinate("cmd").arguments(Collections.emptyList()).invoke(Util.wrap(k)); assertEquals("foo", k.opt); } public void testSpecifyClassOptionAfterSubordinate() throws Exception { CommandDescriptor<Instance<K>> desc = CommandFactory.DEFAULT.create(K.class); K k = new K(); desc.matcher().parse("cmd -o foo").invoke(Util.wrap(k)); assertEquals(null, k.opt); k = new K(); desc.matcher().subordinate("cmd").option("o", Collections.singletonList("foo")).arguments(Collections.emptyList()).invoke(Util.wrap(k)); assertEquals(null, k.opt); } public static class L { String opt; @Command public void cmd(@Option(names = "o") String opt) { this.opt = opt; } @Command public void dummy() {} } public void testSpecifySubordinateOptionBeforeSubordinate() throws Exception { CommandDescriptor<Instance<L>> desc = CommandFactory.DEFAULT.create(L.class); L l = new L(); desc.matcher().parse("-o foo cmd").invoke(Util.wrap(l)); assertEquals(null, l.opt); l = new L(); desc.matcher().option("o", Collections.singletonList("foo")).subordinate("cmd").arguments(Collections.emptyList()).invoke(Util.wrap(l)); assertEquals(null, l.opt); } public void testSpecifySubordinateOptionAfterSubordinate() throws Exception { CommandDescriptor<Instance<L>> desc = CommandFactory.DEFAULT.create(L.class); L l = new L(); desc.matcher().parse("cmd -o foo").invoke(Util.wrap(l)); assertEquals("foo", l.opt); l = new L(); desc.matcher().subordinate("cmd").option("o", Collections.singletonList("foo")).arguments(Collections.emptyList()).invoke(Util.wrap(l)); assertEquals("foo", l.opt); } public static class M { String opt; @Command public void main(@Option(names = "o") String opt) { this.opt = opt; } } public void testImplicitSubordinateOption() throws Exception { CommandDescriptor<Instance<M>> desc = CommandFactory.DEFAULT.create(M.class); M m = new M(); desc.matcher().parse("-o foo").invoke(Util.wrap(m)); assertEquals("foo", m.opt); m = new M(); desc.matcher().option("o", Collections.singletonList("foo")).arguments(Collections.emptyList()).invoke(Util.wrap(m)); assertEquals("foo", m.opt); } public void testBooleanParameter() throws Exception { class A implements Runnable { @Option(names = "o") boolean o; public void run() {} } CommandDescriptor<Instance<A>> desc = CommandFactory.DEFAULT.create(A.class); InvocationMatcher<Instance<A>> analyzer = desc.matcher(); // A a = new A(); analyzer.parse("-o").invoke(Util.wrap(a)); assertEquals(true, a.o); a = new A(); analyzer.option("o", Collections.singletonList(true)).arguments(Collections.emptyList()).invoke(Util.wrap(a)); assertEquals(true, a.o); } public void testSCP() throws Exception { class SCP implements Runnable { @Option(names = "t") boolean t; @Argument @Required String target; public void run() {} } CommandDescriptor<Instance<SCP>> desc = CommandFactory.DEFAULT.create(SCP.class); InvocationMatcher<Instance<SCP>> matcher = desc.matcher(); // SCP scp = new SCP(); matcher.parse("-t -- portal:collaboration:/Documents").invoke(Util.wrap(scp)); assertEquals(true, scp.t); assertEquals("portal:collaboration:/Documents", scp.target); scp = new SCP(); matcher.option("t", Collections.singletonList(true)).arguments(Collections.singletonList("portal:collaboration:/Documents")).invoke(Util.wrap(scp)); assertEquals(true, scp.t); assertEquals("portal:collaboration:/Documents", scp.target); // scp = new SCP(); try { matcher.parse("-t").invoke(Util.wrap(scp)); fail(); } catch (CLIException e) { } scp = new SCP(); try { matcher.option("t", Collections.singletonList(true)).arguments(Collections.emptyList()).invoke(Util.wrap(scp)); fail(); } catch (CLIException e) { } } }