mirror of
https://github.com/jlengrand/picocli.git
synced 2026-03-10 08:41:17 +00:00
Second cut of adding support for argument groups:
* mutually exclusive options (#199) * option that must co-occur (#295) * option grouping in the usage help message (#450) * repeating composite arguments (#358 and #635) (this should also cover the use cases presented in #454 and #434 requests for repeatable subcommands)
This commit is contained in:
11
build.gradle
11
build.gradle
@@ -9,11 +9,12 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath "org.asciidoctor:asciidoctor-gradle-plugin:$asciidoctorGradlePluginVersion"
|
||||
classpath 'org.asciidoctor:asciidoctorj-pdf:1.5.0-alpha.15'
|
||||
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradleBintrayPluginVersion"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'org.asciidoctor.convert'
|
||||
apply plugin: 'org.asciidoctor.convert' // version '1.5.8.1'
|
||||
apply plugin: 'distribution'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'com.jfrog.bintray'
|
||||
@@ -158,10 +159,18 @@ jar {
|
||||
|
||||
javadoc.options.overview = "src/main/java/overview.html"
|
||||
javadoc.dependsOn('asciidoctor')
|
||||
asciidoctorj {
|
||||
version = '1.5.5'
|
||||
}
|
||||
asciidoctor {
|
||||
sourceDir = file('docs')
|
||||
outputDir = file('build/docs')
|
||||
logDocuments = true
|
||||
// backends 'pdf', 'html'
|
||||
// attributes 'sourcedir': file('docs') //project.sourceSets.main.java.srcDirs[0]
|
||||
//// attributes 'pdf-stylesdir': 'theme',
|
||||
//// 'pdf-style': 'custom',
|
||||
//// 'sourcedir': file('docs') //project.sourceSets.main.java.srcDirs[0]
|
||||
}
|
||||
// jacoco 0.8.2 does not work with Java 13; gradle 4.x has no JavaVersion enum value for Java 12
|
||||
if (org.gradle.api.JavaVersion.current().isJava11Compatible()) {
|
||||
|
||||
@@ -14,7 +14,7 @@ jacocoTestCoverageVerification {
|
||||
violationRules {
|
||||
rule {
|
||||
limit {
|
||||
minimum = 0.98
|
||||
minimum = 0.97
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ plugins {
|
||||
group 'info.picocli'
|
||||
description 'Picocli Code Generation - Tools to generate documentation, configuration, source code and other files from a picocli model.'
|
||||
version "$projectVersion"
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
|
||||
dependencies {
|
||||
compile rootProject
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package picocli.codegen.annotation.processing;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.ArgGroup;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.IFactory;
|
||||
import picocli.CommandLine.Mixin;
|
||||
@@ -942,6 +943,7 @@ public abstract class AbstractCommandSpecProcessor extends AbstractProcessor {
|
||||
return false
|
||||
|| e.getAnnotation(Option.class) == null
|
||||
|| e.getAnnotation(Parameters.class) == null
|
||||
|| e.getAnnotation(ArgGroup.class) == null
|
||||
|| e.getAnnotation(Unmatched.class) == null
|
||||
|| e.getAnnotation(Mixin.class) == null
|
||||
|| e.getAnnotation(Spec.class) == null
|
||||
@@ -995,6 +997,7 @@ public abstract class AbstractCommandSpecProcessor extends AbstractProcessor {
|
||||
public boolean isArgSpec() { return isOption() || isParameter() || isMethodParameter(); }
|
||||
public boolean isOption() { return isAnnotationPresent(Option.class); }
|
||||
public boolean isParameter() { return isAnnotationPresent(Parameters.class); }
|
||||
public boolean isArgGroup() { return isAnnotationPresent(ArgGroup.class); }
|
||||
public boolean isMixin() { return isAnnotationPresent(Mixin.class); }
|
||||
public boolean isUnmatched() { return isAnnotationPresent(Unmatched.class); }
|
||||
public boolean isInjectSpec() { return isAnnotationPresent(Spec.class); }
|
||||
@@ -1011,6 +1014,12 @@ public abstract class AbstractCommandSpecProcessor extends AbstractProcessor {
|
||||
public boolean hasInitialValue() { return hasInitialValue; }
|
||||
public boolean isMethodParameter() { return position >= 0; }
|
||||
public int getMethodParamPosition() { return position; }
|
||||
|
||||
@Override
|
||||
public CommandLine.Model.IScope scope() {
|
||||
return null; // FIXME
|
||||
}
|
||||
|
||||
public String getMixinName() {
|
||||
String annotationName = getAnnotation(Mixin.class).name();
|
||||
return empty(annotationName) ? getName() : annotationName;
|
||||
|
||||
@@ -319,6 +319,17 @@
|
||||
{ "name" : "helpRequested" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "picocli.CommandLine$Model$ObjectScope",
|
||||
"allDeclaredConstructors" : true,
|
||||
"allPublicConstructors" : true,
|
||||
"allDeclaredMethods" : true,
|
||||
"allPublicMethods" : true,
|
||||
"methods" : [
|
||||
{ "name" : "setMinimum", "parameterTypes" : ["int"] },
|
||||
{ "name" : "setOtherFiles", "parameterTypes" : ["java.util.List"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "picocli.codegen.aot.graalvm.Example",
|
||||
"allDeclaredConstructors" : true,
|
||||
|
||||
@@ -262,6 +262,13 @@
|
||||
{ "name" : "out" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name" : "picocli.CommandLine$Model$ObjectScope",
|
||||
"allDeclaredConstructors" : true,
|
||||
"allPublicConstructors" : true,
|
||||
"allDeclaredMethods" : true,
|
||||
"allPublicMethods" : true
|
||||
},
|
||||
{
|
||||
"name" : "picocli.codegen.aot.graalvm.Issue622AbstractCommand",
|
||||
"allDeclaredConstructors" : true,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1593,4 +1593,17 @@ public class CommandLineArityTest {
|
||||
assertEquals("positional parameter at index 0..* (<String=String>) requires at least 2 values, but only 1 were specified: [a=c]", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlap() {
|
||||
Range r1 = Range.valueOf("1..5");
|
||||
assertTrue(r1.overlaps(Range.valueOf("1..1")));
|
||||
assertTrue(r1.overlaps(Range.valueOf("2..2")));
|
||||
assertTrue(r1.overlaps(Range.valueOf("2..5")));
|
||||
assertTrue(r1.overlaps(Range.valueOf("5")));
|
||||
assertTrue(r1.overlaps(Range.valueOf("0..6")));
|
||||
assertTrue(r1.overlaps(Range.valueOf("0..*")));
|
||||
assertFalse(r1.overlaps(Range.valueOf("6")));
|
||||
assertFalse(r1.overlaps(Range.valueOf("0")));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import org.junit.contrib.java.lang.system.SystemErrRule;
|
||||
import org.junit.contrib.java.lang.system.SystemOutRule;
|
||||
import picocli.CommandLine.*;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
import picocli.CommandLine.Model.IScope;
|
||||
import picocli.CommandLine.Model.MethodParam;
|
||||
import picocli.CommandLine.Model.ObjectScope;
|
||||
import picocli.CommandLine.Model.TypedMember;
|
||||
import picocli.CommandLineTest.CompactFields;
|
||||
|
||||
@@ -1044,21 +1046,21 @@ public class CommandLineCommandMethodTest {
|
||||
|
||||
@Test
|
||||
public void testTypedMemberConstructorRejectsGetterNorSetter() throws Exception {
|
||||
Constructor<TypedMember> constructor = TypedMember.class.getDeclaredConstructor(Method.class, Object.class, CommandSpec.class);
|
||||
Constructor<TypedMember> constructor = TypedMember.class.getDeclaredConstructor(Method.class, IScope.class, CommandSpec.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
Method getterNorSetter1 = TypedMemberObj.class.getDeclaredMethod("getterNorSetter1");
|
||||
Method getterNorSetter2 = TypedMemberObj.class.getDeclaredMethod("getterNorSetter2");
|
||||
|
||||
try {
|
||||
constructor.newInstance(getterNorSetter1, new TypedMemberObj(), CommandSpec.create());
|
||||
constructor.newInstance(getterNorSetter1, new ObjectScope(new TypedMemberObj()), CommandSpec.create());
|
||||
fail("expect exception");
|
||||
} catch (InvocationTargetException ex) {
|
||||
InitializationException ex2 = (InitializationException) ex.getCause();
|
||||
assertEquals("Invalid method, must be either getter or setter: void picocli.CommandLineCommandMethodTest$TypedMemberObj.getterNorSetter1()", ex2.getMessage());
|
||||
}
|
||||
try {
|
||||
constructor.newInstance(getterNorSetter2, new TypedMemberObj(), CommandSpec.create());
|
||||
constructor.newInstance(getterNorSetter2, new ObjectScope(new TypedMemberObj()), CommandSpec.create());
|
||||
fail("expect exception");
|
||||
} catch (InvocationTargetException ex) {
|
||||
InitializationException ex2 = (InitializationException) ex.getCause();
|
||||
@@ -1068,22 +1070,22 @@ public class CommandLineCommandMethodTest {
|
||||
|
||||
@Test
|
||||
public void testTypedMemberConstructorNonProxyObject() throws Exception {
|
||||
Constructor<TypedMember> constructor = TypedMember.class.getDeclaredConstructor(Method.class, Object.class, CommandSpec.class);
|
||||
Constructor<TypedMember> constructor = TypedMember.class.getDeclaredConstructor(Method.class, IScope.class, CommandSpec.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
Method getter = TypedMemberObj.class.getDeclaredMethod("getter");
|
||||
TypedMember typedMember = constructor.newInstance(getter, new TypedMemberObj(), CommandSpec.create());
|
||||
TypedMember typedMember = constructor.newInstance(getter, new ObjectScope(new TypedMemberObj()), CommandSpec.create());
|
||||
assertSame(typedMember.getter(), typedMember.setter());
|
||||
assertTrue(typedMember.getter() instanceof Model.MethodBinding);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypedMemberInitializeInitialValue() throws Exception {
|
||||
Constructor<TypedMember> constructor = TypedMember.class.getDeclaredConstructor(Method.class, Object.class, CommandSpec.class);
|
||||
Constructor<TypedMember> constructor = TypedMember.class.getDeclaredConstructor(Method.class, IScope.class, CommandSpec.class);
|
||||
constructor.setAccessible(true);
|
||||
|
||||
Method setter = TypedMemberObj.class.getDeclaredMethod("setter", String.class);
|
||||
TypedMember typedMember = constructor.newInstance(setter, new TypedMemberObj(), CommandSpec.create());
|
||||
TypedMember typedMember = constructor.newInstance(setter, new ObjectScope(new TypedMemberObj()), CommandSpec.create());
|
||||
|
||||
Method initializeInitialValue = TypedMember.class.getDeclaredMethod("initializeInitialValue", Object.class);
|
||||
initializeInitialValue.setAccessible(true);
|
||||
|
||||
@@ -848,7 +848,7 @@ public class CommandLineTest {
|
||||
"[picocli DEBUG] Set initial value for field boolean picocli.CommandLineTest$CompactFields.recursive of type boolean to false.%n" +
|
||||
"[picocli DEBUG] Set initial value for field java.io.File picocli.CommandLineTest$CompactFields.outputFile of type class java.io.File to null.%n" +
|
||||
"[picocli DEBUG] Set initial value for field java.io.File[] picocli.CommandLineTest$CompactFields.inputFiles of type class [Ljava.io.File; to null.%n" +
|
||||
"[picocli DEBUG] Initializing %1$s$CompactFields: 3 options, 1 positional parameters, 0 required, 0 subcommands.%n" +
|
||||
"[picocli DEBUG] Initializing %1$s$CompactFields: 3 options, 1 positional parameters, 0 required, 0 groups, 0 subcommands.%n" +
|
||||
"[picocli DEBUG] Processing argument '-oout'. Remainder=[--, -r, -v, p1, p2]%n" +
|
||||
"[picocli DEBUG] '-oout' cannot be separated into <option>=<option-parameter>%n" +
|
||||
"[picocli DEBUG] Trying to process '-oout' as clustered short options%n" +
|
||||
@@ -857,22 +857,22 @@ public class CommandLineTest {
|
||||
"[picocli INFO] Setting field java.io.File picocli.CommandLineTest$CompactFields.outputFile to 'out' (was 'null') for option -o%n" +
|
||||
"[picocli DEBUG] Processing argument '--'. Remainder=[-r, -v, p1, p2]%n" +
|
||||
"[picocli INFO] Found end-of-options delimiter '--'. Treating remainder as positional parameters.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=0. Remainder=[-r, -v, p1, p2]%n" +
|
||||
"[picocli DEBUG] Position 0 is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=0. Remainder=[-r, -v, p1, p2]%n" +
|
||||
"[picocli DEBUG] Position 0 (command-local) is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [-r] to field java.io.File[] picocli.CommandLineTest$CompactFields.inputFiles for args[0..*] at position 0%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 1.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=1. Remainder=[-v, p1, p2]%n" +
|
||||
"[picocli DEBUG] Position 1 is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 1.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=1. Remainder=[-v, p1, p2]%n" +
|
||||
"[picocli DEBUG] Position 1 (command-local) is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [-v] to field java.io.File[] picocli.CommandLineTest$CompactFields.inputFiles for args[0..*] at position 1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 2.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=2. Remainder=[p1, p2]%n" +
|
||||
"[picocli DEBUG] Position 2 is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 2.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=2. Remainder=[p1, p2]%n" +
|
||||
"[picocli DEBUG] Position 2 (command-local) is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [p1] to field java.io.File[] picocli.CommandLineTest$CompactFields.inputFiles for args[0..*] at position 2%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 3.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=3. Remainder=[p2]%n" +
|
||||
"[picocli DEBUG] Position 3 is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 3.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=3. Remainder=[p2]%n" +
|
||||
"[picocli DEBUG] Position 3 (command-local) is in index range 0..*. Trying to assign args to field java.io.File[] %1$s$CompactFields.inputFiles, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [p2] to field java.io.File[] picocli.CommandLineTest$CompactFields.inputFiles for args[0..*] at position 3%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 4.%n",
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 4.%n",
|
||||
CommandLineTest.class.getName(),
|
||||
new File("/home/rpopma/picocli"),
|
||||
CommandLine.versionString());
|
||||
@@ -1766,7 +1766,7 @@ public class CommandLineTest {
|
||||
"[picocli DEBUG] Set initial value for field java.io.File picocli.Demo$Git.gitDir of type class java.io.File to null.%n" +
|
||||
"[picocli DEBUG] Set initial value for field boolean picocli.CommandLine$AutoHelpMixin.helpRequested of type boolean to false.%n" +
|
||||
"[picocli DEBUG] Set initial value for field boolean picocli.CommandLine$AutoHelpMixin.versionRequested of type boolean to false.%n" +
|
||||
"[picocli DEBUG] Initializing %1$s$Git: 3 options, 0 positional parameters, 0 required, 12 subcommands.%n" +
|
||||
"[picocli DEBUG] Initializing %1$s$Git: 3 options, 0 positional parameters, 0 required, 0 groups, 12 subcommands.%n" +
|
||||
"[picocli DEBUG] Processing argument '--git-dir=/home/rpopma/picocli'. Remainder=[commit, -m, \"Fixed typos\", --, src1.java, src2.java, src3.java]%n" +
|
||||
"[picocli DEBUG] Separated '--git-dir' option from '/home/rpopma/picocli' option parameter%n" +
|
||||
"[picocli DEBUG] Found option named '--git-dir': field java.io.File %1$s$Git.gitDir, arity=1%n" +
|
||||
@@ -1782,25 +1782,25 @@ public class CommandLineTest {
|
||||
"[picocli DEBUG] Set initial value for field java.io.File picocli.Demo$GitCommit.file of type class java.io.File to null.%n" +
|
||||
"[picocli DEBUG] Set initial value for field java.util.List<String> picocli.Demo$GitCommit.message of type interface java.util.List to [].%n" +
|
||||
"[picocli DEBUG] Set initial value for field java.util.List<java.io.File> picocli.Demo$GitCommit.files of type interface java.util.List to [].%n" +
|
||||
"[picocli DEBUG] Initializing %1$s$GitCommit: 8 options, 1 positional parameters, 0 required, 0 subcommands.%n" +
|
||||
"[picocli DEBUG] Initializing %1$s$GitCommit: 8 options, 1 positional parameters, 0 required, 0 groups, 0 subcommands.%n" +
|
||||
"[picocli DEBUG] Processing argument '-m'. Remainder=[\"Fixed typos\", --, src1.java, src2.java, src3.java]%n" +
|
||||
"[picocli DEBUG] '-m' cannot be separated into <option>=<option-parameter>%n" +
|
||||
"[picocli DEBUG] Found option named '-m': field java.util.List<String> %1$s$GitCommit.message, arity=1%n" +
|
||||
"[picocli INFO] Adding [\"Fixed typos\"] to field java.util.List<String> picocli.Demo$GitCommit.message for option -m%n" +
|
||||
"[picocli DEBUG] Processing argument '--'. Remainder=[src1.java, src2.java, src3.java]%n" +
|
||||
"[picocli INFO] Found end-of-options delimiter '--'. Treating remainder as positional parameters.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=0. Remainder=[src1.java, src2.java, src3.java]%n" +
|
||||
"[picocli DEBUG] Position 0 is in index range 0..*. Trying to assign args to field java.util.List<java.io.File> %1$s$GitCommit.files, arity=0..1%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=0. Remainder=[src1.java, src2.java, src3.java]%n" +
|
||||
"[picocli DEBUG] Position 0 (command-local) is in index range 0..*. Trying to assign args to field java.util.List<java.io.File> %1$s$GitCommit.files, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [src1.java] to field java.util.List<java.io.File> picocli.Demo$GitCommit.files for args[0..*] at position 0%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 1.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=1. Remainder=[src2.java, src3.java]%n" +
|
||||
"[picocli DEBUG] Position 1 is in index range 0..*. Trying to assign args to field java.util.List<java.io.File> %1$s$GitCommit.files, arity=0..1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 1.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=1. Remainder=[src2.java, src3.java]%n" +
|
||||
"[picocli DEBUG] Position 1 (command-local) is in index range 0..*. Trying to assign args to field java.util.List<java.io.File> %1$s$GitCommit.files, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [src2.java] to field java.util.List<java.io.File> picocli.Demo$GitCommit.files for args[0..*] at position 1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 2.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter at index=2. Remainder=[src3.java]%n" +
|
||||
"[picocli DEBUG] Position 2 is in index range 0..*. Trying to assign args to field java.util.List<java.io.File> %1$s$GitCommit.files, arity=0..1%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 2.%n" +
|
||||
"[picocli DEBUG] Processing next arg as a positional parameter. Command-local position=2. Remainder=[src3.java]%n" +
|
||||
"[picocli DEBUG] Position 2 (command-local) is in index range 0..*. Trying to assign args to field java.util.List<java.io.File> %1$s$GitCommit.files, arity=0..1%n" +
|
||||
"[picocli INFO] Adding [src3.java] to field java.util.List<java.io.File> picocli.Demo$GitCommit.files for args[0..*] at position 2%n" +
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving position to index 3.%n",
|
||||
"[picocli DEBUG] Consumed 1 arguments and 0 interactive values, moving command-local position to index 3.%n",
|
||||
Demo.class.getName(),
|
||||
new File("/home/rpopma/picocli"),
|
||||
CommandLine.versionString());
|
||||
@@ -3506,14 +3506,9 @@ public class CommandLineTest {
|
||||
@Command class App {
|
||||
@Unmatched String unmatched;
|
||||
}
|
||||
try {
|
||||
new CommandLine(new App());
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "Invalid type for %s: must be either String[] or List<String>";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
Object app = new App();
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertInvalidUnmatchedFieldType(app, f);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3521,12 +3516,17 @@ public class CommandLineTest {
|
||||
@Command class App {
|
||||
@Unmatched List<Object> unmatched;
|
||||
}
|
||||
Object app = new App();
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertInvalidUnmatchedFieldType(app, f);
|
||||
}
|
||||
|
||||
private void assertInvalidUnmatchedFieldType(Object app, Field f) {
|
||||
try {
|
||||
new CommandLine(new App());
|
||||
new CommandLine(app);
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "Invalid type for %s: must be either String[] or List<String>";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -3540,7 +3540,7 @@ public class CommandLineTest {
|
||||
new CommandLine(new App());
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "A member cannot have both @Unmatched and @Option or @Parameters annotations, but '%s' has both.";
|
||||
String pattern = "A member cannot have both @Unmatched and @Option annotations, but '%s' has both.";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
@@ -3555,7 +3555,7 @@ public class CommandLineTest {
|
||||
new CommandLine(new App());
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "A member cannot have both @Unmatched and @Option or @Parameters annotations, but '%s' has both.";
|
||||
String pattern = "A member cannot have both @Unmatched and @Parameters annotations, but '%s' has both.";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
@@ -3570,7 +3570,7 @@ public class CommandLineTest {
|
||||
new CommandLine(new App());
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "A member cannot be both a @Mixin command and an @Unmatched but '%s' is both.";
|
||||
String pattern = "A member cannot have both @Mixin and @Unmatched annotations, but '%s' has both.";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
@@ -3585,7 +3585,7 @@ public class CommandLineTest {
|
||||
new CommandLine(new App());
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "A member cannot be both a @Mixin command and an @Option or @Parameters, but '%s' is both.";
|
||||
String pattern = "A member cannot have both @Mixin and @Option annotations, but '%s' has both.";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
@@ -3600,7 +3600,7 @@ public class CommandLineTest {
|
||||
new CommandLine(new App());
|
||||
fail("Expected exception");
|
||||
} catch (InitializationException ex) {
|
||||
String pattern = "A member cannot be both a @Mixin command and an @Option or @Parameters, but '%s' is both.";
|
||||
String pattern = "A member cannot have both @Mixin and @Parameters annotations, but '%s' has both.";
|
||||
Field f = App.class.getDeclaredField("unmatched");
|
||||
assertEquals(format(pattern, f), ex.getMessage());
|
||||
}
|
||||
@@ -3864,6 +3864,7 @@ public class CommandLineTest {
|
||||
System.setOut(new PrintStream(baos));
|
||||
System.setIn(new ByteArrayInputStream("123".getBytes()));
|
||||
|
||||
HelpTestUtil.setTraceLevel("DEBUG");
|
||||
App app = new App();
|
||||
CommandLine cmd = new CommandLine(app);
|
||||
cmd.parse("987");
|
||||
|
||||
@@ -49,17 +49,21 @@ public class InnerClassFactory implements IFactory {
|
||||
|
||||
public <K> K create(final Class<K> cls) throws Exception {
|
||||
try {
|
||||
Constructor<K> constructor = cls.getDeclaredConstructor(outer.getClass());
|
||||
return constructor.newInstance(outer);
|
||||
} catch (Exception ex) {
|
||||
return CommandLine.defaultFactory().create(cls);
|
||||
} catch (Exception ex0) {
|
||||
try {
|
||||
return cls.newInstance();
|
||||
} catch (Exception ex2) {
|
||||
Constructor<K> constructor = cls.getDeclaredConstructor(outer.getClass());
|
||||
return constructor.newInstance(outer);
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
Constructor<K> constructor = cls.getDeclaredConstructor();
|
||||
return constructor.newInstance();
|
||||
} catch (Exception ex3) {
|
||||
throw new InitializationException("Could not instantiate " + cls.getName() + " either with or without construction parameter " + outer + ": " + ex, ex);
|
||||
return cls.newInstance();
|
||||
} catch (Exception ex2) {
|
||||
try {
|
||||
Constructor<K> constructor = cls.getDeclaredConstructor();
|
||||
return constructor.newInstance();
|
||||
} catch (Exception ex3) {
|
||||
throw new InitializationException("Could not instantiate " + cls.getName() + " either with or without construction parameter " + outer + ": " + ex, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ public class ModelArgSpecTest {
|
||||
@Test
|
||||
public void testArgSpecBuilderObjectBindingToString() {
|
||||
Builder builder = OptionSpec.builder("-x");
|
||||
assertEquals("picocli.CommandLine.Model.ObjectBinding(value=null)", builder.getter().toString());
|
||||
assertEquals("ObjectBinding(value=null)", builder.getter().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -68,34 +68,6 @@ public class ModelCommandReflectionTest {
|
||||
}
|
||||
}
|
||||
|
||||
static class TypedMemberObj {
|
||||
int x;
|
||||
}
|
||||
@Test
|
||||
public void testValidateMixin() throws Exception {
|
||||
Class<?> reflection = Class.forName("picocli.CommandLine$Model$CommandReflection");
|
||||
Method validateMixin = reflection.getDeclaredMethod("validateMixin", CommandLine.Model.TypedMember.class);
|
||||
validateMixin.setAccessible(true);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(TypedMemberObj.class.getDeclaredField("x"));
|
||||
try {
|
||||
validateMixin.invoke(null, typedMember);
|
||||
fail("expected Exception");
|
||||
} catch (InvocationTargetException ite) {
|
||||
IllegalStateException ex = (IllegalStateException) ite.getCause();
|
||||
assertEquals("Bug: validateMixin() should only be called with mixins", ex.getMessage());
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testValidateUnmatched() throws Exception {
|
||||
Class<?> reflection = Class.forName("picocli.CommandLine$Model$CommandReflection");
|
||||
Method validateUnmatched = reflection.getDeclaredMethod("validateUnmatched", CommandLine.Model.IAnnotatedElement.class);
|
||||
validateUnmatched.setAccessible(true);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(TypedMemberObj.class.getDeclaredField("x"));
|
||||
validateUnmatched.invoke(null, typedMember); // no error
|
||||
}
|
||||
|
||||
static class ValidateArgSpecField {
|
||||
@Mixin
|
||||
@Option(names = "-x")
|
||||
@@ -110,7 +82,7 @@ public class ModelCommandReflectionTest {
|
||||
@Test
|
||||
public void testValidateArgSpecField() throws Exception {
|
||||
Class<?> reflection = Class.forName("picocli.CommandLine$Model$CommandReflection");
|
||||
Method validateArgSpecField = reflection.getDeclaredMethod("validateArgSpecField", CommandLine.Model.TypedMember.class);
|
||||
Method validateArgSpecField = reflection.getDeclaredMethod("validateArgSpecMember", CommandLine.Model.TypedMember.class);
|
||||
validateArgSpecField.setAccessible(true);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(ValidateArgSpecField.class.getDeclaredField("x"));
|
||||
@@ -119,14 +91,14 @@ public class ModelCommandReflectionTest {
|
||||
fail("expected Exception");
|
||||
} catch (InvocationTargetException ite) {
|
||||
CommandLine.DuplicateOptionAnnotationsException ex = (CommandLine.DuplicateOptionAnnotationsException) ite.getCause();
|
||||
assertEquals("A member cannot be both a @Mixin command and an @Option or @Parameters, but 'int picocli.ModelCommandReflectionTest$ValidateArgSpecField.x' is both.", ex.getMessage());
|
||||
assertEquals("A member cannot have both @Option and @Mixin annotations, but 'int picocli.ModelCommandReflectionTest$ValidateArgSpecField.x' has both.", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateArgSpecField_final() throws Exception {
|
||||
Class<?> reflection = Class.forName("picocli.CommandLine$Model$CommandReflection");
|
||||
Method validateArgSpecField = reflection.getDeclaredMethod("validateArgSpecField", CommandLine.Model.TypedMember.class);
|
||||
Method validateArgSpecField = reflection.getDeclaredMethod("validateArgSpecMember", CommandLine.Model.TypedMember.class);
|
||||
validateArgSpecField.setAccessible(true);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(ValidateArgSpecField.class.getDeclaredField("f"));
|
||||
@@ -137,7 +109,7 @@ public class ModelCommandReflectionTest {
|
||||
@Test
|
||||
public void testValidateArgSpecField_neither() throws Exception {
|
||||
Class<?> reflection = Class.forName("picocli.CommandLine$Model$CommandReflection");
|
||||
Method validateArgSpecField = reflection.getDeclaredMethod("validateArgSpecField", CommandLine.Model.TypedMember.class);
|
||||
Method validateArgSpecField = reflection.getDeclaredMethod("validateArgSpecMember", CommandLine.Model.TypedMember.class);
|
||||
validateArgSpecField.setAccessible(true);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(ValidateArgSpecField.class.getDeclaredField("neither"));
|
||||
@@ -147,23 +119,23 @@ public class ModelCommandReflectionTest {
|
||||
static class ValidateInjectSpec {
|
||||
int notAnnotated;
|
||||
|
||||
@CommandLine.Spec
|
||||
@Spec
|
||||
@Option(names = "-x")
|
||||
int x;
|
||||
|
||||
@CommandLine.Spec
|
||||
@Spec
|
||||
@CommandLine.Parameters
|
||||
int y;
|
||||
|
||||
@CommandLine.Spec
|
||||
@Spec
|
||||
@Unmatched
|
||||
List<String> unmatched;
|
||||
|
||||
@CommandLine.Spec
|
||||
@Spec
|
||||
@Mixin
|
||||
Object mixin = new Object();
|
||||
|
||||
@CommandLine.Spec
|
||||
@Spec
|
||||
Object invalidType;
|
||||
}
|
||||
@Test
|
||||
@@ -194,7 +166,7 @@ public class ModelCommandReflectionTest {
|
||||
fail("expected Exception");
|
||||
} catch (InvocationTargetException ite) {
|
||||
CommandLine.DuplicateOptionAnnotationsException ex = (CommandLine.DuplicateOptionAnnotationsException) ite.getCause();
|
||||
assertEquals("A member cannot have both @Spec and @Option or @Parameters annotations, but 'int picocli.ModelCommandReflectionTest$ValidateInjectSpec.x' has both.", ex.getMessage());
|
||||
assertEquals("A member cannot have both @Spec and @Option annotations, but 'int picocli.ModelCommandReflectionTest$ValidateInjectSpec.x' has both.", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +182,7 @@ public class ModelCommandReflectionTest {
|
||||
fail("expected Exception");
|
||||
} catch (InvocationTargetException ite) {
|
||||
CommandLine.DuplicateOptionAnnotationsException ex = (CommandLine.DuplicateOptionAnnotationsException) ite.getCause();
|
||||
assertEquals("A member cannot have both @Spec and @Option or @Parameters annotations, but 'int picocli.ModelCommandReflectionTest$ValidateInjectSpec.y' has both.", ex.getMessage());
|
||||
assertEquals("A member cannot have both @Spec and @Parameters annotations, but 'int picocli.ModelCommandReflectionTest$ValidateInjectSpec.y' has both.", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,7 +236,7 @@ public class ModelCommandReflectionTest {
|
||||
@Test
|
||||
public void testValidateArgSpec() throws Exception {
|
||||
Class<?> reflection = Class.forName("picocli.CommandLine$Model$CommandReflection");
|
||||
Method validateArgSpec = reflection.getDeclaredMethod("validateArgSpecField", CommandLine.Model.TypedMember.class);
|
||||
Method validateArgSpec = reflection.getDeclaredMethod("validateArgSpecMember", CommandLine.Model.TypedMember.class);
|
||||
validateArgSpec.setAccessible(true);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(ValidateInjectSpec.class.getDeclaredField("notAnnotated"));
|
||||
@@ -273,7 +245,7 @@ public class ModelCommandReflectionTest {
|
||||
fail("expected Exception");
|
||||
} catch (InvocationTargetException ite) {
|
||||
IllegalStateException ex = (IllegalStateException) ite.getCause();
|
||||
assertEquals("Bug: validateArgSpecField() should only be called with an @Option or @Parameters member", ex.getMessage());
|
||||
assertEquals("Bug: validateArgSpecMember() should only be called with an @Option or @Parameters member", ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,6 @@ public class ModelFieldBindingTest {
|
||||
ModelMethodBindingBean value = new ModelMethodBindingBean();
|
||||
FieldBinding binding = new FieldBinding(value, f);
|
||||
|
||||
assertEquals("picocli.CommandLine.Model.FieldBinding(int picocli.ModelMethodBindingBean.x)", binding.toString());
|
||||
assertEquals("FieldBinding(int picocli.ModelMethodBindingBean.x)", binding.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package picocli;
|
||||
import org.junit.Test;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
import picocli.CommandLine.Model.MethodBinding;
|
||||
import picocli.CommandLine.Model.ObjectScope;
|
||||
import picocli.CommandLine.ParameterException;
|
||||
import picocli.CommandLine.PicocliException;
|
||||
|
||||
@@ -16,7 +17,7 @@ public class ModelMethodBindingTest {
|
||||
@Test
|
||||
public void testGetDoesNotInvokeMethod() throws Exception {
|
||||
Method getX = ModelMethodBindingBean.class.getDeclaredMethod("getX");
|
||||
MethodBinding binding = new MethodBinding(new ModelMethodBindingBean(), getX, CommandSpec.create());
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(new ModelMethodBindingBean()), getX, CommandSpec.create());
|
||||
binding.get(); // no IllegalAccessException
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@ public class ModelMethodBindingTest {
|
||||
getX.setAccessible(true);
|
||||
|
||||
ModelMethodBindingBean bean = new ModelMethodBindingBean();
|
||||
MethodBinding binding = new MethodBinding(bean, getX, CommandSpec.create());
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(bean), getX, CommandSpec.create());
|
||||
assertNull(binding.get());
|
||||
assertEquals("actual value returned by getX() method", 7, bean.publicGetX());
|
||||
}
|
||||
@@ -38,7 +39,7 @@ public class ModelMethodBindingTest {
|
||||
|
||||
ModelMethodBindingBean bean = new ModelMethodBindingBean();
|
||||
CommandSpec spec = CommandSpec.create();
|
||||
MethodBinding binding = new MethodBinding(bean, getX, spec);
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(bean), getX, spec);
|
||||
|
||||
try {
|
||||
binding.set(41);
|
||||
@@ -57,7 +58,7 @@ public class ModelMethodBindingTest {
|
||||
setX.setAccessible(true);
|
||||
|
||||
ModelMethodBindingBean bean = new ModelMethodBindingBean();
|
||||
MethodBinding binding = new MethodBinding(bean, setX, CommandSpec.create());
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(bean), setX, CommandSpec.create());
|
||||
assertNull("initial", binding.get());
|
||||
assertEquals(7, bean.publicGetX());
|
||||
|
||||
@@ -69,7 +70,7 @@ public class ModelMethodBindingTest {
|
||||
@Test
|
||||
public void testMethodMustBeAccessible() throws Exception {
|
||||
Method setX = ModelMethodBindingBean.class.getDeclaredMethod("setX", int.class);
|
||||
MethodBinding binding = new MethodBinding(new ModelMethodBindingBean(), setX, CommandSpec.create());
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(new ModelMethodBindingBean()), setX, CommandSpec.create());
|
||||
try {
|
||||
binding.set(1);
|
||||
fail("Expected exception");
|
||||
@@ -84,7 +85,7 @@ public class ModelMethodBindingTest {
|
||||
setX.setAccessible(true);
|
||||
|
||||
ModelMethodBindingBean value = new ModelMethodBindingBean();
|
||||
MethodBinding binding = new MethodBinding(value, setX, CommandSpec.create());
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(value), setX, CommandSpec.create());
|
||||
|
||||
binding.set(987);
|
||||
assertEquals(987, value.publicGetX());
|
||||
@@ -97,7 +98,7 @@ public class ModelMethodBindingTest {
|
||||
setX.setAccessible(true);
|
||||
|
||||
CommandSpec spec = CommandSpec.create();
|
||||
MethodBinding binding = new MethodBinding(null, setX, spec);
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(null), setX, spec);
|
||||
|
||||
try {
|
||||
binding.set(41);
|
||||
@@ -117,7 +118,7 @@ public class ModelMethodBindingTest {
|
||||
CommandSpec spec = CommandSpec.create();
|
||||
CommandLine cmd = new CommandLine(spec);
|
||||
spec.commandLine(cmd);
|
||||
MethodBinding binding = new MethodBinding(null, setX, spec);
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(null), setX, spec);
|
||||
|
||||
try {
|
||||
binding.set(41);
|
||||
@@ -135,7 +136,7 @@ public class ModelMethodBindingTest {
|
||||
|
||||
CommandSpec spec = CommandSpec.create();
|
||||
assertNull(spec.commandLine());
|
||||
MethodBinding binding = new MethodBinding(null, setX, spec);
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(null), setX, spec);
|
||||
|
||||
try {
|
||||
binding.set(41);
|
||||
@@ -155,8 +156,8 @@ public class ModelMethodBindingTest {
|
||||
setX.setAccessible(true);
|
||||
|
||||
ModelMethodBindingBean value = new ModelMethodBindingBean();
|
||||
MethodBinding binding = new MethodBinding(value, setX, CommandSpec.create());
|
||||
MethodBinding binding = new MethodBinding(new ObjectScope(value), setX, CommandSpec.create());
|
||||
|
||||
assertEquals("picocli.CommandLine.Model.MethodBinding(private void picocli.ModelMethodBindingBean.setX(int))", binding.toString());
|
||||
assertEquals("MethodBinding(private void picocli.ModelMethodBindingBean.setX(int))", binding.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ModelTestUtil {
|
||||
return option(obj, fieldName, CommandLine.defaultFactory());
|
||||
}
|
||||
public static OptionSpec option(Object obj, String fieldName, CommandLine.IFactory factory) throws Exception {
|
||||
return OptionSpec.builder(TypedMember.createIfAnnotated(obj.getClass().getDeclaredField(fieldName), obj), factory).build();
|
||||
return OptionSpec.builder(TypedMember.createIfAnnotated(obj.getClass().getDeclaredField(fieldName), new ObjectScope(obj)), factory).build();
|
||||
}
|
||||
public static OptionSpec[] options(Object obj, String... fieldNames) throws Exception {
|
||||
OptionSpec[] result = new OptionSpec[fieldNames.length];
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ModelTypedMemberTest {
|
||||
Method method = App.class.getDeclaredMethod("mymethod", char.class);
|
||||
CommandLine.Model.MethodParam param = new CommandLine.Model.MethodParam(method, 0);
|
||||
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(param, new App());
|
||||
CommandLine.Model.TypedMember typedMember = new CommandLine.Model.TypedMember(param, new CommandLine.Model.ObjectScope(new App()));
|
||||
assertEquals(0, typedMember.getMethodParamPosition());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class PicocliTestUtil {
|
||||
clear.setAccessible(true);
|
||||
clear.invoke(interpreter); // initializes the interpreter instance
|
||||
|
||||
Field parseResultField = c.getDeclaredField("parseResult");
|
||||
Field parseResultField = c.getDeclaredField("parseResultBuilder");
|
||||
parseResultField.setAccessible(true);
|
||||
Field nowProcessing = CommandLine.ParseResult.Builder.class.getDeclaredField("nowProcessing");
|
||||
nowProcessing.setAccessible(true);
|
||||
|
||||
Reference in New Issue
Block a user