summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorIgor Murashkin <iam@google.com>2016-03-24 14:21:34 -0700
committerIgor Murashkin <iam@google.com>2016-03-24 14:21:57 -0700
commit7f95581d269e0815eab16115f0e36c0ee325dc88 (patch)
treef1aa3cbaef213c6d2693df6d0ae4d449cc3e6815 /src
parentb3994367e22d0ce3670ff9fb693a4f2939ef5d58 (diff)
parent5321f6ff3251784760f79982b1a720e3607c5003 (diff)
downloadplatform_external_jcommander-7f95581d269e0815eab16115f0e36c0ee325dc88.tar.gz
platform_external_jcommander-7f95581d269e0815eab16115f0e36c0ee325dc88.tar.bz2
platform_external_jcommander-7f95581d269e0815eab16115f0e36c0ee325dc88.zip
Merge remote-tracking branch 'goog/master' into nyc-dev
Bug: 27552463 Change-Id: Icaacbb9acf1454b39974d319d30023aea6fea5f6
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/beust/jcommander/DynamicParameter.java50
-rw-r--r--src/main/java/com/beust/jcommander/FuzzyMap.java61
-rw-r--r--src/main/java/com/beust/jcommander/IDefaultProvider.java35
-rw-r--r--src/main/java/com/beust/jcommander/IParameterValidator.java38
-rw-r--r--src/main/java/com/beust/jcommander/IParameterValidator2.java34
-rw-r--r--src/main/java/com/beust/jcommander/IStringConverter.java39
-rw-r--r--src/main/java/com/beust/jcommander/IStringConverterFactory.java30
-rw-r--r--src/main/java/com/beust/jcommander/IValueValidator.java14
-rw-r--r--src/main/java/com/beust/jcommander/IVariableArity.java16
-rw-r--r--src/main/java/com/beust/jcommander/JCommander.java1599
-rw-r--r--src/main/java/com/beust/jcommander/MissingCommandException.java36
-rw-r--r--src/main/java/com/beust/jcommander/Parameter.java130
-rw-r--r--src/main/java/com/beust/jcommander/ParameterDescription.java364
-rw-r--r--src/main/java/com/beust/jcommander/ParameterException.java42
-rw-r--r--src/main/java/com/beust/jcommander/Parameterized.java244
-rw-r--r--src/main/java/com/beust/jcommander/Parameters.java75
-rw-r--r--src/main/java/com/beust/jcommander/ParametersDelegate.java44
-rw-r--r--src/main/java/com/beust/jcommander/ResourceBundle.java38
-rw-r--r--src/main/java/com/beust/jcommander/StringKey.java48
-rw-r--r--src/main/java/com/beust/jcommander/Strings.java7
-rw-r--r--src/main/java/com/beust/jcommander/WrappedParameter.java115
-rw-r--r--src/main/java/com/beust/jcommander/converters/BaseConverter.java44
-rw-r--r--src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java43
-rw-r--r--src/main/java/com/beust/jcommander/converters/BooleanConverter.java42
-rw-r--r--src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java12
-rw-r--r--src/main/java/com/beust/jcommander/converters/DoubleConverter.java42
-rw-r--r--src/main/java/com/beust/jcommander/converters/FileConverter.java36
-rw-r--r--src/main/java/com/beust/jcommander/converters/FloatConverter.java42
-rw-r--r--src/main/java/com/beust/jcommander/converters/IParameterSplitter.java11
-rw-r--r--src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java48
-rw-r--r--src/main/java/com/beust/jcommander/converters/IntegerConverter.java42
-rw-r--r--src/main/java/com/beust/jcommander/converters/LongConverter.java42
-rw-r--r--src/main/java/com/beust/jcommander/converters/NoConverter.java34
-rw-r--r--src/main/java/com/beust/jcommander/converters/PathConverter.java37
-rw-r--r--src/main/java/com/beust/jcommander/converters/StringConverter.java34
-rw-r--r--src/main/java/com/beust/jcommander/converters/URIConverter.java45
-rw-r--r--src/main/java/com/beust/jcommander/converters/URLConverter.java46
-rw-r--r--src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java70
-rw-r--r--src/main/java/com/beust/jcommander/internal/Console.java10
-rw-r--r--src/main/java/com/beust/jcommander/internal/DefaultConsole.java32
-rw-r--r--src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java79
-rw-r--r--src/main/java/com/beust/jcommander/internal/JDK6Console.java45
-rw-r--r--src/main/java/com/beust/jcommander/internal/Lists.java54
-rw-r--r--src/main/java/com/beust/jcommander/internal/Maps.java43
-rw-r--r--src/main/java/com/beust/jcommander/internal/Nullable.java12
-rw-r--r--src/main/java/com/beust/jcommander/internal/Sets.java35
-rw-r--r--src/main/java/com/beust/jcommander/validators/NoValidator.java35
-rw-r--r--src/main/java/com/beust/jcommander/validators/NoValueValidator.java35
-rw-r--r--src/main/java/com/beust/jcommander/validators/PositiveInteger.java40
-rw-r--r--src/main/license/license-header.txt15
-rw-r--r--src/test/java/com/beust/jcommander/ArgsRequiredWrongMain.java6
-rw-r--r--src/test/java/com/beust/jcommander/ArgsValidate2.java24
-rw-r--r--src/test/java/com/beust/jcommander/CmdTest.java86
-rw-r--r--src/test/java/com/beust/jcommander/ConverterFactoryTest.java86
-rw-r--r--src/test/java/com/beust/jcommander/DefaultProviderTest.java120
-rw-r--r--src/test/java/com/beust/jcommander/DefaultValueTest.java113
-rw-r--r--src/test/java/com/beust/jcommander/FinderTest.java97
-rw-r--r--src/test/java/com/beust/jcommander/HostPort.java29
-rw-r--r--src/test/java/com/beust/jcommander/HostPortConverter.java32
-rw-r--r--src/test/java/com/beust/jcommander/JCommanderTest.java1081
-rw-r--r--src/test/java/com/beust/jcommander/MethodSetterTest.java100
-rw-r--r--src/test/java/com/beust/jcommander/MyClass.java24
-rw-r--r--src/test/java/com/beust/jcommander/ParametersDelegateTest.java227
-rw-r--r--src/test/java/com/beust/jcommander/PositiveIntegerTest.java65
-rw-r--r--src/test/java/com/beust/jcommander/SetConverter.java16
-rw-r--r--src/test/java/com/beust/jcommander/ValidatePropertiesWhenParsingTest.java42
-rw-r--r--src/test/java/com/beust/jcommander/VariableArityTest.java66
-rw-r--r--src/test/java/com/beust/jcommander/args/AlternateNamesForListArgs.java32
-rw-r--r--src/test/java/com/beust/jcommander/args/Args1.java56
-rw-r--r--src/test/java/com/beust/jcommander/args/Args1Setter.java93
-rw-r--r--src/test/java/com/beust/jcommander/args/Args2.java42
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsArityInteger.java37
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsArityString.java37
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsBooleanArity.java26
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsBooleanArity0.java26
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsConverter.java57
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsConverterFactory.java28
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsDefault.java43
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsEnum.java55
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsEquals.java11
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsHelp.java30
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsI18N1.java27
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsI18N2.java30
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsI18N2New.java34
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsInherited.java28
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsList.java49
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsLongDescription.java25
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsMainParameter1.java40
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsMainParameter2.java41
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsMaster.java31
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsMultipleUnparsed.java35
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsOutOfMemory.java13
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsPassword.java26
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsPrivate.java30
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsRequired.java31
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsSlave.java31
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsSlaveBogus.java31
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsValidate1.java10
-rw-r--r--src/test/java/com/beust/jcommander/args/ArgsWithSet.java11
-rw-r--r--src/test/java/com/beust/jcommander/args/Arity1.java9
-rw-r--r--src/test/java/com/beust/jcommander/args/CommandLineArgs.java120
-rw-r--r--src/test/java/com/beust/jcommander/args/CommandLineArgs2.java72
-rw-r--r--src/test/java/com/beust/jcommander/args/IHostPorts.java27
-rw-r--r--src/test/java/com/beust/jcommander/args/SeparatorColon.java29
-rw-r--r--src/test/java/com/beust/jcommander/args/SeparatorEqual.java32
-rw-r--r--src/test/java/com/beust/jcommander/args/SeparatorMixed.java32
-rw-r--r--src/test/java/com/beust/jcommander/args/SlashSeparator.java32
-rw-r--r--src/test/java/com/beust/jcommander/args/VariableArity.java26
-rw-r--r--src/test/java/com/beust/jcommander/command/CommandAdd.java35
-rw-r--r--src/test/java/com/beust/jcommander/command/CommandAliasTest.java175
-rw-r--r--src/test/java/com/beust/jcommander/command/CommandCommit.java37
-rw-r--r--src/test/java/com/beust/jcommander/command/CommandHidden.java17
-rw-r--r--src/test/java/com/beust/jcommander/command/CommandMain.java27
-rw-r--r--src/test/java/com/beust/jcommander/command/CommandTest.java115
-rw-r--r--src/test/java/com/beust/jcommander/command/NamedCommandAdd.java17
-rw-r--r--src/test/java/com/beust/jcommander/dynamic/DSimple.java16
-rw-r--r--src/test/java/com/beust/jcommander/dynamic/DSimpleBad.java11
-rw-r--r--src/test/java/com/beust/jcommander/dynamic/DynamicParameterTest.java60
-rw-r--r--src/test/java/com/beust/jcommander/internal/DefaultConsoleTest.java64
-rw-r--r--src/test/java/test/QuotedMainTest.java29
-rw-r--r--src/test/resources/MessageBundle_en_US.properties21
-rw-r--r--src/test/resources/MessageBundle_fr_FR.properties20
-rw-r--r--src/test/resources/jcommander.properties21
-rw-r--r--src/test/resources/testng-single.xml19
-rw-r--r--src/test/resources/testng.xml24
125 files changed, 8561 insertions, 0 deletions
diff --git a/src/main/java/com/beust/jcommander/DynamicParameter.java b/src/main/java/com/beust/jcommander/DynamicParameter.java
new file mode 100644
index 0000000..2159c1f
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/DynamicParameter.java
@@ -0,0 +1,50 @@
+package com.beust.jcommander;
+
+import static java.lang.annotation.ElementType.FIELD;
+
+import com.beust.jcommander.validators.NoValidator;
+import com.beust.jcommander.validators.NoValueValidator;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({ FIELD })
+public @interface DynamicParameter {
+ /**
+ * An array of allowed command line parameters (e.g. "-D", "--define", etc...).
+ */
+ String[] names() default {};
+
+ /**
+ * Whether this option is required.
+ */
+ boolean required() default false;
+
+ /**
+ * A description of this option.
+ */
+ String description() default "";
+
+ /**
+ * The key used to find the string in the message bundle.
+ */
+ String descriptionKey() default "";
+
+ /**
+ * If true, this parameter won't appear in the usage().
+ */
+ boolean hidden() default false;
+
+ /**
+ * The validation class to use.
+ */
+ Class<? extends IParameterValidator> validateWith() default NoValidator.class;
+
+ /**
+ * The character(s) used to assign the values.
+ */
+ String assignment() default "=";
+
+ Class<? extends IValueValidator> validateValueWith() default NoValueValidator.class;
+}
diff --git a/src/main/java/com/beust/jcommander/FuzzyMap.java b/src/main/java/com/beust/jcommander/FuzzyMap.java
new file mode 100644
index 0000000..5f3939b
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/FuzzyMap.java
@@ -0,0 +1,61 @@
+package com.beust.jcommander;
+
+import com.beust.jcommander.internal.Maps;
+
+import java.util.Map;
+
+/**
+ * Helper class to perform fuzzy key look ups: looking up case insensitive or
+ * abbreviated keys.
+ */
+public class FuzzyMap {
+ interface IKey {
+ String getName();
+ }
+
+ public static <V> V findInMap(Map<? extends IKey, V> map, IKey name,
+ boolean caseSensitive, boolean allowAbbreviations) {
+ if (allowAbbreviations) {
+ return findAbbreviatedValue(map, name, caseSensitive);
+ } else {
+ if (caseSensitive) {
+ return map.get(name);
+ } else {
+ for (IKey c : map.keySet()) {
+ if (c.getName().equalsIgnoreCase(name.getName())) {
+ return map.get(c);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static <V> V findAbbreviatedValue(Map<? extends IKey, V> map, IKey name,
+ boolean caseSensitive) {
+ String string = name.getName();
+ Map<String, V> results = Maps.newHashMap();
+ for (IKey c : map.keySet()) {
+ String n = c.getName();
+ boolean match = (caseSensitive && n.startsWith(string))
+ || ((! caseSensitive) && n.toLowerCase().startsWith(string.toLowerCase()));
+ if (match) {
+ results.put(n, map.get(c));
+ }
+ }
+
+ V result;
+ if (results.size() > 1) {
+ throw new ParameterException("Ambiguous option: " + name
+ + " matches " + results.keySet());
+ } else if (results.size() == 1) {
+ result = results.values().iterator().next();
+ } else {
+ result = null;
+ }
+
+ return result;
+ }
+
+
+}
diff --git a/src/main/java/com/beust/jcommander/IDefaultProvider.java b/src/main/java/com/beust/jcommander/IDefaultProvider.java
new file mode 100644
index 0000000..0353928
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IDefaultProvider.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+/**
+ * Allows the specification of default values.
+ *
+ * @author cbeust
+ */
+public interface IDefaultProvider {
+
+ /**
+ * @param optionName The name of the option as specified in the names() attribute
+ * of the @Parameter option (e.g. "-file").
+ *
+ * @return the default value for this option.
+ */
+ String getDefaultValueFor(String optionName);
+}
diff --git a/src/main/java/com/beust/jcommander/IParameterValidator.java b/src/main/java/com/beust/jcommander/IParameterValidator.java
new file mode 100644
index 0000000..19fee0d
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IParameterValidator.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2011 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+/**
+ * The class used to validate parameters.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+public interface IParameterValidator {
+
+ /**
+ * Validate the parameter.
+ *
+ * @param name The name of the parameter (e.g. "-host").
+ * @param value The value of the parameter that we need to validate
+ *
+ * @throws ParameterException Thrown if the value of the parameter is invalid.
+ */
+ void validate(String name, String value) throws ParameterException;
+
+}
diff --git a/src/main/java/com/beust/jcommander/IParameterValidator2.java b/src/main/java/com/beust/jcommander/IParameterValidator2.java
new file mode 100644
index 0000000..77e7dd3
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IParameterValidator2.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2011 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+public interface IParameterValidator2 extends IParameterValidator {
+
+ /**
+ * Validate the parameter.
+ *
+ * @param name The name of the parameter (e.g. "-host").
+ * @param value The value of the parameter that we need to validate
+ * @param pd The description of this parameter
+ *
+ * @throws ParameterException Thrown if the value of the parameter is invalid.
+ */
+ void validate(String name, String value, ParameterDescription pd) throws ParameterException;
+
+}
diff --git a/src/main/java/com/beust/jcommander/IStringConverter.java b/src/main/java/com/beust/jcommander/IStringConverter.java
new file mode 100644
index 0000000..fb51a79
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IStringConverter.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+/**
+ * An interface that converts strings to any arbitrary type.
+ *
+ * If your class implements a constructor that takes a String, this
+ * constructor will be used to instantiate your converter and the
+ * parameter will receive the name of the option that's being parsed,
+ * which can be useful to issue a more useful error message if the
+ * conversion fails.
+ *
+ * You can also extend BaseConverter to make your life easier.
+ *
+ * @author cbeust
+ */
+public interface IStringConverter<T> {
+ /**
+ * @return an object of type <T> created from the parameter value.
+ */
+ T convert(String value);
+}
diff --git a/src/main/java/com/beust/jcommander/IStringConverterFactory.java b/src/main/java/com/beust/jcommander/IStringConverterFactory.java
new file mode 100644
index 0000000..0e53ca0
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IStringConverterFactory.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+/**
+ * A factory for IStringConverter. This interface lets you specify your
+ * converters in one place instead of having them repeated all over
+ * your argument classes.
+ *
+ * @author cbeust
+ */
+public interface IStringConverterFactory {
+ <T> Class<? extends IStringConverter<T>> getConverter(Class<T> forType);
+}
diff --git a/src/main/java/com/beust/jcommander/IValueValidator.java b/src/main/java/com/beust/jcommander/IValueValidator.java
new file mode 100644
index 0000000..feed25d
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IValueValidator.java
@@ -0,0 +1,14 @@
+package com.beust.jcommander;
+
+public interface IValueValidator<T> {
+ /**
+ * Validate the parameter.
+ *
+ * @param name The name of the parameter (e.g. "-host").
+ * @param value The value of the parameter that we need to validate
+ *
+ * @throws ParameterException Thrown if the value of the parameter is invalid.
+ */
+ void validate(String name, T value) throws ParameterException;
+
+}
diff --git a/src/main/java/com/beust/jcommander/IVariableArity.java b/src/main/java/com/beust/jcommander/IVariableArity.java
new file mode 100644
index 0000000..e8a40ba
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/IVariableArity.java
@@ -0,0 +1,16 @@
+package com.beust.jcommander;
+
+/**
+ * Must be implemented by argument classes that contain at least one
+ * \@Parameter with "variableArity = true".
+ */
+public interface IVariableArity {
+
+ /**
+ * @param optionName the name of the option to process.
+ * @param options the entire list of options.
+ *
+ * @return how many options were processed.
+ */
+ int processVariableArity(String optionName, String[] options);
+}
diff --git a/src/main/java/com/beust/jcommander/JCommander.java b/src/main/java/com/beust/jcommander/JCommander.java
new file mode 100644
index 0000000..2e049a1
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/JCommander.java
@@ -0,0 +1,1599 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import com.beust.jcommander.FuzzyMap.IKey;
+import com.beust.jcommander.converters.IParameterSplitter;
+import com.beust.jcommander.converters.NoConverter;
+import com.beust.jcommander.converters.StringConverter;
+import com.beust.jcommander.internal.Console;
+import com.beust.jcommander.internal.DefaultConsole;
+import com.beust.jcommander.internal.DefaultConverterFactory;
+import com.beust.jcommander.internal.JDK6Console;
+import com.beust.jcommander.internal.Lists;
+import com.beust.jcommander.internal.Maps;
+import com.beust.jcommander.internal.Nullable;
+
+/**
+ * The main class for JCommander. It's responsible for parsing the object that contains
+ * all the annotated fields, parse the command line and assign the fields with the correct
+ * values and a few other helper methods, such as usage().
+ *
+ * The object(s) you pass in the constructor are expected to have one or more
+ * \@Parameter annotations on them. You can pass either a single object, an array of objects
+ * or an instance of Iterable. In the case of an array or Iterable, JCommander will collect
+ * the \@Parameter annotations from all the objects passed in parameter.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+public class JCommander {
+ public static final String DEBUG_PROPERTY = "jcommander.debug";
+
+ /**
+ * A map to look up parameter description per option name.
+ */
+ private Map<IKey, ParameterDescription> m_descriptions;
+
+ /**
+ * The objects that contain fields annotated with @Parameter.
+ */
+ private List<Object> m_objects = Lists.newArrayList();
+
+ private boolean m_firstTimeMainParameter = true;
+
+ /**
+ * This field/method will contain whatever command line parameter is not an option.
+ * It is expected to be a List<String>.
+ */
+ private Parameterized m_mainParameter = null;
+
+ /**
+ * The object on which we found the main parameter field.
+ */
+ private Object m_mainParameterObject;
+
+ /**
+ * The annotation found on the main parameter field.
+ */
+ private Parameter m_mainParameterAnnotation;
+
+ private ParameterDescription m_mainParameterDescription;
+
+ /**
+ * A set of all the parameterizeds that are required. During the reflection phase,
+ * this field receives all the fields that are annotated with required=true
+ * and during the parsing phase, all the fields that are assigned a value
+ * are removed from it. At the end of the parsing phase, if it's not empty,
+ * then some required fields did not receive a value and an exception is
+ * thrown.
+ */
+ private Map<Parameterized, ParameterDescription> m_requiredFields = Maps.newHashMap();
+
+ /**
+ * A map of all the parameterized fields/methods.
+ */
+ private Map<Parameterized, ParameterDescription> m_fields = Maps.newHashMap();
+
+ private ResourceBundle m_bundle;
+
+ /**
+ * A default provider returns default values for the parameters.
+ */
+ private IDefaultProvider m_defaultProvider;
+
+ /**
+ * List of commands and their instance.
+ */
+ private Map<ProgramName, JCommander> m_commands = Maps.newLinkedHashMap();
+
+ /**
+ * Alias database for reverse lookup
+ */
+ private Map<IKey, ProgramName> aliasMap = Maps.newLinkedHashMap();
+
+ /**
+ * The name of the command after the parsing has run.
+ */
+ private String m_parsedCommand;
+
+ /**
+ * The name of command or alias as it was passed to the
+ * command line
+ */
+ private String m_parsedAlias;
+
+ private ProgramName m_programName;
+
+ private Comparator<? super ParameterDescription> m_parameterDescriptionComparator
+ = new Comparator<ParameterDescription>() {
+ @Override
+ public int compare(ParameterDescription p0, ParameterDescription p1) {
+ return p0.getLongestName().compareTo(p1.getLongestName());
+ }
+ };
+
+ private int m_columnSize = 79;
+
+ private boolean m_helpWasSpecified;
+
+ private List<String> m_unknownArgs = Lists.newArrayList();
+ private boolean m_acceptUnknownOptions = false;
+ private boolean m_allowParameterOverwriting = false;
+
+ private static Console m_console;
+
+ /**
+ * The factories used to look up string converters.
+ */
+ private static LinkedList<IStringConverterFactory> CONVERTER_FACTORIES = Lists.newLinkedList();
+
+ static {
+ CONVERTER_FACTORIES.addFirst(new DefaultConverterFactory());
+ };
+
+ /**
+ * Creates a new un-configured JCommander object.
+ */
+ public JCommander() {
+ }
+
+ /**
+ * @param object The arg object expected to contain {@link Parameter} annotations.
+ */
+ public JCommander(Object object) {
+ addObject(object);
+ createDescriptions();
+ }
+
+ /**
+ * @param object The arg object expected to contain {@link Parameter} annotations.
+ * @param bundle The bundle to use for the descriptions. Can be null.
+ */
+ public JCommander(Object object, @Nullable ResourceBundle bundle) {
+ addObject(object);
+ setDescriptionsBundle(bundle);
+ }
+
+ /**
+ * @param object The arg object expected to contain {@link Parameter} annotations.
+ * @param bundle The bundle to use for the descriptions. Can be null.
+ * @param args The arguments to parse (optional).
+ */
+ public JCommander(Object object, ResourceBundle bundle, String... args) {
+ addObject(object);
+ setDescriptionsBundle(bundle);
+ parse(args);
+ }
+
+ /**
+ * @param object The arg object expected to contain {@link Parameter} annotations.
+ * @param args The arguments to parse (optional).
+ */
+ public JCommander(Object object, String... args) {
+ addObject(object);
+ parse(args);
+ }
+
+ public static Console getConsole() {
+ if (m_console == null) {
+ try {
+ Method consoleMethod = System.class.getDeclaredMethod("console", new Class<?>[0]);
+ Object console = consoleMethod.invoke(null, new Object[0]);
+ m_console = new JDK6Console(console);
+ } catch (Throwable t) {
+ m_console = new DefaultConsole();
+ }
+ }
+ return m_console;
+ }
+
+ /**
+ * Adds the provided arg object to the set of objects that this commander
+ * will parse arguments into.
+ *
+ * @param object The arg object expected to contain {@link Parameter}
+ * annotations. If <code>object</code> is an array or is {@link Iterable},
+ * the child objects will be added instead.
+ */
+ // declared final since this is invoked from constructors
+ public final void addObject(Object object) {
+ if (object instanceof Iterable) {
+ // Iterable
+ for (Object o : (Iterable<?>) object) {
+ m_objects.add(o);
+ }
+ } else if (object.getClass().isArray()) {
+ // Array
+ for (Object o : (Object[]) object) {
+ m_objects.add(o);
+ }
+ } else {
+ // Single object
+ m_objects.add(object);
+ }
+ }
+
+ /**
+ * Sets the {@link ResourceBundle} to use for looking up descriptions.
+ * Set this to <code>null</code> to use description text directly.
+ */
+ // declared final since this is invoked from constructors
+ public final void setDescriptionsBundle(ResourceBundle bundle) {
+ m_bundle = bundle;
+ }
+
+ /**
+ * Parse and validate the command line parameters.
+ */
+ public void parse(String... args) {
+ parse(true /* validate */, args);
+ }
+
+ /**
+ * Parse the command line parameters without validating them.
+ */
+ public void parseWithoutValidation(String... args) {
+ parse(false /* no validation */, args);
+ }
+
+ private void parse(boolean validate, String... args) {
+ StringBuilder sb = new StringBuilder("Parsing \"");
+ sb.append(join(args).append("\"\n with:").append(join(m_objects.toArray())));
+ p(sb.toString());
+
+ if (m_descriptions == null) createDescriptions();
+ initializeDefaultValues();
+ parseValues(expandArgs(args), validate);
+ if (validate) validateOptions();
+ }
+
+ private StringBuilder join(Object[] args) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < args.length; i++) {
+ if (i > 0) result.append(" ");
+ result.append(args[i]);
+ }
+ return result;
+ }
+
+ private void initializeDefaultValues() {
+ if (m_defaultProvider != null) {
+ for (ParameterDescription pd : m_descriptions.values()) {
+ initializeDefaultValue(pd);
+ }
+
+ for (Map.Entry<ProgramName, JCommander> entry : m_commands.entrySet()) {
+ entry.getValue().initializeDefaultValues();
+ }
+ }
+ }
+
+ /**
+ * Make sure that all the required parameters have received a value.
+ */
+ private void validateOptions() {
+ // No validation if we found a help parameter
+ if (m_helpWasSpecified) {
+ return;
+ }
+
+ if (! m_requiredFields.isEmpty()) {
+ StringBuilder missingFields = new StringBuilder();
+ for (ParameterDescription pd : m_requiredFields.values()) {
+ missingFields.append(pd.getNames()).append(" ");
+ }
+ throw new ParameterException("The following "
+ + pluralize(m_requiredFields.size(), "option is required: ", "options are required: ")
+ + missingFields);
+ }
+
+ if (m_mainParameterDescription != null) {
+ if (m_mainParameterDescription.getParameter().required() &&
+ !m_mainParameterDescription.isAssigned()) {
+ throw new ParameterException("Main parameters are required (\""
+ + m_mainParameterDescription.getDescription() + "\")");
+ }
+ }
+ }
+
+ private static String pluralize(int quantity, String singular, String plural) {
+ return quantity == 1 ? singular : plural;
+ }
+
+ /**
+ * Expand the command line parameters to take @ parameters into account.
+ * When @ is encountered, the content of the file that follows is inserted
+ * in the command line.
+ *
+ * @param originalArgv the original command line parameters
+ * @return the new and enriched command line parameters
+ */
+ private String[] expandArgs(String[] originalArgv) {
+ List<String> vResult1 = Lists.newArrayList();
+
+ //
+ // Expand @
+ //
+ for (String arg : originalArgv) {
+
+ if (arg.startsWith("@")) {
+ String fileName = arg.substring(1);
+ vResult1.addAll(readFile(fileName));
+ }
+ else {
+ List<String> expanded = expandDynamicArg(arg);
+ vResult1.addAll(expanded);
+ }
+ }
+
+ // Expand separators
+ //
+ List<String> vResult2 = Lists.newArrayList();
+ for (int i = 0; i < vResult1.size(); i++) {
+ String arg = vResult1.get(i);
+ String[] v1 = vResult1.toArray(new String[0]);
+ if (isOption(v1, arg)) {
+ String sep = getSeparatorFor(v1, arg);
+ if (! " ".equals(sep)) {
+ String[] sp = arg.split("[" + sep + "]", 2);
+ for (String ssp : sp) {
+ vResult2.add(ssp);
+ }
+ } else {
+ vResult2.add(arg);
+ }
+ } else {
+ vResult2.add(arg);
+ }
+ }
+
+ return vResult2.toArray(new String[vResult2.size()]);
+ }
+
+ private List<String> expandDynamicArg(String arg) {
+ for (ParameterDescription pd : m_descriptions.values()) {
+ if (pd.isDynamicParameter()) {
+ for (String name : pd.getParameter().names()) {
+ if (arg.startsWith(name) && !arg.equals(name)) {
+ return Arrays.asList(name, arg.substring(name.length()));
+ }
+ }
+ }
+ }
+
+ return Arrays.asList(arg);
+ }
+
+ private boolean isOption(String[] args, String arg) {
+ String prefixes = getOptionPrefixes(args, arg);
+ return arg.length() > 0 && prefixes.indexOf(arg.charAt(0)) >= 0;
+ }
+
+ private ParameterDescription getPrefixDescriptionFor(String arg) {
+ for (Map.Entry<IKey, ParameterDescription> es : m_descriptions.entrySet()) {
+ if (arg.startsWith(es.getKey().getName())) return es.getValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * If arg is an option, we can look it up directly, but if it's a value,
+ * we need to find the description for the option that precedes it.
+ */
+ private ParameterDescription getDescriptionFor(String[] args, String arg) {
+ ParameterDescription result = getPrefixDescriptionFor(arg);
+ if (result != null) return result;
+
+ for (String a : args) {
+ ParameterDescription pd = getPrefixDescriptionFor(arg);
+ if (pd != null) result = pd;
+ if (a.equals(arg)) return result;
+ }
+
+ throw new ParameterException("Unknown parameter: " + arg);
+ }
+
+ private String getSeparatorFor(String[] args, String arg) {
+ ParameterDescription pd = getDescriptionFor(args, arg);
+
+ // Could be null if only main parameters were passed
+ if (pd != null) {
+ Parameters p = pd.getObject().getClass().getAnnotation(Parameters.class);
+ if (p != null) return p.separators();
+ }
+
+ return " ";
+ }
+
+ private String getOptionPrefixes(String[] args, String arg) {
+ ParameterDescription pd = getDescriptionFor(args, arg);
+
+ // Could be null if only main parameters were passed
+ if (pd != null) {
+ Parameters p = pd.getObject().getClass()
+ .getAnnotation(Parameters.class);
+ if (p != null) return p.optionPrefixes();
+ }
+ String result = Parameters.DEFAULT_OPTION_PREFIXES;
+
+ // See if any of the objects contains a @Parameters(optionPrefixes)
+ StringBuilder sb = new StringBuilder();
+ for (Object o : m_objects) {
+ Parameters p = o.getClass().getAnnotation(Parameters.class);
+ if (p != null && !Parameters.DEFAULT_OPTION_PREFIXES.equals(p.optionPrefixes())) {
+ sb.append(p.optionPrefixes());
+ }
+ }
+
+ if (! Strings.isStringEmpty(sb.toString())) {
+ result = sb.toString();
+ }
+
+ return result;
+ }
+
+ /**
+ * Reads the file specified by filename and returns the file content as a string.
+ * End of lines are replaced by a space.
+ *
+ * @param fileName the command line filename
+ * @return the file content as a string.
+ */
+ private static List<String> readFile(String fileName) {
+ List<String> result = Lists.newArrayList();
+
+ try {
+ BufferedReader bufRead = new BufferedReader(new FileReader(fileName));
+
+ String line;
+
+ // Read through file one line at time. Print line # and line
+ while ((line = bufRead.readLine()) != null) {
+ // Allow empty lines and # comments in these at files
+ if (line.length() > 0 && ! line.trim().startsWith("#")) {
+ result.add(line);
+ }
+ }
+
+ bufRead.close();
+ }
+ catch (IOException e) {
+ throw new ParameterException("Could not read file " + fileName + ": " + e);
+ }
+
+ return result;
+ }
+
+ /**
+ * Remove spaces at both ends and handle double quotes.
+ */
+ private static String trim(String string) {
+ String result = string.trim();
+ if (result.startsWith("\"") && result.endsWith("\"") && result.length() > 1) {
+ result = result.substring(1, result.length() - 1);
+ }
+ return result;
+ }
+
+ /**
+ * Create the ParameterDescriptions for all the \@Parameter found.
+ */
+ private void createDescriptions() {
+ m_descriptions = Maps.newHashMap();
+
+ for (Object object : m_objects) {
+ addDescription(object);
+ }
+ }
+
+ private void addDescription(Object object) {
+ Class<?> cls = object.getClass();
+
+ List<Parameterized> parameterizeds = Parameterized.parseArg(object);
+ for (Parameterized parameterized : parameterizeds) {
+ WrappedParameter wp = parameterized.getWrappedParameter();
+ if (wp != null && wp.getParameter() != null) {
+ Parameter annotation = wp.getParameter();
+ //
+ // @Parameter
+ //
+ Parameter p = annotation;
+ if (p.names().length == 0) {
+ p("Found main parameter:" + parameterized);
+ if (m_mainParameter != null) {
+ throw new ParameterException("Only one @Parameter with no names attribute is"
+ + " allowed, found:" + m_mainParameter + " and " + parameterized);
+ }
+ m_mainParameter = parameterized;
+ m_mainParameterObject = object;
+ m_mainParameterAnnotation = p;
+ m_mainParameterDescription =
+ new ParameterDescription(object, p, parameterized, m_bundle, this);
+ } else {
+ ParameterDescription pd =
+ new ParameterDescription(object, p, parameterized, m_bundle, this);
+ for (String name : p.names()) {
+ if (m_descriptions.containsKey(new StringKey(name))) {
+ throw new ParameterException("Found the option " + name + " multiple times");
+ }
+ p("Adding description for " + name);
+ m_fields.put(parameterized, pd);
+ m_descriptions.put(new StringKey(name), pd);
+
+ if (p.required()) m_requiredFields.put(parameterized, pd);
+ }
+ }
+ } else if (parameterized.getDelegateAnnotation() != null) {
+ //
+ // @ParametersDelegate
+ //
+ Object delegateObject = parameterized.get(object);
+ if (delegateObject == null){
+ throw new ParameterException("Delegate field '" + parameterized.getName()
+ + "' cannot be null.");
+ }
+ addDescription(delegateObject);
+ } else if (wp != null && wp.getDynamicParameter() != null) {
+ //
+ // @DynamicParameter
+ //
+ DynamicParameter dp = wp.getDynamicParameter();
+ for (String name : dp.names()) {
+ if (m_descriptions.containsKey(name)) {
+ throw new ParameterException("Found the option " + name + " multiple times");
+ }
+ p("Adding description for " + name);
+ ParameterDescription pd =
+ new ParameterDescription(object, dp, parameterized, m_bundle, this);
+ m_fields.put(parameterized, pd);
+ m_descriptions.put(new StringKey(name), pd);
+
+ if (dp.required()) m_requiredFields.put(parameterized, pd);
+ }
+ }
+ }
+
+// while (!Object.class.equals(cls)) {
+// for (Field f : cls.getDeclaredFields()) {
+// p("Field:" + cls.getSimpleName() + "." + f.getName());
+// f.setAccessible(true);
+// Annotation annotation = f.getAnnotation(Parameter.class);
+// Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class);
+// Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class);
+// if (annotation != null) {
+// //
+// // @Parameter
+// //
+// Parameter p = (Parameter) annotation;
+// if (p.names().length == 0) {
+// p("Found main parameter:" + f);
+// if (m_mainParameterField != null) {
+// throw new ParameterException("Only one @Parameter with no names attribute is"
+// + " allowed, found:" + m_mainParameterField + " and " + f);
+// }
+// m_mainParameterField = parameterized;
+// m_mainParameterObject = object;
+// m_mainParameterAnnotation = p;
+// m_mainParameterDescription = new ParameterDescription(object, p, f, m_bundle, this);
+// } else {
+// for (String name : p.names()) {
+// if (m_descriptions.containsKey(name)) {
+// throw new ParameterException("Found the option " + name + " multiple times");
+// }
+// p("Adding description for " + name);
+// ParameterDescription pd = new ParameterDescription(object, p, f, m_bundle, this);
+// m_fields.put(f, pd);
+// m_descriptions.put(name, pd);
+//
+// if (p.required()) m_requiredFields.put(f, pd);
+// }
+// }
+// } else if (delegateAnnotation != null) {
+// //
+// // @ParametersDelegate
+// //
+// try {
+// Object delegateObject = f.get(object);
+// if (delegateObject == null){
+// throw new ParameterException("Delegate field '" + f.getName() + "' cannot be null.");
+// }
+// addDescription(delegateObject);
+// } catch (IllegalAccessException e) {
+// }
+// } else if (dynamicParameter != null) {
+// //
+// // @DynamicParameter
+// //
+// DynamicParameter dp = (DynamicParameter) dynamicParameter;
+// for (String name : dp.names()) {
+// if (m_descriptions.containsKey(name)) {
+// throw new ParameterException("Found the option " + name + " multiple times");
+// }
+// p("Adding description for " + name);
+// ParameterDescription pd = new ParameterDescription(object, dp, f, m_bundle, this);
+// m_fields.put(f, pd);
+// m_descriptions.put(name, pd);
+//
+// if (dp.required()) m_requiredFields.put(f, pd);
+// }
+// }
+// }
+// // Traverse the super class until we find Object.class
+// cls = cls.getSuperclass();
+// }
+ }
+
+ private void initializeDefaultValue(ParameterDescription pd) {
+ for (String optionName : pd.getParameter().names()) {
+ String def = m_defaultProvider.getDefaultValueFor(optionName);
+ if (def != null) {
+ p("Initializing " + optionName + " with default value:" + def);
+ pd.addValue(def, true /* default */);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Main method that parses the values and initializes the fields accordingly.
+ */
+ private void parseValues(String[] args, boolean validate) {
+ // This boolean becomes true if we encounter a command, which indicates we need
+ // to stop parsing (the parsing of the command will be done in a sub JCommander
+ // object)
+ boolean commandParsed = false;
+ int i = 0;
+ boolean isDashDash = false; // once we encounter --, everything goes into the main parameter
+ while (i < args.length && ! commandParsed) {
+ String arg = args[i];
+ String a = trim(arg);
+ args[i] = a;
+ p("Parsing arg: " + a);
+
+ JCommander jc = findCommandByAlias(arg);
+ int increment = 1;
+ if (! isDashDash && ! "--".equals(a) && isOption(args, a) && jc == null) {
+ //
+ // Option
+ //
+ ParameterDescription pd = findParameterDescription(a);
+
+ if (pd != null) {
+ if (pd.getParameter().password()) {
+ //
+ // Password option, use the Console to retrieve the password
+ //
+ char[] password = readPassword(pd.getDescription(), pd.getParameter().echoInput());
+ pd.addValue(new String(password));
+ m_requiredFields.remove(pd.getParameterized());
+ } else {
+ if (pd.getParameter().variableArity()) {
+ //
+ // Variable arity?
+ //
+ increment = processVariableArity(args, i, pd);
+ } else {
+ //
+ // Regular option
+ //
+ Class<?> fieldType = pd.getParameterized().getType();
+
+ // Boolean, set to true as soon as we see it, unless it specified
+ // an arity of 1, in which case we need to read the next value
+ if ((fieldType == boolean.class || fieldType == Boolean.class)
+ && pd.getParameter().arity() == -1) {
+ pd.addValue("true");
+ m_requiredFields.remove(pd.getParameterized());
+ } else {
+ increment = processFixedArity(args, i, pd, fieldType);
+ }
+ // If it's a help option, remember for later
+ if (pd.isHelp()) {
+ m_helpWasSpecified = true;
+ }
+ }
+ }
+ } else {
+ if (m_acceptUnknownOptions) {
+ m_unknownArgs.add(arg);
+ i++;
+ while (i < args.length && ! isOption(args, args[i])) {
+ m_unknownArgs.add(args[i++]);
+ }
+ increment = 0;
+ } else {
+ throw new ParameterException("Unknown option: " + arg);
+ }
+ }
+ }
+ else {
+ //
+ // Main parameter
+ //
+ if (! Strings.isStringEmpty(arg)) {
+ if ("--".equals(arg)) {
+ isDashDash = true;
+ a = trim(args[++i]);
+ }
+ if (m_commands.isEmpty()) {
+ //
+ // Regular (non-command) parsing
+ //
+ List mp = getMainParameter(arg);
+ String value = a; // If there's a non-quoted version, prefer that one
+ Object convertedValue = value;
+
+ if (m_mainParameter.getGenericType() instanceof ParameterizedType) {
+ ParameterizedType p = (ParameterizedType) m_mainParameter.getGenericType();
+ Type cls = p.getActualTypeArguments()[0];
+ if (cls instanceof Class) {
+ convertedValue = convertValue(m_mainParameter, (Class) cls, value);
+ }
+ }
+
+ ParameterDescription.validateParameter(m_mainParameterDescription,
+ m_mainParameterAnnotation.validateWith(),
+ "Default", value);
+
+ m_mainParameterDescription.setAssigned(true);
+ mp.add(convertedValue);
+ }
+ else {
+ //
+ // Command parsing
+ //
+ if (jc == null && validate) {
+ throw new MissingCommandException("Expected a command, got " + arg);
+ } else if (jc != null){
+ m_parsedCommand = jc.m_programName.m_name;
+ m_parsedAlias = arg; //preserve the original form
+
+ // Found a valid command, ask it to parse the remainder of the arguments.
+ // Setting the boolean commandParsed to true will force the current
+ // loop to end.
+ jc.parse(subArray(args, i + 1));
+ commandParsed = true;
+ }
+ }
+ }
+ }
+ i += increment;
+ }
+
+ // Mark the parameter descriptions held in m_fields as assigned
+ for (ParameterDescription parameterDescription : m_descriptions.values()) {
+ if (parameterDescription.isAssigned()) {
+ m_fields.get(parameterDescription.getParameterized()).setAssigned(true);
+ }
+ }
+
+ }
+
+ private class DefaultVariableArity implements IVariableArity {
+
+ @Override
+ public int processVariableArity(String optionName, String[] options) {
+ int i = 0;
+ while (i < options.length && !isOption(options, options[i])) {
+ i++;
+ }
+ return i;
+ }
+ }
+ private final IVariableArity DEFAULT_VARIABLE_ARITY = new DefaultVariableArity();
+
+ private int m_verbose = 0;
+
+ private boolean m_caseSensitiveOptions = true;
+ private boolean m_allowAbbreviatedOptions = false;
+
+ /**
+ * @return the number of options that were processed.
+ */
+ private int processVariableArity(String[] args, int index, ParameterDescription pd) {
+ Object arg = pd.getObject();
+ IVariableArity va;
+ if (! (arg instanceof IVariableArity)) {
+ va = DEFAULT_VARIABLE_ARITY;
+ } else {
+ va = (IVariableArity) arg;
+ }
+
+ List<String> currentArgs = Lists.newArrayList();
+ for (int j = index + 1; j < args.length; j++) {
+ currentArgs.add(args[j]);
+ }
+ int arity = va.processVariableArity(pd.getParameter().names()[0],
+ currentArgs.toArray(new String[0]));
+
+ int result = processFixedArity(args, index, pd, List.class, arity);
+ return result;
+ }
+
+ private int processFixedArity(String[] args, int index, ParameterDescription pd,
+ Class<?> fieldType) {
+ // Regular parameter, use the arity to tell use how many values
+ // we need to consume
+ int arity = pd.getParameter().arity();
+ int n = (arity != -1 ? arity : 1);
+
+ return processFixedArity(args, index, pd, fieldType, n);
+ }
+
+ private int processFixedArity(String[] args, int originalIndex, ParameterDescription pd,
+ Class<?> fieldType, int arity) {
+ int index = originalIndex;
+ String arg = args[index];
+ // Special case for boolean parameters of arity 0
+ if (arity == 0 &&
+ (Boolean.class.isAssignableFrom(fieldType)
+ || boolean.class.isAssignableFrom(fieldType))) {
+ pd.addValue("true");
+ m_requiredFields.remove(pd.getParameterized());
+ } else if (index < args.length - 1) {
+ int offset = "--".equals(args[index + 1]) ? 1 : 0;
+
+ if (index + arity < args.length) {
+ for (int j = 1; j <= arity; j++) {
+ pd.addValue(trim(args[index + j + offset]));
+ m_requiredFields.remove(pd.getParameterized());
+ }
+ index += arity + offset;
+ } else {
+ throw new ParameterException("Expected " + arity + " values after " + arg);
+ }
+ } else {
+ throw new ParameterException("Expected a value after parameter " + arg);
+ }
+
+ return arity + 1;
+ }
+
+ /**
+ * Invoke Console.readPassword through reflection to avoid depending
+ * on Java 6.
+ */
+ private char[] readPassword(String description, boolean echoInput) {
+ getConsole().print(description + ": ");
+ return getConsole().readPassword(echoInput);
+ }
+
+ private String[] subArray(String[] args, int index) {
+ int l = args.length - index;
+ String[] result = new String[l];
+ System.arraycopy(args, index, result, 0, l);
+
+ return result;
+ }
+
+ /**
+ * @return the field that's meant to receive all the parameters that are not options.
+ *
+ * @param arg the arg that we're about to add (only passed here to output a meaningful
+ * error message).
+ */
+ private List<?> getMainParameter(String arg) {
+ if (m_mainParameter == null) {
+ throw new ParameterException(
+ "Was passed main parameter '" + arg + "' but no main parameter was defined");
+ }
+
+ List<?> result = (List<?>) m_mainParameter.get(m_mainParameterObject);
+ if (result == null) {
+ result = Lists.newArrayList();
+ if (! List.class.isAssignableFrom(m_mainParameter.getType())) {
+ throw new ParameterException("Main parameter field " + m_mainParameter
+ + " needs to be of type List, not " + m_mainParameter.getType());
+ }
+ m_mainParameter.set(m_mainParameterObject, result);
+ }
+ if (m_firstTimeMainParameter) {
+ result.clear();
+ m_firstTimeMainParameter = false;
+ }
+ return result;
+ }
+
+ public String getMainParameterDescription() {
+ if (m_descriptions == null) createDescriptions();
+ return m_mainParameterAnnotation != null ? m_mainParameterAnnotation.description()
+ : null;
+ }
+
+// private int longestName(Collection<?> objects) {
+// int result = 0;
+// for (Object o : objects) {
+// int l = o.toString().length();
+// if (l > result) result = l;
+// }
+//
+// return result;
+// }
+
+ /**
+ * Set the program name (used only in the usage).
+ */
+ public void setProgramName(String name) {
+ setProgramName(name, new String[0]);
+ }
+
+ /**
+ * Set the program name
+ *
+ * @param name program name
+ * @param aliases aliases to the program name
+ */
+ public void setProgramName(String name, String... aliases) {
+ m_programName = new ProgramName(name, Arrays.asList(aliases));
+ }
+
+ /**
+ * Display the usage for this command.
+ */
+ public void usage(String commandName) {
+ StringBuilder sb = new StringBuilder();
+ usage(commandName, sb);
+ getConsole().println(sb.toString());
+ }
+
+ /**
+ * Store the help for the command in the passed string builder.
+ */
+ public void usage(String commandName, StringBuilder out) {
+ usage(commandName, out, "");
+ }
+
+ /**
+ * Store the help for the command in the passed string builder, indenting
+ * every line with "indent".
+ */
+ public void usage(String commandName, StringBuilder out, String indent) {
+ String description = getCommandDescription(commandName);
+ JCommander jc = findCommandByAlias(commandName);
+ if (description != null) {
+ out.append(indent).append(description);
+ out.append("\n");
+ }
+ jc.usage(out, indent);
+ }
+
+ /**
+ * @return the description of the command.
+ */
+ public String getCommandDescription(String commandName) {
+ JCommander jc = findCommandByAlias(commandName);
+ if (jc == null) {
+ throw new ParameterException("Asking description for unknown command: " + commandName);
+ }
+
+ Object arg = jc.getObjects().get(0);
+ Parameters p = arg.getClass().getAnnotation(Parameters.class);
+ ResourceBundle bundle = null;
+ String result = null;
+ if (p != null) {
+ result = p.commandDescription();
+ String bundleName = p.resourceBundle();
+ if (!"".equals(bundleName)) {
+ bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
+ } else {
+ bundle = m_bundle;
+ }
+
+ if (bundle != null) {
+ result = getI18nString(bundle, p.commandDescriptionKey(), p.commandDescription());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @return The internationalized version of the string if available, otherwise
+ * return def.
+ */
+ private String getI18nString(ResourceBundle bundle, String key, String def) {
+ String s = bundle != null ? bundle.getString(key) : null;
+ return s != null ? s : def;
+ }
+
+ /**
+ * Display the help on System.out.
+ */
+ public void usage() {
+ StringBuilder sb = new StringBuilder();
+ usage(sb);
+ getConsole().println(sb.toString());
+ }
+
+ /**
+ * Store the help in the passed string builder.
+ */
+ public void usage(StringBuilder out) {
+ usage(out, "");
+ }
+
+ public void usage(StringBuilder out, String indent) {
+ if (m_descriptions == null) createDescriptions();
+ boolean hasCommands = !m_commands.isEmpty();
+
+ //
+ // First line of the usage
+ //
+ String programName = m_programName != null ? m_programName.getDisplayName() : "<main class>";
+ out.append(indent).append("Usage: " + programName + " [options]");
+ if (hasCommands) out.append(indent).append(" [command] [command options]");
+ if (m_mainParameterDescription != null) {
+ out.append(" " + m_mainParameterDescription.getDescription());
+ }
+ out.append("\n");
+
+ //
+ // Align the descriptions at the "longestName" column
+ //
+ int longestName = 0;
+ List<ParameterDescription> sorted = Lists.newArrayList();
+ for (ParameterDescription pd : m_fields.values()) {
+ if (! pd.getParameter().hidden()) {
+ sorted.add(pd);
+ // + to have an extra space between the name and the description
+ int length = pd.getNames().length() + 2;
+ if (length > longestName) {
+ longestName = length;
+ }
+ }
+ }
+
+ //
+ // Sort the options
+ //
+ Collections.sort(sorted, getParameterDescriptionComparator());
+
+ //
+ // Display all the names and descriptions
+ //
+ int descriptionIndent = 6;
+ if (sorted.size() > 0) out.append(indent).append(" Options:\n");
+ for (ParameterDescription pd : sorted) {
+ WrappedParameter parameter = pd.getParameter();
+ out.append(indent).append(" "
+ + (parameter.required() ? "* " : " ")
+ + pd.getNames()
+ + "\n"
+ + indent + s(descriptionIndent));
+ int indentCount = indent.length() + descriptionIndent;
+ wrapDescription(out, indentCount, pd.getDescription());
+ Object def = pd.getDefault();
+ if (pd.isDynamicParameter()) {
+ out.append("\n" + s(indentCount + 1))
+ .append("Syntax: " + parameter.names()[0]
+ + "key" + parameter.getAssignment()
+ + "value");
+ }
+ if (def != null) {
+ String displayedDef = Strings.isStringEmpty(def.toString())
+ ? "<empty string>"
+ : def.toString();
+ out.append("\n" + s(indentCount + 1))
+ .append("Default: " + (parameter.password()?"********" : displayedDef));
+ }
+ Class<?> type = pd.getParameterized().getType();
+ if(type.isEnum()){
+ out.append("\n" + s(indentCount + 1))
+ .append("Possible Values: " + EnumSet.allOf((Class<? extends Enum>) type));
+ }
+ out.append("\n");
+ }
+
+ //
+ // If commands were specified, show them as well
+ //
+ if (hasCommands) {
+ out.append(" Commands:\n");
+ // The magic value 3 is the number of spaces between the name of the option
+ // and its description
+ for (Map.Entry<ProgramName, JCommander> commands : m_commands.entrySet()) {
+ Object arg = commands.getValue().getObjects().get(0);
+ Parameters p = arg.getClass().getAnnotation(Parameters.class);
+ if (!p.hidden()) {
+ ProgramName progName = commands.getKey();
+ String dispName = progName.getDisplayName();
+ out.append(indent).append(" " + dispName); // + s(spaceCount) + getCommandDescription(progName.name) + "\n");
+
+ // Options for this command
+ usage(progName.getName(), out, " ");
+ out.append("\n");
+ }
+ }
+ }
+ }
+
+ private Comparator<? super ParameterDescription> getParameterDescriptionComparator() {
+ return m_parameterDescriptionComparator;
+ }
+
+ public void setParameterDescriptionComparator(Comparator<? super ParameterDescription> c) {
+ m_parameterDescriptionComparator = c;
+ }
+
+ public void setColumnSize(int columnSize) {
+ m_columnSize = columnSize;
+ }
+
+ public int getColumnSize() {
+ return m_columnSize;
+ }
+
+ private void wrapDescription(StringBuilder out, int indent, String description) {
+ int max = getColumnSize();
+ String[] words = description.split(" ");
+ int current = indent;
+ int i = 0;
+ while (i < words.length) {
+ String word = words[i];
+ if (word.length() > max || current + word.length() <= max) {
+ out.append(" ").append(word);
+ current += word.length() + 1;
+ } else {
+ out.append("\n").append(s(indent + 1)).append(word);
+ current = indent;
+ }
+ i++;
+ }
+ }
+
+ /**
+ * @return a Collection of all the \@Parameter annotations found on the
+ * target class. This can be used to display the usage() in a different
+ * format (e.g. HTML).
+ */
+ public List<ParameterDescription> getParameters() {
+ return new ArrayList<ParameterDescription>(m_fields.values());
+ }
+
+ /**
+ * @return the main parameter description or null if none is defined.
+ */
+ public ParameterDescription getMainParameter() {
+ return m_mainParameterDescription;
+ }
+
+ private void p(String string) {
+ if (m_verbose > 0 || System.getProperty(JCommander.DEBUG_PROPERTY) != null) {
+ getConsole().println("[JCommander] " + string);
+ }
+ }
+
+ /**
+ * Define the default provider for this instance.
+ */
+ public void setDefaultProvider(IDefaultProvider defaultProvider) {
+ m_defaultProvider = defaultProvider;
+
+ for (Map.Entry<ProgramName, JCommander> entry : m_commands.entrySet()) {
+ entry.getValue().setDefaultProvider(defaultProvider);
+ }
+ }
+
+ public void addConverterFactory(IStringConverterFactory converterFactory) {
+ CONVERTER_FACTORIES.addFirst(converterFactory);
+ }
+
+ public <T> Class<? extends IStringConverter<T>> findConverter(Class<T> cls) {
+ for (IStringConverterFactory f : CONVERTER_FACTORIES) {
+ Class<? extends IStringConverter<T>> result = f.getConverter(cls);
+ if (result != null) return result;
+ }
+
+ return null;
+ }
+
+ public Object convertValue(ParameterDescription pd, String value) {
+ return convertValue(pd.getParameterized(), pd.getParameterized().getType(), value);
+ }
+
+ /**
+ * @param type The type of the actual parameter
+ * @param value The value to convert
+ */
+ public Object convertValue(Parameterized parameterized, Class type,
+ String value) {
+ Parameter annotation = parameterized.getParameter();
+
+ // Do nothing if it's a @DynamicParameter
+ if (annotation == null) return value;
+
+ Class<? extends IStringConverter<?>> converterClass = annotation.converter();
+ boolean listConverterWasSpecified = annotation.listConverter() != NoConverter.class;
+
+ //
+ // Try to find a converter on the annotation
+ //
+ if (converterClass == null || converterClass == NoConverter.class) {
+ // If no converter specified and type is enum, used enum values to convert
+ if (type.isEnum()){
+ converterClass = type;
+ } else {
+ converterClass = findConverter(type);
+ }
+ }
+
+ if (converterClass == null) {
+ Type elementType = parameterized.findFieldGenericType();
+ converterClass = elementType != null
+ ? findConverter((Class<? extends IStringConverter<?>>) elementType)
+ : StringConverter.class;
+ // Check for enum type parameter
+ if (converterClass == null && Enum.class.isAssignableFrom((Class) elementType)) {
+ converterClass = (Class<? extends IStringConverter<?>>) elementType;
+ }
+ }
+
+ IStringConverter<?> converter;
+ Object result = null;
+ try {
+ String[] names = annotation.names();
+ String optionName = names.length > 0 ? names[0] : "[Main class]";
+ if (converterClass != null && converterClass.isEnum()) {
+ try {
+ result = Enum.valueOf((Class<? extends Enum>) converterClass, value);
+ } catch (IllegalArgumentException e) {
+ try {
+ result = Enum.valueOf((Class<? extends Enum>) converterClass, value.toUpperCase());
+ } catch (IllegalArgumentException ex) {
+ throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" +
+ EnumSet.allOf((Class<? extends Enum>) converterClass));
+ }
+ } catch (Exception e) {
+ throw new ParameterException("Invalid value for " + optionName + " parameter. Allowed values:" +
+ EnumSet.allOf((Class<? extends Enum>) converterClass));
+ }
+ } else {
+ converter = instantiateConverter(optionName, converterClass);
+ if (type.isAssignableFrom(List.class)
+ && parameterized.getGenericType() instanceof ParameterizedType) {
+
+ // The field is a List
+ if (listConverterWasSpecified) {
+ // If a list converter was specified, pass the value to it
+ // for direct conversion
+ IStringConverter<?> listConverter =
+ instantiateConverter(optionName, annotation.listConverter());
+ result = listConverter.convert(value);
+ } else {
+ // No list converter: use the single value converter and pass each
+ // parsed value to it individually
+ result = convertToList(value, converter, annotation.splitter());
+ }
+ } else {
+ result = converter.convert(value);
+ }
+ }
+ } catch (InstantiationException e) {
+ throw new ParameterException(e);
+ } catch (IllegalAccessException e) {
+ throw new ParameterException(e);
+ } catch (InvocationTargetException e) {
+ throw new ParameterException(e);
+ }
+
+ return result;
+ }
+
+ /**
+ * Use the splitter to split the value into multiple values and then convert
+ * each of them individually.
+ */
+ private Object convertToList(String value, IStringConverter<?> converter,
+ Class<? extends IParameterSplitter> splitterClass)
+ throws InstantiationException, IllegalAccessException {
+ IParameterSplitter splitter = splitterClass.newInstance();
+ List<Object> result = Lists.newArrayList();
+ for (String param : splitter.split(value)) {
+ result.add(converter.convert(param));
+ }
+ return result;
+ }
+
+ private IStringConverter<?> instantiateConverter(String optionName,
+ Class<? extends IStringConverter<?>> converterClass)
+ throws IllegalArgumentException, InstantiationException, IllegalAccessException,
+ InvocationTargetException {
+ Constructor<IStringConverter<?>> ctor = null;
+ Constructor<IStringConverter<?>> stringCtor = null;
+ Constructor<IStringConverter<?>>[] ctors
+ = (Constructor<IStringConverter<?>>[]) converterClass.getDeclaredConstructors();
+ for (Constructor<IStringConverter<?>> c : ctors) {
+ Class<?>[] types = c.getParameterTypes();
+ if (types.length == 1 && types[0].equals(String.class)) {
+ stringCtor = c;
+ } else if (types.length == 0) {
+ ctor = c;
+ }
+ }
+
+ IStringConverter<?> result = stringCtor != null
+ ? stringCtor.newInstance(optionName)
+ : (ctor != null
+ ? ctor.newInstance()
+ : null);
+
+ return result;
+ }
+
+ /**
+ * Add a command object.
+ */
+ public void addCommand(String name, Object object) {
+ addCommand(name, object, new String[0]);
+ }
+
+ public void addCommand(Object object) {
+ Parameters p = object.getClass().getAnnotation(Parameters.class);
+ if (p != null && p.commandNames().length > 0) {
+ for (String commandName : p.commandNames()) {
+ addCommand(commandName, object);
+ }
+ } else {
+ throw new ParameterException("Trying to add command " + object.getClass().getName()
+ + " without specifying its names in @Parameters");
+ }
+ }
+
+ /**
+ * Add a command object and its aliases.
+ */
+ public void addCommand(String name, Object object, String... aliases) {
+ JCommander jc = new JCommander(object);
+ jc.setProgramName(name, aliases);
+ jc.setDefaultProvider(m_defaultProvider);
+ jc.setAcceptUnknownOptions(m_acceptUnknownOptions);
+ ProgramName progName = jc.m_programName;
+ m_commands.put(progName, jc);
+
+ /*
+ * Register aliases
+ */
+ //register command name as an alias of itself for reverse lookup
+ //Note: Name clash check is intentionally omitted to resemble the
+ // original behaviour of clashing commands.
+ // Aliases are, however, are strictly checked for name clashes.
+ aliasMap.put(new StringKey(name), progName);
+ for (String a : aliases) {
+ IKey alias = new StringKey(a);
+ //omit pointless aliases to avoid name clash exception
+ if (!alias.equals(name)) {
+ ProgramName mappedName = aliasMap.get(alias);
+ if (mappedName != null && !mappedName.equals(progName)) {
+ throw new ParameterException("Cannot set alias " + alias
+ + " for " + name
+ + " command because it has already been defined for "
+ + mappedName.m_name + " command");
+ }
+ aliasMap.put(alias, progName);
+ }
+ }
+ }
+
+ public Map<String, JCommander> getCommands() {
+ Map<String, JCommander> res = Maps.newLinkedHashMap();
+ for (Map.Entry<ProgramName, JCommander> entry : m_commands.entrySet()) {
+ res.put(entry.getKey().m_name, entry.getValue());
+ }
+ return res;
+ }
+
+ public String getParsedCommand() {
+ return m_parsedCommand;
+ }
+
+ /**
+ * The name of the command or the alias in the form it was
+ * passed to the command line. <code>null</code> if no
+ * command or alias was specified.
+ *
+ * @return Name of command or alias passed to command line. If none passed: <code>null</code>.
+ */
+ public String getParsedAlias() {
+ return m_parsedAlias;
+ }
+
+ /**
+ * @return n spaces
+ */
+ private String s(int count) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < count; i++) {
+ result.append(" ");
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * @return the objects that JCommander will fill with the result of
+ * parsing the command line.
+ */
+ public List<Object> getObjects() {
+ return m_objects;
+ }
+
+ private ParameterDescription findParameterDescription(String arg) {
+ return FuzzyMap.findInMap(m_descriptions, new StringKey(arg), m_caseSensitiveOptions,
+ m_allowAbbreviatedOptions);
+ }
+
+ private JCommander findCommand(ProgramName name) {
+ return FuzzyMap.findInMap(m_commands, name,
+ m_caseSensitiveOptions, m_allowAbbreviatedOptions);
+// if (! m_caseSensitiveOptions) {
+// return m_commands.get(name);
+// } else {
+// for (ProgramName c : m_commands.keySet()) {
+// if (c.getName().equalsIgnoreCase(name.getName())) {
+// return m_commands.get(c);
+// }
+// }
+// }
+// return null;
+ }
+
+ private ProgramName findProgramName(String name) {
+ return FuzzyMap.findInMap(aliasMap, new StringKey(name),
+ m_caseSensitiveOptions, m_allowAbbreviatedOptions);
+ }
+
+ /*
+ * Reverse lookup JCommand object by command's name or its alias
+ */
+ private JCommander findCommandByAlias(String commandOrAlias) {
+ ProgramName progName = findProgramName(commandOrAlias);
+ if (progName == null) {
+ return null;
+ }
+ JCommander jc = findCommand(progName);
+ if (jc == null) {
+ throw new IllegalStateException(
+ "There appears to be inconsistency in the internal command database. " +
+ " This is likely a bug. Please report.");
+ }
+ return jc;
+ }
+
+ /**
+ * Encapsulation of either a main application or an individual command.
+ */
+ private static final class ProgramName implements IKey {
+ private final String m_name;
+ private final List<String> m_aliases;
+
+ ProgramName(String name, List<String> aliases) {
+ m_name = name;
+ m_aliases = aliases;
+ }
+
+ @Override
+ public String getName() {
+ return m_name;
+ }
+
+ private String getDisplayName() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(m_name);
+ if (!m_aliases.isEmpty()) {
+ sb.append("(");
+ Iterator<String> aliasesIt = m_aliases.iterator();
+ while (aliasesIt.hasNext()) {
+ sb.append(aliasesIt.next());
+ if (aliasesIt.hasNext()) {
+ sb.append(",");
+ }
+ }
+ sb.append(")");
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ProgramName other = (ProgramName) obj;
+ if (m_name == null) {
+ if (other.m_name != null)
+ return false;
+ } else if (!m_name.equals(other.m_name))
+ return false;
+ return true;
+ }
+
+ /*
+ * Important: ProgramName#toString() is used by longestName(Collection) function
+ * to format usage output.
+ */
+ @Override
+ public String toString() {
+ return getDisplayName();
+
+ }
+ }
+
+ public void setVerbose(int verbose) {
+ m_verbose = verbose;
+ }
+
+ public void setCaseSensitiveOptions(boolean b) {
+ m_caseSensitiveOptions = b;
+ }
+
+ public void setAllowAbbreviatedOptions(boolean b) {
+ m_allowAbbreviatedOptions = b;
+ }
+
+ public void setAcceptUnknownOptions(boolean b) {
+ m_acceptUnknownOptions = b;
+ }
+
+ public List<String> getUnknownOptions() {
+ return m_unknownArgs;
+ }
+ public void setAllowParameterOverwriting(boolean b) {
+ m_allowParameterOverwriting = b;
+ }
+
+ public boolean isParameterOverwritingAllowed() {
+ return m_allowParameterOverwriting;
+ }
+// public void setCaseSensitiveCommands(boolean b) {
+// m_caseSensitiveCommands = b;
+// }
+}
+
diff --git a/src/main/java/com/beust/jcommander/MissingCommandException.java b/src/main/java/com/beust/jcommander/MissingCommandException.java
new file mode 100644
index 0000000..1d572ab
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/MissingCommandException.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+/**
+ * Thrown when a command was expected.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+@SuppressWarnings("serial")
+public class MissingCommandException extends ParameterException {
+
+ public MissingCommandException(String string) {
+ super(string);
+ }
+
+ public MissingCommandException(Throwable t) {
+ super(t);
+ }
+}
diff --git a/src/main/java/com/beust/jcommander/Parameter.java b/src/main/java/com/beust/jcommander/Parameter.java
new file mode 100644
index 0000000..d8cf87d
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/Parameter.java
@@ -0,0 +1,130 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+import com.beust.jcommander.converters.CommaParameterSplitter;
+import com.beust.jcommander.converters.IParameterSplitter;
+import com.beust.jcommander.converters.NoConverter;
+import com.beust.jcommander.validators.NoValidator;
+import com.beust.jcommander.validators.NoValueValidator;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({ FIELD, METHOD })
+public @interface Parameter {
+
+ /**
+ * An array of allowed command line parameters (e.g. "-d", "--outputdir", etc...).
+ * If this attribute is omitted, the field it's annotating will receive all the
+ * unparsed options. There can only be at most one such annotation.
+ */
+ String[] names() default {};
+
+ /**
+ * A description of this option.
+ */
+ String description() default "";
+
+ /**
+ * Whether this option is required.
+ */
+ boolean required() default false;
+
+ /**
+ * The key used to find the string in the message bundle.
+ */
+ String descriptionKey() default "";
+
+ /**
+ * How many parameter values this parameter will consume. For example,
+ * an arity of 2 will allow "-pair value1 value2".
+ */
+ int arity() default -1;
+
+ /**
+ * If true, this parameter is a password and it will be prompted on the console
+ * (if available).
+ */
+ boolean password() default false;
+
+ /**
+ * The string converter to use for this field. If the field is of type <tt>List</tt>
+ * and not <tt>listConverter</tt> attribute was specified, JCommander will split
+ * the input in individual values and convert each of them separately.
+ */
+ Class<? extends IStringConverter<?>> converter() default NoConverter.class;
+
+ /**
+ * The list string converter to use for this field. If it's specified, the
+ * field has to be of type <tt>List</tt> and the converter needs to return
+ * a List that's compatible with that type.
+ */
+ Class<? extends IStringConverter<?>> listConverter() default NoConverter.class;
+
+ /**
+ * If true, this parameter won't appear in the usage().
+ */
+ boolean hidden() default false;
+
+ /**
+ * Validate the parameter found on the command line.
+ */
+ Class<? extends IParameterValidator> validateWith() default NoValidator.class;
+
+ /**
+ * Validate the value for this parameter.
+ */
+ Class<? extends IValueValidator> validateValueWith() default NoValueValidator.class;
+
+ /**
+ * @return true if this parameter has a variable arity. See @{IVariableArity}
+ */
+ boolean variableArity() default false;
+
+ /**
+ * What splitter to use (applicable only on fields of type <tt>List</tt>). By default,
+ * a comma separated splitter will be used.
+ */
+ Class<? extends IParameterSplitter> splitter() default CommaParameterSplitter.class;
+
+ /**
+ * If true, console will not echo typed input
+ * Used in conjunction with password = true
+ */
+ boolean echoInput() default false;
+
+ /**
+ * If true, this parameter is for help. If such a parameter is specified,
+ * required parameters are no longer checked for their presence.
+ */
+ boolean help() default false;
+
+ /**
+ * If true, this parameter can be overwritten through a file or another appearance of the parameter
+ * @return
+ */
+ boolean forceNonOverwritable() default false;
+
+
+}
diff --git a/src/main/java/com/beust/jcommander/ParameterDescription.java b/src/main/java/com/beust/jcommander/ParameterDescription.java
new file mode 100644
index 0000000..2ef2d5f
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ParameterDescription.java
@@ -0,0 +1,364 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import com.beust.jcommander.validators.NoValidator;
+import com.beust.jcommander.validators.NoValueValidator;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class ParameterDescription {
+ private Object m_object;
+
+ private WrappedParameter m_wrappedParameter;
+ private Parameter m_parameterAnnotation;
+ private DynamicParameter m_dynamicParameterAnnotation;
+
+ /** The field/method */
+ private Parameterized m_parameterized;
+ /** Keep track of whether a value was added to flag an error */
+ private boolean m_assigned = false;
+ private ResourceBundle m_bundle;
+ private String m_description;
+ private JCommander m_jCommander;
+ private Object m_default;
+ /** Longest of the names(), used to present usage() alphabetically */
+ private String m_longestName = "";
+
+ public ParameterDescription(Object object, DynamicParameter annotation,
+ Parameterized parameterized,
+ ResourceBundle bundle, JCommander jc) {
+ if (! Map.class.isAssignableFrom(parameterized.getType())) {
+ throw new ParameterException("@DynamicParameter " + parameterized.getName()
+ + " should be of type "
+ + "Map but is " + parameterized.getType().getName());
+ }
+
+ m_dynamicParameterAnnotation = annotation;
+ m_wrappedParameter = new WrappedParameter(m_dynamicParameterAnnotation);
+ init(object, parameterized, bundle, jc);
+ }
+
+ public ParameterDescription(Object object, Parameter annotation, Parameterized parameterized,
+ ResourceBundle bundle, JCommander jc) {
+ m_parameterAnnotation = annotation;
+ m_wrappedParameter = new WrappedParameter(m_parameterAnnotation);
+ init(object, parameterized, bundle, jc);
+ }
+
+ /**
+ * Find the resource bundle in the annotations.
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ private ResourceBundle findResourceBundle(Object o) {
+ ResourceBundle result = null;
+
+ Parameters p = o.getClass().getAnnotation(Parameters.class);
+ if (p != null && ! isEmpty(p.resourceBundle())) {
+ result = ResourceBundle.getBundle(p.resourceBundle(), Locale.getDefault());
+ } else {
+ com.beust.jcommander.ResourceBundle a = o.getClass().getAnnotation(
+ com.beust.jcommander.ResourceBundle.class);
+ if (a != null && ! isEmpty(a.value())) {
+ result = ResourceBundle.getBundle(a.value(), Locale.getDefault());
+ }
+ }
+
+ return result;
+ }
+
+ private boolean isEmpty(String s) {
+ return s == null || "".equals(s);
+ }
+
+ private void initDescription(String description, String descriptionKey, String[] names) {
+ m_description = description;
+ if (! "".equals(descriptionKey)) {
+ if (m_bundle != null) {
+ m_description = m_bundle.getString(descriptionKey);
+ } else {
+// JCommander.getConsole().println("Warning: field " + object.getClass() + "." + field.getName()
+// + " has a descriptionKey but no bundle was defined with @ResourceBundle, using " +
+// "default description:'" + m_description + "'");
+ }
+ }
+
+ for (String name : names) {
+ if (name.length() > m_longestName.length()) m_longestName = name;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void init(Object object, Parameterized parameterized, ResourceBundle bundle,
+ JCommander jCommander) {
+ m_object = object;
+ m_parameterized = parameterized;
+ m_bundle = bundle;
+ if (m_bundle == null) {
+ m_bundle = findResourceBundle(object);
+ }
+ m_jCommander = jCommander;
+
+ if (m_parameterAnnotation != null) {
+ String description;
+ if (Enum.class.isAssignableFrom(parameterized.getType())
+ && m_parameterAnnotation.description().isEmpty()) {
+ description = "Options: " + EnumSet.allOf((Class<? extends Enum>) parameterized.getType());
+ }else {
+ description = m_parameterAnnotation.description();
+ }
+ initDescription(description, m_parameterAnnotation.descriptionKey(),
+ m_parameterAnnotation.names());
+ } else if (m_dynamicParameterAnnotation != null) {
+ initDescription(m_dynamicParameterAnnotation.description(),
+ m_dynamicParameterAnnotation.descriptionKey(),
+ m_dynamicParameterAnnotation.names());
+ } else {
+ throw new AssertionError("Shound never happen");
+ }
+
+ try {
+ m_default = parameterized.get(object);
+ } catch (Exception e) {
+ }
+
+ //
+ // Validate default values, if any and if applicable
+ //
+ if (m_default != null) {
+ if (m_parameterAnnotation != null) {
+ validateDefaultValues(m_parameterAnnotation.names());
+ }
+ }
+ }
+
+ private void validateDefaultValues(String[] names) {
+ String name = names.length > 0 ? names[0] : "";
+ validateValueParameter(name, m_default);
+ }
+
+ public String getLongestName() {
+ return m_longestName;
+ }
+
+ public Object getDefault() {
+ return m_default;
+ }
+
+ public String getDescription() {
+ return m_description;
+ }
+
+ public Object getObject() {
+ return m_object;
+ }
+
+ public String getNames() {
+ StringBuilder sb = new StringBuilder();
+ String[] names = m_wrappedParameter.names();
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) sb.append(", ");
+ sb.append(names[i]);
+ }
+ return sb.toString();
+ }
+
+ public WrappedParameter getParameter() {
+ return m_wrappedParameter;
+ }
+
+ public Parameterized getParameterized() {
+ return m_parameterized;
+ }
+
+ private boolean isMultiOption() {
+ Class<?> fieldType = m_parameterized.getType();
+ return fieldType.equals(List.class) || fieldType.equals(Set.class)
+ || m_parameterized.isDynamicParameter();
+ }
+
+ public void addValue(String value) {
+ addValue(value, false /* not default */);
+ }
+
+ /**
+ * @return true if this parameter received a value during the parsing phase.
+ */
+ public boolean isAssigned() {
+ return m_assigned;
+ }
+
+
+ public void setAssigned(boolean b) {
+ m_assigned = b;
+ }
+
+ /**
+ * Add the specified value to the field. First, validate the value if a
+ * validator was specified. Then look up any field converter, then any type
+ * converter, and if we can't find any, throw an exception.
+ */
+ public void addValue(String value, boolean isDefault) {
+ p("Adding " + (isDefault ? "default " : "") + "value:" + value
+ + " to parameter:" + m_parameterized.getName());
+ String name = m_wrappedParameter.names()[0];
+ if (m_assigned && ! isMultiOption() && !m_jCommander.isParameterOverwritingAllowed() || isNonOverwritableForced()) {
+ throw new ParameterException("Can only specify option " + name + " once.");
+ }
+
+ validateParameter(name, value);
+
+ Class<?> type = m_parameterized.getType();
+
+ Object convertedValue = m_jCommander.convertValue(this, value);
+ validateValueParameter(name, convertedValue);
+ boolean isCollection = Collection.class.isAssignableFrom(type);
+
+ if (isCollection) {
+ @SuppressWarnings("unchecked")
+ Collection<Object> l = (Collection<Object>) m_parameterized.get(m_object);
+ if (l == null || fieldIsSetForTheFirstTime(isDefault)) {
+ l = newCollection(type);
+ m_parameterized.set(m_object, l);
+ }
+ if (convertedValue instanceof Collection) {
+ l.addAll((Collection) convertedValue);
+ } else { // if (isMainParameter || m_parameterAnnotation.arity() > 1) {
+ l.add(convertedValue);
+// } else {
+// l.
+ }
+ } else {
+ m_wrappedParameter.addValue(m_parameterized, m_object, convertedValue);
+ }
+ if (! isDefault) m_assigned = true;
+ }
+
+ private void validateParameter(String name, String value) {
+ Class<? extends IParameterValidator> validator = m_wrappedParameter.validateWith();
+ if (validator != null) {
+ validateParameter(this, validator, name, value);
+ }
+ }
+
+ private void validateValueParameter(String name, Object value) {
+ Class<? extends IValueValidator> validator = m_wrappedParameter.validateValueWith();
+ if (validator != null) {
+ validateValueParameter(validator, name, value);
+ }
+ }
+
+ public static void validateValueParameter(Class<? extends IValueValidator> validator,
+ String name, Object value) {
+ try {
+ if (validator != NoValueValidator.class) {
+ p("Validating value parameter:" + name + " value:" + value + " validator:" + validator);
+ }
+ validator.newInstance().validate(name, value);
+ } catch (InstantiationException e) {
+ throw new ParameterException("Can't instantiate validator:" + e);
+ } catch (IllegalAccessException e) {
+ throw new ParameterException("Can't instantiate validator:" + e);
+ }
+ }
+
+ public static void validateParameter(ParameterDescription pd,
+ Class<? extends IParameterValidator> validator,
+ String name, String value) {
+ try {
+ if (validator != NoValidator.class) {
+ p("Validating parameter:" + name + " value:" + value + " validator:" + validator);
+ }
+ validator.newInstance().validate(name, value);
+ if (IParameterValidator2.class.isAssignableFrom(validator)) {
+ IParameterValidator2 instance = (IParameterValidator2) validator.newInstance();
+ instance.validate(name, value, pd);
+ }
+ } catch (InstantiationException e) {
+ throw new ParameterException("Can't instantiate validator:" + e);
+ } catch (IllegalAccessException e) {
+ throw new ParameterException("Can't instantiate validator:" + e);
+ } catch(ParameterException ex) {
+ throw ex;
+ } catch(Exception ex) {
+ throw new ParameterException(ex);
+ }
+ }
+
+ /*
+ * Creates a new collection for the field's type.
+ *
+ * Currently only List and Set are supported. Support for
+ * Queues and Stacks could be useful.
+ */
+ @SuppressWarnings("unchecked")
+ private Collection<Object> newCollection(Class<?> type) {
+ if (SortedSet.class.isAssignableFrom(type)) return new TreeSet();
+ else if (LinkedHashSet.class.isAssignableFrom(type)) return new LinkedHashSet();
+ else if (Set.class.isAssignableFrom(type)) return new HashSet();
+ else if (List.class.isAssignableFrom(type)) return new ArrayList();
+ else {
+ throw new ParameterException("Parameters of Collection type '" + type.getSimpleName()
+ + "' are not supported. Please use List or Set instead.");
+ }
+ }
+
+ /*
+ * Tests if its the first time a non-default value is
+ * being added to the field.
+ */
+ private boolean fieldIsSetForTheFirstTime(boolean isDefault) {
+ return (!isDefault && !m_assigned);
+ }
+
+ private static void p(String string) {
+ if (System.getProperty(JCommander.DEBUG_PROPERTY) != null) {
+ JCommander.getConsole().println("[ParameterDescription] " + string);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "[ParameterDescription " + m_parameterized.getName() + "]";
+ }
+
+ public boolean isDynamicParameter() {
+ return m_dynamicParameterAnnotation != null;
+ }
+
+ public boolean isHelp() {
+ return m_wrappedParameter.isHelp();
+ }
+
+ public boolean isNonOverwritableForced() {
+ return m_wrappedParameter.isNonOverwritableForced();
+ }
+}
diff --git a/src/main/java/com/beust/jcommander/ParameterException.java b/src/main/java/com/beust/jcommander/ParameterException.java
new file mode 100644
index 0000000..2bba7d1
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ParameterException.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+/**
+ * The main exception that JCommand will throw when something goes wrong while
+ * parsing parameters.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+@SuppressWarnings("serial")
+public class ParameterException extends RuntimeException {
+
+ public ParameterException(Throwable t) {
+ super(t);
+ }
+
+ public ParameterException(String string) {
+ super(string);
+ }
+
+ public ParameterException(String string, Throwable t) {
+ super(string, t);
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/Parameterized.java b/src/main/java/com/beust/jcommander/Parameterized.java
new file mode 100644
index 0000000..ff8753b
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/Parameterized.java
@@ -0,0 +1,244 @@
+package com.beust.jcommander;
+
+import com.beust.jcommander.internal.Lists;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * Encapsulate a field or a method annotated with @Parameter or @DynamicParameter
+ */
+public class Parameterized {
+
+ // Either a method or a field
+ private Field m_field;
+ private Method m_method;
+ private Method m_getter;
+
+ // Either of these two
+ private WrappedParameter m_wrappedParameter;
+ private ParametersDelegate m_parametersDelegate;
+
+ public Parameterized(WrappedParameter wp, ParametersDelegate pd,
+ Field field, Method method) {
+ m_wrappedParameter = wp;
+ m_method = method;
+ m_field = field;
+ if (m_field != null) {
+ m_field.setAccessible(true);
+ }
+ m_parametersDelegate = pd;
+ }
+
+ public static List<Parameterized> parseArg(Object arg) {
+ List<Parameterized> result = Lists.newArrayList();
+
+ Class<? extends Object> cls = arg.getClass();
+ while (!Object.class.equals(cls)) {
+ for (Field f : cls.getDeclaredFields()) {
+ Annotation annotation = f.getAnnotation(Parameter.class);
+ Annotation delegateAnnotation = f.getAnnotation(ParametersDelegate.class);
+ Annotation dynamicParameter = f.getAnnotation(DynamicParameter.class);
+ if (annotation != null) {
+ result.add(new Parameterized(new WrappedParameter((Parameter) annotation), null,
+ f, null));
+ } else if (dynamicParameter != null) {
+ result.add(new Parameterized(new WrappedParameter((DynamicParameter) dynamicParameter), null,
+ f, null));
+ } else if (delegateAnnotation != null) {
+ result.add(new Parameterized(null, (ParametersDelegate) delegateAnnotation,
+ f, null));
+ }
+ }
+ cls = cls.getSuperclass();
+ }
+
+ // Reassigning
+ cls = arg.getClass();
+ while (!Object.class.equals(cls)) {
+ for (Method m : cls.getDeclaredMethods()) {
+ Annotation annotation = m.getAnnotation(Parameter.class);
+ Annotation delegateAnnotation = m.getAnnotation(ParametersDelegate.class);
+ Annotation dynamicParameter = m.getAnnotation(DynamicParameter.class);
+ if (annotation != null) {
+ result.add(new Parameterized(new WrappedParameter((Parameter) annotation), null,
+ null, m));
+ } else if (dynamicParameter != null) {
+ result.add(new Parameterized(new WrappedParameter((DynamicParameter) annotation), null,
+ null, m));
+ } else if (delegateAnnotation != null) {
+ result.add(new Parameterized(null, (ParametersDelegate) delegateAnnotation,
+ null, m));
+ }
+ }
+ cls = cls.getSuperclass();
+ }
+
+ return result;
+ }
+
+ public WrappedParameter getWrappedParameter() {
+ return m_wrappedParameter;
+ }
+
+ public Class<?> getType() {
+ if (m_method != null) {
+ return m_method.getParameterTypes()[0];
+ } else {
+ return m_field.getType();
+ }
+ }
+
+ public String getName() {
+ if (m_method != null) {
+ return m_method.getName();
+ } else {
+ return m_field.getName();
+ }
+ }
+
+ public Object get(Object object) {
+ try {
+ if (m_method != null) {
+ if (m_getter == null) {
+ m_getter = m_method.getDeclaringClass()
+ .getMethod("g" + m_method.getName().substring(1),
+ new Class[0]);
+ }
+ return m_getter.invoke(object);
+ } else {
+ return m_field.get(object);
+ }
+ } catch (SecurityException e) {
+ throw new ParameterException(e);
+ } catch (NoSuchMethodException e) {
+ // Try to find a field
+ String name = m_method.getName();
+ String fieldName = Character.toLowerCase(name.charAt(3)) + name.substring(4);
+ Object result = null;
+ try {
+ Field field = m_method.getDeclaringClass().getDeclaredField(fieldName);
+ if (field != null) {
+ field.setAccessible(true);
+ result = field.get(object);
+ }
+ } catch(NoSuchFieldException ex) {
+ // ignore
+ } catch(IllegalAccessException ex) {
+ // ignore
+ }
+ return result;
+ } catch (IllegalArgumentException e) {
+ throw new ParameterException(e);
+ } catch (IllegalAccessException e) {
+ throw new ParameterException(e);
+ } catch (InvocationTargetException e) {
+ throw new ParameterException(e);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((m_field == null) ? 0 : m_field.hashCode());
+ result = prime * result + ((m_method == null) ? 0 : m_method.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Parameterized other = (Parameterized) obj;
+ if (m_field == null) {
+ if (other.m_field != null)
+ return false;
+ } else if (!m_field.equals(other.m_field))
+ return false;
+ if (m_method == null) {
+ if (other.m_method != null)
+ return false;
+ } else if (!m_method.equals(other.m_method))
+ return false;
+ return true;
+ }
+
+ public boolean isDynamicParameter(Field field) {
+ if (m_method != null) {
+ return m_method.getAnnotation(DynamicParameter.class) != null;
+ } else {
+ return m_field.getAnnotation(DynamicParameter.class) != null;
+ }
+ }
+
+ public void set(Object object, Object value) {
+ try {
+ if (m_method != null) {
+ m_method.invoke(object, value);
+ } else {
+ m_field.set(object, value);
+ }
+ } catch (IllegalArgumentException ex) {
+ throw new ParameterException(ex);
+ } catch (IllegalAccessException ex) {
+ throw new ParameterException(ex);
+ } catch (InvocationTargetException ex) {
+ // If a ParameterException was thrown, don't wrap it into another one
+ if (ex.getTargetException() instanceof ParameterException) {
+ throw (ParameterException) ex.getTargetException();
+ } else {
+ throw new ParameterException(ex);
+ }
+ }
+ }
+
+ public ParametersDelegate getDelegateAnnotation() {
+ return m_parametersDelegate;
+ }
+
+ public Type getGenericType() {
+ if (m_method != null) {
+ return m_method.getGenericParameterTypes()[0];
+ } else {
+ return m_field.getGenericType();
+ }
+ }
+
+ public Parameter getParameter() {
+ return m_wrappedParameter.getParameter();
+ }
+
+ /**
+ * @return the generic type of the collection for this field, or null if not applicable.
+ */
+ public Type findFieldGenericType() {
+ if (m_method != null) {
+ return null;
+ } else {
+ if (m_field.getGenericType() instanceof ParameterizedType) {
+ ParameterizedType p = (ParameterizedType) m_field.getGenericType();
+ Type cls = p.getActualTypeArguments()[0];
+ if (cls instanceof Class) {
+ return cls;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public boolean isDynamicParameter() {
+ return m_wrappedParameter.getDynamicParameter() != null;
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/Parameters.java b/src/main/java/com/beust/jcommander/Parameters.java
new file mode 100644
index 0000000..f2e8c76
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/Parameters.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ * An annotation used to specify settings for parameter parsing.
+ *
+ * @author cbeust
+ */
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({ TYPE })
+@Inherited
+public @interface Parameters {
+
+ public static final String DEFAULT_OPTION_PREFIXES = "-";
+
+ /**
+ * The name of the resource bundle to use for this class.
+ */
+ String resourceBundle() default "";
+
+ /**
+ * The character(s) that separate options.
+ */
+ String separators() default " ";
+
+ /**
+ * What characters an option starts with.
+ */
+ String optionPrefixes() default DEFAULT_OPTION_PREFIXES;
+
+ /**
+ * If the annotated class was added to {@link JCommander} as a command with
+ * {@link JCommander#addCommand}, then this string will be displayed in the
+ * description when @{link JCommander#usage} is invoked.
+ */
+ String commandDescription() default "";
+
+ /**
+ * @return the key used to find the command description in the resource bundle.
+ */
+ String commandDescriptionKey() default "";
+
+ /**
+ * An array of allowed command names.
+ */
+ String[] commandNames() default {};
+
+ /**
+ * If true, this command won't appear in the usage().
+ */
+ boolean hidden() default false;
+}
diff --git a/src/main/java/com/beust/jcommander/ParametersDelegate.java b/src/main/java/com/beust/jcommander/ParametersDelegate.java
new file mode 100644
index 0000000..5a06f8e
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ParametersDelegate.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+
+/**
+ * <p>When applied to a field all of its child fields annotated
+ * with {@link Parameter} will be included during arguments
+ * parsing.</p>
+ *
+ * <p>Mainly useful when creating complex command based CLI interfaces,
+ * where several commands can share a set of arguments, but using
+ * object inheritance is not enough, due to no-multiple-inheritance
+ * restriction. Using {@link ParametersDelegate} any number of
+ * command sets can be shared by using composition pattern.</p>
+ *
+ * <p>Delegations can be chained (nested).</p>
+ *
+ * @author rodionmoiseev
+ */
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({ FIELD })
+public @interface ParametersDelegate {
+}
diff --git a/src/main/java/com/beust/jcommander/ResourceBundle.java b/src/main/java/com/beust/jcommander/ResourceBundle.java
new file mode 100644
index 0000000..806ade8
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/ResourceBundle.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * @deprecated use @Parameters
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({ TYPE })
+public @interface ResourceBundle {
+ /**
+ * The name of the resource bundle to use for this class.
+ */
+ String value();
+}
diff --git a/src/main/java/com/beust/jcommander/StringKey.java b/src/main/java/com/beust/jcommander/StringKey.java
new file mode 100644
index 0000000..09d1149
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/StringKey.java
@@ -0,0 +1,48 @@
+package com.beust.jcommander;
+
+import com.beust.jcommander.FuzzyMap.IKey;
+
+public class StringKey implements IKey {
+
+ private String m_name;
+
+ public StringKey(String name) {
+ m_name = name;
+ }
+
+ @Override
+ public String getName() {
+ return m_name;
+ }
+
+ @Override
+ public String toString() {
+ return m_name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StringKey other = (StringKey) obj;
+ if (m_name == null) {
+ if (other.m_name != null)
+ return false;
+ } else if (!m_name.equals(other.m_name))
+ return false;
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/Strings.java b/src/main/java/com/beust/jcommander/Strings.java
new file mode 100644
index 0000000..591a38a
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/Strings.java
@@ -0,0 +1,7 @@
+package com.beust.jcommander;
+
+public class Strings {
+ public static boolean isStringEmpty(String s) {
+ return s == null || "".equals(s);
+ }
+}
diff --git a/src/main/java/com/beust/jcommander/WrappedParameter.java b/src/main/java/com/beust/jcommander/WrappedParameter.java
new file mode 100644
index 0000000..f4e7d56
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/WrappedParameter.java
@@ -0,0 +1,115 @@
+package com.beust.jcommander;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Encapsulates the operations common to @Parameter and @DynamicParameter
+ */
+public class WrappedParameter {
+ private Parameter m_parameter;
+ private DynamicParameter m_dynamicParameter;
+
+ public WrappedParameter(Parameter p) {
+ m_parameter = p;
+ }
+
+ public WrappedParameter(DynamicParameter p) {
+ m_dynamicParameter = p;
+ }
+
+ public Parameter getParameter() {
+ return m_parameter;
+ }
+
+ public DynamicParameter getDynamicParameter() {
+ return m_dynamicParameter;
+ }
+
+ public int arity() {
+ return m_parameter != null ? m_parameter.arity() : 1;
+ }
+
+ public boolean hidden() {
+ return m_parameter != null ? m_parameter.hidden() : m_dynamicParameter.hidden();
+ }
+
+ public boolean required() {
+ return m_parameter != null ? m_parameter.required() : m_dynamicParameter.required();
+ }
+
+ public boolean password() {
+ return m_parameter != null ? m_parameter.password() : false;
+ }
+
+ public String[] names() {
+ return m_parameter != null ? m_parameter.names() : m_dynamicParameter.names();
+ }
+
+ public boolean variableArity() {
+ return m_parameter != null ? m_parameter.variableArity() : false;
+ }
+
+ public Class<? extends IParameterValidator> validateWith() {
+ return m_parameter != null ? m_parameter.validateWith() : m_dynamicParameter.validateWith();
+ }
+
+ public Class<? extends IValueValidator> validateValueWith() {
+ return m_parameter != null
+ ? m_parameter.validateValueWith()
+ : m_dynamicParameter.validateValueWith();
+ }
+
+ public boolean echoInput() {
+ return m_parameter != null ? m_parameter.echoInput() : false;
+ }
+
+ public void addValue(Parameterized parameterized, Object object, Object value) {
+ if (m_parameter != null) {
+ parameterized.set(object, value);
+ } else {
+ String a = m_dynamicParameter.assignment();
+ String sv = value.toString();
+
+ int aInd = sv.indexOf(a);
+ if (aInd == -1) {
+ throw new ParameterException(
+ "Dynamic parameter expected a value of the form a" + a + "b"
+ + " but got:" + sv);
+ }
+ callPut(object, parameterized, sv.substring(0, aInd), sv.substring(aInd + 1));
+ }
+ }
+
+ private void callPut(Object object, Parameterized parameterized, String key, String value) {
+ try {
+ Method m;
+ m = findPut(parameterized.getType());
+ m.invoke(parameterized.get(object), key, value);
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch(IllegalAccessException e) {
+ e.printStackTrace();
+ } catch(InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Method findPut(Class<?> cls) throws SecurityException, NoSuchMethodException {
+ return cls.getMethod("put", Object.class, Object.class);
+ }
+
+ public String getAssignment() {
+ return m_dynamicParameter != null ? m_dynamicParameter.assignment() : "";
+ }
+
+ public boolean isHelp() {
+ return m_parameter != null && m_parameter.help();
+ }
+
+ public boolean isNonOverwritableForced() {
+ return m_parameter != null && m_parameter.forceNonOverwritable();
+ }
+}
diff --git a/src/main/java/com/beust/jcommander/converters/BaseConverter.java b/src/main/java/com/beust/jcommander/converters/BaseConverter.java
new file mode 100644
index 0000000..4287163
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/BaseConverter.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.IStringConverter;
+
+/**
+ * Base class for converters that stores the name of the option.
+ *
+ * @author cbeust
+ */
+abstract public class BaseConverter<T> implements IStringConverter<T> {
+
+ private String m_optionName;
+
+ public BaseConverter(String optionName) {
+ m_optionName = optionName;
+ }
+
+ public String getOptionName() {
+ return m_optionName;
+ }
+
+ protected String getErrorString(String value, String to) {
+ return "\"" + getOptionName() + "\": couldn't convert \"" + value + "\" to " + to;
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java
new file mode 100644
index 0000000..dfbba34
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/BigDecimalConverter.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+import java.math.BigDecimal;
+
+/**
+ * Converts a String to a BigDecimal.
+ *
+ * @author Angus Smithson
+ */
+public class BigDecimalConverter extends BaseConverter<BigDecimal> {
+
+ public BigDecimalConverter(String optionName) {
+ super(optionName);
+ }
+
+ public BigDecimal convert(String value) {
+ try {
+ return new BigDecimal(value);
+ } catch (NumberFormatException nfe) {
+ throw new ParameterException(getErrorString(value, "a BigDecimal"));
+ }
+ }
+}
diff --git a/src/main/java/com/beust/jcommander/converters/BooleanConverter.java b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java
new file mode 100644
index 0000000..5126d22
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/BooleanConverter.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+/**
+ * Converts a string to a boolean.
+ *
+ * @author cbeust
+ */
+public class BooleanConverter extends BaseConverter<Boolean> {
+
+ public BooleanConverter(String optionName) {
+ super(optionName);
+ }
+
+ public Boolean convert(String value) {
+ if ("false".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value)) {
+ return Boolean.parseBoolean(value);
+ } else {
+ throw new ParameterException(getErrorString(value, "a boolean"));
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java b/src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java
new file mode 100644
index 0000000..0e3bb18
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/CommaParameterSplitter.java
@@ -0,0 +1,12 @@
+package com.beust.jcommander.converters;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class CommaParameterSplitter implements IParameterSplitter {
+
+ public List<String> split(String value) {
+ return Arrays.asList(value.split(","));
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/DoubleConverter.java b/src/main/java/com/beust/jcommander/converters/DoubleConverter.java
new file mode 100644
index 0000000..0c36c68
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/DoubleConverter.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+/**
+ * Convert a string to a double.
+ *
+ * @author acornejo
+ */
+public class DoubleConverter extends BaseConverter<Double> {
+
+ public DoubleConverter(String optionName) {
+ super(optionName);
+ }
+
+ public Double convert(String value) {
+ try {
+ return Double.parseDouble(value);
+ } catch(NumberFormatException ex) {
+ throw new ParameterException(getErrorString(value, "a double"));
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/FileConverter.java b/src/main/java/com/beust/jcommander/converters/FileConverter.java
new file mode 100644
index 0000000..c18b575
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/FileConverter.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.IStringConverter;
+
+import java.io.File;
+
+/**
+ * Convert a string into a file.
+ *
+ * @author cbeust
+ */
+public class FileConverter implements IStringConverter<File> {
+
+ public File convert(String value) {
+ return new File(value);
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/FloatConverter.java b/src/main/java/com/beust/jcommander/converters/FloatConverter.java
new file mode 100644
index 0000000..2e2eff8
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/FloatConverter.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+/**
+ * Convert a string to a float.
+ *
+ * @author acornejo
+ */
+public class FloatConverter extends BaseConverter<Float> {
+
+ public FloatConverter(String optionName) {
+ super(optionName);
+ }
+
+ public Float convert(String value) {
+ try {
+ return Float.parseFloat(value);
+ } catch(NumberFormatException ex) {
+ throw new ParameterException(getErrorString(value, "a float"));
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java b/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java
new file mode 100644
index 0000000..5859f4a
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/IParameterSplitter.java
@@ -0,0 +1,11 @@
+package com.beust.jcommander.converters;
+
+import java.util.List;
+
+/**
+ * Convert a string representing several parameters (e.g. "a,b,c" or "d/e/f") into a
+ * list of arguments ([a,b,c] and [d,e,f]).
+ */
+public interface IParameterSplitter {
+ List<String> split(String value);
+}
diff --git a/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java
new file mode 100644
index 0000000..f024f5c
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/ISO8601DateConverter.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Converts a String to a Date.
+ * TODO Modify to work with all valid ISO 8601 date formats (currently only works with yyyy-MM-dd).
+ *
+ * @author Angus Smithson
+ */
+public class ISO8601DateConverter extends BaseConverter<Date> {
+
+ private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+ public ISO8601DateConverter(String optionName) {
+ super(optionName);
+ }
+
+ public Date convert(String value) {
+ try {
+ return DATE_FORMAT.parse(value);
+ } catch (ParseException pe) {
+ throw new ParameterException(getErrorString(value, String.format("an ISO-8601 formatted date (%s)", DATE_FORMAT.toPattern())));
+ }
+ }
+}
diff --git a/src/main/java/com/beust/jcommander/converters/IntegerConverter.java b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java
new file mode 100644
index 0000000..53d1119
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/IntegerConverter.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+/**
+ * Convert a string to an integer.
+ *
+ * @author cbeust
+ */
+public class IntegerConverter extends BaseConverter<Integer> {
+
+ public IntegerConverter(String optionName) {
+ super(optionName);
+ }
+
+ public Integer convert(String value) {
+ try {
+ return Integer.parseInt(value);
+ } catch(NumberFormatException ex) {
+ throw new ParameterException(getErrorString(value, "an integer"));
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/LongConverter.java b/src/main/java/com/beust/jcommander/converters/LongConverter.java
new file mode 100644
index 0000000..863956b
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/LongConverter.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+/**
+ * Convert a string to a long.
+ *
+ * @author cbeust
+ */
+public class LongConverter extends BaseConverter<Long> {
+
+ public LongConverter(String optionName) {
+ super(optionName);
+ }
+
+ public Long convert(String value) {
+ try {
+ return Long.parseLong(value);
+ } catch(NumberFormatException ex) {
+ throw new ParameterException(getErrorString(value, "a long"));
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/NoConverter.java b/src/main/java/com/beust/jcommander/converters/NoConverter.java
new file mode 100644
index 0000000..618daf9
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/NoConverter.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.IStringConverter;
+
+/**
+ * Default value for a converter when none is specified.
+ *
+ * @author cbeust
+ */
+public class NoConverter implements IStringConverter<String> {
+
+ public String convert(String value) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/PathConverter.java b/src/main/java/com/beust/jcommander/converters/PathConverter.java
new file mode 100644
index 0000000..b7fdafd
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/PathConverter.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.IStringConverter;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Convert a string into a path.
+ *
+ * @author samvv
+ */
+public class PathConverter implements IStringConverter<Path> {
+
+ public Path convert(String value) {
+ return Paths.get(value);
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/StringConverter.java b/src/main/java/com/beust/jcommander/converters/StringConverter.java
new file mode 100644
index 0000000..ea1ae38
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/StringConverter.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.IStringConverter;
+
+/**
+ * Default converter for strings.
+ *
+ * @author cbeust
+ */
+public class StringConverter implements IStringConverter<String> {
+
+ public String convert(String value) {
+ return value;
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/URIConverter.java b/src/main/java/com/beust/jcommander/converters/URIConverter.java
new file mode 100644
index 0000000..3473bf0
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/URIConverter.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ * Convert a string into a URI.
+ *
+ * @author samvv
+ */
+public class URIConverter extends BaseConverter<URI> {
+
+ public URIConverter(String optionName) {
+ super(optionName);
+ }
+
+ public URI convert(String value) {
+ try {
+ return new URI(value);
+ } catch (URISyntaxException e) {
+ throw new ParameterException(getErrorString(value, "a RFC 2396 and RFC 2732 compliant URI"));
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/converters/URLConverter.java b/src/main/java/com/beust/jcommander/converters/URLConverter.java
new file mode 100644
index 0000000..1f3734b
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/converters/URLConverter.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.converters;
+
+import com.beust.jcommander.ParameterException;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Convert a string into a URI.
+ *
+ * @author samvv
+ */
+public class URLConverter extends BaseConverter<URL> {
+
+ public URLConverter(String optionName) {
+ super(optionName);
+ }
+
+ public URL convert(String value) {
+ try {
+ return new URL(value);
+ } catch (MalformedURLException e) {
+ throw new ParameterException(
+ getErrorString(value, "a RFC 2396 and RFC 2732 compliant URL"));
+
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java
new file mode 100644
index 0000000..d5401a1
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/defaultprovider/PropertyFileDefaultProvider.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.defaultprovider;
+
+import com.beust.jcommander.IDefaultProvider;
+import com.beust.jcommander.ParameterException;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+/**
+ * A default provider that reads its default values from a property file.
+ *
+ * @author cbeust
+ */
+public class PropertyFileDefaultProvider implements IDefaultProvider {
+ public static final String DEFAULT_FILE_NAME = "jcommander.properties";
+ private Properties m_properties;
+
+ public PropertyFileDefaultProvider() {
+ init(DEFAULT_FILE_NAME);
+ }
+
+ public PropertyFileDefaultProvider(String fileName) {
+ init(fileName);
+ }
+
+ private void init(String fileName) {
+ try {
+ m_properties = new Properties();
+ URL url = ClassLoader.getSystemResource(fileName);
+ if (url != null) {
+ m_properties.load(url.openStream());
+ } else {
+ throw new ParameterException("Could not find property file: " + fileName
+ + " on the class path");
+ }
+ }
+ catch (IOException e) {
+ throw new ParameterException("Could not open property file: " + fileName);
+ }
+ }
+
+ public String getDefaultValueFor(String optionName) {
+ int index = 0;
+ while (index < optionName.length() && ! Character.isLetterOrDigit(optionName.charAt(index))) {
+ index++;
+ }
+ String key = optionName.substring(index);
+ return m_properties.getProperty(key);
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/internal/Console.java b/src/main/java/com/beust/jcommander/internal/Console.java
new file mode 100644
index 0000000..95eafe1
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/Console.java
@@ -0,0 +1,10 @@
+package com.beust.jcommander.internal;
+
+public interface Console {
+
+ void print(String msg);
+
+ void println(String msg);
+
+ char[] readPassword(boolean echoInput);
+}
diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConsole.java b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java
new file mode 100644
index 0000000..8fd7d6d
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/DefaultConsole.java
@@ -0,0 +1,32 @@
+package com.beust.jcommander.internal;
+
+import com.beust.jcommander.ParameterException;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class DefaultConsole implements Console {
+
+ public void print(String msg) {
+ System.out.print(msg);
+ }
+
+ public void println(String msg) {
+ System.out.println(msg);
+ }
+
+ public char[] readPassword(boolean echoInput) {
+ try {
+ // Do not close the readers since System.in should not be closed
+ InputStreamReader isr = new InputStreamReader(System.in);
+ BufferedReader in = new BufferedReader(isr);
+ String result = in.readLine();
+ return result.toCharArray();
+ }
+ catch (IOException e) {
+ throw new ParameterException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java
new file mode 100644
index 0000000..7eb5ae5
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/DefaultConverterFactory.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.internal;
+
+import com.beust.jcommander.IStringConverter;
+import com.beust.jcommander.IStringConverterFactory;
+import com.beust.jcommander.converters.BigDecimalConverter;
+import com.beust.jcommander.converters.BooleanConverter;
+import com.beust.jcommander.converters.DoubleConverter;
+import com.beust.jcommander.converters.FileConverter;
+import com.beust.jcommander.converters.FloatConverter;
+import com.beust.jcommander.converters.ISO8601DateConverter;
+import com.beust.jcommander.converters.IntegerConverter;
+import com.beust.jcommander.converters.LongConverter;
+import com.beust.jcommander.converters.StringConverter;
+import com.beust.jcommander.converters.URIConverter;
+import com.beust.jcommander.converters.URLConverter;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.net.URI;
+import java.net.URL;
+import java.util.Map;
+
+public class DefaultConverterFactory implements IStringConverterFactory {
+ /**
+ * A map of converters per class.
+ */
+ private static Map<Class, Class<? extends IStringConverter<?>>> m_classConverters;
+
+ static {
+ m_classConverters = Maps.newHashMap();
+ m_classConverters.put(String.class, StringConverter.class);
+ m_classConverters.put(Integer.class, IntegerConverter.class);
+ m_classConverters.put(int.class, IntegerConverter.class);
+ m_classConverters.put(Long.class, LongConverter.class);
+ m_classConverters.put(long.class, LongConverter.class);
+ m_classConverters.put(Float.class, FloatConverter.class);
+ m_classConverters.put(float.class, FloatConverter.class);
+ m_classConverters.put(Double.class, DoubleConverter.class);
+ m_classConverters.put(double.class, DoubleConverter.class);
+ m_classConverters.put(Boolean.class, BooleanConverter.class);
+ m_classConverters.put(boolean.class, BooleanConverter.class);
+ m_classConverters.put(File.class, FileConverter.class);
+ m_classConverters.put(BigDecimal.class, BigDecimalConverter.class);
+ m_classConverters.put(Date.class, ISO8601DateConverter.class);
+ try {
+ Class<?> pathClass = Class.forName("java.nio.file.Path");
+ Class<?> pathConverterClass = Class.forName("com.beust.jcommander.converters.PathConverter");
+ m_classConverters.put(pathClass, (Class<? extends IStringConverter<?>>)pathConverterClass);
+ } catch (ClassNotFoundException e) {
+ // Do nothing: Android does not have java.nio.file.Path
+ }
+ m_classConverters.put(URI.class, URIConverter.class);
+ m_classConverters.put(URL.class, URLConverter.class);
+ }
+
+ public Class<? extends IStringConverter<?>> getConverter(Class forType) {
+ return m_classConverters.get(forType);
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/internal/JDK6Console.java b/src/main/java/com/beust/jcommander/internal/JDK6Console.java
new file mode 100644
index 0000000..70cb186
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/JDK6Console.java
@@ -0,0 +1,45 @@
+package com.beust.jcommander.internal;
+
+import com.beust.jcommander.ParameterException;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Method;
+
+public class JDK6Console implements Console {
+
+ private Object console;
+
+ private PrintWriter writer;
+
+ public JDK6Console(Object console) throws Exception {
+ this.console = console;
+ Method writerMethod = console.getClass().getDeclaredMethod("writer", new Class<?>[0]);
+ writer = (PrintWriter) writerMethod.invoke(console, new Object[0]);
+ }
+
+ public void print(String msg) {
+ writer.print(msg);
+ }
+
+ public void println(String msg) {
+ writer.println(msg);
+ }
+
+ public char[] readPassword(boolean echoInput) {
+ try {
+ writer.flush();
+ Method method;
+ if (echoInput) {
+ method = console.getClass().getDeclaredMethod("readLine", new Class<?>[0]);
+ return ((String) method.invoke(console, new Object[0])).toCharArray();
+ } else {
+ method = console.getClass().getDeclaredMethod("readPassword", new Class<?>[0]);
+ return (char[]) method.invoke(console, new Object[0]);
+ }
+ }
+ catch (Exception e) {
+ throw new ParameterException(e);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/com/beust/jcommander/internal/Lists.java b/src/main/java/com/beust/jcommander/internal/Lists.java
new file mode 100644
index 0000000..fdbee55
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/Lists.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+public class Lists {
+
+ public static <K> List<K> newArrayList() {
+ return new ArrayList<K>();
+ }
+
+ public static <K> List<K> newArrayList(Collection<K> c) {
+ return new ArrayList<K>(c);
+ }
+
+ public static <K> List<K> newArrayList(K... c) {
+ return new ArrayList<K>(Arrays.asList(c));
+ }
+
+ public static <K> List<K> newArrayList(int size) {
+ return new ArrayList<K>(size);
+ }
+
+ public static <K> LinkedList<K> newLinkedList() {
+ return new LinkedList<K>();
+ }
+
+ public static <K> LinkedList<K> newLinkedList(Collection<K> c) {
+ return new LinkedList<K>(c);
+ }
+
+
+}
diff --git a/src/main/java/com/beust/jcommander/internal/Maps.java b/src/main/java/com/beust/jcommander/internal/Maps.java
new file mode 100644
index 0000000..e272122
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/Maps.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.internal;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class Maps {
+
+ public static <K, V> Map<K,V> newHashMap() {
+ return new HashMap<K, V>();
+ }
+
+ public static <K, V> Map<K,V> newLinkedHashMap() {
+ return new LinkedHashMap<K, V>();
+ }
+
+ public static <T> Map<T, T> newHashMap(T... parameters) {
+ Map<T, T> result = Maps.newHashMap();
+ for (int i = 0; i < parameters.length; i += 2) {
+ result.put(parameters[i], parameters[i + 1]);
+ }
+ return result;
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/internal/Nullable.java b/src/main/java/com/beust/jcommander/internal/Nullable.java
new file mode 100644
index 0000000..b988373
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/Nullable.java
@@ -0,0 +1,12 @@
+package com.beust.jcommander.internal;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@Target({FIELD, PARAMETER})
+public @interface Nullable {
+}
diff --git a/src/main/java/com/beust/jcommander/internal/Sets.java b/src/main/java/com/beust/jcommander/internal/Sets.java
new file mode 100644
index 0000000..77949c3
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/internal/Sets.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.internal;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class Sets {
+
+ public static <K> Set<K> newHashSet() {
+ return new HashSet<K>();
+ }
+
+ public static <K> Set<K> newLinkedHashSet() {
+ return new LinkedHashSet<K>();
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/validators/NoValidator.java b/src/main/java/com/beust/jcommander/validators/NoValidator.java
new file mode 100644
index 0000000..f1b4df2
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/validators/NoValidator.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2011 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.validators;
+
+import com.beust.jcommander.IParameterValidator;
+import com.beust.jcommander.ParameterException;
+
+/**
+ * This is the default value of the validateWith attribute.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+public class NoValidator implements IParameterValidator {
+
+ public void validate(String parameterName, String parameterValue)
+ throws ParameterException {
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/validators/NoValueValidator.java b/src/main/java/com/beust/jcommander/validators/NoValueValidator.java
new file mode 100644
index 0000000..21fa820
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/validators/NoValueValidator.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2011 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.validators;
+
+import com.beust.jcommander.IValueValidator;
+import com.beust.jcommander.ParameterException;
+
+/**
+ * This is the default value of the validateValueWith attribute.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+public class NoValueValidator<T> implements IValueValidator<T> {
+
+ public void validate(String parameterName, T parameterValue)
+ throws ParameterException {
+ }
+
+}
diff --git a/src/main/java/com/beust/jcommander/validators/PositiveInteger.java b/src/main/java/com/beust/jcommander/validators/PositiveInteger.java
new file mode 100644
index 0000000..7b5c1b7
--- /dev/null
+++ b/src/main/java/com/beust/jcommander/validators/PositiveInteger.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2011 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.validators;
+
+import com.beust.jcommander.IParameterValidator;
+import com.beust.jcommander.ParameterException;
+
+/**
+ * A validator that makes sure the value of the parameter is a positive integer.
+ *
+ * @author Cedric Beust <cedric@beust.com>
+ */
+public class PositiveInteger implements IParameterValidator {
+
+ public void validate(String name, String value)
+ throws ParameterException {
+ int n = Integer.parseInt(value);
+ if (n < 0) {
+ throw new ParameterException("Parameter " + name
+ + " should be positive (found " + value +")");
+ }
+ }
+
+}
diff --git a/src/main/license/license-header.txt b/src/main/license/license-header.txt
new file mode 100644
index 0000000..4cbe379
--- /dev/null
+++ b/src/main/license/license-header.txt
@@ -0,0 +1,15 @@
+Copyright (C) 2010 the original author or authors.
+See the notice.md file distributed with this work for additional
+information regarding copyright ownership.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/src/test/java/com/beust/jcommander/ArgsRequiredWrongMain.java b/src/test/java/com/beust/jcommander/ArgsRequiredWrongMain.java
new file mode 100644
index 0000000..c2124d9
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/ArgsRequiredWrongMain.java
@@ -0,0 +1,6 @@
+package com.beust.jcommander;
+
+public class ArgsRequiredWrongMain {
+ @Parameter(required = true)
+ public String[] file;
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/ArgsValidate2.java b/src/test/java/com/beust/jcommander/ArgsValidate2.java
new file mode 100644
index 0000000..2b8f07b
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/ArgsValidate2.java
@@ -0,0 +1,24 @@
+package com.beust.jcommander;
+
+import com.beust.jcommander.converters.FileConverter;
+
+import java.io.File;
+
+public class ArgsValidate2 {
+ public static class FailingValidator implements IValueValidator<File> {
+
+ public void validate(String name, File value) throws ParameterException {
+ throw new ParameterException("Validation will always fail:" + name + " " + value);
+ }
+
+ }
+
+ public static final String POSSIBLE_TEMPLATE_FILE = "mayOrMayNotExist.template";
+
+ @Parameter(names = { "-template"},
+ description = "The default file may or may not exist",
+ converter = FileConverter.class,
+ validateValueWith = FailingValidator.class
+ )
+ public File template = new File(POSSIBLE_TEMPLATE_FILE);
+}
diff --git a/src/test/java/com/beust/jcommander/CmdTest.java b/src/test/java/com/beust/jcommander/CmdTest.java
new file mode 100644
index 0000000..6601193
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/CmdTest.java
@@ -0,0 +1,86 @@
+package com.beust.jcommander;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class CmdTest {
+
+ @Parameters(commandNames = "--cmd-one")
+ public static class CmdOne {
+ }
+
+ @Parameters(commandNames = "--cmd-two")
+ class CmdTwo {
+ @Parameter
+ List<String> params = new java.util.LinkedList<String>();
+ }
+
+ public String parseArgs(boolean withDefault, String[] args) {
+ JCommander jc = new JCommander();
+ jc.addCommand(new CmdOne());
+ jc.addCommand(new CmdTwo());
+
+ if (withDefault) {
+ // First check if a command was given, when not prepend default
+ // command (--cmd-two")
+ // In version up to 1.23 JCommander throws an Exception in this
+ // line,
+ // which might be incorrect, at least its not reasonable if the
+ // method
+ // is named "WithoutValidation".
+ jc.parseWithoutValidation(args);
+ if (jc.getParsedCommand() == null) {
+ LinkedList<String> newArgs = new LinkedList<String>();
+ newArgs.add("--cmd-two");
+ newArgs.addAll(Arrays.asList(args));
+ jc.parse(newArgs.toArray(new String[0]));
+ }
+ } else {
+ jc.parse(args);
+ }
+ return jc.getParsedCommand();
+ }
+
+ @DataProvider
+ public Object[][] testData() {
+ return new Object[][] {
+ new Object[] { "--cmd-one", false, new String[] { "--cmd-one" } },
+ new Object[] { "--cmd-two", false, new String[] { "--cmd-two" } },
+ new Object[] { "--cmd-two", false,
+ new String[] { "--cmd-two", "param1", "param2" } },
+ // This is the relevant test case to test default commands
+ new Object[] { "--cmd-two", true,
+ new String[] { "param1", "param2" } } };
+ }
+
+ @Test(dataProvider = "testData")
+ public void testArgsWithoutDefaultCmd(String expected,
+ boolean requireDefault, String[] args) {
+ if (!requireDefault) {
+ Assert.assertEquals(parseArgs(false, args), expected);
+ }
+ }
+
+ @Test(dataProvider = "testData", expectedExceptions = MissingCommandException.class)
+ public void testArgsWithoutDefaultCmdFail(String expected,
+ boolean requireDefault, String[] args) {
+ if (requireDefault) {
+ parseArgs(false, args);
+ } else {
+ throw new MissingCommandException("irrelevant test case");
+ }
+ }
+
+ // We do not expect a MissingCommandException!
+ @Test(dataProvider = "testData")
+ public void testArgsWithDefaultCmd(String expected, boolean requireDefault,
+ String[] args) {
+ Assert.assertEquals(parseArgs(true, args), expected);
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/ConverterFactoryTest.java b/src/test/java/com/beust/jcommander/ConverterFactoryTest.java
new file mode 100644
index 0000000..e02166e
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/ConverterFactoryTest.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import com.beust.jcommander.args.ArgsConverterFactory;
+import com.beust.jcommander.args.ArgsMainParameter1;
+import com.beust.jcommander.args.ArgsMainParameter2;
+import com.beust.jcommander.args.IHostPorts;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Test the converter factory feature.
+ *
+ * @author cbeust
+ */
+public class ConverterFactoryTest {
+ private static final Map<Class, Class<? extends IStringConverter<?>>> MAP = new HashMap() {{
+ put(HostPort.class, HostPortConverter.class);
+ }};
+
+ private static final IStringConverterFactory CONVERTER_FACTORY = new IStringConverterFactory() {
+
+ public Class<? extends IStringConverter<?>> getConverter(Class forType) {
+ return MAP.get(forType);
+ }
+
+ };
+
+ @Test
+ public void parameterWithHostPortParameters() {
+ ArgsConverterFactory a = new ArgsConverterFactory();
+ JCommander jc = new JCommander(a);
+ jc.addConverterFactory(CONVERTER_FACTORY);
+ jc.parse("-hostport", "example.com:8080");
+
+ Assert.assertEquals(a.hostPort.host, "example.com");
+ Assert.assertEquals(a.hostPort.port.intValue(), 8080);
+ }
+
+ /**
+ * Test that main parameters can be used with string converters,
+ * either with a factory or from the annotation.
+ */
+ private void mainWithHostPortParameters(IStringConverterFactory f, IHostPorts a) {
+ JCommander jc = new JCommander(a);
+ if (f != null) jc.addConverterFactory(f);
+ jc.parse("a.com:10", "b.com:20");
+ Assert.assertEquals(a.getHostPorts().get(0).host, "a.com");
+ Assert.assertEquals(a.getHostPorts().get(0).port.intValue(), 10);
+ Assert.assertEquals(a.getHostPorts().get(1).host, "b.com");
+ Assert.assertEquals(a.getHostPorts().get(1).port.intValue(), 20);
+ }
+
+ @Test
+ public void mainWithoutFactory() {
+ mainWithHostPortParameters(null, new ArgsMainParameter1());
+ }
+
+ @Test
+ public void mainWithFactory() {
+ mainWithHostPortParameters(CONVERTER_FACTORY, new ArgsMainParameter2());
+ }
+
+}
+
diff --git a/src/test/java/com/beust/jcommander/DefaultProviderTest.java b/src/test/java/com/beust/jcommander/DefaultProviderTest.java
new file mode 100644
index 0000000..45ab6b6
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/DefaultProviderTest.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import com.beust.jcommander.args.ArgsDefault;
+import com.beust.jcommander.defaultprovider.PropertyFileDefaultProvider;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class DefaultProviderTest {
+ private static final IDefaultProvider DEFAULT_PROVIDER = new IDefaultProvider() {
+
+ public String getDefaultValueFor(String optionName) {
+ return "-debug".equals(optionName) ? "false" : "42";
+ }
+
+ };
+
+ private ArgsDefault defaultProvider(IDefaultProvider provider, String... args) {
+ ArgsDefault a = new ArgsDefault();
+ JCommander jc = new JCommander(a);
+ jc.setDefaultProvider(provider);
+
+ jc.parse(args);
+ return a;
+ }
+
+ @Test
+ public void defaultProvider1() {
+ ArgsDefault a = defaultProvider(DEFAULT_PROVIDER, "f");
+
+ Assert.assertEquals(a.groups, "42");
+ Assert.assertEquals(a.level, 42);
+ Assert.assertEquals(a.log.intValue(), 42);
+ }
+
+ @Test
+ public void defaultProvider2() {
+ ArgsDefault a = defaultProvider(DEFAULT_PROVIDER, "-groups", "foo", "f");
+
+ Assert.assertEquals(a.groups, "foo");
+ Assert.assertEquals(a.level, 42);
+ Assert.assertEquals(a.log.intValue(), 42);
+ }
+
+ @Test
+ public void defaultProvider3() {
+ ArgsDefault a = defaultProvider(DEFAULT_PROVIDER, "-groups", "foo", "-level", "13", "f");
+
+ Assert.assertEquals(a.groups, "foo");
+ Assert.assertEquals(a.level, 13);
+ Assert.assertEquals(a.log.intValue(), 42);
+ }
+
+ @Test
+ public void defaultProvider4() {
+ ArgsDefault a = defaultProvider(DEFAULT_PROVIDER,
+ "-log", "19", "-groups", "foo", "-level", "13", "f");
+
+ Assert.assertEquals(a.groups, "foo");
+ Assert.assertEquals(a.level, 13);
+ Assert.assertEquals(a.log.intValue(), 19);
+ }
+
+ @Test
+ public void propertyFileDefaultProvider1() {
+ ArgsDefault a = defaultProvider(new PropertyFileDefaultProvider(), "f");
+
+ Assert.assertEquals(a.groups, "unit");
+ Assert.assertEquals(a.level, 17);
+ Assert.assertEquals(a.log.intValue(), 18);
+ }
+
+ @Test
+ public void propertyFileDefaultProvider2() {
+ ArgsDefault a = defaultProvider(new PropertyFileDefaultProvider(), "-groups", "foo", "f");
+
+ Assert.assertEquals(a.groups, "foo");
+ Assert.assertEquals(a.level, 17);
+ Assert.assertEquals(a.log.intValue(), 18);
+ }
+
+ @Test
+ public void propertyFileDefaultProvider3() {
+ ArgsDefault a = defaultProvider(new PropertyFileDefaultProvider(),
+ "-groups", "foo", "-level", "13", "f");
+
+ Assert.assertEquals(a.groups, "foo");
+ Assert.assertEquals(a.level, 13);
+ Assert.assertEquals(a.log.intValue(), 18);
+ }
+
+ @Test
+ public void propertyFileDefaultProvider4() {
+ ArgsDefault a = defaultProvider(new PropertyFileDefaultProvider(),
+ "-log", "19", "-groups", "foo", "-level", "13", "f");
+
+ Assert.assertEquals(a.groups, "foo");
+ Assert.assertEquals(a.level, 13);
+ Assert.assertEquals(a.log.intValue(), 19);
+ }
+
+}
diff --git a/src/test/java/com/beust/jcommander/DefaultValueTest.java b/src/test/java/com/beust/jcommander/DefaultValueTest.java
new file mode 100644
index 0000000..3b1f29c
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/DefaultValueTest.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import com.beust.jcommander.internal.Lists;
+import com.beust.jcommander.internal.Sets;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Test behaviour of default parameter values
+ * @author rodionmoiseev
+ */
+public class DefaultValueTest {
+ @Test
+ public void emptyDefaultValueForListParameterStaysEmptyIfNotAssignedOrIsSetOtherwise() {
+ MyOptsWithEmptyDefaults opts = new MyOptsWithEmptyDefaults();
+ JCommander cmd = new JCommander(opts);
+ cmd.parse(new String[]{"-a", "anotherValue"});
+ Assert.assertEquals(opts.list.size(), 1);
+ Assert.assertEquals(opts.list.get(0), "anotherValue");
+ Assert.assertEquals(opts.set.size(), 0);
+ }
+
+ @Test
+ public void defaultValueForListParametersGetsOverwrittenWithSpecifiedValueOrStaysAsDefaultOtherwise() {
+ MyOptsWithDefaultValues opts = new MyOptsWithDefaultValues();
+ JCommander cmd = new JCommander(opts);
+ cmd.parse(new String[]{"-a", "anotherValue"});
+ Assert.assertEquals(opts.list.size(), 1);
+ Assert.assertEquals(opts.list.get(0), "anotherValue");
+ Assert.assertEquals(opts.set.size(), 1);
+ Assert.assertEquals(opts.set.iterator().next(), "defaultValue");
+ }
+
+ @Test
+ public void anyNumberOfValuesCanBeSetToListParameters_ForEmptyDefaults(){
+ MyOptsWithEmptyDefaults opts = new MyOptsWithEmptyDefaults();
+ testSettingMultipleValuesToListTypeParameters(opts);
+ }
+
+ @Test
+ public void anyNumberOfValuesCanBeSetToListParameters_ForNonEmptyDefaults(){
+ MyOptsWithDefaultValues opts = new MyOptsWithDefaultValues();
+ testSettingMultipleValuesToListTypeParameters(opts);
+ }
+
+ private void testSettingMultipleValuesToListTypeParameters(MyOpts opts) {
+ JCommander cmd = new JCommander(opts);
+ cmd.parse(new String[]{"-a", "anotherValue", "-a", "anotherValue2",
+ "-b", "anotherValue3", "-b", "anotherValue4"});
+ Assert.assertEquals(opts.list.size(), 2);
+ Assert.assertEquals(opts.list.get(0), "anotherValue");
+ Assert.assertEquals(opts.list.get(1), "anotherValue2");
+ Assert.assertEquals(opts.set.size(), 2);
+ Iterator<String> arg2it = opts.set.iterator();
+ Assert.assertEquals(arg2it.next(), "anotherValue3");
+ Assert.assertEquals(arg2it.next(), "anotherValue4");
+ }
+
+ public static class MyOpts {
+ @Parameter(names = "-a")
+ public List<String> list;
+ @Parameter(names = "-b")
+ public Set<String> set;
+ }
+
+ public static final class MyOptsWithDefaultValues extends MyOpts {
+ public MyOptsWithDefaultValues(){
+ this.list = singletonList("defaultValue");
+ this.set = singletonSet("defaultValue");
+ }
+ }
+
+ public static final class MyOptsWithEmptyDefaults extends MyOpts {
+ public MyOptsWithEmptyDefaults(){
+ this.list = Lists.newArrayList();
+ this.set = Sets.newLinkedHashSet();
+ }
+ }
+
+ public static final List<String> singletonList(String value) {
+ List<String> list = Lists.newArrayList();
+ list.add(value);
+ return list;
+ }
+
+ public static final Set<String> singletonSet(String value){
+ Set<String> set = Sets.newLinkedHashSet();
+ set.add(value);
+ return set;
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/FinderTest.java b/src/test/java/com/beust/jcommander/FinderTest.java
new file mode 100644
index 0000000..94bf812
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/FinderTest.java
@@ -0,0 +1,97 @@
+package com.beust.jcommander;
+
+import com.beust.jcommander.JCommanderTest.BaseArgs;
+import com.beust.jcommander.JCommanderTest.ConfigureArgs;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class FinderTest {
+ public void caseInsensitiveOption() {
+ class Arg {
+
+ @Parameter(names = { "-p", "--param" })
+ private String param;
+ }
+ Arg a = new Arg();
+ JCommander jc = new JCommander(a);
+ jc.setCaseSensitiveOptions(false);
+ jc.parse(new String[] { "--PARAM", "foo" });
+ Assert.assertEquals(a.param, "foo");
+ }
+
+ public void caseInsensitiveCommand() {
+ BaseArgs a = new BaseArgs();
+ ConfigureArgs conf = new ConfigureArgs();
+ JCommander jc = new JCommander(a);
+ jc.addCommand(conf);
+ jc.setCaseSensitiveOptions(false);
+// jc.setCaseSensitiveCommands(false);
+ jc.parse("--CONFIGURE");
+ String command = jc.getParsedCommand();
+ Assert.assertEquals(command, "--configure");
+ }
+
+ public void abbreviatedOptions() {
+ class Arg {
+ @Parameter(names = { "-p", "--param" })
+ private String param;
+ }
+ Arg a = new Arg();
+ JCommander jc = new JCommander(a);
+ jc.setAllowAbbreviatedOptions(true);
+ jc.parse(new String[] { "--par", "foo" });
+ Assert.assertEquals(a.param, "foo");
+ }
+
+ public void abbreviatedOptionsCaseInsensitive() {
+ class Arg {
+ @Parameter(names = { "-p", "--param" })
+ private String param;
+ }
+ Arg a = new Arg();
+ JCommander jc = new JCommander(a);
+ jc.setCaseSensitiveOptions(false);
+ jc.setAllowAbbreviatedOptions(true);
+ jc.parse(new String[] { "--PAR", "foo" });
+ Assert.assertEquals(a.param, "foo");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void ambiguousAbbreviatedOptions() {
+ class Arg {
+ @Parameter(names = { "--param" })
+ private String param;
+ @Parameter(names = { "--parb" })
+ private String parb;
+ }
+ Arg a = new Arg();
+ JCommander jc = new JCommander(a);
+ jc.setAllowAbbreviatedOptions(true);
+ jc.parse(new String[] { "--par", "foo" });
+ Assert.assertEquals(a.param, "foo");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void ambiguousAbbreviatedOptionsCaseInsensitive() {
+ class Arg {
+ @Parameter(names = { "--param" })
+ private String param;
+ @Parameter(names = { "--parb" })
+ private String parb;
+ }
+ Arg a = new Arg();
+ JCommander jc = new JCommander(a);
+ jc.setCaseSensitiveOptions(false);
+ jc.setAllowAbbreviatedOptions(true);
+ jc.parse(new String[] { "--PAR", "foo" });
+ Assert.assertEquals(a.param, "foo");
+ }
+
+ @Test(enabled = false)
+ public static void main(String[] args) throws Exception {
+ new FinderTest().ambiguousAbbreviatedOptionsCaseInsensitive();
+ }
+
+}
diff --git a/src/test/java/com/beust/jcommander/HostPort.java b/src/test/java/com/beust/jcommander/HostPort.java
new file mode 100644
index 0000000..a18018e
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/HostPort.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+public class HostPort {
+ public String host;
+ public Integer port;
+ @Override
+
+ public String toString() {
+ return "[Host:" + host + " port:" + port + "]";
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/HostPortConverter.java b/src/test/java/com/beust/jcommander/HostPortConverter.java
new file mode 100644
index 0000000..f45e3ba
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/HostPortConverter.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+public class HostPortConverter implements IStringConverter<HostPort> {
+
+ public HostPort convert(String value) {
+ HostPort result = new HostPort();
+ String[] s = value.split(":");
+ result.host = s[0];
+ result.port = Integer.parseInt(s[1]);
+
+ return result;
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/JCommanderTest.java b/src/test/java/com/beust/jcommander/JCommanderTest.java
new file mode 100644
index 0000000..ad2c5e8
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/JCommanderTest.java
@@ -0,0 +1,1081 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.TreeSet;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.beust.jcommander.args.AlternateNamesForListArgs;
+import com.beust.jcommander.args.Args1;
+import com.beust.jcommander.args.Args1Setter;
+import com.beust.jcommander.args.Args2;
+import com.beust.jcommander.args.ArgsArityString;
+import com.beust.jcommander.args.ArgsBooleanArity;
+import com.beust.jcommander.args.ArgsBooleanArity0;
+import com.beust.jcommander.args.ArgsConverter;
+import com.beust.jcommander.args.ArgsEnum;
+import com.beust.jcommander.args.ArgsEnum.ChoiceType;
+import com.beust.jcommander.args.ArgsEquals;
+import com.beust.jcommander.args.ArgsHelp;
+import com.beust.jcommander.args.ArgsI18N1;
+import com.beust.jcommander.args.ArgsI18N2;
+import com.beust.jcommander.args.ArgsI18N2New;
+import com.beust.jcommander.args.ArgsInherited;
+import com.beust.jcommander.args.ArgsList;
+import com.beust.jcommander.args.ArgsMainParameter1;
+import com.beust.jcommander.args.ArgsMaster;
+import com.beust.jcommander.args.ArgsMultipleUnparsed;
+import com.beust.jcommander.args.ArgsOutOfMemory;
+import com.beust.jcommander.args.ArgsPrivate;
+import com.beust.jcommander.args.ArgsRequired;
+import com.beust.jcommander.args.ArgsSlave;
+import com.beust.jcommander.args.ArgsSlaveBogus;
+import com.beust.jcommander.args.ArgsValidate1;
+import com.beust.jcommander.args.ArgsWithSet;
+import com.beust.jcommander.args.Arity1;
+import com.beust.jcommander.args.SeparatorColon;
+import com.beust.jcommander.args.SeparatorEqual;
+import com.beust.jcommander.args.SeparatorMixed;
+import com.beust.jcommander.args.SlashSeparator;
+import com.beust.jcommander.args.VariableArity;
+import com.beust.jcommander.command.CommandAdd;
+import com.beust.jcommander.command.CommandCommit;
+import com.beust.jcommander.command.CommandMain;
+import com.beust.jcommander.internal.Lists;
+import com.beust.jcommander.internal.Maps;
+
+@Test
+public class JCommanderTest {
+ public void simpleArgs() throws ParseException {
+ Args1 args = new Args1();
+ String[] argv = { "-debug", "-log", "2", "-float", "1.2", "-double", "1.3", "-bigdecimal", "1.4",
+ "-date", "2011-10-26", "-groups", "unit", "a", "b", "c" };
+ new JCommander(args, argv);
+
+ Assert.assertTrue(args.debug);
+ Assert.assertEquals(args.verbose.intValue(), 2);
+ Assert.assertEquals(args.groups, "unit");
+ Assert.assertEquals(args.parameters, Arrays.asList("a", "b", "c"));
+ Assert.assertEquals(args.floa, 1.2f, 0.1f);
+ Assert.assertEquals(args.doub, 1.3f, 0.1f);
+ Assert.assertEquals(args.bigd, new BigDecimal("1.4"));
+ Assert.assertEquals(args.date, new SimpleDateFormat("yyyy-MM-dd").parse("2011-10-26"));
+ }
+
+ @DataProvider
+ public Object[][] alternateNamesListArgs() {
+ return new Object[][] {
+ new String[][] {new String[] {"--servers", "1", "-s", "2", "--servers", "3"}},
+ new String[][] {new String[] {"-s", "1", "-s", "2", "--servers", "3"}},
+ new String[][] {new String[] {"--servers", "1", "--servers", "2", "-s", "3"}},
+ new String[][] {new String[] {"-s", "1", "--servers", "2", "-s", "3"}},
+ new String[][] {new String[] {"-s", "1", "-s", "2", "--servers", "3"}},
+ };
+ }
+
+ /**
+ * Confirm that List<?> parameters with alternate names return the correct
+ * List regardless of how the arguments are specified
+ */
+
+ @Test(dataProvider = "alternateNamesListArgs")
+ public void testAlternateNamesForListArguments(String[] argv) {
+ AlternateNamesForListArgs args = new AlternateNamesForListArgs();
+
+ new JCommander(args, argv);
+
+ Assert.assertEquals(args.serverNames.size(), 3);
+ Assert.assertEquals(args.serverNames.get(0), argv[1]);
+ Assert.assertEquals(args.serverNames.get(1), argv[3]);
+ Assert.assertEquals(args.serverNames.get(2), argv[5]);
+ }
+
+
+ /**
+ * Make sure that if there are args with multiple names (e.g. "-log" and "-verbose"),
+ * the usage will only display it once.
+ */
+ public void repeatedArgs() {
+ Args1 args = new Args1();
+ String[] argv = { "-log", "2" };
+ JCommander jc = new JCommander(args, argv);
+ Assert.assertEquals(jc.getParameters().size(), 8);
+ }
+
+ /**
+ * Not specifying a required option should throw an exception.
+ */
+ @Test(expectedExceptions = ParameterException.class)
+ public void requiredFields1Fail() {
+ Args1 args = new Args1();
+ String[] argv = { "-debug" };
+ new JCommander(args, argv);
+ }
+
+ /**
+ * Getting the description of a nonexistent command should throw an exception.
+ */
+ @Test(expectedExceptions = ParameterException.class)
+ public void nonexistentCommandShouldThrow() {
+ String[] argv = { };
+ JCommander jc = new JCommander(new Object(), argv);
+ jc.getCommandDescription("foo");
+ }
+
+ /**
+ * Required options with multiple names should work with all names.
+ */
+ private void multipleNames(String option) {
+ Args1 args = new Args1();
+ String[] argv = { option, "2" };
+ new JCommander(args, argv);
+ Assert.assertEquals(args.verbose.intValue(), 2);
+ }
+
+ public void multipleNames1() {
+ multipleNames("-log");
+ }
+
+ public void multipleNames2() {
+ multipleNames("-verbose");
+ }
+
+ private void i18n1(String bundleName, Locale locale, String expectedString) {
+ ResourceBundle bundle = locale != null ? ResourceBundle.getBundle(bundleName, locale)
+ : null;
+
+ ArgsI18N1 i18n = new ArgsI18N1();
+ String[] argv = { "-host", "localhost" };
+ JCommander jc = new JCommander(i18n, bundle, argv);
+// jc.usage();
+
+ ParameterDescription pd = jc.getParameters().get(0);
+ Assert.assertEquals(pd.getDescription(), expectedString);
+ }
+
+ public void i18nNoLocale() {
+ i18n1("MessageBundle", null, "Host");
+ }
+
+ public void i18nUsLocale() {
+ i18n1("MessageBundle", new Locale("en", "US"), "Host");
+ }
+
+ public void i18nFrLocale() {
+ i18n1("MessageBundle", new Locale("fr", "FR"), "Hôte");
+ }
+
+ private void i18n2(Object i18n) {
+ String[] argv = { "-host", "localhost" };
+ Locale.setDefault(new Locale("fr", "FR"));
+ JCommander jc = new JCommander(i18n, argv);
+ ParameterDescription pd = jc.getParameters().get(0);
+ Assert.assertEquals(pd.getDescription(), "Hôte");
+ }
+
+ public void i18nWithResourceAnnotation() {
+ i18n2(new ArgsI18N2());
+ }
+
+ public void i18nWithResourceAnnotationNew() {
+ i18n2(new ArgsI18N2New());
+ }
+
+ public void noParseConstructor() {
+ JCommander jCommander = new JCommander(new ArgsMainParameter1());
+ jCommander.usage(new StringBuilder());
+ // Before fix, this parse would throw an exception, because it calls createDescription, which
+ // was already called by usage(), and can only be called once.
+ jCommander.parse();
+ }
+
+ /**
+ * Test a use case where there are required parameters, but you still want
+ * to interrogate the options which are specified.
+ */
+ public void usageWithRequiredArgsAndResourceBundle() {
+ ArgsHelp argsHelp = new ArgsHelp();
+ JCommander jc = new JCommander(new Object[]{argsHelp, new ArgsRequired()},
+ java.util.ResourceBundle.getBundle("MessageBundle"));
+ // Should be able to display usage without triggering validation
+ jc.usage(new StringBuilder());
+ try {
+ jc.parse("-h");
+ Assert.fail("Should have thrown a required parameter exception");
+ } catch (ParameterException e) {
+ Assert.assertTrue(e.getMessage().contains("are required"));
+ }
+ Assert.assertTrue(argsHelp.help);
+ }
+
+ public void multiObjects() {
+ ArgsMaster m = new ArgsMaster();
+ ArgsSlave s = new ArgsSlave();
+ String[] argv = { "-master", "master", "-slave", "slave" };
+ new JCommander(new Object[] { m , s }, argv);
+
+ Assert.assertEquals(m.master, "master");
+ Assert.assertEquals(s.slave, "slave");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void multiObjectsWithDuplicatesFail() {
+ ArgsMaster m = new ArgsMaster();
+ ArgsSlave s = new ArgsSlaveBogus();
+ String[] argv = { "-master", "master", "-slave", "slave" };
+ new JCommander(new Object[] { m , s }, argv);
+ }
+
+ public void arityString() {
+ ArgsArityString args = new ArgsArityString();
+ String[] argv = { "-pairs", "pair0", "pair1", "rest" };
+ new JCommander(args, argv);
+
+ Assert.assertEquals(args.pairs.size(), 2);
+ Assert.assertEquals(args.pairs.get(0), "pair0");
+ Assert.assertEquals(args.pairs.get(1), "pair1");
+ Assert.assertEquals(args.rest.size(), 1);
+ Assert.assertEquals(args.rest.get(0), "rest");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void arity2Fail() {
+ ArgsArityString args = new ArgsArityString();
+ String[] argv = { "-pairs", "pair0" };
+ new JCommander(args, argv);
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void multipleUnparsedFail() {
+ ArgsMultipleUnparsed args = new ArgsMultipleUnparsed();
+ String[] argv = { };
+ new JCommander(args, argv);
+ }
+
+ public void privateArgs() {
+ ArgsPrivate args = new ArgsPrivate();
+ new JCommander(args, "-verbose", "3");
+ Assert.assertEquals(args.getVerbose().intValue(), 3);
+ }
+
+ public void converterArgs() {
+ ArgsConverter args = new ArgsConverter();
+ String fileName = "a";
+ new JCommander(args, "-file", "/tmp/" + fileName,
+ "-listStrings", "Tuesday,Thursday",
+ "-listInts", "-1,8",
+ "-listBigDecimals", "-11.52,100.12");
+ Assert.assertEquals(args.file.getName(), fileName);
+ Assert.assertEquals(args.listStrings.size(), 2);
+ Assert.assertEquals(args.listStrings.get(0), "Tuesday");
+ Assert.assertEquals(args.listStrings.get(1), "Thursday");
+ Assert.assertEquals(args.listInts.size(), 2);
+ Assert.assertEquals(args.listInts.get(0).intValue(), -1);
+ Assert.assertEquals(args.listInts.get(1).intValue(), 8);
+ Assert.assertEquals(args.listBigDecimals.size(), 2);
+ Assert.assertEquals(args.listBigDecimals.get(0), new BigDecimal("-11.52"));
+ Assert.assertEquals(args.listBigDecimals.get(1), new BigDecimal("100.12"));
+ }
+
+ private void argsBoolean1(String[] params, Boolean expected) {
+ ArgsBooleanArity args = new ArgsBooleanArity();
+ new JCommander(args, params);
+ Assert.assertEquals(args.debug, expected);
+ }
+
+ private void argsBoolean0(String[] params, Boolean expected) {
+ ArgsBooleanArity0 args = new ArgsBooleanArity0();
+ new JCommander(args, params);
+ Assert.assertEquals(args.debug, expected);
+ }
+
+ public void booleanArity1() {
+ argsBoolean1(new String[] {}, Boolean.FALSE);
+ argsBoolean1(new String[] { "-debug", "true" }, Boolean.TRUE);
+ }
+
+ public void booleanArity0() {
+ argsBoolean0(new String[] {}, Boolean.FALSE);
+ argsBoolean0(new String[] { "-debug"}, Boolean.TRUE);
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void badParameterShouldThrowParameter1Exception() {
+ Args1 args = new Args1();
+ String[] argv = { "-log", "foo" };
+ new JCommander(args, argv);
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void badParameterShouldThrowParameter2Exception() {
+ Args1 args = new Args1();
+ String[] argv = { "-long", "foo" };
+ new JCommander(args, argv);
+ }
+
+ public void listParameters() {
+ Args2 a = new Args2();
+ String[] argv = {"-log", "2", "-groups", "unit", "a", "b", "c", "-host", "host2"};
+ new JCommander(a, argv);
+ Assert.assertEquals(a.verbose.intValue(), 2);
+ Assert.assertEquals(a.groups, "unit");
+ Assert.assertEquals(a.hosts, Arrays.asList("host2"));
+ Assert.assertEquals(a.parameters, Arrays.asList("a", "b", "c"));
+ }
+
+ public void separatorEqual() {
+ SeparatorEqual s = new SeparatorEqual();
+ String[] argv = { "-log=3", "--longoption=10" };
+ new JCommander(s, argv);
+ Assert.assertEquals(s.log.intValue(), 3);
+ Assert.assertEquals(s.longOption.intValue(), 10);
+ }
+
+ public void separatorColon() {
+ SeparatorColon s = new SeparatorColon();
+ String[] argv = { "-verbose:true" };
+ new JCommander(s, argv);
+ Assert.assertTrue(s.verbose);
+ }
+
+ public void separatorBoth() {
+ SeparatorColon s = new SeparatorColon();
+ SeparatorEqual s2 = new SeparatorEqual();
+ String[] argv = { "-verbose:true", "-log=3" };
+ new JCommander(new Object[] { s, s2 }, argv);
+ Assert.assertTrue(s.verbose);
+ Assert.assertEquals(s2.log.intValue(), 3);
+ }
+
+ public void separatorMixed1() {
+ SeparatorMixed s = new SeparatorMixed();
+ String[] argv = { "-long:1", "-level=42" };
+ new JCommander(s, argv);
+ Assert.assertEquals(s.l.longValue(), 1l);
+ Assert.assertEquals(s.level.intValue(), 42);
+ }
+
+ public void slashParameters() {
+ SlashSeparator a = new SlashSeparator();
+ String[] argv = { "/verbose", "/file", "/tmp/a" };
+ new JCommander(a, argv);
+ Assert.assertTrue(a.verbose);
+ Assert.assertEquals(a.file, "/tmp/a");
+ }
+
+ public void inheritance() {
+ ArgsInherited args = new ArgsInherited();
+ String[] argv = { "-log", "3", "-child", "2" };
+ new JCommander(args, argv);
+ Assert.assertEquals(args.child.intValue(), 2);
+ Assert.assertEquals(args.log.intValue(), 3);
+ }
+
+ public void negativeNumber() {
+ Args1 a = new Args1();
+ String[] argv = { "-verbose", "-3" };
+ new JCommander(a, argv);
+ Assert.assertEquals(a.verbose.intValue(), -3);
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void requiredMainParameters() {
+ ArgsRequired a = new ArgsRequired();
+ String[] argv = {};
+ new JCommander(a, argv);
+ }
+
+ public void usageShouldNotChange() {
+ JCommander jc = new JCommander(new Args1(), new String[]{"-log", "1"});
+ StringBuilder sb = new StringBuilder();
+ jc.usage(sb);
+ String expected = sb.toString();
+ jc = new JCommander(new Args1(), new String[]{"-debug", "-log", "2", "-long", "5"});
+ sb = new StringBuilder();
+ jc.usage(sb);
+ String actual = sb.toString();
+ Assert.assertEquals(actual, expected);
+ }
+
+ private void verifyCommandOrdering(String[] commandNames, Object[] commands) {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+
+ for (int i = 0; i < commands.length; i++) {
+ jc.addCommand(commandNames[i], commands[i]);
+ }
+
+ Map<String, JCommander> c = jc.getCommands();
+ Assert.assertEquals(c.size(), commands.length);
+
+ Iterator<String> it = c.keySet().iterator();
+ for (int i = 0; i < commands.length; i++) {
+ Assert.assertEquals(it.next(), commandNames[i]);
+ }
+ }
+
+ public void commandsShouldBeShownInOrderOfInsertion() {
+ verifyCommandOrdering(new String[] { "add", "commit" },
+ new Object[] { new CommandAdd(), new CommandCommit() });
+ verifyCommandOrdering(new String[] { "commit", "add" },
+ new Object[] { new CommandCommit(), new CommandAdd() });
+ }
+
+ @DataProvider
+ public static Object[][] f() {
+ return new Integer[][] {
+ new Integer[] { 3, 5, 1 },
+ new Integer[] { 3, 8, 1 },
+ new Integer[] { 3, 12, 2 },
+ new Integer[] { 8, 12, 2 },
+ new Integer[] { 9, 10, 1 },
+ };
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void arity1Fail() {
+ final Arity1 arguments = new Arity1();
+ final JCommander jCommander = new JCommander(arguments);
+ final String[] commands = {
+ "-inspect"
+ };
+ jCommander.parse(commands);
+ }
+
+ public void arity1Success1() {
+ final Arity1 arguments = new Arity1();
+ final JCommander jCommander = new JCommander(arguments);
+ final String[] commands = {
+ "-inspect", "true"
+ };
+ jCommander.parse(commands);
+ Assert.assertTrue(arguments.inspect);
+ }
+
+ public void arity1Success2() {
+ final Arity1 arguments = new Arity1();
+ final JCommander jCommander = new JCommander(arguments);
+ final String[] commands = {
+ "-inspect", "false"
+ };
+ jCommander.parse(commands);
+ Assert.assertFalse(arguments.inspect);
+ }
+
+ @Parameters(commandDescription = "Help for the given commands.")
+ public static class Help {
+ public static final String NAME = "help";
+
+ @Parameter(description = "List of commands.")
+ public List<String> commands=new ArrayList<String>();
+ }
+
+ @Test(expectedExceptions = ParameterException.class,
+ description = "Verify that the main parameter's type is checked to be a List")
+ public void wrongMainTypeShouldThrow() {
+ JCommander jc = new JCommander(new ArgsRequiredWrongMain());
+ jc.parse(new String[] { "f1", "f2" });
+ }
+
+ @Test(description = "This used to run out of memory")
+ public void oom() {
+ JCommander jc = new JCommander(new ArgsOutOfMemory());
+ jc.usage(new StringBuilder());
+ }
+
+ @Test
+ public void getParametersShouldNotNpe() {
+ JCommander jc = new JCommander(new Args1());
+ List<ParameterDescription> parameters = jc.getParameters();
+ }
+
+ public void validationShouldWork1() {
+ ArgsValidate1 a = new ArgsValidate1();
+ JCommander jc = new JCommander(a);
+ jc.parse(new String[] { "-age", "2 "});
+ Assert.assertEquals(a.age, new Integer(2));
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void validationShouldWorkWithDefaultValues() {
+ ArgsValidate2 a = new ArgsValidate2();
+ new JCommander(a);
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void validationShouldWork2() {
+ ArgsValidate1 a = new ArgsValidate1();
+ JCommander jc = new JCommander(a);
+ jc.parse(new String[] { "-age", "-2 "});
+ }
+
+ public void atFileCanContainEmptyLines() throws IOException {
+ File f = File.createTempFile("JCommander", null);
+ f.deleteOnExit();
+ FileWriter fw = new FileWriter(f);
+ fw.write("-log\n");
+ fw.write("\n");
+ fw.write("2\n");
+ fw.close();
+ new JCommander(new Args1(), "@" + f.getAbsolutePath());
+ }
+
+ public void handleEqualSigns() {
+ ArgsEquals a = new ArgsEquals();
+ JCommander jc = new JCommander(a);
+ jc.parse(new String[] { "-args=a=b,b=c" });
+ Assert.assertEquals(a.args, "a=b,b=c");
+ }
+
+ @SuppressWarnings("serial")
+ public void handleSets() {
+ ArgsWithSet a = new ArgsWithSet();
+ new JCommander(a, new String[] { "-s", "3,1,2" });
+ Assert.assertEquals(a.set, new TreeSet<Integer>() {{ add(1); add(2); add(3); }});
+ }
+
+ private static final List<String> V = Arrays.asList("a", "b", "c", "d");
+
+ @DataProvider
+ public Object[][] variable() {
+ return new Object[][] {
+ new Object[] { 0, V.subList(0, 0), V },
+ new Object[] { 1, V.subList(0, 1), V.subList(1, 4) },
+ new Object[] { 2, V.subList(0, 2), V.subList(2, 4) },
+ new Object[] { 3, V.subList(0, 3), V.subList(3, 4) },
+ new Object[] { 4, V.subList(0, 4), V.subList(4, 4) },
+ };
+ }
+
+ @Test(dataProvider = "variable")
+ public void variableArity(int count, List<String> var, List<String> main) {
+ VariableArity va = new VariableArity(count);
+ new JCommander(va).parse("-variable", "a", "b", "c", "d");
+ Assert.assertEquals(var, va.var);
+ Assert.assertEquals(main, va.main);
+ }
+
+ public void enumArgs() {
+ ArgsEnum args = new ArgsEnum();
+ String[] argv = { "-choice", "ONE", "-choices", "ONE", "Two" };
+ JCommander jc = new JCommander(args, argv);
+
+ Assert.assertEquals(args.choice, ArgsEnum.ChoiceType.ONE);
+
+ List<ChoiceType> expected = Arrays.asList(ChoiceType.ONE, ChoiceType.Two);
+ Assert.assertEquals(expected, args.choices);
+ Assert.assertEquals(jc.getParameters().get(0).getDescription(),
+ "Options: " + EnumSet.allOf((Class<? extends Enum>) ArgsEnum.ChoiceType.class));
+
+ }
+
+ public void enumArgsCaseInsensitive() {
+ ArgsEnum args = new ArgsEnum();
+ String[] argv = { "-choice", "one"};
+ JCommander jc = new JCommander(args, argv);
+
+ Assert.assertEquals(args.choice, ArgsEnum.ChoiceType.ONE);
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void enumArgsFail() {
+ ArgsEnum args = new ArgsEnum();
+ String[] argv = { "-choice", "A" };
+ new JCommander(args, argv);
+ }
+
+ public void testListAndSplitters() {
+ ArgsList al = new ArgsList();
+ JCommander j = new JCommander(al);
+ j.parse("-groups", "a,b", "-ints", "41,42", "-hp", "localhost:1000;example.com:1001",
+ "-hp2", "localhost:1000,example.com:1001", "-uppercase", "ab,cd");
+ Assert.assertEquals(al.groups.get(0), "a");
+ Assert.assertEquals(al.groups.get(1), "b");
+ Assert.assertEquals(al.ints.get(0).intValue(), 41);
+ Assert.assertEquals(al.ints.get(1).intValue(), 42);
+ Assert.assertEquals(al.hostPorts.get(0).host, "localhost");
+ Assert.assertEquals(al.hostPorts.get(0).port.intValue(), 1000);
+ Assert.assertEquals(al.hostPorts.get(1).host, "example.com");
+ Assert.assertEquals(al.hostPorts.get(1).port.intValue(), 1001);
+ Assert.assertEquals(al.hp2.get(1).host, "example.com");
+ Assert.assertEquals(al.hp2.get(1).port.intValue(), 1001);
+ Assert.assertEquals(al.uppercase.get(0), "AB");
+ Assert.assertEquals(al.uppercase.get(1), "CD");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void shouldThrowIfUnknownOption() {
+ class A {
+ @Parameter(names = "-long")
+ public long l;
+ }
+ A a = new A();
+ new JCommander(a).parse("-lon", "32");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void mainParameterShouldBeValidate() {
+ class V implements IParameterValidator {
+
+ @Override
+ public void validate(String name, String value) throws ParameterException {
+ Assert.assertEquals("a", value);
+ }
+ }
+
+ class A {
+ @Parameter(validateWith = V.class)
+ public List<String> m;
+ }
+
+ A a = new A();
+ new JCommander(a).parse("b");
+ }
+
+ @Parameters(commandNames = { "--configure" })
+ public static class ConfigureArgs {
+ }
+
+ public static class BaseArgs {
+ @Parameter(names = { "-h", "--help" }, description = "Show this help screen")
+ private boolean help = false;
+
+ @Parameter(names = { "--version", "-version" }, description = "Show the program version")
+ private boolean version;
+ }
+
+ public void commandsWithSamePrefixAsOptionsShouldWork() {
+ BaseArgs a = new BaseArgs();
+ ConfigureArgs conf = new ConfigureArgs();
+ JCommander jc = new JCommander(a);
+ jc.addCommand(conf);
+ jc.parse("--configure");
+ }
+
+ // Tests:
+ // required unparsed parameter
+ @Test(enabled = false,
+ description = "For some reason, this test still asks the password on stdin")
+ public void askedRequiredPassword() {
+ class A {
+ @Parameter(names = { "--password", "-p" }, description = "Private key password",
+ password = true, required = true)
+ public String password;
+
+ @Parameter(names = { "--port", "-o" }, description = "Port to bind server to",
+ required = true)
+ public int port;
+ }
+ A a = new A();
+ InputStream stdin = System.in;
+ try {
+ System.setIn(new ByteArrayInputStream("password".getBytes()));
+ new JCommander(a,new String[]{"--port", "7","--password"});
+ Assert.assertEquals(a.port, 7);
+ Assert.assertEquals(a.password, "password");
+ } finally {
+ System.setIn(stdin);
+ }
+ }
+
+ public void dynamicParameters() {
+ class Command {
+ @DynamicParameter(names = {"-P"}, description = "Additional command parameters")
+ private Map<String, String> params = Maps.newHashMap();
+ }
+ JCommander commander = new JCommander();
+ Command c = new Command();
+ commander.addCommand("command", c);
+ commander.parse(new String[] { "command", "-Pparam='name=value'" });
+ Assert.assertEquals(c.params.get("param"), "'name=value'");
+ }
+
+ public void exeParser() {
+ class Params {
+ @Parameter( names= "-i")
+ private String inputFile;
+ }
+
+ String args[] = { "-i", "" };
+ Params p = new Params();
+ new JCommander(p, args);
+ }
+
+ public void multiVariableArityList() {
+ class Params {
+ @Parameter(names = "-paramA", description = "ParamA", variableArity = true)
+ private List<String> paramA = Lists.newArrayList();
+
+ @Parameter(names = "-paramB", description = "ParamB", variableArity = true)
+ private List<String> paramB = Lists.newArrayList();
+ }
+
+ {
+ String args[] = { "-paramA", "a1", "a2", "-paramB", "b1", "b2", "b3" };
+ Params p = new Params();
+ new JCommander(p, args).parse();
+ Assert.assertEquals(p.paramA, Arrays.asList(new String[] { "a1", "a2" }));
+ Assert.assertEquals(p.paramB, Arrays.asList(new String[] { "b1", "b2", "b3" }));
+ }
+
+ {
+ String args[] = { "-paramA", "a1", "a2", "-paramB", "b1", "-paramA", "a3" };
+ Params p = new Params();
+ new JCommander(p, args).parse();
+ Assert.assertEquals(p.paramA, Arrays.asList(new String[] { "a1", "a2", "a3" }));
+ Assert.assertEquals(p.paramB, Arrays.asList(new String[] { "b1" }));
+ }
+ }
+
+ @Test(enabled = false,
+ description = "Need to double check that the command description is i18n'ed in the usage")
+ public void commandKey() {
+ @Parameters(resourceBundle = "MessageBundle", commandDescriptionKey = "command")
+ class Args {
+ @Parameter(names="-myoption", descriptionKey="myoption")
+ private boolean option;
+ }
+ JCommander j = new JCommander();
+ Args a = new Args();
+ j.addCommand("comm", a);
+ j.usage();
+ }
+
+ public void tmp() {
+ class A {
+ @Parameter(names = "-b")
+ public String b;
+ }
+ new JCommander(new A()).parse("");
+ }
+
+ public void unknownOptionWithDifferentPrefix() {
+ @Parameters(optionPrefixes = "/")
+ class SlashSeparator {
+
+ @Parameter(names = "/verbose")
+ public boolean verbose = false;
+
+ @Parameter(names = "/file")
+ public String file;
+ }
+ SlashSeparator ss = new SlashSeparator();
+ try {
+ new JCommander(ss).parse("/notAParam");
+ } catch (ParameterException ex) {
+ boolean result = ex.getMessage().contains("Unknown option");
+ Assert.assertTrue(result);
+ }
+ }
+
+ public void equalSeparator() {
+ @Parameters(separators = "=", commandDescription = "My command")
+ class MyClass {
+
+ @Parameter(names = { "-p", "--param" }, required = true, description = "param desc...")
+ private String param;
+ }
+ MyClass c = new MyClass();
+ String expected = "\"hello\"world";
+ new JCommander(c).parse("--param=" + expected);
+ Assert.assertEquals(expected, c.param);
+ }
+
+ public void simpleArgsSetter() throws ParseException {
+ Args1Setter args = new Args1Setter();
+ String[] argv = { "-debug", "-log", "2", "-float", "1.2", "-double", "1.3", "-bigdecimal", "1.4",
+ "-date", "2011-10-26", "-groups", "unit", "a", "b", "c" };
+ new JCommander(args, argv);
+
+ Assert.assertTrue(args.debug);
+ Assert.assertEquals(args.verbose.intValue(), 2);
+ Assert.assertEquals(args.groups, "unit");
+ Assert.assertEquals(args.parameters, Arrays.asList("a", "b", "c"));
+ Assert.assertEquals(args.floa, 1.2f, 0.1f);
+ Assert.assertEquals(args.doub, 1.3f, 0.1f);
+ Assert.assertEquals(args.bigd, new BigDecimal("1.4"));
+ Assert.assertEquals(args.date, new SimpleDateFormat("yyyy-MM-dd").parse("2011-10-26"));
+ }
+
+ public void verifyHelp() {
+ class Arg {
+ @Parameter(names = "--help", help = true)
+ public boolean help = false;
+
+ @Parameter(names = "file", required = true)
+ public String file;
+ }
+ Arg arg = new Arg();
+ String[] argv = { "--help" };
+ new JCommander(arg, argv);
+
+ Assert.assertTrue(arg.help);
+ }
+
+ public void helpTest() {
+ class Arg {
+ @Parameter(names = { "?", "-help", "--help" }, description = "Shows help", help = true)
+ private boolean help = false;
+ }
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg);
+ jc.parse(new String[] { "-help" });
+// System.out.println("helpTest:" + arg.help);
+ }
+
+ @Test(enabled = false, description = "Should only be enable once multiple parameters are allowed")
+ public void duplicateParameterNames() {
+ class ArgBase {
+ @Parameter(names = { "-host" })
+ protected String host;
+ }
+
+ class Arg1 extends ArgBase {}
+ Arg1 arg1 = new Arg1();
+
+ class Arg2 extends ArgBase {}
+ Arg2 arg2 = new Arg2();
+
+ JCommander jc = new JCommander(new Object[] { arg1, arg2});
+ jc.parse(new String[] { "-host", "foo" });
+ Assert.assertEquals(arg1.host, "foo");
+ Assert.assertEquals(arg2.host, "foo");
+ }
+
+ public void parameterWithOneDoubleQuote() {
+ @Parameters(separators = "=")
+ class Arg {
+ @Parameter(names = { "-p", "--param" })
+ private String param;
+ }
+ JCommander jc = new JCommander(new MyClass());
+ jc.parse("-p=\"");
+ }
+
+ public void emptyStringAsDefault() {
+ class Arg {
+ @Parameter(names = "-x")
+ String s = "";
+ }
+ Arg a = new Arg();
+ StringBuilder sb = new StringBuilder();
+ new JCommander(a).usage(sb);
+ Assert.assertTrue(sb.toString().contains("Default: <empty string>"));
+ }
+
+ public void spaces() {
+ class Arg {
+ @Parameter(names = "-rule", description = "rule")
+ private List<String> rules = new ArrayList<String>();
+ }
+ Arg a = new Arg();
+ new JCommander(a, "-rule", "some test");
+ Assert.assertEquals(a.rules, Arrays.asList("some test"));
+ }
+
+ static class V2 implements IParameterValidator2 {
+ final static List<String> names = Lists.newArrayList();
+ static boolean validateCalled = false;
+
+ @Override
+ public void validate(String name, String value) throws ParameterException {
+ validateCalled = true;
+ }
+
+ @Override
+ public void validate(String name, String value, ParameterDescription pd)
+ throws ParameterException {
+ names.addAll(Arrays.asList(pd.getParameter().names()));
+ }
+ }
+
+ public void validator2() {
+ class Arg {
+ @Parameter(names = { "-h", "--host" }, validateWith = V2.class)
+ String host;
+ }
+ Arg a = new Arg();
+ V2.names.clear();
+ V2.validateCalled = false;
+ JCommander jc = new JCommander(a, "--host", "h");
+ jc.setAcceptUnknownOptions(true);
+ Assert.assertEquals(V2.names, Arrays.asList(new String[] { "-h", "--host" }));
+ Assert.assertTrue(V2.validateCalled);
+ }
+
+ public void usageCommandsUnderUsage() {
+ class Arg {
+ }
+ @Parameters(commandDescription = "command a")
+ class ArgCommandA {
+ @Parameter(description = "command a parameters")
+ List<String> parameters;
+ }
+ @Parameters(commandDescription = "command b")
+ class ArgCommandB {
+ @Parameter(description = "command b parameters")
+ List<String> parameters;
+ }
+
+ Arg a = new Arg();
+
+ JCommander c = new JCommander(a);
+ c.addCommand("a", new ArgCommandA());
+ c.addCommand("b", new ArgCommandB());
+
+ StringBuilder sb = new StringBuilder();
+ c.usage(sb);
+ Assert.assertTrue(sb.toString().contains("[command options]\n Commands:"));
+ }
+
+ public void usageWithEmpytLine() {
+ class Arg {
+ }
+ @Parameters(commandDescription = "command a")
+ class ArgCommandA {
+ @Parameter(description = "command a parameters")
+ List<String> parameters;
+ }
+ @Parameters(commandDescription = "command b")
+ class ArgCommandB {
+ @Parameter(description = "command b parameters")
+ List<String> parameters;
+ }
+
+ Arg a = new Arg();
+
+ JCommander c = new JCommander(a);
+ c.addCommand("a", new ArgCommandA());
+ c.addCommand("b", new ArgCommandB());
+
+ StringBuilder sb = new StringBuilder();
+ c.usage(sb);
+ Assert.assertTrue(sb.toString().contains("command a parameters\n\n b"));
+ }
+
+ public void partialValidation() {
+ class Arg {
+ @Parameter(names = { "-h", "--host" })
+ String host;
+ }
+ Arg a = new Arg();
+ JCommander jc = new JCommander();
+ jc.setAcceptUnknownOptions(true);
+ jc.addObject(a);
+ jc.parse("-a", "foo", "-h", "host");
+ Assert.assertEquals(a.host, "host");
+ Assert.assertEquals(jc.getUnknownOptions(), Lists.newArrayList("-a", "foo"));
+ }
+
+ /**
+ * GITHUB-137.
+ */
+ public void listArgShouldBeCleared() {
+ class Args {
+ @Parameter(description = "[endpoint]")
+ public List<String> endpoint = Lists.newArrayList("prod");
+ }
+ Args a = new Args();
+ new JCommander(a, new String[] { "dev" });
+ Assert.assertEquals(a.endpoint, Lists.newArrayList("dev"));
+ }
+
+ public void dashDashParameter() {
+ class Arguments {
+ @Parameter(names = { "-name" })
+ public String name;
+ @Parameter
+ public List<String> mainParameters;
+ }
+
+ Arguments a = new Arguments();
+ new JCommander(a, new String[] {
+ "-name", "theName", "--", "param1", "param2"}
+ );
+ Assert.assertEquals(a.name, "theName");
+ Assert.assertEquals(a.mainParameters.size(), 2);
+ Assert.assertEquals(a.mainParameters.get(0), "param1");
+ Assert.assertEquals(a.mainParameters.get(1), "param2");
+ }
+
+ public void dashDashParameter2() {
+ class Arguments {
+ @Parameter(names = { "-name" })
+ public String name;
+ @Parameter
+ public List<String> mainParameters;
+ }
+
+ Arguments a = new Arguments();
+ new JCommander(a, new String[] {
+ "param1", "param2", "--", "param3", "-name", "theName"}
+ );
+ Assert.assertNull(a.name);
+ Assert.assertEquals(a.mainParameters.size(), 5);
+ Assert.assertEquals(a.mainParameters.get(0), "param1");
+ Assert.assertEquals(a.mainParameters.get(1), "param2");
+ Assert.assertEquals(a.mainParameters.get(2), "param3");
+ Assert.assertEquals(a.mainParameters.get(3), "-name");
+ Assert.assertEquals(a.mainParameters.get(4), "theName");
+ }
+
+ @Test(enabled = false)
+ public static void main(String[] args) throws Exception {
+ new JCommanderTest().enumArgsFail();
+// class A {
+// @Parameter(names = "-short", required = true)
+// List<String> parameters;
+//
+// @Parameter(names = "-long", required = true)
+// public long l;
+// }
+// A a = new A();
+// new JCommander(a).parse();
+// System.out.println(a.l);
+// System.out.println(a.parameters);
+// ArgsList al = new ArgsList();
+// JCommander j = new JCommander(al);
+// j.setColumnSize(40);
+// j.usage();
+// new JCommanderTest().testListAndSplitters();
+// new JCommanderTest().converterArgs();
+ }
+
+ // Tests:
+ // required unparsed parameter
+}
diff --git a/src/test/java/com/beust/jcommander/MethodSetterTest.java b/src/test/java/com/beust/jcommander/MethodSetterTest.java
new file mode 100644
index 0000000..f995ad6
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/MethodSetterTest.java
@@ -0,0 +1,100 @@
+package com.beust.jcommander;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+/**
+ * Tests for @Parameter on top of methods.
+ */
+@Test
+public class MethodSetterTest {
+ public void arityStringsSetter() {
+ class ArgsArityStringSetter {
+
+ @Parameter(names = "-pairs", arity = 2, description = "Pairs")
+ public void setPairs(List<String> pairs) {
+ this.pairs = pairs;
+ }
+ public List<String> getPairs() {
+ return this.pairs;
+ }
+ public List<String> pairs;
+
+ @Parameter(description = "Rest")
+ public void setRest(List<String> rest) {
+ this.rest = rest;
+ }
+// public List<String> getRest() {
+// return this.rest;
+// }
+ public List<String> rest;
+ }
+ ArgsArityStringSetter args = new ArgsArityStringSetter();
+ String[] argv = { "-pairs", "pair0", "pair1", "rest" };
+ new JCommander(args, argv);
+
+ Assert.assertEquals(args.pairs.size(), 2);
+ Assert.assertEquals(args.pairs.get(0), "pair0");
+ Assert.assertEquals(args.pairs.get(1), "pair1");
+ Assert.assertEquals(args.rest.size(), 1);
+ Assert.assertEquals(args.rest.get(0), "rest");
+ }
+
+ public void setterThatThrows() {
+ class Arg {
+ @Parameter(names = "--host")
+ public void setHost(String host) {
+ throw new ParameterException("Illegal host");
+ }
+ }
+ boolean passed = false;
+ try {
+ new JCommander(new Arg(), new String[] { "--host", "host" });
+ } catch(ParameterException ex) {
+ Assert.assertEquals(ex.getCause(), null);
+ passed = true;
+ }
+ Assert.assertTrue(passed, "Should have thrown an exception");
+ }
+
+ public void getterReturningNonString() {
+ class Arg {
+ private Integer port;
+
+ @Parameter(names = "--port")
+ public void setPort(String port) {
+ this.port = Integer.parseInt(port);
+ }
+
+ public Integer getPort() {
+ return port;
+ }
+ }
+ Arg arg = new Arg();
+ new JCommander(arg, new String[] { "--port", "42" });
+
+ Assert.assertEquals(arg.port, new Integer(42));
+ }
+
+ public void noGetterButWithField() {
+ class Arg {
+ private Integer port = 43;
+
+ @Parameter(names = "--port")
+ public void setPort(String port) {
+ this.port = Integer.parseInt(port);
+ }
+ }
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg, new String[] { "--port", "42" });
+ ParameterDescription pd = jc.getParameters().get(0);
+ Assert.assertEquals(pd.getDefault(), 43);
+ }
+
+ @Test(enabled = false)
+ public static void main(String[] args) throws Exception {
+ new MethodSetterTest().noGetterButWithField();
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/MyClass.java b/src/test/java/com/beust/jcommander/MyClass.java
new file mode 100644
index 0000000..c2d3371
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/MyClass.java
@@ -0,0 +1,24 @@
+package com.beust.jcommander;
+
+import org.testng.Assert;
+
+
+@Parameters(separators = "=")
+public class MyClass {
+
+ @Parameter(names = { "-p", "--param" }, validateWith = MyValidator.class)
+ private String param;
+
+ public static void main(String[] args) {
+ JCommander jCommander = new JCommander(new MyClass());
+ jCommander.parse("--param=value");
+ }
+
+ public static class MyValidator implements IParameterValidator {
+ @Override
+ public void validate(String name, String value) throws ParameterException {
+ Assert.assertEquals(value, "\"");
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/ParametersDelegateTest.java b/src/test/java/com/beust/jcommander/ParametersDelegateTest.java
new file mode 100644
index 0000000..46c7c6a
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/ParametersDelegateTest.java
@@ -0,0 +1,227 @@
+package com.beust.jcommander;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author rodionmoiseev
+ */
+public class ParametersDelegateTest {
+
+ @Test
+ public void delegatingEmptyClassHasNoEffect() {
+ class EmptyDelegate {
+ public String nonParamString = "a";
+ }
+ class MainParams {
+ @Parameter(names = "-a")
+ public boolean isA;
+ @Parameter(names = {"-b", "--long-b"})
+ public String bValue = "";
+ @ParametersDelegate
+ public EmptyDelegate delegate = new EmptyDelegate();
+ }
+
+ MainParams p = new MainParams();
+ JCommander cmd = new JCommander(p);
+ cmd.parse("-a", "-b", "someValue");
+ Assert.assertTrue(p.isA);
+ Assert.assertEquals(p.bValue, "someValue");
+ Assert.assertEquals(p.delegate.nonParamString, "a");
+ }
+
+ @Test
+ public void delegatingSetsFieldsOnBothMainParamsAndTheDelegatedParams() {
+ class ComplexDelegate {
+ @Parameter(names = "-c")
+ public boolean isC;
+ @Parameter(names = {"-d", "--long-d"})
+ public Integer d;
+ }
+ class MainParams {
+ @Parameter(names = "-a")
+ public boolean isA;
+ @Parameter(names = {"-b", "--long-b"})
+ public String bValue = "";
+ @ParametersDelegate
+ public ComplexDelegate delegate = new ComplexDelegate();
+ }
+
+ MainParams p = new MainParams();
+ JCommander cmd = new JCommander(p);
+ cmd.parse("-c", "--long-d", "123", "--long-b", "bValue");
+ Assert.assertFalse(p.isA);
+ Assert.assertEquals(p.bValue, "bValue");
+ Assert.assertTrue(p.delegate.isC);
+ Assert.assertEquals(p.delegate.d, Integer.valueOf(123));
+ }
+
+ @Test
+ public void combinedAndNestedDelegates() {
+ abstract class LeafAbstractDelegate {
+ abstract float getFloat();
+ }
+ class LeafDelegate {
+ @Parameter(names = "--list")
+ public List<String> list = new ArrayList<String>() {{
+ add("value1");
+ add("value2");
+ }};
+ @Parameter(names = "--bool")
+ public boolean bool;
+ }
+ class NestedDelegate1 {
+ @ParametersDelegate
+ public LeafDelegate leafDelegate = new LeafDelegate();
+ @Parameter(names = {"-d", "--long-d"})
+ public Integer d;
+ }
+ class NestedDelegate2 {
+ @Parameter(names = "-c")
+ public boolean isC;
+ @ParametersDelegate
+ public NestedDelegate1 nestedDelegate1 = new NestedDelegate1();
+ @ParametersDelegate
+ public LeafAbstractDelegate anonymousDelegate = new LeafAbstractDelegate() {
+ @Parameter(names = "--anon-float")
+ public float anon = 999f;
+
+ @Override
+ float getFloat() {
+ return anon;
+ }
+ };
+ }
+ class MainParams {
+ @Parameter(names = "-a")
+ public boolean isA;
+ @Parameter(names = {"-b", "--long-b"})
+ public String bValue = "";
+ @ParametersDelegate
+ public NestedDelegate2 nestedDelegate2 = new NestedDelegate2();
+ }
+
+ MainParams p = new MainParams();
+ JCommander cmd = new JCommander(p);
+ cmd.parse("--anon-float 1.2 -d 234 --list a --list b -a".split(" "));
+ Assert.assertEquals(p.nestedDelegate2.anonymousDelegate.getFloat(), 1.2f);
+ Assert.assertEquals(p.nestedDelegate2.nestedDelegate1.leafDelegate.list, new ArrayList<String>() {{
+ add("a");
+ add("b");
+ }});
+ Assert.assertFalse(p.nestedDelegate2.nestedDelegate1.leafDelegate.bool);
+ Assert.assertEquals(p.nestedDelegate2.nestedDelegate1.d, Integer.valueOf(234));
+ Assert.assertFalse(p.nestedDelegate2.isC);
+ Assert.assertTrue(p.isA);
+ Assert.assertEquals(p.bValue, "");
+ }
+
+ @Test
+ public void commandTest() {
+ class Delegate {
+ @Parameter(names = "-a")
+ public String a = "b";
+ }
+ class Command {
+ @ParametersDelegate
+ public Delegate delegate = new Delegate();
+ }
+
+ Command c = new Command();
+
+ JCommander cmd = new JCommander();
+ cmd.addCommand("command", c);
+
+ cmd.parse("command -a a".split(" "));
+ Assert.assertEquals(c.delegate.a, "a");
+ }
+
+ @Test
+ public void mainParametersTest() {
+ class Delegate {
+ @Parameter
+ public List<String> mainParams = new ArrayList<String>();
+ }
+ class Command {
+ @ParametersDelegate
+ public Delegate delegate = new Delegate();
+ }
+
+ Command c = new Command();
+
+ JCommander cmd = new JCommander();
+ cmd.addCommand("command", c);
+
+ cmd.parse("command main params".split(" "));
+ Assert.assertEquals(c.delegate.mainParams, new ArrayList<String>() {{
+ add("main");
+ add("params");
+ }});
+ }
+
+ @Test(expectedExceptions = ParameterException.class,
+ expectedExceptionsMessageRegExp = ".*delegate.*null.*")
+ public void nullDelegatesAreProhibited() {
+ class ComplexDelegate {
+ }
+ class MainParams {
+ @ParametersDelegate
+ public ComplexDelegate delegate;
+ }
+
+ MainParams p = new MainParams();
+ JCommander cmd = new JCommander(p);
+ cmd.parse();
+ }
+
+ @Test(expectedExceptions = ParameterException.class,
+ expectedExceptionsMessageRegExp = ".*-a.*")
+ public void duplicateDelegateThrowDuplicateOptionException() {
+ class Delegate {
+ @Parameter(names = "-a")
+ public String a;
+ }
+ class MainParams {
+ @ParametersDelegate
+ public Delegate d1 = new Delegate();
+ @ParametersDelegate
+ public Delegate d2 = new Delegate();
+ }
+
+ MainParams p = new MainParams();
+ JCommander cmd = new JCommander(p);
+ cmd.parse("-a value".split(" "));
+ }
+
+ @Test(expectedExceptions = ParameterException.class, expectedExceptionsMessageRegExp = "Only one.*is allowed.*")
+ public void duplicateMainParametersAreNotAllowed() {
+ class Delegate1 {
+ @Parameter
+ public List<String> mainParams1 = new ArrayList<String>();
+ }
+ class Delegate2 {
+ @Parameter
+ public List<String> mainParams2 = new ArrayList<String>();
+ }
+ class Command {
+ @ParametersDelegate
+ public Delegate1 delegate1 = new Delegate1();
+ @ParametersDelegate
+ public Delegate2 delegate2 = new Delegate2();
+ }
+
+ Command c = new Command();
+
+ JCommander cmd = new JCommander();
+ cmd.addCommand("command", c);
+
+ cmd.parse("command main params".split(" "));
+ }
+
+ public static void main(String[] args) {
+ new ParametersDelegateTest().commandTest();
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/PositiveIntegerTest.java b/src/test/java/com/beust/jcommander/PositiveIntegerTest.java
new file mode 100644
index 0000000..ec7d273
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/PositiveIntegerTest.java
@@ -0,0 +1,65 @@
+package com.beust.jcommander;
+
+import com.beust.jcommander.validators.PositiveInteger;
+
+import org.testng.annotations.Test;
+
+public class PositiveIntegerTest {
+
+ @Test
+ public void validateTest() {
+ class Arg {
+ @Parameter(names = { "-p", "--port" }, description = "Shows help", validateWith = PositiveInteger.class)
+ private int port = 0;
+ }
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg);
+ jc.parse(new String[] { "-p", "8080" });
+
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void validateTest2() {
+ class Arg {
+ @Parameter(names = { "-p", "--port" }, description = "Shows help", validateWith = PositiveInteger.class)
+ private int port = 0;
+ }
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg);
+ jc.parse(new String[] { "-p", "" });
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void validateTest3() {
+ class Arg {
+ @Parameter(names = { "-p", "--port" }, description = "Shows help", validateWith = PositiveInteger.class)
+ private int port = 0;
+ }
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg);
+ jc.parse(new String[] { "-p", "-1" });
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void validateTest4() {
+ class Arg {
+ @Parameter(names = { "-p", "--port" }, description = "Port Number", validateWith = PositiveInteger.class)
+ private int port = 0;
+ }
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg);
+ jc.parse(new String[] { "-p", "abc" });
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void validateTest5() {
+ class Arg {
+ @Parameter(names = { "-p", "--port" }, description = "Port Number", validateWith = PositiveInteger.class)
+ private int port = 0;
+ }
+
+ Arg arg = new Arg();
+ JCommander jc = new JCommander(arg);
+ jc.parse(new String[] { "--port", " " });
+ }
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/SetConverter.java b/src/test/java/com/beust/jcommander/SetConverter.java
new file mode 100644
index 0000000..c19df11
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/SetConverter.java
@@ -0,0 +1,16 @@
+package com.beust.jcommander;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class SetConverter implements IStringConverter<SortedSet<Integer>> {
+
+ public SortedSet<Integer> convert(String value) {
+ SortedSet<Integer> set = new TreeSet<Integer>();
+ String[] values = value.split(",");
+ for (String num : values) {
+ set.add(Integer.parseInt(num));
+ }
+ return set;
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/ValidatePropertiesWhenParsingTest.java b/src/test/java/com/beust/jcommander/ValidatePropertiesWhenParsingTest.java
new file mode 100644
index 0000000..6a3a98f
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/ValidatePropertiesWhenParsingTest.java
@@ -0,0 +1,42 @@
+package com.beust.jcommander;
+
+import org.testng.annotations.Test;
+
+public class ValidatePropertiesWhenParsingTest {
+ @Test
+ public void f()
+ throws Exception {
+
+ JCommander cmd = new JCommander();
+
+ cmd.addCommand("a", new A());
+// cmd.addCommand("b", new B());
+
+ cmd.parse(new String[] { "a", "-path", "myPathToHappiness" });
+ }
+
+ public static class MyPathValidator implements IParameterValidator {
+
+ public void validate(String name, String value) throws ParameterException {
+ throw new RuntimeException("I shouldn't be called for command A!");
+ }
+ }
+
+ @Parameters
+ public static class A {
+
+ @Parameter(names = "-path")
+ private String path = "W";
+ }
+
+ @Parameters
+ public static class B {
+
+ @Parameter(names = "-path", validateWith = MyPathValidator.class)
+ private String path = "W";
+ }
+
+ public static void main(String[] args) throws Exception {
+ new ValidatePropertiesWhenParsingTest().f();
+ }
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/VariableArityTest.java b/src/test/java/com/beust/jcommander/VariableArityTest.java
new file mode 100644
index 0000000..a90392f
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/VariableArityTest.java
@@ -0,0 +1,66 @@
+package com.beust.jcommander;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class VariableArityTest {
+
+ public static class ModelGenerationConfig {
+
+ @Parameter(names = { "-m", "--matrixData" }, variableArity = true,
+ description = "File containing a list of instances and their runtimes on various configurations", required = false)
+ public List<String> modelMatrixFile = new LinkedList<String>();
+
+ @Parameter(names = { "-f", "--featureData" }, variableArity = true,
+ description = "File containing a list of instances and their corresponding features", required = true)
+ public List<String> featureFile = new LinkedList<String>();
+
+ @Parameter(names = { "-c", "--configData" }, variableArity = true,
+ description = "File containing a list of configuration parameter values")
+ public List<String> configFile = new LinkedList<String>();
+
+ @Parameter(names = { "-o", "--outputFile" },
+ description = "File to output the resulting data to. Defaults to ./matrix-generation.zip", required = false)
+ public String outputFile = "matrix-generation.zip";
+
+ @Parameter(names = { "--seed" }, description = "Seed used for PRNG [0 means don't use a Seed]")
+ public long seed = 0;
+
+ public void print() {
+ System.out.println("modelMatrixFile: " + modelMatrixFile);
+ System.out.println("featureData: " + featureFile);
+ System.out.println("configFile: " + configFile);
+ System.out.println("output: " + outputFile);
+ System.out.println("seed: " + seed);
+
+ }
+ }
+
+ @Test
+ public void verifyVariableArity() {
+ String input = "-m foo --seed 1024 -c foo -o foo -f foo ";
+
+ String[] split = input.split("\\s+");
+
+ ModelGenerationConfig config = new ModelGenerationConfig();
+ JCommander com = new JCommander(config);
+ com.setProgramName("modelgen");
+
+ com.parse(split);
+
+// config.print();
+ Assert.assertNotEquals(config.seed, 0);
+ Assert.assertEquals(config.modelMatrixFile, Arrays.asList(new String[] { "foo" }));
+ Assert.assertEquals(config.featureFile, Arrays.asList(new String[] { "foo" }));
+ Assert.assertEquals(config.seed, 1024);
+ Assert.assertEquals(config.outputFile, "foo");
+ }
+
+ public static void main(String[] args) {
+ new VariableArityTest().verifyVariableArity();
+ }
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/args/AlternateNamesForListArgs.java b/src/test/java/com/beust/jcommander/args/AlternateNamesForListArgs.java
new file mode 100644
index 0000000..18a1655
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/AlternateNamesForListArgs.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.internal.Lists;
+import java.util.List;
+
+/**
+ *
+ * @author Andy Law <andy.law@roslin.ed.ac.uk>
+ */
+public class AlternateNamesForListArgs {
+
+ @Parameter(names = {"-s", "--servers"}, description = "blah")
+ public List<String> serverNames = Lists.newLinkedList();
+}
diff --git a/src/test/java/com/beust/jcommander/args/Args1.java b/src/test/java/com/beust/jcommander/args/Args1.java
new file mode 100644
index 0000000..093abec
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/Args1.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+import org.testng.collections.Lists;
+
+import com.beust.jcommander.Parameter;
+
+public class Args1 {
+ @Parameter
+ public List<String> parameters = Lists.newArrayList();
+
+ @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity", required = true)
+ public Integer verbose = 1;
+
+ @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
+ public String groups;
+
+ @Parameter(names = "-debug", description = "Debug mode")
+ public boolean debug = false;
+
+ @Parameter(names = "-long", description = "A long number")
+ public long l;
+
+ @Parameter(names = "-double", description = "A double number")
+ public double doub;
+
+ @Parameter(names = "-float", description = "A float number")
+ public float floa;
+
+ @Parameter(names = "-bigdecimal", description = "A BigDecimal number")
+ public BigDecimal bigd;
+
+ @Parameter(names = "-date", description = "An ISO 8601 formatted date.")
+ public Date date;
+}
diff --git a/src/test/java/com/beust/jcommander/args/Args1Setter.java b/src/test/java/com/beust/jcommander/args/Args1Setter.java
new file mode 100644
index 0000000..10f9ef3
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/Args1Setter.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.internal.Lists;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+public class Args1Setter {
+ @Parameter
+ public void setParameters(List<String> p) {
+ parameters = p;
+ }
+
+ public List<String> getParameters() {
+ return this.parameters;
+ }
+ public List<String> parameters = Lists.newArrayList();
+
+ @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity", required = true)
+ public void setVerbose(Integer v) {
+ verbose = v;
+ }
+ public Integer verbose = 1;
+
+ @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
+ public void setGroups(String g) {
+ groups = g;
+ }
+
+ public String groups;
+
+ @Parameter(names = "-debug", description = "Debug mode")
+ public void setDebug(boolean d) {
+ debug = d;
+ }
+
+ public boolean debug = false;
+
+ @Parameter(names = "-long", description = "A long number")
+ public void setLong(long ll) {
+ l = ll;
+ }
+
+ public long l;
+
+ @Parameter(names = "-double", description = "A double number")
+ public void setDouble(double d) {
+ doub = d;
+ }
+
+ public double doub;
+
+ @Parameter(names = "-float", description = "A float number")
+ public void setFloat(float f) {
+ floa = f;
+ }
+
+ public float floa;
+
+ @Parameter(names = "-bigdecimal", description = "A BigDecimal number")
+ public void setBigDecimal(BigDecimal bd) {
+ bigd = bd;
+ }
+
+ public BigDecimal bigd;
+
+ @Parameter(names = "-date", description = "An ISO 8601 formatted date.")
+ public void setDate(Date d) {
+ date = d;
+ }
+
+ public Date date;
+}
diff --git a/src/test/java/com/beust/jcommander/args/Args2.java b/src/test/java/com/beust/jcommander/args/Args2.java
new file mode 100644
index 0000000..89f622b
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/Args2.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.internal.Lists;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Args2 {
+ @Parameter(description = "List of parameters")
+ public List parameters = Lists.newArrayList();
+
+ @Parameter(names = {"-log", "-verbose"}, description = "Level of verbosity")
+ public Integer verbose = 1;
+
+ @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
+ public String groups;
+
+ @Parameter(names = "-debug", description = "Debug mode")
+ public boolean debug = false;
+
+ @Parameter(names = "-host", description = "The host")
+ public List hosts = new ArrayList();
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsArityInteger.java b/src/test/java/com/beust/jcommander/args/ArgsArityInteger.java
new file mode 100644
index 0000000..9c1611f
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsArityInteger.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+import java.util.List;
+
+/**
+ * Test parameter arity.
+ *
+ * @author cbeust
+ */
+public class ArgsArityInteger {
+
+ @Parameter(names = "-pairs", arity = 2, description = "Pairs")
+ public List<Integer> pairs;
+
+ @Parameter(description = "Rest")
+ public List<String> rest;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsArityString.java b/src/test/java/com/beust/jcommander/args/ArgsArityString.java
new file mode 100644
index 0000000..056ae85
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsArityString.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+import java.util.List;
+
+/**
+ * Test parameter arity.
+ *
+ * @author cbeust
+ */
+public class ArgsArityString {
+
+ @Parameter(names = "-pairs", arity = 2, description = "Pairs")
+ public List<String> pairs;
+
+ @Parameter(description = "Rest")
+ public List<String> rest;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsBooleanArity.java b/src/test/java/com/beust/jcommander/args/ArgsBooleanArity.java
new file mode 100644
index 0000000..242e347
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsBooleanArity.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsBooleanArity {
+ @Parameter(names = "-debug", arity = 1)
+ public Boolean debug = false;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsBooleanArity0.java b/src/test/java/com/beust/jcommander/args/ArgsBooleanArity0.java
new file mode 100644
index 0000000..62895ec
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsBooleanArity0.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsBooleanArity0 {
+ @Parameter(names = "-debug", arity = 0)
+ public Boolean debug = false;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsConverter.java b/src/test/java/com/beust/jcommander/args/ArgsConverter.java
new file mode 100644
index 0000000..677cf9b
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsConverter.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.converters.FileConverter;
+import com.beust.jcommander.converters.PathConverter;
+import com.beust.jcommander.converters.URIConverter;
+import com.beust.jcommander.converters.URLConverter;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.List;
+
+public class ArgsConverter {
+
+ @Parameter(names = "-file", converter = FileConverter.class)
+ public File file;
+
+ @Parameter(names = "-url", converter = URLConverter.class)
+ public URL url;
+
+ @Parameter(names = "-uri", converter = URIConverter.class)
+ public URI uri;
+
+ @Parameter(names = "-path", converter = PathConverter.class)
+ public Path path;
+
+ @Parameter(names = "-listStrings")
+ public List<String> listStrings;
+
+ @Parameter(names = "-listInts")
+ public List<Integer> listInts;
+
+ @Parameter(names = "-listBigDecimals")
+ public List<BigDecimal> listBigDecimals;
+
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsConverterFactory.java b/src/test/java/com/beust/jcommander/args/ArgsConverterFactory.java
new file mode 100644
index 0000000..f8463a0
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsConverterFactory.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.HostPort;
+import com.beust.jcommander.Parameter;
+
+public class ArgsConverterFactory {
+
+ @Parameter(names = "-hostport")
+ public HostPort hostPort;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsDefault.java b/src/test/java/com/beust/jcommander/args/ArgsDefault.java
new file mode 100644
index 0000000..1adcd73
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsDefault.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+import org.testng.collections.Lists;
+
+import java.util.List;
+
+public class ArgsDefault {
+ @Parameter
+ public List<String> parameters = Lists.newArrayList();
+
+ @Parameter(names = "-log", description = "Level of verbosity")
+ public Integer log = 1;
+
+ @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
+ public String groups;
+
+ @Parameter(names = "-debug", description = "Debug mode")
+ public boolean debug = false;
+
+ @Parameter(names = "-level", description = "A long number")
+ public long level;
+
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsEnum.java b/src/test/java/com/beust/jcommander/args/ArgsEnum.java
new file mode 100644
index 0000000..bef663b
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsEnum.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+
+import org.testng.Assert;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+
+/**
+ * Test enums.
+ *
+ * @author Adrian Muraru
+ */
+public class ArgsEnum {
+
+ public enum ChoiceType { ONE, Two, THREE };
+ @Parameter(names = "-choice")
+ public ChoiceType choice = ChoiceType.ONE;
+
+ @Parameter(names = "-choices", variableArity = true)
+ public List<ChoiceType> choices = new ArrayList<ChoiceType>();
+
+ public static void main(String[] args1) {
+ ArgsEnum args = new ArgsEnum();
+ String[] argv = { "-choice", "ONE"};
+ JCommander jc = new JCommander(args, argv);
+ jc.usage();
+ Assert.assertEquals(jc.getParameters().get(0).getDescription(),
+ "Options: " + EnumSet.allOf((Class<? extends Enum>) ArgsEnum.ChoiceType.class));
+ }
+
+}
+
+
diff --git a/src/test/java/com/beust/jcommander/args/ArgsEquals.java b/src/test/java/com/beust/jcommander/args/ArgsEquals.java
new file mode 100644
index 0000000..016166d
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsEquals.java
@@ -0,0 +1,11 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+@Parameters(separators = "=")
+public class ArgsEquals {
+
+ @Parameter(names = "-args")
+ public String args;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsHelp.java b/src/test/java/com/beust/jcommander/args/ArgsHelp.java
new file mode 100644
index 0000000..4baaddd
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsHelp.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+/**
+ * Test a help option which overrides other options and option validations
+ */
+public class ArgsHelp {
+
+ @Parameter(names = "-h", description = "Display help")
+ public boolean help;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsI18N1.java b/src/test/java/com/beust/jcommander/args/ArgsI18N1.java
new file mode 100644
index 0000000..80e29e2
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsI18N1.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsI18N1 {
+
+ @Parameter(names = "-host", description = "Host", descriptionKey = "host")
+ String hostName;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsI18N2.java b/src/test/java/com/beust/jcommander/args/ArgsI18N2.java
new file mode 100644
index 0000000..1ccfd43
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsI18N2.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ResourceBundle;
+
+@SuppressWarnings("deprecation")
+@ResourceBundle("MessageBundle")
+public class ArgsI18N2 {
+
+ @Parameter(names = "-host", description = "Host", descriptionKey = "host")
+ String hostName;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsI18N2New.java b/src/test/java/com/beust/jcommander/args/ArgsI18N2New.java
new file mode 100644
index 0000000..c760973
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsI18N2New.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+import java.util.List;
+
+@Parameters(resourceBundle = "MessageBundle")
+public class ArgsI18N2New {
+
+ @Parameter(names = "-host", description = "Host", descriptionKey = "host")
+ String hostName;
+
+ @Parameter(descriptionKey = "files")
+ List<String> files;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsInherited.java b/src/test/java/com/beust/jcommander/args/ArgsInherited.java
new file mode 100644
index 0000000..abc0e82
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsInherited.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsInherited extends ArgsDefault {
+
+ @Parameter(names = "-child", description = "Child parameter")
+ public Integer child = 1;
+
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsList.java b/src/test/java/com/beust/jcommander/args/ArgsList.java
new file mode 100644
index 0000000..e827773
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsList.java
@@ -0,0 +1,49 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.HostPort;
+import com.beust.jcommander.HostPortConverter;
+import com.beust.jcommander.IStringConverter;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.converters.IParameterSplitter;
+
+import org.testng.collections.Lists;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ArgsList {
+ @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
+ public List<String> groups;
+
+ @Parameter(names = "-ints")
+ public List<Integer> ints;
+
+ @Parameter(names = "-hp", converter = HostPortConverter.class, splitter = SemiColonSplitter.class)
+ public List<HostPort> hostPorts;
+
+ @Parameter(names = "-hp2", converter = HostPortConverter.class)
+ public List<HostPort> hp2;
+
+ @Parameter(names = "-uppercase", listConverter = UppercaseConverter.class)
+ public List<String> uppercase;
+
+ public static class UppercaseConverter implements IStringConverter<List<String>> {
+ public List<String> convert(String value) {
+ List<String> result = Lists.newArrayList();
+ String[] s = value.split(",");
+ for (String p : s) {
+ result.add(p.toUpperCase());
+ }
+ return result;
+ }
+ }
+
+ public static class SemiColonSplitter implements IParameterSplitter {
+
+ public List<String> split(String value) {
+ return Arrays.asList(value.split(";"));
+ }
+
+ }
+
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsLongDescription.java b/src/test/java/com/beust/jcommander/args/ArgsLongDescription.java
new file mode 100644
index 0000000..e961016
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsLongDescription.java
@@ -0,0 +1,25 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsLongDescription {
+
+ @Parameter(names = "--classpath", description = "The classpath. This is a very long "
+ + "description in order to test the line wrapping. Let's see how this works."
+ + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor"
+ + " incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis "
+ + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.")
+ public String classpath = "/tmp";
+
+ @Parameter(names = { "-c", "--convention" }, description = "The convention", required = true)
+ public String convention = "Java";
+
+ @Parameter(names = { "-d", "--destination" }, description = "The destination to go to")
+ public String destination;
+
+ @Parameter(names = "--configure", description = "How to configure")
+ public String configure;
+
+ @Parameter(names = "--filespec")
+ public String filespec;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsMainParameter1.java b/src/test/java/com/beust/jcommander/args/ArgsMainParameter1.java
new file mode 100644
index 0000000..cd5c52d
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsMainParameter1.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.HostPort;
+import com.beust.jcommander.Parameter;
+
+import org.testng.collections.Lists;
+
+import java.util.List;
+
+/**
+ * A class with main parameter that is not a List<String>
+ *
+ * @author cbeust
+ */
+public class ArgsMainParameter1 implements IHostPorts {
+ @Parameter
+ public List<HostPort> parameters = Lists.newArrayList();
+
+ public List<HostPort> getHostPorts() {
+ return parameters;
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsMainParameter2.java b/src/test/java/com/beust/jcommander/args/ArgsMainParameter2.java
new file mode 100644
index 0000000..57422e3
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsMainParameter2.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.HostPort;
+import com.beust.jcommander.HostPortConverter;
+import com.beust.jcommander.Parameter;
+
+import org.testng.collections.Lists;
+
+import java.util.List;
+
+/**
+ * A class with main parameter that is not a List<String>
+ *
+ * @author cbeust
+ */
+public class ArgsMainParameter2 implements IHostPorts {
+ @Parameter(converter = HostPortConverter.class)
+ public List<HostPort> parameters = Lists.newArrayList();
+
+ public List<HostPort> getHostPorts() {
+ return parameters;
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsMaster.java b/src/test/java/com/beust/jcommander/args/ArgsMaster.java
new file mode 100644
index 0000000..ebcba67
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsMaster.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+/**
+ * Test multi-object parsing, along with ArgsSlave.
+ *
+ * @author cbeust
+ */
+public class ArgsMaster {
+ @Parameter(names = "-master")
+ public String master;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsMultipleUnparsed.java b/src/test/java/com/beust/jcommander/args/ArgsMultipleUnparsed.java
new file mode 100644
index 0000000..f7b0628
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsMultipleUnparsed.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+/**
+ * Error case if multiple unparsed (without a names attribute) arguments are defined.
+ *
+ * @author cbeust
+ */
+public class ArgsMultipleUnparsed {
+
+ @Parameter(description = "Bogus1")
+ public String unparsed1;
+
+ @Parameter(description = "Bogus2")
+ public String unparsed2;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsOutOfMemory.java b/src/test/java/com/beust/jcommander/args/ArgsOutOfMemory.java
new file mode 100644
index 0000000..f059ebb
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsOutOfMemory.java
@@ -0,0 +1,13 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsOutOfMemory
+{
+ @Parameter(names = { "-p", "--pattern" },
+ description = "pattern used by 'tail'. See http://logback.qos.ch/manual/layouts.html#ClassicPatternLayout and http://logback.qos.ch/manual/layouts.html#AccessPatternLayout")
+ public String pattern;
+
+ @Parameter(names = "-q", description = "Filler arg")
+ public String filler;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsPassword.java b/src/test/java/com/beust/jcommander/args/ArgsPassword.java
new file mode 100644
index 0000000..06c468e
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsPassword.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsPassword {
+ @Parameter(names = "-password", description = "Connection password", password = true)
+ public String password;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsPrivate.java b/src/test/java/com/beust/jcommander/args/ArgsPrivate.java
new file mode 100644
index 0000000..16e4b4e
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsPrivate.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class ArgsPrivate {
+ @Parameter(names = "-verbose")
+ private Integer verbose = 1;
+
+ public Integer getVerbose() {
+ return verbose;
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsRequired.java b/src/test/java/com/beust/jcommander/args/ArgsRequired.java
new file mode 100644
index 0000000..69cb814
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsRequired.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.internal.Lists;
+
+import java.util.List;
+
+public class ArgsRequired {
+
+ @Parameter(description = "List of files", required = true)
+ public List<String> parameters = Lists.newArrayList();
+
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsSlave.java b/src/test/java/com/beust/jcommander/args/ArgsSlave.java
new file mode 100644
index 0000000..dabeb57
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsSlave.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+/**
+ * Test multi-object parsing, along with ArgsSlave.
+ *
+ * @author cbeust
+ */
+public class ArgsSlave {
+ @Parameter(names = "-slave")
+ public String slave;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsSlaveBogus.java b/src/test/java/com/beust/jcommander/args/ArgsSlaveBogus.java
new file mode 100644
index 0000000..1abdf1f
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsSlaveBogus.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+/**
+ * Same as ArgsMaster class, should cause an error.
+ *
+ * @author cbeust
+ */
+public class ArgsSlaveBogus extends ArgsSlave {
+ @Parameter(names = "-master")
+ public String master;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsValidate1.java b/src/test/java/com/beust/jcommander/args/ArgsValidate1.java
new file mode 100644
index 0000000..5274220
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsValidate1.java
@@ -0,0 +1,10 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.validators.PositiveInteger;
+
+public class ArgsValidate1 {
+
+ @Parameter(names = "-age", validateWith = PositiveInteger.class)
+ public Integer age;
+}
diff --git a/src/test/java/com/beust/jcommander/args/ArgsWithSet.java b/src/test/java/com/beust/jcommander/args/ArgsWithSet.java
new file mode 100644
index 0000000..1e41cd3
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/ArgsWithSet.java
@@ -0,0 +1,11 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.SetConverter;
+
+import java.util.SortedSet;
+
+public class ArgsWithSet {
+ @Parameter(names = "-s", converter = SetConverter.class)
+ public SortedSet<Integer> set;
+} \ No newline at end of file
diff --git a/src/test/java/com/beust/jcommander/args/Arity1.java b/src/test/java/com/beust/jcommander/args/Arity1.java
new file mode 100644
index 0000000..8cbf086
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/Arity1.java
@@ -0,0 +1,9 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+
+public class Arity1
+{
+ @Parameter(arity = 1, names = "-inspect", description = "", required = false)
+ public boolean inspect;
+}
diff --git a/src/test/java/com/beust/jcommander/args/CommandLineArgs.java b/src/test/java/com/beust/jcommander/args/CommandLineArgs.java
new file mode 100644
index 0000000..7c8414f
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/CommandLineArgs.java
@@ -0,0 +1,120 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.internal.Lists;
+
+import java.util.List;
+
+public class CommandLineArgs {
+
+ @Parameter(description = "The XML suite files to run")
+ public List<String> suiteFiles = Lists.newArrayList();
+
+ @Parameter(names = { "-log", "-verbose" }, description = "Level of verbosity")
+ public Integer verbose;
+
+ @Parameter(names = "-groups", description = "Comma-separated list of group names to be run")
+ public String groups;
+
+ @Parameter(names = "-excludedgroups", description ="Comma-separated list of group names to be " +
+ "run")
+ public String excludedGroups;
+
+ @Parameter(names = "-d", description ="Output directory")
+ public String outputDirectory;
+
+ @Parameter(names = "-junit", description ="JUnit mode")
+ public Boolean junit = Boolean.FALSE;
+
+ @Parameter(names = "-listener", description = "List of .class files or list of class names" +
+ " implementing ITestListener or ISuiteListener")
+ public String listener;
+
+ @Parameter(names = "-methodselectors", description = "List of .class files or list of class " +
+ "names implementing IMethodSelector")
+ public String methodSelectors;
+
+ @Parameter(names = "-objectfactory", description = "List of .class files or list of class " +
+ "names implementing ITestRunnerFactory")
+ public String objectFactory;
+
+ @Parameter(names = "-parallel", description = "Parallel mode (methods, tests or classes)")
+ public String parallelMode;
+
+ @Parameter(names = "-configfailurepolicy", description = "Configuration failure policy (skip or continue)")
+ public String configFailurePolicy;
+
+ @Parameter(names = "-threadcount", description = "Number of threads to use when running tests " +
+ "in parallel")
+ public Integer threadCount;
+
+ @Parameter(names = "-dataproviderthreadcount", description = "Number of threads to use when " +
+ "running data providers")
+ public Integer dataProviderThreadCount;
+
+ @Parameter(names = "-suitename", description = "Default name of test suite, if not specified " +
+ "in suite definition file or source code")
+ public String suiteName;
+
+ @Parameter(names = "-testname", description = "Default name of test, if not specified in suite" +
+ "definition file or source code")
+ public String testName;
+
+ @Parameter(names = "-reporter", description = "Extended configuration for custom report listener")
+ public String reporter;
+
+ /**
+ * Used as map key for the complete list of report listeners provided with the above argument
+ */
+ @Parameter(names = "-reporterslist")
+ public String reportersList;
+
+ @Parameter(names = "-usedefaultlisteners", description = "Whether to use the default listeners")
+ public String useDefaultListeners = "true";
+
+ @Parameter(names = "-skipfailedinvocationcounts")
+ public Boolean skipFailedInvocationCounts;
+
+ @Parameter(names = "-testclass", description = "The list of test classes")
+ public String testClass;
+
+ @Parameter(names = "-testnames", description = "The list of test names to run")
+ public String testNames;
+
+ @Parameter(names = "-testjar", description = "")
+ public String testJar;
+
+ @Parameter(names = "-testRunFactory", description = "")
+ public String testRunFactory;
+
+ @Parameter(names = "-port", description = "The port")
+ public Integer port;
+
+ @Parameter(names = "-host", description = "The host")
+ public String host;
+
+ @Parameter(names = "-master", description ="Host where the master is")
+ public String master;
+
+ @Parameter(names = "-slave", description ="Host where the slave is")
+ public String slave;
+
+}
diff --git a/src/test/java/com/beust/jcommander/args/CommandLineArgs2.java b/src/test/java/com/beust/jcommander/args/CommandLineArgs2.java
new file mode 100644
index 0000000..ac62792
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/CommandLineArgs2.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.converters.FileConverter;
+
+import java.io.File;
+import java.util.List;
+
+public class CommandLineArgs2 {
+ @Parameter(description = "list of files")
+ List<String> list;
+
+ @Parameter(names = { "-v", "--verbose" }, description = "print verbose log messages.", arity = 1)
+ public boolean verbose = false;
+
+ @Parameter(names = { "-h", "--help" }, description = "show this help.")
+ public boolean showHelp = false;
+
+ @Parameter(names = { "-F", "--flush-preferences" }, description = "flush gui preferences.")
+ public boolean flushPreferences = false;
+
+ @Parameter(names = { "-L", "--flush-licensed" }, description = "flush licensed.")
+ public boolean flushLicensed = false;
+
+ @Parameter(names = { "-I", "--index-file" }, description = "indexes the given file.")
+ public Long indexFile;
+
+ @Parameter(names = { "-b", "--bonjour" }, description = "enable Bonjour.")
+ public boolean enableBonjour = false;
+
+ @Parameter(names = { "-m", "--md5" }, description = "create an MD5 checksum for the given file.", converter = FileConverter.class)
+ public File md5File;
+
+ @Parameter(names = { "-c", "--cat" }, description = "'cat' the given Lilith logfile.", converter = FileConverter.class)
+ public File catFile;
+
+ @Parameter(names = { "-t", "--tail" }, description = "'tail' the given Lilith logfile.", converter = FileConverter.class)
+ public File tailFile;
+
+ @Parameter(names = { "-p", "--pattern" }, description = "pattern used by 'cat' or 'tail'.")
+ public String pattern;
+
+ @Parameter(names = { "-f", "--keep-running" }, description = "keep tailing the given Lilith logfile.")
+ public boolean keepRunning = false;
+
+ @Parameter(names = { "-n", "--number-of-lines" }, description = "number of entries printed by cat or tail")
+ public Integer numberOfLines = -1;
+
+ @Parameter(names = { "-e", "--export-preferences" }, description = "export preferences into the given file.")
+ public String exportPreferencesFile;
+
+ @Parameter(names = { "-i", "--import-preferences" }, description = "import preferences from the given file.")
+ public String importPreferencesFile;
+}
diff --git a/src/test/java/com/beust/jcommander/args/IHostPorts.java b/src/test/java/com/beust/jcommander/args/IHostPorts.java
new file mode 100644
index 0000000..2020c77
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/IHostPorts.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.HostPort;
+
+import java.util.List;
+
+public interface IHostPorts {
+ List<HostPort> getHostPorts();
+}
diff --git a/src/test/java/com/beust/jcommander/args/SeparatorColon.java b/src/test/java/com/beust/jcommander/args/SeparatorColon.java
new file mode 100644
index 0000000..ab454fc
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/SeparatorColon.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+@Parameters(separators = ":")
+public class SeparatorColon {
+
+ @Parameter(names = "-verbose", arity = 1)
+ public boolean verbose = false;
+}
diff --git a/src/test/java/com/beust/jcommander/args/SeparatorEqual.java b/src/test/java/com/beust/jcommander/args/SeparatorEqual.java
new file mode 100644
index 0000000..a135207
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/SeparatorEqual.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+@Parameters(separators = "=")
+public class SeparatorEqual {
+
+ @Parameter(names = "-log")
+ public Integer log = 2;
+
+ @Parameter(names = "--longoption")
+ public Integer longOption;
+}
diff --git a/src/test/java/com/beust/jcommander/args/SeparatorMixed.java b/src/test/java/com/beust/jcommander/args/SeparatorMixed.java
new file mode 100644
index 0000000..aa2641f
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/SeparatorMixed.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+@Parameters(separators = ":=")
+public class SeparatorMixed {
+
+ @Parameter(names = "-level")
+ public Integer level = 0;
+
+ @Parameter(names = "-long")
+ public Long l = 0l;
+}
diff --git a/src/test/java/com/beust/jcommander/args/SlashSeparator.java b/src/test/java/com/beust/jcommander/args/SlashSeparator.java
new file mode 100644
index 0000000..64d3930
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/SlashSeparator.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+@Parameters(optionPrefixes = "/")
+public class SlashSeparator {
+
+ @Parameter(names = "/verbose")
+ public boolean verbose = false;
+
+ @Parameter(names = "/file")
+ public String file;
+}
diff --git a/src/test/java/com/beust/jcommander/args/VariableArity.java b/src/test/java/com/beust/jcommander/args/VariableArity.java
new file mode 100644
index 0000000..21a861d
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/args/VariableArity.java
@@ -0,0 +1,26 @@
+package com.beust.jcommander.args;
+
+import com.beust.jcommander.IVariableArity;
+import com.beust.jcommander.Parameter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class VariableArity implements IVariableArity {
+
+ private int m_count;
+
+ public VariableArity(int count) {
+ m_count = count;
+ }
+
+ @Parameter
+ public List<String> main = new ArrayList<String>();
+
+ @Parameter(names = "-variable", variableArity = true)
+ public List<String> var = new ArrayList<String>();
+
+ public int processVariableArity(String optionName, String[] options) {
+ return m_count;
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/command/CommandAdd.java b/src/test/java/com/beust/jcommander/command/CommandAdd.java
new file mode 100644
index 0000000..733e490
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/CommandAdd.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+import java.util.List;
+
+@Parameters(commandDescription = "Add file contents to the index")
+public class CommandAdd {
+
+ @Parameter(description = "Patterns of files to be added")
+ public List<String> patterns;
+
+ @Parameter(names = "-i")
+ public Boolean interactive = false;
+
+}
diff --git a/src/test/java/com/beust/jcommander/command/CommandAliasTest.java b/src/test/java/com/beust/jcommander/command/CommandAliasTest.java
new file mode 100644
index 0000000..4eee7f2
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/CommandAliasTest.java
@@ -0,0 +1,175 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Tests command alias functionality
+ *
+ * @author rodionmoiseev
+ */
+public class CommandAliasTest {
+ @Test
+ public void oneCommandWithSingleAlias() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add, "a");
+ jc.parse("a", "-i", "A.java");
+
+ Assert.assertEquals(jc.getParsedCommand(), "add");
+ Assert.assertEquals(jc.getParsedAlias(), "a");
+ Assert.assertEquals(add.interactive.booleanValue(), true);
+ Assert.assertEquals(add.patterns, Arrays.asList("A.java"));
+ }
+
+ @Test
+ public void oneCommandWithMultipleAliases_commit_ci() {
+ testCommitWithAlias("ci");
+ }
+
+ @Test
+ public void oneCommandWithMultipleAliases_commit_cmt() {
+ testCommitWithAlias("cmt");
+ }
+
+ private void testCommitWithAlias(String alias) {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit, "ci", "cmt");
+ jc.parse(alias, "--amend", "--author", "jack", "file1.txt");
+
+ Assert.assertEquals(jc.getParsedCommand(), "commit");
+ Assert.assertEquals(jc.getParsedAlias(), alias);
+ Assert.assertEquals(commit.amend.booleanValue(), true);
+ Assert.assertEquals(commit.author, "jack");
+ Assert.assertEquals(commit.files, Arrays.asList("file1.txt"));
+ }
+
+ @Test
+ public void twoCommandsWithAliases() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add, "a");
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit, "ci", "cmt");
+ jc.parse("a", "-i", "A.java");
+
+ Assert.assertEquals(jc.getParsedCommand(), "add");
+ Assert.assertEquals(add.interactive.booleanValue(), true);
+ Assert.assertEquals(add.patterns, Arrays.asList("A.java"));
+ }
+
+ @Test
+ public void clashingAliasesAreNotAllowed() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add, "xx");
+ CommandCommit commit = new CommandCommit();
+ try {
+ jc.addCommand("commit", commit, "ci", "xx");
+ Assert.fail("Should not be able to register clashing alias 'xx'");
+ } catch (ParameterException pe) {
+ //Make sure the message mentions that "xx" aliases is already
+ //defined for "add" command
+ Assert.assertTrue(pe.getMessage().contains("xx"));
+ Assert.assertTrue(pe.getMessage().contains("add"));
+ }
+ }
+
+ @Test
+ public void mainCommandReturnsNullsForGetCommandAndGetParsedAlias() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ Assert.assertNull(jc.getParsedCommand());
+ Assert.assertNull(jc.getParsedAlias());
+ }
+
+ @Test
+ public void usageCanBeRetrievedWithBothCommandAndAlias() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit, "ci", "cmt");
+ StringBuilder out = new StringBuilder();
+ jc.usage("commit", out);
+ patternMatchesTimes("commit\\(ci,cmt\\)", out.toString(), 1);
+
+ out = new StringBuilder();
+ jc.usage("ci", out);
+ patternMatchesTimes("commit\\(ci,cmt\\)", out.toString(), 1);
+
+ out = new StringBuilder();
+ jc.usage("cmt", out);
+ patternMatchesTimes("commit\\(ci,cmt\\)", out.toString(), 1);
+ }
+
+ @Test
+ public void usageDisplaysCommandWithAliasesOnlyOnce() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit, "ci", "cmt");
+ StringBuilder out = new StringBuilder();
+ jc.usage(out);
+ // The usage should display this string twice: one as the command name
+ // and one after Usage:
+ patternMatchesTimes("commit\\(ci,cmt\\)", out.toString(), 2);
+ }
+
+ /**
+ * Visually test the formatting for "prettiness"
+ */
+ @Test(enabled = false, description = "TODO: test the output instead of displaying it")
+ public void formattingLooksNice(){
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add, "a");
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit, "ci", "cmt");
+ StringBuilder sb = new StringBuilder();
+ jc.usage(sb);
+ System.out.println("--- usage() formatting ---");
+ System.out.println(sb.toString());
+
+ sb = new StringBuilder();
+ jc.usage("commit", sb);
+ System.out.println("--- usage('commit') formatting ---");
+ System.out.println(sb.toString());
+ }
+
+ private void patternMatchesTimes(String pattern, String input, int times) {
+ Matcher m = Pattern.compile(pattern).matcher(input);
+ int matches = 0;
+ while (m.find()) matches++;
+ Assert.assertEquals(matches, times);
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/command/CommandCommit.java b/src/test/java/com/beust/jcommander/command/CommandCommit.java
new file mode 100644
index 0000000..2934a89
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/CommandCommit.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+import java.util.List;
+
+@Parameters(separators = "=", commandDescription = "Record changes to the repository")
+public class CommandCommit {
+
+ @Parameter(description = "List of files")
+ public List<String> files;
+
+ @Parameter(names = "--amend", description = "Amend")
+ public Boolean amend = false;
+
+ @Parameter(names = "--author")
+ public String author;
+}
diff --git a/src/test/java/com/beust/jcommander/command/CommandHidden.java b/src/test/java/com/beust/jcommander/command/CommandHidden.java
new file mode 100644
index 0000000..a3fc4fa
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/CommandHidden.java
@@ -0,0 +1,17 @@
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+import java.util.List;
+
+@Parameters(commandNames = "add", commandDescription = "Hidden command to add file contents to the index", hidden = true)
+public class CommandHidden {
+
+ @Parameter(description = "Patterns of files to be added")
+ public List<String> patterns;
+
+ @Parameter(names = "-i")
+ public Boolean interactive = false;
+
+}
diff --git a/src/test/java/com/beust/jcommander/command/CommandMain.java b/src/test/java/com/beust/jcommander/command/CommandMain.java
new file mode 100644
index 0000000..c205116
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/CommandMain.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.Parameter;
+
+public class CommandMain {
+
+ @Parameter(names = "-v", description = "Verbose mode")
+ public Boolean verbose = false;
+}
diff --git a/src/test/java/com/beust/jcommander/command/CommandTest.java b/src/test/java/com/beust/jcommander/command/CommandTest.java
new file mode 100644
index 0000000..cf921bd
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/CommandTest.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (C) 2010 the original author or authors.
+ * See the notice.md file distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class CommandTest {
+ @Test
+ public void namedCommandTest1() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ NamedCommandAdd add = new NamedCommandAdd();
+ jc.addCommand(add);
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit);
+ jc.parse("add", "-i", "A.java");
+
+ Assert.assertEquals(jc.getParsedCommand(), "add");
+ Assert.assertEquals(add.interactive.booleanValue(), true);
+ Assert.assertEquals(add.patterns, Arrays.asList("A.java"));
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void shouldComplainIfNoAnnotations() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand(add);
+ }
+
+ @Test
+ public void commandTest1() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add);
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit);
+ jc.parse("add", "-i", "A.java");
+
+ Assert.assertEquals(jc.getParsedCommand(), "add");
+ Assert.assertEquals(add.interactive.booleanValue(), true);
+ Assert.assertEquals(add.patterns, Arrays.asList("A.java"));
+ }
+
+ @Test
+ public void commandTest2() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add);
+ CommandCommit commit = new CommandCommit();
+ jc.addCommand("commit", commit);
+ jc.parse("-v", "commit", "--amend", "--author=cbeust", "A.java", "B.java");
+
+// jc.setProgramName("TestCommander");
+// jc.usage();
+// jc.usage("add");
+// jc.usage("commit");
+
+ Assert.assertTrue(cm.verbose);
+ Assert.assertEquals(jc.getParsedCommand(), "commit");
+ Assert.assertTrue(commit.amend);
+ Assert.assertEquals(commit.author, "cbeust");
+ Assert.assertEquals(commit.files, Arrays.asList("A.java", "B.java"));
+ }
+
+ @Test
+ public void hiddenCommandTest() {
+ CommandMain cm = new CommandMain();
+ JCommander jc = new JCommander(cm);
+ CommandAdd add = new CommandAdd();
+ jc.addCommand("add", add);
+ CommandHidden hidden = new CommandHidden();
+ jc.addCommand("hidden", hidden);
+ jc.parse("hidden", "-i", "A.java");
+
+ Assert.assertEquals(jc.getParsedCommand(), "hidden");
+ Assert.assertEquals(hidden.interactive.booleanValue(), true);
+ Assert.assertEquals(hidden.patterns, Arrays.asList("A.java"));
+
+ jc.setProgramName("TestCommander");
+ StringBuilder out = new StringBuilder();
+ jc.usage(out);
+
+ Assert.assertTrue(out.toString().contains("add Add file contents to the index"));
+ Assert.assertFalse(out.toString().contains("hidden Hidden command to add file contents to the index"));
+ }
+
+ public static void main(String[] args) {
+ new CommandTest().shouldComplainIfNoAnnotations();
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/command/NamedCommandAdd.java b/src/test/java/com/beust/jcommander/command/NamedCommandAdd.java
new file mode 100644
index 0000000..0773e18
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/command/NamedCommandAdd.java
@@ -0,0 +1,17 @@
+package com.beust.jcommander.command;
+
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.Parameters;
+
+import java.util.List;
+
+@Parameters(commandNames = "add", commandDescription = "Add file contents to the index")
+public class NamedCommandAdd {
+
+ @Parameter(description = "Patterns of files to be added")
+ public List<String> patterns;
+
+ @Parameter(names = "-i")
+ public Boolean interactive = false;
+
+}
diff --git a/src/test/java/com/beust/jcommander/dynamic/DSimple.java b/src/test/java/com/beust/jcommander/dynamic/DSimple.java
new file mode 100644
index 0000000..deb5a2b
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/dynamic/DSimple.java
@@ -0,0 +1,16 @@
+package com.beust.jcommander.dynamic;
+
+import com.beust.jcommander.DynamicParameter;
+
+import org.testng.collections.Maps;
+
+import java.util.Map;
+
+public class DSimple {
+
+ @DynamicParameter(names = "-D", description = "Dynamic parameters go here")
+ public Map<String, String> params = Maps.newHashMap();
+
+ @DynamicParameter(names = "-A", assignment = "@")
+ public Map<String, String> params2 = Maps.newHashMap();
+}
diff --git a/src/test/java/com/beust/jcommander/dynamic/DSimpleBad.java b/src/test/java/com/beust/jcommander/dynamic/DSimpleBad.java
new file mode 100644
index 0000000..f859029
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/dynamic/DSimpleBad.java
@@ -0,0 +1,11 @@
+package com.beust.jcommander.dynamic;
+
+import com.beust.jcommander.DynamicParameter;
+
+import java.util.List;
+
+public class DSimpleBad {
+
+ @DynamicParameter(names = "-D")
+ public List<String> params;
+}
diff --git a/src/test/java/com/beust/jcommander/dynamic/DynamicParameterTest.java b/src/test/java/com/beust/jcommander/dynamic/DynamicParameterTest.java
new file mode 100644
index 0000000..98327bd
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/dynamic/DynamicParameterTest.java
@@ -0,0 +1,60 @@
+package com.beust.jcommander.dynamic;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.ParameterException;
+import com.beust.jcommander.internal.Maps;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class DynamicParameterTest {
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void nonMapShouldThrow() {
+ new JCommander(new DSimpleBad()).parse("-D", "a=b", "-D", "c=d");
+ }
+
+ @Test(expectedExceptions = ParameterException.class)
+ public void wrongSeparatorShouldThrow() {
+ DSimple ds = new DSimple();
+ new JCommander(ds).parse("-D", "a:b", "-D", "c=d");
+ }
+
+ private void simple(String... parameters) {
+ DSimple ds = new DSimple();
+ new JCommander(ds).parse(parameters);
+ Assert.assertEquals(ds.params, Maps.newHashMap("a", "b", "c", "d"));
+ }
+
+ public void simpleWithSpaces() {
+ simple("-D", "a=b", "-D", "c=d");
+ }
+
+ public void simpleWithoutSpaces() {
+ simple("-Da=b", "-Dc=d");
+ }
+
+ public void usage() {
+ DSimple ds = new DSimple();
+ new JCommander(ds).usage(new StringBuilder());
+ }
+
+ public void differentAssignment() {
+ DSimple ds = new DSimple();
+ new JCommander(ds).parse("-D", "a=b", "-A", "c@d");
+ Assert.assertEquals(ds.params, Maps.newHashMap("a", "b"));
+ Assert.assertEquals(ds.params2, Maps.newHashMap("c", "d"));
+ }
+
+ @Test(enabled = false)
+ public static void main(String[] args) {
+ DynamicParameterTest dpt = new DynamicParameterTest();
+ dpt.simpleWithSpaces();
+// dpt.nonMapShouldThrow();
+// dpt.wrongSeparatorShouldThrow();
+// dpt.differentAssignment();
+// dpt.arity0();
+// dpt.usage();
+ }
+}
diff --git a/src/test/java/com/beust/jcommander/internal/DefaultConsoleTest.java b/src/test/java/com/beust/jcommander/internal/DefaultConsoleTest.java
new file mode 100644
index 0000000..e101439
--- /dev/null
+++ b/src/test/java/com/beust/jcommander/internal/DefaultConsoleTest.java
@@ -0,0 +1,64 @@
+package com.beust.jcommander.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@Test
+public class DefaultConsoleTest {
+ public void readPasswordCanBeCalledMultipleTimes() {
+ final InputStream inBackup = System.in;
+ try {
+ final StringInputStream in = new StringInputStream();
+ System.setIn(in);
+ final Console console = new DefaultConsole();
+
+ in.setData("password1\n");
+ char[] password = console.readPassword(false);
+ Assert.assertEquals(password, "password1".toCharArray());
+ Assert.assertFalse(in.isClosedCalled(), "System.in stream shouldn't be closed");
+
+ in.setData("password2\n");
+ password = console.readPassword(false);
+ Assert.assertEquals(password, "password2".toCharArray());
+ Assert.assertFalse(in.isClosedCalled(), "System.in stream shouldn't be closed");
+ } finally {
+ System.setIn(inBackup);
+ }
+ }
+
+ private static class StringInputStream extends InputStream {
+ private byte[] data = new byte[0];
+ private int offset = 0;
+ private boolean closedCalled;
+
+ StringInputStream() {
+ super();
+ }
+
+ void setData(final String strData) {
+ data = strData.getBytes();
+ offset = 0;
+ }
+
+ boolean isClosedCalled() {
+ return closedCalled;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (offset >= data.length) {
+ return -1;
+ }
+ return 0xFFFF & data[offset++];
+ }
+
+ @Override
+ public void close() throws IOException {
+ closedCalled = true;
+ super.close();
+ }
+ }
+}
diff --git a/src/test/java/test/QuotedMainTest.java b/src/test/java/test/QuotedMainTest.java
new file mode 100644
index 0000000..abb97c0
--- /dev/null
+++ b/src/test/java/test/QuotedMainTest.java
@@ -0,0 +1,29 @@
+package test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+
+public class QuotedMainTest {
+ @Parameter
+ List<String> args = new ArrayList<String>();
+
+ String quoted = "\" \"";
+
+ @Test
+ public void testMain() {
+ JCommander jc = new JCommander(this);
+ jc.parse(quoted);
+ Assert.assertEquals(args.size(), 1);
+ Assert.assertEquals(args.get(0), " ");
+ }
+
+ public static void main(String[] args) {
+ new QuotedMainTest().testMain();
+ }
+}
diff --git a/src/test/resources/MessageBundle_en_US.properties b/src/test/resources/MessageBundle_en_US.properties
new file mode 100644
index 0000000..11e19e4
--- /dev/null
+++ b/src/test/resources/MessageBundle_en_US.properties
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2010 the original author or authors.
+# See the notice.md file distributed with this work for additional
+# information regarding copyright ownership.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+host = Host
+command = Command from the bundle
+myoption = My option \ No newline at end of file
diff --git a/src/test/resources/MessageBundle_fr_FR.properties b/src/test/resources/MessageBundle_fr_FR.properties
new file mode 100644
index 0000000..4ae83a9
--- /dev/null
+++ b/src/test/resources/MessageBundle_fr_FR.properties
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2010 the original author or authors.
+# See the notice.md file distributed with this work for additional
+# information regarding copyright ownership.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+host = Hôte
+files = Les fichiers
diff --git a/src/test/resources/jcommander.properties b/src/test/resources/jcommander.properties
new file mode 100644
index 0000000..3cea84b
--- /dev/null
+++ b/src/test/resources/jcommander.properties
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2010 the original author or authors.
+# See the notice.md file distributed with this work for additional
+# information regarding copyright ownership.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+groups=unit
+level=17
+log=18 \ No newline at end of file
diff --git a/src/test/resources/testng-single.xml b/src/test/resources/testng-single.xml
new file mode 100644
index 0000000..cc0602c
--- /dev/null
+++ b/src/test/resources/testng-single.xml
@@ -0,0 +1,19 @@
+<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
+
+<suite name="JCommander" verbose="2">
+
+ <test name="JCommander tests">
+ <classes>
+<!--
+ <class name="com.beust.jcommander.FinderTest" />
+-->
+ <class name="com.beust.jcommander.JCommanderTest">
+ <methods>
+ <include name="partialValidation"></include>
+ </methods>
+ </class>
+ </classes>
+ </test>
+
+</suite>
+
diff --git a/src/test/resources/testng.xml b/src/test/resources/testng.xml
new file mode 100644
index 0000000..f804418
--- /dev/null
+++ b/src/test/resources/testng.xml
@@ -0,0 +1,24 @@
+<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
+
+<suite name="JCommander">
+
+ <test name="JCommander tests">
+ <classes>
+ <class name="com.beust.jcommander.command.CommandTest" />
+ <class name="com.beust.jcommander.command.CommandAliasTest" />
+ <class name="com.beust.jcommander.ConverterFactoryTest" />
+ <class name="com.beust.jcommander.DefaultProviderTest" />
+ <class name="com.beust.jcommander.DefaultValueTest" />
+ <class name="com.beust.jcommander.JCommanderTest" />
+ <class name="com.beust.jcommander.ParametersDelegateTest" />
+ <class name="com.beust.jcommander.dynamic.DynamicParameterTest" />
+ <class name="com.beust.jcommander.VariableArityTest" />
+ <class name="com.beust.jcommander.MethodSetterTest" />
+ <class name="com.beust.jcommander.PositiveIntegerTest" />
+ <class name="com.beust.jcommander.FinderTest" />
+ <class name="com.beust.jcommander.CmdTest" />
+ </classes>
+ </test>
+
+</suite>
+