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.Model.ArgSpec; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; import picocli.CommandLine.ParseResult; import picocli.CommandLine.UnmatchedArgumentException; import java.io.*; import java.security.MessageDigest; import java.util.Arrays; import java.util.List; import java.util.concurrent.Callable; import static java.lang.String.format; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.*; public class InteractiveArgTest { // 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"); @Test public void testInteractiveOptionReadsFromStdIn() { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true) int x; @Option(names = "-z") int z; } PrintStream out = System.out; PrintStream err = System.err; InputStream in = System.in; System.setProperty("picocli.trace", "DEBUG"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); System.setErr(new PrintStream(errBaos)); System.setIn(new ByteArrayInputStream("1234567890".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); ParseResult result = cmd.parseArgs("-x"); ArgSpec specX = result.matchedArgs().get(0); assertThat(specX.toString(), containsString("App.x")); assertEquals("Enter value for -x (Pwd): ", baos.toString()); assertEquals(1234567890, app.x); assertEquals(0, app.z); String trace = errBaos.toString(); assertThat(trace, containsString("User entered 10 characters")); assertThat(trace, containsString( "Setting " + specX.toString() + " to *** (masked interactive value)")); assertThat(trace, not(containsString("1234567890"))); cmd.parseArgs("-z", "678"); assertEquals(0, app.x); assertEquals(678, app.z); } finally { System.setOut(out); System.setOut(err); System.setIn(in); } } @Test public void testInteractiveOptionReadsFromStdInWithEchoing() { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true, echo = true) int x; } PrintStream out = System.out; PrintStream err = System.err; InputStream in = System.in; System.setProperty("picocli.trace", "DEBUG"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); System.setErr(new PrintStream(errBaos)); System.setIn(new ByteArrayInputStream("1234567890".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); ParseResult result = cmd.parseArgs("-x"); ArgSpec specX = result.matchedArgs().get(0); assertThat(specX.toString(), containsString("App.x")); assertEquals("Enter value for -x (Pwd): ", baos.toString()); assertEquals(1234567890, app.x); String trace = errBaos.toString(); assertThat(trace, containsString("User entered 1234567890")); assertThat(trace, containsString( "Setting " + specX.toString() + " to 1234567890")); assertThat(trace, not(containsString("10 characters"))); assertThat(trace, not(containsString("***"))); } finally { System.setOut(out); System.setErr(err); System.setIn(in); } } @Test public void testInteractiveOptionReadsFromStdInWithCustomPrompt() { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true, prompt = "[Customized]Enter your X: ") int x; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(new ByteArrayInputStream("123".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x"); assertEquals("[Customized]Enter your X: ", baos.toString()); assertEquals(123, app.x); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionAsListOfIntegers() throws IOException { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true) List x; @Option(names = "-z") int z; } PrintStream out = System.out; PrintStream err = System.err; InputStream in = System.in; System.setProperty("picocli.trace", "DEBUG"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); System.setErr(new PrintStream(errBaos)); System.setIn(inputStream("1234567890")); App app = new App(); CommandLine cmd = new CommandLine(app); ParseResult result = cmd.parseArgs("-x", "-x"); ArgSpec specX = result.matchedArgs().get(0); assertThat(specX.toString(), containsString("App.x")); assertEquals("Enter value for -x (Pwd): Enter value for -x (Pwd): ", baos.toString()); assertEquals(Arrays.asList(1234567890, 1234567890), app.x); assertEquals(0, app.z); String trace = errBaos.toString(); assertThat(trace, containsString("User entered 10 characters")); assertThat(trace, containsString( "Adding *** (masked interactive value) to " + specX.toString() + " for option -x on " + app.getClass().getSimpleName())); assertThat(trace, not(containsString("1234567890"))); cmd.parseArgs("-z", "678"); assertNull(app.x); assertEquals(678, app.z); } finally { System.setOut(out); System.setOut(err); System.setIn(in); } } @Test public void testInteractiveOptionAsListOfIntegersWithEchoing() { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true, echo = true) List x; @Option(names = "-z") int z; } PrintStream out = System.out; PrintStream err = System.err; InputStream in = System.in; System.setProperty("picocli.trace", "DEBUG"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); System.setErr(new PrintStream(errBaos)); System.setIn(inputStream("1234567890")); App app = new App(); CommandLine cmd = new CommandLine(app); ParseResult result = cmd.parseArgs("-x", "-x"); ArgSpec specX = result.matchedArgs().get(0); assertThat(specX.toString(), containsString("App.x")); assertEquals("Enter value for -x (Pwd): Enter value for -x (Pwd): ", baos.toString()); assertEquals(Arrays.asList(1234567890, 1234567890), app.x); assertEquals(0, app.z); String trace = errBaos.toString(); assertThat(trace, containsString("User entered 1234567890")); assertThat(trace, containsString( "Adding 1234567890 (interactive value) to " + specX.toString() + " for option -x on " + app.getClass().getSimpleName())); assertThat(trace, not(containsString("10 characters"))); assertThat(trace, not(containsString("***"))); } finally { System.setOut(out); System.setOut(err); System.setIn(in); } } @Test public void testInteractiveOptionAsListOfIntegersWithCustomPrompt() { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true, prompt = "[Customized]Enter your x: ") List x; @Option(names = "-z") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-x"); assertEquals("[Customized]Enter your x: [Customized]Enter your x: ", baos.toString()); assertEquals(Arrays.asList(123, 123), app.x); assertEquals(0, app.z); } finally { System.setOut(out); System.setIn(in); } } ByteArrayInputStream inputStream(final String value) { return new ByteArrayInputStream(value.getBytes()) { int count; @Override public synchronized int read(byte[] b, int off, int len) { System.arraycopy(value.getBytes(), 0, b, off, value.length()); return (count++ % 3) == 0 ? value.length() : -1; } }; } @Test public void testInteractiveOptionAsListOfCharArrays() throws IOException { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true) List x; @Option(names = "-z") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-x"); assertEquals("Enter value for -x (Pwd): Enter value for -x (Pwd): ", baos.toString()); assertEquals(2, app.x.size()); assertArrayEquals("123".toCharArray(), app.x.get(0)); assertArrayEquals("123".toCharArray(), app.x.get(1)); assertEquals(0, app.z); cmd.parseArgs("-z", "678"); assertNull(app.x); assertEquals(678, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionAsCharArray() throws IOException { class App { @Option(names = "-x", description = {"Pwd", "line2"}, interactive = true) char[] x; @Option(names = "-z") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x"); assertEquals("Enter value for -x (Pwd): ", baos.toString()); assertArrayEquals("123".toCharArray(), app.x); assertEquals(0, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionArity_0_1_ConsumesFromCommandLineIfPossible() throws IOException { class App { @Option(names = "-x", arity = "0..1", interactive = true) char[] x; @Parameters() String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "456", "abc"); assertArrayEquals("456".toCharArray(), app.x); assertArrayEquals(new String[]{"abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionAsListOfCharArraysArity_0_1_ConsumesFromCommandLineIfPossible() throws IOException { class App { @Option(names = "-x", arity = "0..1", interactive = true) List x; @Parameters() String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "456", "-x", "789", "abc"); assertEquals(2, app.x.size()); assertArrayEquals("456".toCharArray(), app.x.get(0)); assertArrayEquals("789".toCharArray(), app.x.get(1)); assertArrayEquals(new String[]{"abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionArity_0_1_AvoidsConsumingOption() throws IOException { class App { @Option(names = "-x", arity = "0..1", interactive = true) char[] x; @Option(names = "-z") int z; @Parameters() String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-z", "456", "abc"); assertArrayEquals("123".toCharArray(), app.x); assertEquals(456, app.z); assertArrayEquals(new String[]{"abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionAsListOfCharArraysArity_0_1_AvoidsConsumingOption() throws IOException { class App { @Option(names = "-x", arity = "0..1", interactive = true) List x; @Option(names = "-z") int z; @Parameters() String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-z", "456", "abc"); assertEquals(1, app.x.size()); assertArrayEquals("123".toCharArray(), app.x.get(0)); assertEquals(456, app.z); assertArrayEquals(new String[]{"abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionArity_0_1_ConsumesUnknownOption() throws IOException { class App { @Option(names = "-x", arity = "0..1", interactive = true) char[] x; @Option(names = "-z") int z; @Parameters() String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-y", "456", "abc"); assertArrayEquals("-y".toCharArray(), app.x); assertEquals(0, app.z); assertArrayEquals(new String[]{"456", "abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionAsListOfCharArraysArity_0_1_ConsumesUnknownOption() throws IOException { class App { @Option(names = "-x", arity = "0..1", interactive = true) List x; @Option(names = "-z") int z; @Parameters() String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-y", "-x", "-w", "456", "abc"); assertEquals(2, app.x.size()); assertArrayEquals("-y".toCharArray(), app.x.get(0)); assertArrayEquals("-w".toCharArray(), app.x.get(1)); assertEquals(0, app.z); assertArrayEquals(new String[]{"456", "abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractiveOptionReadsFromStdInMultiLinePrompt() { class App { @Option(names = "-x", description = {"Pwd%nline2", "ignored"}, interactive = true) int x; @Option(names = "-z") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(new ByteArrayInputStream("123".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-x", "-z", "987"); String expectedPrompt = format("Enter value for -x (Pwd%nline2): "); assertEquals(expectedPrompt, baos.toString()); assertEquals(123, app.x); assertEquals(987, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalReadsFromStdIn() { class App { @Parameters(index = "0", description = {"Pwd%nline2", "ignored"}, interactive = true) int x; @Parameters(index = "1") int z; } PrintStream out = System.out; PrintStream err = System.err; InputStream in = System.in; System.setProperty("picocli.trace", "DEBUG"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); System.setErr(new PrintStream(errBaos)); System.setIn(new ByteArrayInputStream("1234567890".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); ParseResult result = cmd.parseArgs("987"); ArgSpec specX = result.matchedArgs().get(0); assertThat(specX.toString(), containsString("App.x")); String expectedPrompt = format("Enter value for position 0 (Pwd%nline2): "); assertEquals(expectedPrompt, baos.toString()); assertEquals(1234567890, app.x); assertEquals(987, app.z); String trace = errBaos.toString(); assertThat(trace, containsString("User entered 10 characters")); assertThat(trace, containsString( "Setting " + specX.toString() + " to *** (masked interactive value)")); assertThat(trace, not(containsString("1234567890"))); } finally { System.setOut(out); System.setOut(err); System.setIn(in); } } @Test public void testInteractivePositionalReadsFromStdInWithEchoing() { class App { @Parameters(index = "0", description = {"Pwd%nline2", "ignored"}, interactive = true, echo = true) int x; @Parameters(index = "1") int z; } PrintStream out = System.out; PrintStream err = System.err; InputStream in = System.in; System.setProperty("picocli.trace", "DEBUG"); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); System.setErr(new PrintStream(errBaos)); System.setIn(new ByteArrayInputStream("1234567890".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); ParseResult result = cmd.parseArgs("987"); ArgSpec specX = result.matchedArgs().get(0); assertThat(specX.toString(), containsString("App.x")); String expectedPrompt = format("Enter value for position 0 (Pwd%nline2): "); assertEquals(expectedPrompt, baos.toString()); assertEquals(1234567890, app.x); assertEquals(987, app.z); String trace = errBaos.toString(); assertThat(trace, containsString("User entered 1234567890")); assertThat(trace, containsString( "Setting " + specX.toString() + " to 123")); assertThat(trace, not(containsString("10 characters"))); assertThat(trace, not(containsString("***"))); } finally { System.setOut(out); System.setOut(err); System.setIn(in); } } @Test public void testInteractivePositionalReadsFromStdInWithCustomPrompt() { class App { @Parameters(index = "0", description = {"Pwd%nline2", "ignored"}, interactive = true, prompt = "[Customized]Enter your value: ") int x; @Parameters(index = "1") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(new ByteArrayInputStream("123".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("987"); String expectedPrompt = format("[Customized]Enter your value: "); assertEquals(expectedPrompt, baos.toString()); assertEquals(123, app.x); assertEquals(987, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalDoesntReadFromStdInIfNoFollowingPositionalParam() { class App { @Parameters(index = "0", interactive = true, description = {"Pwd"}) int x; @Option(names = "-s") String str; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(new ByteArrayInputStream("123".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("-s", "abc"); assertEquals("abc", app.str); //assertEquals(123, app.x); assertEquals("No value was read from console", 0, app.x); //String expectedPrompt = format("Enter value for position 0 (Pwd): "); String expectedPrompt = ""; // interactive arg was not prompted assertEquals(expectedPrompt, baos.toString()); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositional2ReadsFromStdIn() { class App { @Parameters(index = "0") int a; @Parameters(index = "1", description = {"Pwd%nline2", "ignored"}, interactive = true) int x; @Parameters(index = "2") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(new ByteArrayInputStream("123".getBytes())); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("333", "987"); String expectedPrompt = format("Enter value for position 1 (Pwd%nline2): "); assertEquals(expectedPrompt, baos.toString()); assertEquals(333, app.a); assertEquals(123, app.x); assertEquals(987, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testLoginExample() { class Login implements Callable { @Option(names = {"-u", "--user"}, description = "User name") String user; @Option(names = {"-p", "--password"}, description = "Password or passphrase", interactive = true) char[] password; public Object call() throws Exception { byte[] bytes = new byte[password.length]; for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) password[i]; } MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(bytes); System.out.printf("Hi %s, your password is hashed to %s.%n", user, base64(md.digest())); // null out the arrays when done Arrays.fill(bytes, (byte) 0); Arrays.fill(password, ' '); return null; } private String base64(byte[] arr) throws Exception { //return javax.xml.bind.DatatypeConverter.printBase64Binary(arr); try { Object enc = Class.forName("java.util.Base64").getDeclaredMethod("getEncoder").invoke(null, new Object[0]); return (String) Class.forName("java.util.Base64$Encoder").getDeclaredMethod("encodeToString", new Class[]{byte[].class}).invoke(enc, new Object[] {arr}); } catch (Exception beforeJava8) { //return new sun.misc.BASE64Encoder().encode(arr); return "75K3eLr+dx6JJFuJ7LwIpEpOFmwGZZkRiB84PURz6U8="; // :-) } } } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(inputStream("password123")); Login login = new Login(); new CommandLine(login).execute("-u", "user123", "-p"); String expectedPrompt = format("Enter value for --password (Password or passphrase): " + "Hi user123, your password is hashed to 75K3eLr+dx6JJFuJ7LwIpEpOFmwGZZkRiB84PURz6U8=.%n"); assertEquals(expectedPrompt, baos.toString()); assertEquals("user123", login.user); assertArrayEquals(" ".toCharArray(), login.password); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalAsListOfCharArrays() throws IOException { class App { @Parameters(index = "0..1", description = {"Pwd", "line2"}, interactive = true) List x; @Parameters(index = "2") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("999"); assertEquals("Enter value for position 0 (Pwd): Enter value for position 1 (Pwd): ", baos.toString()); assertEquals(2, app.x.size()); assertArrayEquals("123".toCharArray(), app.x.get(0)); assertArrayEquals("123".toCharArray(), app.x.get(1)); assertEquals(999, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalAsCharArray() throws IOException { class App { @Parameters(index = "0", description = {"Pwd", "line2"}, interactive = true) char[] x; @Parameters(index = "1") int z; } PrintStream out = System.out; InputStream in = System.in; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("9"); assertEquals("Enter value for position 0 (Pwd): ", baos.toString()); assertArrayEquals("123".toCharArray(), app.x); assertEquals(9, app.z); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalArity_0_1_ConsumesFromCommandLineIfPossible() throws IOException { class App { @Parameters(index = "0", arity = "0..1", interactive = true) char[] x; @Parameters(index = "1") String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("456", "abc"); assertArrayEquals("456".toCharArray(), app.x); assertArrayEquals(new String[]{"abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalAsListOfCharArraysArity_0_1_ConsumesFromCommandLineIfPossible() throws IOException { class App { @Parameters(index = "0..1", arity = "0..1", interactive = true) List x; @Parameters(index = "2") String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); cmd.parseArgs("456", "789", "abc"); assertEquals(2, app.x.size()); assertArrayEquals("456".toCharArray(), app.x.get(0)); assertArrayEquals("789".toCharArray(), app.x.get(1)); assertArrayEquals(new String[]{"abc"}, app.remainder); } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalArity_0_1_DoesNotConsumeUnknownOption() throws IOException { class App { @Parameters(index = "0", arity = "0..1", interactive = true) char[] x; @Option(names = "-z") int z; @Parameters(index = "1") String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); try { cmd.parseArgs("-y", "456", "abc"); fail("Expect exception"); } catch (UnmatchedArgumentException ex) { assertEquals("Unknown option: '-y'", ex.getMessage()); } } finally { System.setOut(out); System.setIn(in); } } @Test public void testInteractivePositionalAsListOfCharArraysArity_0_1_DoesNotConsumeUnknownOption() throws IOException { class App { @Parameters(index = "0..1", arity = "0..1", interactive = true) List x; @Option(names = "-z") int z; @Parameters(index = "2") String[] remainder; } PrintStream out = System.out; InputStream in = System.in; try { System.setOut(new PrintStream(new ByteArrayOutputStream())); System.setIn(inputStream("123")); App app = new App(); CommandLine cmd = new CommandLine(app); try { cmd.parseArgs("-y", "-w", "456", "abc"); fail("Expect exception"); } catch (UnmatchedArgumentException ex) { assertEquals("Unknown options: '-y', '-w'", ex.getMessage()); } } finally { System.setOut(out); System.setIn(in); } } }