JCommanderTest.java revision df883e8495e143f92d363225e48b45a81cf449fd
1/**
2 * Copyright (C) 2010 the original author or authors.
3 * See the notice.md file distributed with this work for additional
4 * information regarding copyright ownership.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19package com.beust.jcommander;
20
21import java.io.ByteArrayInputStream;
22import java.io.File;
23import java.io.FileWriter;
24import java.io.IOException;
25import java.io.InputStream;
26import java.math.BigDecimal;
27import java.text.ParseException;
28import java.text.SimpleDateFormat;
29import java.util.ArrayList;
30import java.util.Arrays;
31import java.util.EnumSet;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Locale;
35import java.util.Map;
36import java.util.ResourceBundle;
37import java.util.TreeSet;
38
39import org.testng.Assert;
40import org.testng.annotations.DataProvider;
41import org.testng.annotations.Test;
42
43import com.beust.jcommander.args.AlternateNamesForListArgs;
44import com.beust.jcommander.args.Args1;
45import com.beust.jcommander.args.Args1Setter;
46import com.beust.jcommander.args.Args2;
47import com.beust.jcommander.args.ArgsArityString;
48import com.beust.jcommander.args.ArgsBooleanArity;
49import com.beust.jcommander.args.ArgsBooleanArity0;
50import com.beust.jcommander.args.ArgsConverter;
51import com.beust.jcommander.args.ArgsEnum;
52import com.beust.jcommander.args.ArgsEnum.ChoiceType;
53import com.beust.jcommander.args.ArgsEquals;
54import com.beust.jcommander.args.ArgsHelp;
55import com.beust.jcommander.args.ArgsI18N1;
56import com.beust.jcommander.args.ArgsI18N2;
57import com.beust.jcommander.args.ArgsI18N2New;
58import com.beust.jcommander.args.ArgsInherited;
59import com.beust.jcommander.args.ArgsList;
60import com.beust.jcommander.args.ArgsMainParameter1;
61import com.beust.jcommander.args.ArgsMaster;
62import com.beust.jcommander.args.ArgsMultipleUnparsed;
63import com.beust.jcommander.args.ArgsOutOfMemory;
64import com.beust.jcommander.args.ArgsPrivate;
65import com.beust.jcommander.args.ArgsRequired;
66import com.beust.jcommander.args.ArgsSlave;
67import com.beust.jcommander.args.ArgsSlaveBogus;
68import com.beust.jcommander.args.ArgsValidate1;
69import com.beust.jcommander.args.ArgsWithSet;
70import com.beust.jcommander.args.Arity1;
71import com.beust.jcommander.args.SeparatorColon;
72import com.beust.jcommander.args.SeparatorEqual;
73import com.beust.jcommander.args.SeparatorMixed;
74import com.beust.jcommander.args.SlashSeparator;
75import com.beust.jcommander.args.VariableArity;
76import com.beust.jcommander.command.CommandAdd;
77import com.beust.jcommander.command.CommandCommit;
78import com.beust.jcommander.command.CommandMain;
79import com.beust.jcommander.internal.Lists;
80import com.beust.jcommander.internal.Maps;
81
82@Test
83public class JCommanderTest {
84  public void simpleArgs() throws ParseException {
85    Args1 args = new Args1();
86    String[] argv = { "-debug", "-log", "2", "-float", "1.2", "-double", "1.3", "-bigdecimal", "1.4",
87            "-date", "2011-10-26", "-groups", "unit", "a", "b", "c" };
88    new JCommander(args, argv);
89
90    Assert.assertTrue(args.debug);
91    Assert.assertEquals(args.verbose.intValue(), 2);
92    Assert.assertEquals(args.groups, "unit");
93    Assert.assertEquals(args.parameters, Arrays.asList("a", "b", "c"));
94    Assert.assertEquals(args.floa, 1.2f, 0.1f);
95    Assert.assertEquals(args.doub, 1.3f, 0.1f);
96    Assert.assertEquals(args.bigd, new BigDecimal("1.4"));
97    Assert.assertEquals(args.date, new SimpleDateFormat("yyyy-MM-dd").parse("2011-10-26"));
98  }
99
100  @DataProvider
101  public Object[][] alternateNamesListArgs() {
102    return new Object[][] {
103        new String[][] {new String[] {"--servers", "1", "-s", "2", "--servers", "3"}},
104        new String[][] {new String[] {"-s", "1", "-s", "2", "--servers", "3"}},
105        new String[][] {new String[] {"--servers", "1", "--servers", "2", "-s", "3"}},
106        new String[][] {new String[] {"-s", "1", "--servers", "2", "-s", "3"}},
107        new String[][] {new String[] {"-s", "1", "-s", "2", "--servers", "3"}},
108    };
109  }
110
111  /**
112   *  Confirm that List<?> parameters with alternate names return the correct
113   * List regardless of how the arguments are specified
114   */
115
116  @Test(dataProvider = "alternateNamesListArgs")
117  public void testAlternateNamesForListArguments(String[] argv) {
118      AlternateNamesForListArgs args = new AlternateNamesForListArgs();
119
120      new JCommander(args, argv);
121
122      Assert.assertEquals(args.serverNames.size(), 3);
123      Assert.assertEquals(args.serverNames.get(0), argv[1]);
124      Assert.assertEquals(args.serverNames.get(1), argv[3]);
125      Assert.assertEquals(args.serverNames.get(2), argv[5]);
126  }
127
128
129  /**
130   * Make sure that if there are args with multiple names (e.g. "-log" and "-verbose"),
131   * the usage will only display it once.
132   */
133  public void repeatedArgs() {
134    Args1 args = new Args1();
135    String[] argv = { "-log", "2" };
136    JCommander jc = new JCommander(args, argv);
137    Assert.assertEquals(jc.getParameters().size(), 8);
138  }
139
140  /**
141   * Not specifying a required option should throw an exception.
142   */
143  @Test(expectedExceptions = ParameterException.class)
144  public void requiredFields1Fail() {
145    Args1 args = new Args1();
146    String[] argv = { "-debug" };
147    new JCommander(args, argv);
148  }
149
150  /**
151   * Getting the description of a nonexistent command should throw an exception.
152   */
153  @Test(expectedExceptions = ParameterException.class)
154  public void nonexistentCommandShouldThrow() {
155    String[] argv = { };
156    JCommander jc = new JCommander(new Object(), argv);
157    jc.getCommandDescription("foo");
158  }
159
160  /**
161   * Required options with multiple names should work with all names.
162   */
163  private void multipleNames(String option) {
164    Args1 args = new Args1();
165    String[] argv = { option, "2" };
166    new JCommander(args, argv);
167    Assert.assertEquals(args.verbose.intValue(), 2);
168  }
169
170  public void multipleNames1() {
171    multipleNames("-log");
172  }
173
174  public void multipleNames2() {
175    multipleNames("-verbose");
176  }
177
178  private void i18n1(String bundleName, Locale locale, String expectedString) {
179    ResourceBundle bundle = locale != null ? ResourceBundle.getBundle(bundleName, locale)
180        : null;
181
182    ArgsI18N1 i18n = new ArgsI18N1();
183    String[] argv = { "-host", "localhost" };
184    JCommander jc = new JCommander(i18n, bundle, argv);
185//    jc.usage();
186
187    ParameterDescription pd = jc.getParameters().get(0);
188    Assert.assertEquals(pd.getDescription(), expectedString);
189  }
190
191  public void i18nNoLocale() {
192    i18n1("MessageBundle", null, "Host");
193  }
194
195  public void i18nUsLocale() {
196    i18n1("MessageBundle", new Locale("en", "US"), "Host");
197  }
198
199  public void i18nFrLocale() {
200    i18n1("MessageBundle", new Locale("fr", "FR"), "Hôte");
201  }
202
203  private void i18n2(Object i18n) {
204    String[] argv = { "-host", "localhost" };
205    Locale.setDefault(new Locale("fr", "FR"));
206    JCommander jc = new JCommander(i18n, argv);
207    ParameterDescription pd = jc.getParameters().get(0);
208    Assert.assertEquals(pd.getDescription(), "Hôte");
209  }
210
211  public void i18nWithResourceAnnotation() {
212    i18n2(new ArgsI18N2());
213  }
214
215  public void i18nWithResourceAnnotationNew() {
216    i18n2(new ArgsI18N2New());
217  }
218
219  public void noParseConstructor() {
220    JCommander jCommander = new JCommander(new ArgsMainParameter1());
221    jCommander.usage(new StringBuilder());
222    // Before fix, this parse would throw an exception, because it calls createDescription, which
223    // was already called by usage(), and can only be called once.
224    jCommander.parse();
225  }
226
227  /**
228   * Test a use case where there are required parameters, but you still want
229   * to interrogate the options which are specified.
230   */
231  public void usageWithRequiredArgsAndResourceBundle() {
232    ArgsHelp argsHelp = new ArgsHelp();
233    JCommander jc = new JCommander(new Object[]{argsHelp, new ArgsRequired()},
234        java.util.ResourceBundle.getBundle("MessageBundle"));
235    // Should be able to display usage without triggering validation
236    jc.usage(new StringBuilder());
237    try {
238      jc.parse("-h");
239      Assert.fail("Should have thrown a required parameter exception");
240    } catch (ParameterException e) {
241      Assert.assertTrue(e.getMessage().contains("are required"));
242    }
243    Assert.assertTrue(argsHelp.help);
244  }
245
246  public void multiObjects() {
247    ArgsMaster m = new ArgsMaster();
248    ArgsSlave s = new ArgsSlave();
249    String[] argv = { "-master", "master", "-slave", "slave" };
250    new JCommander(new Object[] { m , s }, argv);
251
252    Assert.assertEquals(m.master, "master");
253    Assert.assertEquals(s.slave, "slave");
254  }
255
256  @Test(expectedExceptions = ParameterException.class)
257  public void multiObjectsWithDuplicatesFail() {
258    ArgsMaster m = new ArgsMaster();
259    ArgsSlave s = new ArgsSlaveBogus();
260    String[] argv = { "-master", "master", "-slave", "slave" };
261    new JCommander(new Object[] { m , s }, argv);
262  }
263
264  public void arityString() {
265    ArgsArityString args = new ArgsArityString();
266    String[] argv = { "-pairs", "pair0", "pair1", "rest" };
267    new JCommander(args, argv);
268
269    Assert.assertEquals(args.pairs.size(), 2);
270    Assert.assertEquals(args.pairs.get(0), "pair0");
271    Assert.assertEquals(args.pairs.get(1), "pair1");
272    Assert.assertEquals(args.rest.size(), 1);
273    Assert.assertEquals(args.rest.get(0), "rest");
274  }
275
276  @Test(expectedExceptions = ParameterException.class)
277  public void arity2Fail() {
278    ArgsArityString args = new ArgsArityString();
279    String[] argv = { "-pairs", "pair0" };
280    new JCommander(args, argv);
281  }
282
283  @Test(expectedExceptions = ParameterException.class)
284  public void multipleUnparsedFail() {
285    ArgsMultipleUnparsed args = new ArgsMultipleUnparsed();
286    String[] argv = { };
287    new JCommander(args, argv);
288  }
289
290  public void privateArgs() {
291    ArgsPrivate args = new ArgsPrivate();
292    new JCommander(args, "-verbose", "3");
293    Assert.assertEquals(args.getVerbose().intValue(), 3);
294  }
295
296  public void converterArgs() {
297    ArgsConverter args = new ArgsConverter();
298    String fileName = "a";
299    new JCommander(args, "-file", "/tmp/" + fileName,
300      "-listStrings", "Tuesday,Thursday",
301      "-listInts", "-1,8",
302      "-listBigDecimals", "-11.52,100.12");
303    Assert.assertEquals(args.file.getName(), fileName);
304    Assert.assertEquals(args.listStrings.size(), 2);
305    Assert.assertEquals(args.listStrings.get(0), "Tuesday");
306    Assert.assertEquals(args.listStrings.get(1), "Thursday");
307    Assert.assertEquals(args.listInts.size(), 2);
308    Assert.assertEquals(args.listInts.get(0).intValue(), -1);
309    Assert.assertEquals(args.listInts.get(1).intValue(), 8);
310    Assert.assertEquals(args.listBigDecimals.size(), 2);
311    Assert.assertEquals(args.listBigDecimals.get(0), new BigDecimal("-11.52"));
312    Assert.assertEquals(args.listBigDecimals.get(1), new BigDecimal("100.12"));
313  }
314
315  private void argsBoolean1(String[] params, Boolean expected) {
316    ArgsBooleanArity args = new ArgsBooleanArity();
317    new JCommander(args, params);
318    Assert.assertEquals(args.debug, expected);
319  }
320
321  private void argsBoolean0(String[] params, Boolean expected) {
322    ArgsBooleanArity0 args = new ArgsBooleanArity0();
323    new JCommander(args, params);
324    Assert.assertEquals(args.debug, expected);
325  }
326
327  public void booleanArity1() {
328    argsBoolean1(new String[] {}, Boolean.FALSE);
329    argsBoolean1(new String[] { "-debug", "true" }, Boolean.TRUE);
330  }
331
332  public void booleanArity0() {
333    argsBoolean0(new String[] {}, Boolean.FALSE);
334    argsBoolean0(new String[] { "-debug"}, Boolean.TRUE);
335  }
336
337  @Test(expectedExceptions = ParameterException.class)
338  public void badParameterShouldThrowParameter1Exception() {
339    Args1 args = new Args1();
340    String[] argv = { "-log", "foo" };
341    new JCommander(args, argv);
342  }
343
344  @Test(expectedExceptions = ParameterException.class)
345  public void badParameterShouldThrowParameter2Exception() {
346    Args1 args = new Args1();
347    String[] argv = { "-long", "foo" };
348    new JCommander(args, argv);
349  }
350
351  public void listParameters() {
352    Args2 a = new Args2();
353    String[] argv = {"-log", "2", "-groups", "unit", "a", "b", "c", "-host", "host2"};
354    new JCommander(a, argv);
355    Assert.assertEquals(a.verbose.intValue(), 2);
356    Assert.assertEquals(a.groups, "unit");
357    Assert.assertEquals(a.hosts, Arrays.asList("host2"));
358    Assert.assertEquals(a.parameters, Arrays.asList("a", "b", "c"));
359  }
360
361  public void separatorEqual() {
362    SeparatorEqual s = new SeparatorEqual();
363    String[] argv = { "-log=3", "--longoption=10" };
364    new JCommander(s, argv);
365    Assert.assertEquals(s.log.intValue(), 3);
366    Assert.assertEquals(s.longOption.intValue(), 10);
367  }
368
369  public void separatorColon() {
370    SeparatorColon s = new SeparatorColon();
371    String[] argv = { "-verbose:true" };
372    new JCommander(s, argv);
373    Assert.assertTrue(s.verbose);
374  }
375
376  public void separatorBoth() {
377    SeparatorColon s = new SeparatorColon();
378    SeparatorEqual s2 = new SeparatorEqual();
379    String[] argv = { "-verbose:true", "-log=3" };
380    new JCommander(new Object[] { s, s2 }, argv);
381    Assert.assertTrue(s.verbose);
382    Assert.assertEquals(s2.log.intValue(), 3);
383  }
384
385  public void separatorMixed1() {
386    SeparatorMixed s = new SeparatorMixed();
387    String[] argv = { "-long:1", "-level=42" };
388    new JCommander(s, argv);
389    Assert.assertEquals(s.l.longValue(), 1l);
390    Assert.assertEquals(s.level.intValue(), 42);
391  }
392
393  public void slashParameters() {
394    SlashSeparator a = new SlashSeparator();
395    String[] argv = { "/verbose", "/file", "/tmp/a" };
396    new JCommander(a, argv);
397    Assert.assertTrue(a.verbose);
398    Assert.assertEquals(a.file, "/tmp/a");
399  }
400
401  public void inheritance() {
402    ArgsInherited args = new ArgsInherited();
403    String[] argv = { "-log", "3", "-child", "2" };
404    new JCommander(args, argv);
405    Assert.assertEquals(args.child.intValue(), 2);
406    Assert.assertEquals(args.log.intValue(), 3);
407  }
408
409  public void negativeNumber() {
410    Args1 a = new Args1();
411    String[] argv = { "-verbose", "-3" };
412    new JCommander(a, argv);
413    Assert.assertEquals(a.verbose.intValue(), -3);
414  }
415
416  @Test(expectedExceptions = ParameterException.class)
417  public void requiredMainParameters() {
418    ArgsRequired a = new ArgsRequired();
419    String[] argv = {};
420    new JCommander(a, argv);
421  }
422
423  public void usageShouldNotChange() {
424    JCommander jc = new JCommander(new Args1(), new String[]{"-log", "1"});
425    StringBuilder sb = new StringBuilder();
426    jc.usage(sb);
427    String expected = sb.toString();
428    jc = new JCommander(new Args1(), new String[]{"-debug", "-log", "2", "-long", "5"});
429    sb = new StringBuilder();
430    jc.usage(sb);
431    String actual = sb.toString();
432    Assert.assertEquals(actual, expected);
433  }
434
435  private void verifyCommandOrdering(String[] commandNames, Object[] commands) {
436    CommandMain cm = new CommandMain();
437    JCommander jc = new JCommander(cm);
438
439    for (int i = 0; i < commands.length; i++) {
440      jc.addCommand(commandNames[i], commands[i]);
441    }
442
443    Map<String, JCommander> c = jc.getCommands();
444    Assert.assertEquals(c.size(), commands.length);
445
446    Iterator<String> it = c.keySet().iterator();
447    for (int i = 0; i < commands.length; i++) {
448      Assert.assertEquals(it.next(), commandNames[i]);
449    }
450  }
451
452  public void commandsShouldBeShownInOrderOfInsertion() {
453    verifyCommandOrdering(new String[] { "add", "commit" },
454        new Object[] { new CommandAdd(), new CommandCommit() });
455    verifyCommandOrdering(new String[] { "commit", "add" },
456        new Object[] { new CommandCommit(), new CommandAdd() });
457  }
458
459  @DataProvider
460  public static Object[][] f() {
461    return new Integer[][] {
462      new Integer[] { 3, 5, 1 },
463      new Integer[] { 3, 8, 1 },
464      new Integer[] { 3, 12, 2 },
465      new Integer[] { 8, 12, 2 },
466      new Integer[] { 9, 10, 1 },
467    };
468  }
469
470  @Test(expectedExceptions = ParameterException.class)
471  public void arity1Fail() {
472    final Arity1 arguments = new Arity1();
473    final JCommander jCommander = new JCommander(arguments);
474    final String[] commands = {
475        "-inspect"
476    };
477    jCommander.parse(commands);
478  }
479
480  public void arity1Success1() {
481    final Arity1 arguments = new Arity1();
482    final JCommander jCommander = new JCommander(arguments);
483    final String[] commands = {
484        "-inspect", "true"
485    };
486    jCommander.parse(commands);
487    Assert.assertTrue(arguments.inspect);
488  }
489
490  public void arity1Success2() {
491    final Arity1 arguments = new Arity1();
492    final JCommander jCommander = new JCommander(arguments);
493    final String[] commands = {
494        "-inspect", "false"
495    };
496    jCommander.parse(commands);
497    Assert.assertFalse(arguments.inspect);
498  }
499
500  @Parameters(commandDescription = "Help for the given commands.")
501  public static class Help {
502      public static final String NAME = "help";
503
504      @Parameter(description = "List of commands.")
505      public List<String> commands=new ArrayList<String>();
506  }
507
508  @Test(expectedExceptions = ParameterException.class,
509      description = "Verify that the main parameter's type is checked to be a List")
510  public void wrongMainTypeShouldThrow() {
511    JCommander jc = new JCommander(new ArgsRequiredWrongMain());
512    jc.parse(new String[] { "f1", "f2" });
513  }
514
515  @Test(description = "This used to run out of memory")
516  public void oom() {
517    JCommander jc = new JCommander(new ArgsOutOfMemory());
518    jc.usage(new StringBuilder());
519  }
520
521  @Test
522  public void getParametersShouldNotNpe() {
523    JCommander jc = new JCommander(new Args1());
524    List<ParameterDescription> parameters = jc.getParameters();
525  }
526
527  public void validationShouldWork1() {
528    ArgsValidate1 a = new ArgsValidate1();
529    JCommander jc = new JCommander(a);
530    jc.parse(new String[] { "-age", "2 "});
531    Assert.assertEquals(a.age, new Integer(2));
532  }
533
534  @Test(expectedExceptions = ParameterException.class)
535  public void validationShouldWorkWithDefaultValues() {
536    ArgsValidate2 a = new ArgsValidate2();
537    new JCommander(a);
538  }
539
540  @Test(expectedExceptions = ParameterException.class)
541  public void validationShouldWork2() {
542    ArgsValidate1 a = new ArgsValidate1();
543    JCommander jc = new JCommander(a);
544    jc.parse(new String[] { "-age", "-2 "});
545  }
546
547  public void atFileCanContainEmptyLines() throws IOException {
548    File f = File.createTempFile("JCommander", null);
549    f.deleteOnExit();
550    FileWriter fw = new FileWriter(f);
551    fw.write("-log\n");
552    fw.write("\n");
553    fw.write("2\n");
554    fw.close();
555    new JCommander(new Args1(), "@" + f.getAbsolutePath());
556  }
557
558  public void handleEqualSigns() {
559    ArgsEquals a = new ArgsEquals();
560    JCommander jc = new JCommander(a);
561    jc.parse(new String[] { "-args=a=b,b=c" });
562    Assert.assertEquals(a.args, "a=b,b=c");
563  }
564
565  @SuppressWarnings("serial")
566  public void handleSets() {
567    ArgsWithSet a = new ArgsWithSet();
568    new JCommander(a, new String[] { "-s", "3,1,2" });
569    Assert.assertEquals(a.set, new TreeSet<Integer>() {{ add(1); add(2); add(3); }});
570  }
571
572  private static final List<String> V = Arrays.asList("a", "b", "c", "d");
573
574  @DataProvider
575  public Object[][] variable() {
576    return new Object[][] {
577        new Object[] { 0, V.subList(0, 0), V },
578        new Object[] { 1, V.subList(0, 1), V.subList(1, 4) },
579        new Object[] { 2, V.subList(0, 2), V.subList(2, 4) },
580        new Object[] { 3, V.subList(0, 3), V.subList(3, 4) },
581        new Object[] { 4, V.subList(0, 4), V.subList(4, 4) },
582    };
583  }
584
585  @Test(dataProvider = "variable")
586  public void variableArity(int count, List<String> var, List<String> main) {
587    VariableArity va = new VariableArity(count);
588    new JCommander(va).parse("-variable", "a", "b", "c", "d");
589    Assert.assertEquals(var, va.var);
590    Assert.assertEquals(main, va.main);
591  }
592
593  public void enumArgs() {
594    ArgsEnum args = new ArgsEnum();
595    String[] argv = { "-choice", "ONE", "-choices", "ONE", "Two" };
596    JCommander jc = new JCommander(args, argv);
597
598    Assert.assertEquals(args.choice, ArgsEnum.ChoiceType.ONE);
599
600    List<ChoiceType> expected = Arrays.asList(ChoiceType.ONE, ChoiceType.Two);
601    Assert.assertEquals(expected, args.choices);
602    Assert.assertEquals(jc.getParameters().get(0).getDescription(),
603        "Options: " + EnumSet.allOf((Class<? extends Enum>) ArgsEnum.ChoiceType.class));
604
605  }
606
607  public void enumArgsCaseInsensitive() {
608      ArgsEnum args = new ArgsEnum();
609      String[] argv = { "-choice", "one"};
610      JCommander jc = new JCommander(args, argv);
611
612      Assert.assertEquals(args.choice, ArgsEnum.ChoiceType.ONE);
613  }
614
615  @Test(expectedExceptions = ParameterException.class)
616  public void enumArgsFail() {
617    ArgsEnum args = new ArgsEnum();
618    String[] argv = { "-choice", "A" };
619    new JCommander(args, argv);
620  }
621
622  public void testListAndSplitters() {
623    ArgsList al = new ArgsList();
624    JCommander j = new JCommander(al);
625    j.parse("-groups", "a,b", "-ints", "41,42", "-hp", "localhost:1000;example.com:1001",
626        "-hp2", "localhost:1000,example.com:1001", "-uppercase", "ab,cd");
627    Assert.assertEquals(al.groups.get(0), "a");
628    Assert.assertEquals(al.groups.get(1), "b");
629    Assert.assertEquals(al.ints.get(0).intValue(), 41);
630    Assert.assertEquals(al.ints.get(1).intValue(), 42);
631    Assert.assertEquals(al.hostPorts.get(0).host, "localhost");
632    Assert.assertEquals(al.hostPorts.get(0).port.intValue(), 1000);
633    Assert.assertEquals(al.hostPorts.get(1).host, "example.com");
634    Assert.assertEquals(al.hostPorts.get(1).port.intValue(), 1001);
635    Assert.assertEquals(al.hp2.get(1).host, "example.com");
636    Assert.assertEquals(al.hp2.get(1).port.intValue(), 1001);
637    Assert.assertEquals(al.uppercase.get(0), "AB");
638    Assert.assertEquals(al.uppercase.get(1), "CD");
639  }
640
641  @Test(expectedExceptions = ParameterException.class)
642  public void shouldThrowIfUnknownOption() {
643    class A {
644      @Parameter(names = "-long")
645      public long l;
646    }
647    A a = new A();
648    new JCommander(a).parse("-lon", "32");
649  }
650
651  @Test(expectedExceptions = ParameterException.class)
652  public void mainParameterShouldBeValidate() {
653    class V implements IParameterValidator {
654
655      @Override
656      public void validate(String name, String value) throws ParameterException {
657        Assert.assertEquals("a", value);
658      }
659    }
660
661    class A {
662      @Parameter(validateWith = V.class)
663      public List<String> m;
664    }
665
666    A a = new A();
667    new JCommander(a).parse("b");
668  }
669
670  @Parameters(commandNames = { "--configure" })
671  public static class ConfigureArgs {
672  }
673
674  public static class BaseArgs {
675    @Parameter(names = { "-h", "--help" }, description = "Show this help screen")
676    private boolean help = false;
677
678    @Parameter(names = { "--version", "-version" }, description = "Show the program version")
679    private boolean version;
680  }
681
682  public void commandsWithSamePrefixAsOptionsShouldWork() {
683    BaseArgs a = new BaseArgs();
684    ConfigureArgs conf = new ConfigureArgs();
685    JCommander jc = new JCommander(a);
686    jc.addCommand(conf);
687    jc.parse("--configure");
688  }
689
690  // Tests:
691  // required unparsed parameter
692  @Test(enabled = false,
693      description = "For some reason, this test still asks the password on stdin")
694  public void askedRequiredPassword() {
695    class A {
696        @Parameter(names = { "--password", "-p" }, description = "Private key password",
697            password = true, required = true)
698        public String password;
699
700        @Parameter(names = { "--port", "-o" }, description = "Port to bind server to",
701            required = true)
702        public int port;
703    }
704    A a = new A();
705    InputStream stdin = System.in;
706    try {
707      System.setIn(new ByteArrayInputStream("password".getBytes()));
708      new JCommander(a,new String[]{"--port", "7","--password"});
709      Assert.assertEquals(a.port, 7);
710      Assert.assertEquals(a.password, "password");
711    } finally {
712      System.setIn(stdin);
713    }
714  }
715
716  public void dynamicParameters() {
717    class Command {
718      @DynamicParameter(names = {"-P"}, description = "Additional command parameters")
719      private Map<String, String> params = Maps.newHashMap();
720    }
721    JCommander commander = new JCommander();
722    Command c = new Command();
723    commander.addCommand("command", c);
724    commander.parse(new String[] { "command", "-Pparam='name=value'" });
725    Assert.assertEquals(c.params.get("param"), "'name=value'");
726  }
727
728  public void exeParser() {
729      class Params {
730        @Parameter( names= "-i")
731        private String inputFile;
732      }
733
734      String args[] = { "-i", "" };
735      Params p = new Params();
736      new JCommander(p, args);
737  }
738
739  public void multiVariableArityList() {
740    class Params {
741      @Parameter(names = "-paramA", description = "ParamA", variableArity = true)
742      private List<String> paramA = Lists.newArrayList();
743
744      @Parameter(names = "-paramB", description = "ParamB", variableArity = true)
745      private List<String> paramB = Lists.newArrayList();
746    }
747
748    {
749      String args[] = { "-paramA", "a1", "a2", "-paramB", "b1", "b2", "b3" };
750      Params p = new Params();
751      new JCommander(p, args).parse();
752      Assert.assertEquals(p.paramA, Arrays.asList(new String[] { "a1", "a2" }));
753      Assert.assertEquals(p.paramB, Arrays.asList(new String[] { "b1", "b2", "b3" }));
754    }
755
756    {
757      String args[] = { "-paramA", "a1", "a2", "-paramB", "b1", "-paramA", "a3" };
758      Params p = new Params();
759      new JCommander(p, args).parse();
760      Assert.assertEquals(p.paramA, Arrays.asList(new String[] { "a1", "a2", "a3" }));
761      Assert.assertEquals(p.paramB, Arrays.asList(new String[] { "b1" }));
762    }
763  }
764
765  @Test(enabled = false,
766      description = "Need to double check that the command description is i18n'ed in the usage")
767  public void commandKey() {
768    @Parameters(resourceBundle = "MessageBundle", commandDescriptionKey = "command")
769    class Args {
770      @Parameter(names="-myoption", descriptionKey="myoption")
771      private boolean option;
772    }
773    JCommander j = new JCommander();
774    Args a = new Args();
775    j.addCommand("comm", a);
776    j.usage();
777  }
778
779  public void tmp() {
780    class A {
781      @Parameter(names = "-b")
782      public String b;
783    }
784    new JCommander(new A()).parse("");
785  }
786
787  public void unknownOptionWithDifferentPrefix() {
788    @Parameters(optionPrefixes = "/")
789    class SlashSeparator {
790
791     @Parameter(names = "/verbose")
792     public boolean verbose = false;
793
794     @Parameter(names = "/file")
795     public String file;
796    }
797    SlashSeparator ss = new SlashSeparator();
798    try {
799      new JCommander(ss).parse("/notAParam");
800    } catch (ParameterException ex) {
801      boolean result = ex.getMessage().contains("Unknown option");
802      Assert.assertTrue(result);
803    }
804  }
805
806  public void equalSeparator() {
807    @Parameters(separators = "=", commandDescription = "My command")
808    class MyClass {
809
810       @Parameter(names = { "-p", "--param" }, required = true, description = "param desc...")
811       private String param;
812    }
813    MyClass c = new MyClass();
814    String expected = "\"hello\"world";
815    new JCommander(c).parse("--param=" + expected);
816    Assert.assertEquals(expected, c.param);
817  }
818
819  public void simpleArgsSetter() throws ParseException {
820    Args1Setter args = new Args1Setter();
821    String[] argv = { "-debug", "-log", "2", "-float", "1.2", "-double", "1.3", "-bigdecimal", "1.4",
822            "-date", "2011-10-26", "-groups", "unit", "a", "b", "c" };
823    new JCommander(args, argv);
824
825    Assert.assertTrue(args.debug);
826    Assert.assertEquals(args.verbose.intValue(), 2);
827    Assert.assertEquals(args.groups, "unit");
828    Assert.assertEquals(args.parameters, Arrays.asList("a", "b", "c"));
829    Assert.assertEquals(args.floa, 1.2f, 0.1f);
830    Assert.assertEquals(args.doub, 1.3f, 0.1f);
831    Assert.assertEquals(args.bigd, new BigDecimal("1.4"));
832    Assert.assertEquals(args.date, new SimpleDateFormat("yyyy-MM-dd").parse("2011-10-26"));
833  }
834
835  public void verifyHelp() {
836    class Arg {
837      @Parameter(names = "--help", help = true)
838      public boolean help = false;
839
840      @Parameter(names = "file", required = true)
841      public String file;
842    }
843    Arg arg = new Arg();
844    String[] argv = { "--help" };
845    new JCommander(arg, argv);
846
847    Assert.assertTrue(arg.help);
848  }
849
850  public void helpTest() {
851    class Arg {
852      @Parameter(names = { "?", "-help", "--help" }, description = "Shows help", help = true)
853      private boolean help = false;
854    }
855    Arg arg = new Arg();
856    JCommander jc = new JCommander(arg);
857    jc.parse(new String[] { "-help" });
858//    System.out.println("helpTest:" + arg.help);
859  }
860
861  @Test(enabled = false, description = "Should only be enable once multiple parameters are allowed")
862  public void duplicateParameterNames() {
863    class ArgBase {
864      @Parameter(names = { "-host" })
865      protected String host;
866    }
867
868    class Arg1 extends ArgBase {}
869    Arg1 arg1 = new Arg1();
870
871    class Arg2 extends ArgBase {}
872    Arg2 arg2 = new Arg2();
873
874    JCommander jc = new JCommander(new Object[] { arg1, arg2});
875    jc.parse(new String[] { "-host", "foo" });
876    Assert.assertEquals(arg1.host, "foo");
877    Assert.assertEquals(arg2.host, "foo");
878  }
879
880  public void parameterWithOneDoubleQuote() {
881    @Parameters(separators = "=")
882    class Arg {
883      @Parameter(names = { "-p", "--param" })
884      private String param;
885    }
886    JCommander jc = new JCommander(new MyClass());
887    jc.parse("-p=\"");
888  }
889
890  public void emptyStringAsDefault() {
891    class Arg {
892      @Parameter(names = "-x")
893      String s = "";
894    }
895    Arg a = new Arg();
896    StringBuilder sb = new StringBuilder();
897    new JCommander(a).usage(sb);
898    Assert.assertTrue(sb.toString().contains("Default: <empty string>"));
899  }
900
901  public void spaces() {
902    class Arg {
903      @Parameter(names = "-rule", description = "rule")
904      private List<String> rules = new ArrayList<String>();
905    }
906    Arg a = new Arg();
907    new JCommander(a, "-rule", "some test");
908    Assert.assertEquals(a.rules, Arrays.asList("some test"));
909  }
910
911  static class V2 implements IParameterValidator2 {
912    final static List<String> names =  Lists.newArrayList();
913    static boolean validateCalled = false;
914
915    @Override
916    public void validate(String name, String value) throws ParameterException {
917      validateCalled = true;
918    }
919
920    @Override
921    public void validate(String name, String value, ParameterDescription pd)
922        throws ParameterException {
923      names.addAll(Arrays.asList(pd.getParameter().names()));
924    }
925  }
926
927  public void validator2() {
928    class Arg {
929      @Parameter(names = { "-h", "--host" }, validateWith = V2.class)
930      String host;
931    }
932    Arg a = new Arg();
933    V2.names.clear();
934    V2.validateCalled = false;
935    JCommander jc = new JCommander(a, "--host", "h");
936    jc.setAcceptUnknownOptions(true);
937    Assert.assertEquals(V2.names, Arrays.asList(new String[] { "-h", "--host" }));
938    Assert.assertTrue(V2.validateCalled);
939  }
940
941  public void usageCommandsUnderUsage() {
942    class Arg {
943    }
944    @Parameters(commandDescription = "command a")
945    class ArgCommandA {
946      @Parameter(description = "command a parameters")
947      List<String> parameters;
948    }
949    @Parameters(commandDescription = "command b")
950    class ArgCommandB {
951      @Parameter(description = "command b parameters")
952      List<String> parameters;
953    }
954
955    Arg a = new Arg();
956
957    JCommander c = new JCommander(a);
958    c.addCommand("a", new ArgCommandA());
959    c.addCommand("b", new ArgCommandB());
960
961    StringBuilder sb = new StringBuilder();
962    c.usage(sb);
963    Assert.assertTrue(sb.toString().contains("[command options]\n  Commands:"));
964  }
965
966  public void usageWithEmpytLine() {
967    class Arg {
968    }
969    @Parameters(commandDescription = "command a")
970    class ArgCommandA {
971      @Parameter(description = "command a parameters")
972      List<String> parameters;
973    }
974    @Parameters(commandDescription = "command b")
975    class ArgCommandB {
976      @Parameter(description = "command b parameters")
977      List<String> parameters;
978    }
979
980    Arg a = new Arg();
981
982    JCommander c = new JCommander(a);
983    c.addCommand("a", new ArgCommandA());
984    c.addCommand("b", new ArgCommandB());
985
986    StringBuilder sb = new StringBuilder();
987    c.usage(sb);
988    Assert.assertTrue(sb.toString().contains("command a parameters\n\n    b"));
989  }
990
991  public void partialValidation() {
992    class Arg {
993      @Parameter(names = { "-h", "--host" })
994      String host;
995    }
996    Arg a = new Arg();
997    JCommander jc = new JCommander();
998    jc.setAcceptUnknownOptions(true);
999    jc.addObject(a);
1000    jc.parse("-a", "foo", "-h", "host");
1001    Assert.assertEquals(a.host, "host");
1002    Assert.assertEquals(jc.getUnknownOptions(), Lists.newArrayList("-a", "foo"));
1003  }
1004
1005  /**
1006   * GITHUB-137.
1007   */
1008  public void listArgShouldBeCleared() {
1009    class Args {
1010      @Parameter(description = "[endpoint]")
1011      public List<String> endpoint = Lists.newArrayList("prod");
1012    }
1013    Args a = new Args();
1014    new JCommander(a, new String[] { "dev" });
1015    Assert.assertEquals(a.endpoint, Lists.newArrayList("dev"));
1016  }
1017
1018  public void dashDashParameter() {
1019    class Arguments {
1020        @Parameter(names = { "-name" })
1021        public String name;
1022        @Parameter
1023        public List<String> mainParameters;
1024    }
1025
1026    Arguments a = new Arguments();
1027    new JCommander(a, new String[] {
1028        "-name", "theName", "--", "param1", "param2"}
1029    );
1030    Assert.assertEquals(a.name, "theName");
1031    Assert.assertEquals(a.mainParameters.size(), 2);
1032    Assert.assertEquals(a.mainParameters.get(0), "param1");
1033    Assert.assertEquals(a.mainParameters.get(1), "param2");
1034  }
1035
1036  public void dashDashParameter2() {
1037    class Arguments {
1038        @Parameter(names = { "-name" })
1039        public String name;
1040        @Parameter
1041        public List<String> mainParameters;
1042    }
1043
1044    Arguments a = new Arguments();
1045    new JCommander(a, new String[] {
1046        "param1", "param2", "--", "-name", "theName"}
1047    );
1048    Assert.assertNull(a.name);
1049    Assert.assertEquals(a.mainParameters.size(), 4);
1050    Assert.assertEquals(a.mainParameters.get(0), "param1");
1051    Assert.assertEquals(a.mainParameters.get(1), "param2");
1052    Assert.assertEquals(a.mainParameters.get(2), "-name");
1053    Assert.assertEquals(a.mainParameters.get(3), "theName");
1054  }
1055
1056  @Test(enabled = false)
1057  public static void main(String[] args) throws Exception {
1058//    new JCommanderTest().a();
1059//    class A {
1060//      @Parameter(names = "-short", required = true)
1061//      List<String> parameters;
1062//
1063//      @Parameter(names = "-long", required = true)
1064//      public long l;
1065//    }
1066//    A a = new A();
1067//    new JCommander(a).parse();
1068//    System.out.println(a.l);
1069//    System.out.println(a.parameters);
1070//    ArgsList al = new ArgsList();
1071//    JCommander j = new JCommander(al);
1072//    j.setColumnSize(40);
1073//    j.usage();
1074//    new JCommanderTest().testListAndSplitters();
1075//    new JCommanderTest().converterArgs();
1076  }
1077
1078  // Tests:
1079  // required unparsed parameter
1080}
1081