@Test public void testParseResetsRawAndOriginalStringValues() { CommandSpec spec = CommandSpec.create() .addOption(OptionSpec.builder("-x").type(String.class).build()) .addPositional(PositionalParamSpec.builder().build()); CommandLine cmd = new CommandLine(spec); ParseResult parseResult = cmd.parseArgs("-x", "XVAL", "POSITIONAL"); assertEquals("XVAL", parseResult.matchedOption('x').getValue()); assertEquals(Arrays.asList("XVAL"), parseResult.matchedOption('x').stringValues()); assertEquals(Arrays.asList("XVAL"), parseResult.matchedOption('x').originalStringValues()); assertEquals("POSITIONAL", parseResult.matchedPositional(0).getValue()); assertEquals(Arrays.asList("POSITIONAL"), parseResult.matchedPositional(0).stringValues()); assertEquals(Arrays.asList("POSITIONAL"), parseResult.matchedPositional(0).originalStringValues()); ParseResult parseResult2 = cmd.parseArgs("-x", "222", "$$$$"); assertEquals("222", parseResult2.matchedOption('x').getValue()); assertEquals(Arrays.asList("222"), parseResult2.matchedOption('x').stringValues()); assertEquals(Arrays.asList("222"), parseResult2.matchedOption('x').originalStringValues()); assertEquals("$$$$", parseResult2.matchedPositional(0).getValue()); assertEquals(Arrays.asList("$$$$"), parseResult2.matchedPositional(0).stringValues()); assertEquals(Arrays.asList("$$$$"), parseResult2.matchedPositional(0).originalStringValues()); }
return false; Range indexRange = ((PositionalParamSpec) argSpec).index(); String sep = ""; String names = ": "; List<PositionalParamSpec> positionalParameters = commandSpec.positionalParameters(); for (int i = indexRange.min; i < positionalParameters.size(); i++) { if (positionalParameters.get(i).arity().min > 0) { names += sep + positionalParameters.get(i).paramLabel(); sep = ", "; count++;
private void printParametersAnnotation(PrintWriter pw, PositionalParamSpec spec, String indent) { pw.printf("%s@%s", indent, importer.getImportedName(Parameters.class.getCanonicalName())); indent = String.format(",%n%s ", indent); String sep = "("; sep = append(pw, sep, indent, "index = \"%s\"", spec.index().toString(), spec.index().isUnspecified()); sep = appendStringArray(pw, sep, indent, "description = %s", spec.description(), EMPTY_ARRAY); sep = append(pw, sep, indent, "arity = \"%s\"", spec.arity().toString(), spec.arity().isUnspecified() ? spec.arity().toString() : ""); sep = append(pw, sep, indent, "paramLabel = \"%s\"", spec.paramLabel(), "<" + argElementName(spec) + ">"); sep = append(pw, sep, indent, "hideParamSyntax = %s", spec.hideParamSyntax(), false); sep = appendTypeInfo(pw, sep, indent, spec.typeInfo()); sep = appendTypeConverter(pw, sep, indent, spec.converters()); sep = append(pw, sep, indent, "split = \"%s\"", spec.splitRegex(), ""); sep = append(pw, sep, indent, "hidden = %s", spec.hidden(), false); sep = append(pw, sep, indent, "defaultValue = \"%s\"", spec.defaultValue() == null ? "__no_default_value__" : spec.defaultValue(), "__no_default_value__"); sep = append(pw, sep, indent, "showDefaultValue = %s", spec.showDefaultValue(), CommandLine.Help.Visibility.ON_DEMAND); sep = appendCompletionCandidates(pw, sep, indent, spec); sep = append(pw, sep, indent, "interactive = %s", spec.interactive(), false); sep = append(pw, sep, indent, "descriptionKey = \"%s\"", spec.descriptionKey(), ""); if (!"(".equals(sep)) { pw.print(")"); } }
return false; Range indexRange = ((PositionalParamSpec) argSpec).index(); String sep = ""; String names = ": "; List<PositionalParamSpec> positionalParameters = commandSpec.positionalParameters(); for (int i = indexRange.min; i < positionalParameters.size(); i++) { if (positionalParameters.get(i).arity().min > 0) { names += sep + positionalParameters.get(i).paramLabel(); sep = ", "; count++;
int originalNowProcessingSize = parseResult.nowProcessing.size(); for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) { Range indexRange = positionalParam.index(); if (!indexRange.contains(position) || positionalParam.typedValueAtPosition.get(position) != null) { continue; Range arity = positionalParam.arity(); if (tracer.isDebug()) {tracer.debug("Position %d is in index range %s. Trying to assign args to %s, arity=%s%n", position, indexRange, positionalParam, arity);} if (!assertNoMissingParameters(positionalParam, arity, argsCopy)) { break; } // #389 collectErrors parsing if (count > 0 || actuallyConsumed > 0) { required.remove(positionalParam); if (positionalParam.interactive()) { interactiveConsumed++; }
@Test public void testMixinAnnotationInjectsOptionsAndParametersInDeclarationOrder() throws Exception { @Command(sortOptions = false) class Receiver { @Mixin InjectsOptionsAndParameters.MixMeIn mixMeIn; @Option(names = {"-b", "--beta"}, description = "Receiver option") private int beta; @Parameters(description = "parameters from receiver") File[] receiverFiles; } CommandLine commandLine = new CommandLine(new Receiver()); CommandSpec commandSpec = commandLine.getCommandSpec(); assertEquals(2, commandSpec.options().size()); assertArrayEquals(new String[]{"-a", "--alpha"}, commandSpec.options().get(0).names()); assertArrayEquals(new String[]{"-b", "--beta"}, commandSpec.options().get(1).names()); assertEquals(2, commandSpec.positionalParameters().size()); assertEquals("<files>", commandSpec.positionalParameters().get(0).paramLabel()); assertEquals("<receiverFiles>", commandSpec.positionalParameters().get(1).paramLabel()); String expects = String.format("" + "Usage: <main class> [-a=<alpha>] [-b=<beta>] [<files>...] [<receiverFiles>...]%n" + " [<files>...] parameters from mixin%n" + " [<receiverFiles>...] parameters from receiver%n" + " -a, --alpha=<alpha> option from mixin%n" + " -b, --beta=<beta> Receiver option%n"); assertEquals(expects, usageString(commandLine, Help.Ansi.OFF)); }
private void verifyMixinInjectsOptionsAndParameters(CommandLine commandLine) throws UnsupportedEncodingException { CommandSpec commandSpec = commandLine.getCommandSpec(); assertEquals(2, commandSpec.options().size()); assertArrayEquals(new String[]{"-b", "--beta"}, commandSpec.options().get(0).names()); assertArrayEquals(new String[]{"-a", "--alpha"}, commandSpec.options().get(1).names()); assertTrue(commandSpec.optionsMap().containsKey("--alpha")); assertTrue(commandSpec.optionsMap().containsKey("--beta")); assertTrue(commandSpec.optionsMap().containsKey("-a")); assertTrue(commandSpec.optionsMap().containsKey("-b")); assertTrue(commandSpec.posixOptionsMap().containsKey('a')); assertTrue(commandSpec.posixOptionsMap().containsKey('b')); assertEquals(2, commandSpec.positionalParameters().size()); assertEquals("<receiverFiles>", commandSpec.positionalParameters().get(0).paramLabel()); assertEquals("<files>", commandSpec.positionalParameters().get(1).paramLabel()); String expects = String.format("" + "Usage: <main class> [-a=<alpha>] [-b=<beta>] [<receiverFiles>...] [<files>...]%n" + " [<receiverFiles>...] parameters from receiver%n" + " [<files>...] parameters from mixin%n" + " -b, --beta=<beta> Receiver option%n" + " -a, --alpha=<alpha> option from mixin%n"); assertEquals(expects, usageString(commandLine, Help.Ansi.OFF)); } @Test
/** Generates a generic synopsis like {@code <command name> [OPTIONS] [PARAM1 [PARAM2]...]}, omitting parts * that don't apply to the command (e.g., does not show [OPTIONS] if the command has no options). * @return a generic synopsis */ public String abbreviatedSynopsis() { StringBuilder sb = new StringBuilder(); if (!commandSpec.optionsMap().isEmpty()) { // only show if annotated object actually has options sb.append(" [OPTIONS]"); } // sb.append(" [--] "); // implied for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) { if (!positionalParam.hidden()) { sb.append(' ').append(parameterLabelRenderer().renderParameterLabel(positionalParam, ansi(), colorScheme.parameterStyles)); } } // only show if object has subcommands if (!commandSpec.subcommands().isEmpty()) { sb.append(" [COMMAND]"); } return colorScheme.commandText(commandSpec.qualifiedName()).toString() + (sb.toString()) + System.getProperty("line.separator"); } /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
public Text[][] render(PositionalParamSpec param, IParamLabelRenderer paramLabelRenderer, ColorScheme scheme) { Text label = paramLabelRenderer.renderParameterLabel(param, scheme.ansi(), scheme.parameterStyles); Text requiredParameter = scheme.parameterText(param.arity().min > 0 ? requiredMarker : ""); Text EMPTY = Ansi.EMPTY_TEXT; boolean[] showDefault = {param.internalShowDefaultValue(showDefaultValues)}; List<Text[]> result = new ArrayList<Text[]>(); String[] description = param.renderedDescription(); Text[] descriptionFirstLines = createDescriptionFirstLines(scheme, param, description, showDefault); result.add(new Text[] { requiredParameter, EMPTY, EMPTY, label, descriptionFirstLines[0] }); for (int i = 1; i < descriptionFirstLines.length; i++) { result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] }); } for (int i = 1; i < description.length; i++) { Text[] descriptionNextLines = scheme.ansi().new Text(description[i]).splitLines(); for (Text line : descriptionNextLines) { result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line }); } } if (showDefault[0]) { addTrailingDefaultLine(result, param, scheme); } return result.toArray(new Text[result.size()][]); } }
@Test public void testAnnotateMethod_unannotatedPositionalMixedWithOptions_indexByParameterOrder() throws Exception { Method m = CommandLine.getCommandMethods(PositionalsMixedWithOptions.class, "mixed").get(0); CommandLine cmd = new CommandLine(m); CommandSpec spec = cmd.getCommandSpec(); List<Model.PositionalParamSpec> positionals = spec.positionalParameters(); String[] labels = { "<arg0>", "<arg3>", "<arg4>"}; assertEquals(positionals.size(), labels.length); String[] ranges = { "0", "1..*", "2..*" }; for (int i = 0; i < positionals.size(); i++) { Model.PositionalParamSpec positional = positionals.get(i); assertEquals(positional.paramLabel() + " at index " + i, CommandLine.Range.valueOf(ranges[i]), positional.index()); assertEquals(labels[i], positional.paramLabel()); } assertEquals(2, spec.options().size()); assertEquals(int.class, spec.findOption("-b").type()); assertEquals(String.class, spec.findOption("-c").type()); }
/** Returns the description template of this positional parameter, before variables are {@linkplain Parameters#description() rendered}. * If a resource bundle has been {@linkplain ArgSpec#messages(Messages) set}, this method will first try to find a value in the resource bundle: * If the resource bundle has no entry for the {@code fully qualified commandName + "." + descriptionKey} or for the unqualified {@code descriptionKey}, * an attempt is made to find the positional parameter description using {@code paramLabel() + "[" + index() + "]"} as key, * first with the {@code fully qualified commandName + "."} prefix, then without. * @see Parameters#description() * @see CommandSpec#qualifiedName(String) * @since 3.6 */ @Override public String[] description() { if (messages() == null) { return super.description(); } String[] newValue = messages().getStringArray(descriptionKey(), null); if (newValue != null) { return newValue; } newValue = messages().getStringArray(paramLabel() + "[" + index() + "]", null); if (newValue != null) { return newValue; } return super.description(); }
@Test public void testAnnotateMethod_unannotatedPositional_indexByParameterOrder() throws Exception { Method m = CommandLine.getCommandMethods(UnannotatedPositional.class, "x").get(0); CommandLine cmd = new CommandLine(m); CommandSpec spec = cmd.getCommandSpec(); List<Model.PositionalParamSpec> positionals = spec.positionalParameters(); String[] labels = { "<arg0>", "<arg1>", "<arg2>", "<arg3>", "<arg4>"}; assertEquals(positionals.size(), labels.length); String[] ranges = { "0", "1", "2", "3..*", "4..*" }; for (int i = 0; i < positionals.size(); i++) { Model.PositionalParamSpec positional = positionals.get(i); assertEquals(positional.paramLabel() + " at index " + i, CommandLine.Range.valueOf(ranges[i]), positional.index()); assertEquals(labels[i], positional.paramLabel()); } }
/** Returns a Text object containing a partial detailed synopsis showing only the positional parameters, starting with a {@code " "} space. * Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}). * @return the formatted positional parameters, starting with a {@code " "} space, or an empty Text if this command has no positional parameters * @since 3.9 */ protected Text createDetailedSynopsisPositionalsText() { Text positionalParamText = ansi().new Text(0); for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) { if (!positionalParam.hidden()) { positionalParamText = positionalParamText.concat(" "); Text label = parameterLabelRenderer().renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles); positionalParamText = positionalParamText.concat(label); } } return positionalParamText; }
@Test public void testArgSpecGetterWrapNonPicocliException() { final Exception expected = new Exception("boom"); IGetter getter = new IGetter() { public <T> T get() throws Exception { throw expected; } }; PositionalParamSpec positional = PositionalParamSpec.builder().getter(getter).build(); try { positional.getValue(); } catch (CommandLine.PicocliException ex) { assertSame(expected, ex.getCause()); } }
@Test public void testPositionalDefaultParamLabel() { assertEquals("PARAM", PositionalParamSpec.builder().build().paramLabel()); }
private static void validatePositionalParameters(List<PositionalParamSpec> positionalParametersFields) { int min = 0; for (PositionalParamSpec positional : positionalParametersFields) { Range index = positional.index(); if (index.min > min) { throw new ParameterIndexGapException("Command definition should have a positional parameter with index=" + min + ". Nearest positional parameter '" + positional.paramLabel() + "' has index=" + index.min); } min = Math.max(min, index.max); min = min == Integer.MAX_VALUE ? min : min + 1; } } @SuppressWarnings("unchecked") private static Stack<String> copy(Stack<String> stack) { return (Stack<String>) stack.clone(); }
@Test public void testCompletionCandidatesPriority_forParameters() { class App { @Parameters(completionCandidates = MyAbcdCandidates.class) MyEfgEnum x; } App app = new App(); CommandLine cmd = new CommandLine(app); assertEquals(Arrays.asList("A", "B", "C", "D"), cmd.getCommandSpec().positionalParameters().get(0).completionCandidates()); } @Test
@Test public void testPositionalInteractiveReadFromAnnotation() { class App { @Parameters(index = "0", interactive = true) int x; @Parameters(index = "1", interactive = false) int y; @Parameters(index = "2") int z; } CommandLine cmd = new CommandLine(new App()); assertTrue(cmd.getCommandSpec().positionalParameters().get(0).interactive()); assertFalse(cmd.getCommandSpec().positionalParameters().get(1).interactive()); assertFalse(cmd.getCommandSpec().positionalParameters().get(2).interactive()); }
@Test public void testCompletionCandidatesValues_forParameters() { class App { @Parameters(completionCandidates = MyAbcdCandidates.class) String x; } CommandLine cmd = new CommandLine(new App()); assertEquals(Arrays.asList("A", "B", "C", "D"), extract(cmd.getCommandSpec().positionalParameters().get(0).completionCandidates())); } @Test