package picocli; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.ProvideSystemProperty; import org.junit.contrib.java.lang.system.RestoreSystemProperties; import org.junit.rules.TestRule; import picocli.CommandLine.Command; import picocli.CommandLine.IExitCodeGenerator; import picocli.CommandLine.Mixin; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import picocli.CommandLine.ParentCommand; import picocli.CommandLine.ParseResult; import java.io.*; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; /** * Tests #454 repeatable subcommands. */ public class RepeatableSubcommandsTest { // allows tests to set any kind of properties they like, without having to individually roll them back @Rule public final TestRule restoreSystemProperties = new RestoreSystemProperties(); @Rule public final ProvideSystemProperty ansiOFF = new ProvideSystemProperty("picocli.ansi", "false"); static class AbstractCommand implements Callable { static Map exitCodes = new HashMap(); boolean executed; public Integer call() { executed = true; return exitCode(); } int exitCode() { Integer result = exitCodes.get(getClass().getSimpleName()); return result == null ? 0 : result; } } @Command(name="A", subcommandsRepeatable = true, subcommands = {B.class, C.class, D.class}) static class A extends AbstractCommand { @Option(names = "-x") String x; static AtomicInteger total = new AtomicInteger(); static AtomicInteger count = new AtomicInteger(); public A() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Command(name="B", subcommandsRepeatable = true, subcommands = {E.class, F.class, G.class}) static class B extends AbstractCommand { @Option(names = "-x") String x; static AtomicInteger count = new AtomicInteger(); public B() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Command(name="C") static class C extends AbstractCommand { @Option(names = "-x") String x; static AtomicInteger count = new AtomicInteger(); public C() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Command(name="D") static class D extends AbstractCommand { @Option(names = "-x") String x; static AtomicInteger count = new AtomicInteger(); public D() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Command(name="E") static class E extends AbstractCommand { @Option(names = "-x") String x; static AtomicInteger count = new AtomicInteger(); public E() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Command(name="F") static class F extends AbstractCommand { static AtomicInteger count = new AtomicInteger(); public F() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Command(name="G") static class G extends AbstractCommand { static AtomicInteger count = new AtomicInteger(); public G() { count.incrementAndGet(); A.total.incrementAndGet(); } } @Test public void testParseResult() { //TestUtil.setTraceLevel("DEBUG"); CommandLine cl = new CommandLine(new A()); String[] args = "B B C D B E F G E E F F".split(" "); ParseResult parseResult = cl.parseArgs(args); StringWriter sw = new StringWriter(); print("", parseResult, new PrintWriter(sw)); String expected = String.format("" + "A%n" + " B%n" + " B%n" + " C%n" + " D%n" + " B%n" + " E%n" + " F%n" + " G%n" + " E%n" + " E%n" + " F%n" + " F%n"); assertEquals(expected, sw.toString()); List commandLines = parseResult.asCommandLineList(); List expectedNames = new ArrayList(Arrays.asList(args)); expectedNames.add(0, "A"); for (int i = 0; i < commandLines.size(); i++) { assertEquals("Command name at " + i, expectedNames.get(i), commandLines.get(i).getCommandName()); } } private void print(String indent, ParseResult parseResult, PrintWriter pw) { pw.println(indent + parseResult.commandSpec().name()); for (ParseResult sub : parseResult.subcommands()) { print(indent + " ", sub, pw); } } private void resetCounters() { A.total.set(0); A.count.set(0); B.count.set(0); C.count.set(0); D.count.set(0); E.count.set(0); F.count.set(0); G.count.set(0); } @Test public void testCommandLazyInstantiation() { resetCounters(); CommandLine cl = new CommandLine(A.class); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl.parseArgs(); assertEquals(1, A.count.get()); assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(1, A.total.get()); resetCounters(); cl.parseArgs("-x=y"); assertEquals(0, A.count.get()); // previously created instance is reused assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl.parseArgs("-x=y", "B"); assertEquals(0, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(1, A.total.get()); resetCounters(); cl.parseArgs("-x=y", "B", "-x=y"); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); // previously created instance is reused assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl.parseArgs("C"); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); assertEquals(1, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(1, A.total.get()); resetCounters(); cl.parseArgs("C", "-x=y"); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); // previously created instance is reused assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl.parseArgs("B", "E"); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); // previously created instance is reused assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(1, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(1, A.total.get()); resetCounters(); cl.parseArgs("B", "E", "-x=y"); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); // previously created instance is reused assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); // previously created instance is reused assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl.parseArgs("B", "-x=y", "E", "-x=y"); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); // instance is reused assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); // instance is reused assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl.parseArgs("-x=y", "B", "-x=y", "E", "-x=y"); assertEquals(0, A.count.get()); // instance is reused assertEquals(0, B.count.get()); // instance is reused assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); // instance is reused assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); } @Test public void testCommandLazyInstantiation2() { resetCounters(); CommandLine cl = new CommandLine(A.class); assertEquals(0, A.count.get()); assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(0, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs(); assertEquals(1, A.count.get()); assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(1, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("-x=y"); assertEquals(1, A.count.get()); assertEquals(0, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(1, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("-x=y", "B"); assertEquals(1, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(2, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("-x=y", "B", "-x=y"); assertEquals(1, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(2, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("C"); assertEquals(1, A.count.get()); assertEquals(0, B.count.get()); assertEquals(1, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(2, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("C", "-x=y"); assertEquals(1, A.count.get()); assertEquals(0, B.count.get()); assertEquals(1, C.count.get()); assertEquals(0, D.count.get()); assertEquals(0, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(2, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("B", "E"); assertEquals(1, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(1, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(3, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("B", "E", "-x=y"); assertEquals(1, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(1, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(3, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("B", "-x=y", "E", "-x=y"); assertEquals(1, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(1, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(3, A.total.get()); resetCounters(); cl = new CommandLine(A.class); cl.parseArgs("-x=y", "B", "-x=y", "E", "-x=y"); assertEquals(1, A.count.get()); assertEquals(1, B.count.get()); assertEquals(0, C.count.get()); assertEquals(0, D.count.get()); assertEquals(1, E.count.get()); assertEquals(0, F.count.get()); assertEquals(0, G.count.get()); assertEquals(3, A.total.get()); } @Test public void testParseResultAsCommandLineList() { CommandLine cl = new CommandLine(new A()); String[] args = "B B C D B E F G E E F F".split(" "); ParseResult parseResult = cl.parseArgs(args); List commandLines = parseResult.asCommandLineList(); List expectedNames = new ArrayList(Arrays.asList(args)); expectedNames.add(0, "A"); for (int i = 0; i < commandLines.size(); i++) { assertEquals("Command name at " + i, expectedNames.get(i), commandLines.get(i).getCommandName()); } } @Test public void testExecution() { CommandLine cl = new CommandLine(new A()); cl.execute("B B C D B E F G E E F F".split(" ")); List commandLines = cl.getParseResult().asCommandLineList(); boolean[] executed = new boolean[] { false, // A false, // B false, // B false, // C false, // D false, // B true, // E true, // F true, // G true, // E true, // E true, // F true, // F }; assertEquals(executed.length, commandLines.size()); for (int i = 0; i < executed.length; i++) { AbstractCommand ac = commandLines.get(i).getCommand(); assertEquals("[" + i + "]: " + ac, executed[i], ac.executed); } } @Test public void testExecutionRunAll() { CommandLine cl = new CommandLine(new A()); cl.setExecutionStrategy(new CommandLine.RunAll()); cl.execute("B B C D B E F G E E F F".split(" ")); List commandLines = cl.getParseResult().asCommandLineList(); boolean[] executed = new boolean[] { true, // A true, // B true, // B true, // C true, // D true, // B true, // E true, // F true, // G true, // E true, // E true, // F true, // F }; assertEquals(executed.length, commandLines.size()); for (int i = 0; i < executed.length; i++) { AbstractCommand ac = commandLines.get(i).getCommand(); assertEquals("[" + i + "]: " + ac, executed[i], ac.executed); } } @SuppressWarnings("deprecation") @Test public void testLegacyExecution() { CommandLine cl = new CommandLine(new A()); cl.parseWithHandler(new CommandLine.RunLast(), "B B C D B E F G E E F F".split(" ")); List commandLines = cl.getParseResult().asCommandLineList(); boolean[] executed = new boolean[] { false, // A false, // B false, // B false, // C false, // D false, // B true, // E true, // F true, // G true, // E true, // E true, // F true, // F }; assertEquals(executed.length, commandLines.size()); for (int i = 0; i < executed.length; i++) { AbstractCommand ac = commandLines.get(i).getCommand(); assertEquals("[" + i + "]: " + ac, executed[i], ac.executed); } } @Test public void testExitCodesPositive() { AbstractCommand.exitCodes.put("A", 20); AbstractCommand.exitCodes.put("B", 7); AbstractCommand.exitCodes.put("C", 10); AbstractCommand.exitCodes.put("E", 6); AbstractCommand.exitCodes.put("F", 5); AbstractCommand.exitCodes.put("G", 4); CommandLine cl = new CommandLine(new A()); int exitCode = cl.execute("B B C D B E F G E E F F".split(" ")); assertEquals(6, exitCode); } @Test public void testExitCodesNegative() { AbstractCommand.exitCodes.put("A", -20); AbstractCommand.exitCodes.put("B", -7); AbstractCommand.exitCodes.put("C", -10); AbstractCommand.exitCodes.put("E", -6); AbstractCommand.exitCodes.put("F", -5); AbstractCommand.exitCodes.put("G", -4); CommandLine cl = new CommandLine(new A()); int exitCode = cl.execute("B B C D B E F G E E F F".split(" ")); assertEquals(-6, exitCode); } @Command(name = "print", subcommands = FileCommand.class, subcommandsRepeatable = true) static class Print implements Runnable { enum Paper {A1, A2, A3, A4, A5, B1, B2, B3, B4, B5} @Option(names = "--paper") Paper paper; public void run() { //System.out.println("Print (paper=" + paper + ")"); } } @Command(name = "file") static class FileCommand implements Callable { @Parameters(index = "0", paramLabel = "FILE") File file; @Option(names = "--count") int count = 1; enum Rotate {left, right} @Option(names = "--rotate") Rotate rotate; public Integer call() { //System.out.printf("File (file=%s, count=%d, rotate=%s)%n", file, count, rotate); return count; } } @Test public void testOriginalUseCase() { Print print = new Print(); CommandLine cmd = new CommandLine(print); int exitCode = cmd.execute(( "--paper A4" + " file A.pdf" + " file B.pdf --count 3" + " file C.pdf --count 2 --rotate left" + " file D.pdf" + " file E.pdf --rotate right").split(" ")); assertEquals(3, exitCode); ParseResult parseResult = cmd.getParseResult(); assertEquals(Print.Paper.A4, print.paper); assertSame(Print.Paper.A4, parseResult.matchedOptionValue("--paper", null)); assertEquals(5, parseResult.subcommands().size()); Object[][] expecteds = new Object[][] { new Object[] {new File("A.pdf"), 1, null}, new Object[] {new File("B.pdf"), 3, null}, new Object[] {new File("C.pdf"), 2, FileCommand.Rotate.left}, new Object[] {new File("D.pdf"), 1, null}, new Object[] {new File("E.pdf"), 1, FileCommand.Rotate.right}, }; int i = 0; for (Object[] expected : expecteds) { ParseResult pr = parseResult.subcommands().get(i++); FileCommand file = (FileCommand) pr.commandSpec().userObject(); assertEquals(expected[0], file.file); assertEquals(expected[1], file.count); assertEquals(expected[2], file.rotate); } } @Command(name = "parent", subcommands = MixinTestSubCommand.class, subcommandsRepeatable = true) static class MixinTestParentCommand { static int methodSubInvocationCount; @Command int methodSub(@Mixin MyMixin myMixin) { return ++methodSubInvocationCount * 100 + myMixin.x; } } @Command(name = "sub") static class MixinTestSubCommand implements Runnable, IExitCodeGenerator { static int invocationCount; @Mixin MyMixin myMixin; @ParentCommand MixinTestParentCommand parent; public void run() { ++invocationCount; } public int getExitCode() { return invocationCount * myMixin.x; } } static class MyMixin { @ParentCommand MixinTestParentCommand parent; @Option(names = "-x", defaultValue = "26") int x; } @Test public void testMixinsAndExitCodeGenerator() { MixinTestParentCommand.methodSubInvocationCount = 0; MixinTestSubCommand.invocationCount = 0; MixinTestParentCommand parent = new MixinTestParentCommand(); CommandLine cl = new CommandLine(parent); int exitCode = cl.execute("sub -x3 sub sub".split(" ")); assertEquals(3 * 26, exitCode); assertEquals(3, MixinTestSubCommand.invocationCount); assertEquals(0, MixinTestParentCommand.methodSubInvocationCount); MixinTestParentCommand.methodSubInvocationCount = 0; MixinTestSubCommand.invocationCount = 0; exitCode = cl.execute("sub -x3 sub -x 4 sub -x5 sub -x=2".split(" ")); assertEquals(4 * 5, exitCode); assertEquals(4, MixinTestSubCommand.invocationCount); assertEquals(0, MixinTestParentCommand.methodSubInvocationCount); MixinTestParentCommand.methodSubInvocationCount = 0; MixinTestSubCommand.invocationCount = 0; exitCode = cl.execute("sub -x3 sub -x 4 methodSub -x2 sub -x5 methodSub -x3 sub -x=2".split(" ")); assertEquals(2 * 100 + 3, exitCode); assertEquals(4, MixinTestSubCommand.invocationCount); assertEquals(2, MixinTestParentCommand.methodSubInvocationCount); } @Test public void testParentOrderInRepeatableCommands() { MixinTestParentCommand.methodSubInvocationCount = 0; MixinTestSubCommand.invocationCount = 0; MixinTestParentCommand parent = new MixinTestParentCommand(); CommandLine cl = new CommandLine(parent); cl.execute("sub -x3 sub sub".split(" ")); assertEquals(3, cl.getParseResult().subcommands().size()); for (ParseResult subPR : cl.getParseResult().subcommands()) { MixinTestSubCommand sub = subPR.commandSpec().commandLine().getCommand(); assertSame(parent, sub.parent); } } @Command(subcommandsRepeatable = true) static class MultivalueTop implements Runnable { @Command int sub1(@Option(names = "-x", arity = "*") List x) { return x.size(); } @Command int sub2(@Option(names = "-y", arity = "*") List y) { return y.size(); } public void run() { } } @Test public void testMultivalueOptions() { int exitCode = new CommandLine(new MultivalueTop()).execute("sub1 -x1 -x2 -x3 sub2 -y1 -y2 -y3 -y4".split(" ")); assertEquals(4, exitCode); } @Test public void testCommandSpec_SubcommandsRepeatable() { class Positional { @Parameters(index = "0") String first; } CommandLine cmd = new CommandLine(new Positional()); CommandLine.Model.CommandSpec spec = cmd.getCommandSpec(); assertFalse("orig", spec.subcommandsRepeatable()); spec.subcommandsRepeatable(true); assertTrue("after", spec.subcommandsRepeatable()); } @Command(name = "issue1007", subcommandsRepeatable = true) static class Issue1007CommandWithCustomConverter { public int count; @Command public void sub(@Option(names = "-x") final MyBean bean) { count++; } static class CustomConverter implements CommandLine.ITypeConverter { public MyBean convert(String value) throws Exception { return new MyBean(value); } } static class MyBean { String value; public MyBean(String value) {this.value = value;} } } @Test public void testCustomConverter() { Issue1007CommandWithCustomConverter cmd = new Issue1007CommandWithCustomConverter(); CommandLine line = new CommandLine(cmd); line.registerConverter(Issue1007CommandWithCustomConverter.MyBean.class, new Issue1007CommandWithCustomConverter.CustomConverter()); assertEquals(0, cmd.count); int exitCode = line.execute("sub -x=abc sub -x=xyz".split(" ")); assertEquals(0, exitCode); assertEquals(2, cmd.count); } @SuppressWarnings("deprecation") @Test public void testCommandLinePublicSetter() throws IOException { PrintWriter ERR = new PrintWriter(new StringWriter()); PrintWriter OUT = new PrintWriter(new StringWriter()); CommandLine.IExecutionExceptionHandler xxh = new CommandLine.IExecutionExceptionHandler() { public int handleExecutionException(Exception ex, CommandLine commandLine, ParseResult parseResult) throws Exception { ex.printStackTrace(); return 0; } }; CommandLine.IExitCodeExceptionMapper xcxm = new CommandLine.IExitCodeExceptionMapper() { public int getExitCode(Throwable exception) { return 0; } }; CommandLine.IHelpFactory helpFactory = new CommandLine.IHelpFactory() { public CommandLine.Help create(CommandLine.Model.CommandSpec commandSpec, CommandLine.Help.ColorScheme colorScheme) { return null; } }; List helpKeys = Arrays.asList("A", "B", "C"); CommandLine.INegatableOptionTransformer transformer = new CommandLine.INegatableOptionTransformer() { public String makeNegative(String optionName, CommandLine.Model.CommandSpec cmd) { return null; } public String makeSynopsis(String optionName, CommandLine.Model.CommandSpec cmd) { return null; } }; CommandLine.IParameterExceptionHandler pex = new CommandLine.IParameterExceptionHandler() { public int handleParseException(CommandLine.ParameterException ex, String[] args) throws Exception { ex.printStackTrace(); return 0; } }; ResourceBundle rb = new PropertyResourceBundle(new ByteArrayInputStream(new byte[0])); //TestUtil.setTraceLevel("DEBUG"); Issue1007CommandWithCustomConverter cmd = new Issue1007CommandWithCustomConverter(); CommandLine line = new CommandLine(cmd); line.registerConverter(Issue1007CommandWithCustomConverter.MyBean.class, new Issue1007CommandWithCustomConverter.CustomConverter()); line.setAdjustLineBreaksForWideCJKCharacters(false); line.setAtFileCommentChar('!'); line.setCaseInsensitiveEnumValuesAllowed(true); line.setColorScheme(new CommandLine.Help.ColorScheme.Builder().commands(CommandLine.Help.Ansi.Style.fg_cyan).build()); line.setCommandName("abcdefg"); line.setDefaultValueProvider(new CommandLine.PropertiesDefaultProvider()); line.setEndOfOptionsDelimiter("EOF"); line.setErr(ERR); line.setExecutionExceptionHandler(xxh); final CommandLine.IExecutionStrategy original = line.getExecutionStrategy(); CommandLine.IExecutionStrategy xs = new CommandLine.IExecutionStrategy() { public int execute(ParseResult parseResult) throws CommandLine.ExecutionException, CommandLine.ParameterException { return original.execute(parseResult); } }; line.setExecutionStrategy(xs); line.setExitCodeExceptionMapper(xcxm); line.setExpandAtFiles(false); line.setHelpFactory(helpFactory); line.setHelpSectionKeys(helpKeys); line.setHelpSectionMap(Collections.emptyMap()); line.setInterpolateVariables(false); line.setNegatableOptionTransformer(transformer); line.setOut(OUT); line.setOverwrittenOptionsAllowed(true); line.setParameterExceptionHandler(pex); line.setPosixClusteredShortOptionsAllowed(false); line.setResourceBundle(rb); line.setSeparator(":"); line.setSplitQuotedStrings(true); line.setStopAtPositional(true); line.setStopAtUnmatched(true); line.setToggleBooleanFlags(true); line.setTrimQuotes(true); line.setUnmatchedArgumentsAllowed(true); line.setUnmatchedOptionsArePositionalParams(true); line.setUsageHelpAutoWidth(true); line.setUsageHelpLongOptionsMaxWidth(55); line.setUsageHelpWidth(99); line.setUseSimplifiedAtFiles(true); assertEquals(0, cmd.count); int exitCode = line.execute("sub -x:abc sub -x:xyz".split(" ")); assertEquals(0, exitCode); assertEquals(2, cmd.count); assertEquals(2, line.getParseResult().subcommands().size()); for (int i = 0; i < line.getParseResult().subcommands().size(); i++) { checkEquals(line, line.getParseResult().subcommands().get(i).commandSpec().commandLine()); } } @SuppressWarnings("deprecation") private void checkEquals(CommandLine line, CommandLine other) { assertSame(line.getAtFileCommentChar(), other.getAtFileCommentChar()); assertSame(line.isCaseInsensitiveEnumValuesAllowed(), other.isCaseInsensitiveEnumValuesAllowed()); assertSame(line.getColorScheme(), other.getColorScheme()); //assertSame(line.getCommandName(), other.getCommandName()); assertSame(line.getDefaultValueProvider(), other.getDefaultValueProvider()); assertSame(line.getEndOfOptionsDelimiter(), other.getEndOfOptionsDelimiter()); assertSame(line.getErr(), other.getErr()); assertSame(line.getExecutionExceptionHandler(), other.getExecutionExceptionHandler()); assertSame(line.getExecutionStrategy(), other.getExecutionStrategy()); assertSame(line.getExitCodeExceptionMapper(), other.getExitCodeExceptionMapper()); //assertSame(line.isExpandAtFiles(), other.isExpandAtFiles()); assertSame(line.getHelpFactory(), other.getHelpFactory()); assertEquals(line.getHelpSectionKeys(), other.getHelpSectionKeys()); assertEquals(line.getHelpSectionMap(), other.getHelpSectionMap()); assertSame(line.isInterpolateVariables(), other.isInterpolateVariables()); assertSame(line.getNegatableOptionTransformer(), other.getNegatableOptionTransformer()); assertSame(line.getOut(), other.getOut()); assertSame(line.isOverwrittenOptionsAllowed(), other.isOverwrittenOptionsAllowed()); assertSame(line.getParameterExceptionHandler(), other.getParameterExceptionHandler()); assertSame(line.isPosixClusteredShortOptionsAllowed(), other.isPosixClusteredShortOptionsAllowed()); assertSame(line.getResourceBundle(), other.getResourceBundle()); assertSame(line.getSeparator(), other.getSeparator()); assertSame(line.isSplitQuotedStrings(), other.isSplitQuotedStrings()); assertSame(line.isStopAtPositional(), other.isStopAtPositional()); assertSame(line.isStopAtUnmatched(), other.isStopAtUnmatched()); assertSame(line.isToggleBooleanFlags(), other.isToggleBooleanFlags()); assertSame(line.isTrimQuotes(), other.isTrimQuotes()); assertSame(line.isUnmatchedArgumentsAllowed(), other.isUnmatchedArgumentsAllowed()); assertSame(line.isUnmatchedOptionsArePositionalParams(), other.isUnmatchedOptionsArePositionalParams()); assertSame(line.isUsageHelpAutoWidth(), other.isUsageHelpAutoWidth()); assertSame(line.getUsageHelpLongOptionsMaxWidth(), other.getUsageHelpLongOptionsMaxWidth()); assertSame(line.getUsageHelpWidth(), other.getUsageHelpWidth()); //assertSame(line.isUseSimplifiedAtFiles(), other.isUseSimplifiedAtFiles()); } }