You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2017/11/11 12:19:42 UTC
[2/2] logging-log4j2 git commit: LOG4J2-2088 Upgrade picocli to 2.0.3
from 0.9.8
LOG4J2-2088 Upgrade picocli to 2.0.3 from 0.9.8
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/23bcd257
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/23bcd257
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/23bcd257
Branch: refs/heads/master
Commit: 23bcd257f7fa2617827c5210b0b1e074d42480cf
Parents: 7d52f13
Author: rpopma <rp...@apache.org>
Authored: Sat Nov 11 21:19:15 2017 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Nov 11 21:19:15 2017 +0900
----------------------------------------------------------------------
.../log4j/core/tools/picocli/CommandLine.java | 241 +++--
.../tools/picocli/CommandLineArityTest.java | 934 ++++++++++++++++++
.../core/tools/picocli/CommandLineHelpTest.java | 93 +-
.../core/tools/picocli/CommandLineTest.java | 963 ++-----------------
.../logging/log4j/core/tools/picocli/Demo.java | 3 +
src/changes/changes.xml | 6 +-
6 files changed, 1281 insertions(+), 959 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23bcd257/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
index ed6cec1..b8a19ab 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java
@@ -55,7 +55,6 @@ import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.SortedSet;
@@ -133,7 +132,7 @@ import static org.apache.logging.log4j.core.tools.picocli.CommandLine.Help.Colum
*/
public class CommandLine {
/** This is picocli version {@value}. */
- public static final String VERSION = "2.0.0";
+ public static final String VERSION = "2.0.3";
private final Tracer tracer = new Tracer();
private final Interpreter interpreter;
@@ -1791,10 +1790,10 @@ public class CommandLine {
}
}
static void init(Class<?> cls,
- List<Field> requiredFields,
- Map<String, Field> optionName2Field,
- Map<Character, Field> singleCharOption2Field,
- List<Field> positionalParametersFields) {
+ List<Field> requiredFields,
+ Map<String, Field> optionName2Field,
+ Map<Character, Field> singleCharOption2Field,
+ List<Field> positionalParametersFields) {
Field[] declaredFields = cls.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
@@ -1863,6 +1862,7 @@ public class CommandLine {
Interpreter(Object command) {
converterRegistry.put(Path.class, new BuiltIn.PathConverter());
+ converterRegistry.put(Object.class, new BuiltIn.StringConverter());
converterRegistry.put(String.class, new BuiltIn.StringConverter());
converterRegistry.put(StringBuilder.class, new BuiltIn.StringBuilderConverter());
converterRegistry.put(CharSequence.class, new BuiltIn.CharSequenceConverter());
@@ -2109,7 +2109,7 @@ public class CommandLine {
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);}
assertNoMissingParameters(positionalParam, arity.min, argsCopy);
int originalSize = argsCopy.size();
- applyOption(positionalParam, Parameters.class, arity, false, argsCopy, initialized, "args[" + indexRange + "]");
+ applyOption(positionalParam, Parameters.class, arity, false, argsCopy, initialized, "args[" + indexRange + "] at position " + position);
int count = originalSize - argsCopy.size();
if (count > 0) { required.remove(positionalParam); }
consumed = Math.max(consumed, count);
@@ -2162,16 +2162,15 @@ public class CommandLine {
if (arity.min > 0 && !empty(cluster)) {
if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as option parameter%n", cluster);}
}
- args.push(cluster); // interpret remainder as option parameter (CAUTION: may be empty string!)
// arity may be >= 1, or
// arity <= 0 && !cluster.startsWith(separator)
// e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
- if (!args.isEmpty() && args.peek().length() == 0 && !paramAttachedToOption) {
- args.pop(); // throw out empty string we get at the end of a group of clustered short options
+ if (!empty(cluster)) {
+ args.push(cluster); // interpret remainder as option parameter
}
int consumed = applyOption(field, Option.class, arity, paramAttachedToOption, args, initialized, argDescription);
// only return if cluster (and maybe more) was consumed, otherwise continue do-while loop
- if (consumed > 0) {
+ if (empty(cluster) || consumed > 0 || args.isEmpty()) {
return;
}
cluster = args.pop();
@@ -2270,7 +2269,7 @@ public class CommandLine {
initialized.add(field);
}
if (tracer.level.isEnabled(level)) { level.print(tracer, traceMessage, field.getType().getSimpleName(),
- field.getDeclaringClass().getSimpleName(), field.getName(), String.valueOf(oldValue), String.valueOf(newValue), argDescription);
+ field.getDeclaringClass().getSimpleName(), field.getName(), String.valueOf(oldValue), String.valueOf(newValue), argDescription);
}
field.set(command, newValue);
return result;
@@ -2620,8 +2619,8 @@ public class CommandLine {
return value == null
? null
: (value.length() > 1 && value.startsWith("\"") && value.endsWith("\""))
- ? value.substring(1, value.length() - 1)
- : value;
+ ? value.substring(1, value.length() - 1)
+ : value;
}
}
private static class PositionalParametersSorter implements Comparator<Field> {
@@ -3163,6 +3162,21 @@ public class CommandLine {
return layout.toString();
}
+ private static String heading(Ansi ansi, String values, Object... params) {
+ StringBuilder sb = join(ansi, new String[] {values}, new StringBuilder(), params);
+ String result = sb.toString();
+ result = result.endsWith(System.getProperty("line.separator"))
+ ? result.substring(0, result.length() - System.getProperty("line.separator").length()) : result;
+ return result + new String(spaces(countTrailingSpaces(values)));
+ }
+ private static char[] spaces(int length) { char[] result = new char[length]; Arrays.fill(result, ' '); return result; }
+ private static int countTrailingSpaces(String str) {
+ if (str == null) {return 0;}
+ int trailingSpaces = 0;
+ for (int i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; i--) { trailingSpaces++; }
+ return trailingSpaces;
+ }
+
/** Formats each of the specified values and appends it to the specified StringBuilder.
* @param ansi whether the result should contain ANSI escape codes or not
* @param values the values to format and append to the StringBuilder
@@ -3174,12 +3188,16 @@ public class CommandLine {
TextTable table = new TextTable(ansi, usageHelpWidth);
table.indentWrappedLines = 0;
for (String summaryLine : values) {
- table.addRowValues(ansi.new Text(String.format(summaryLine, params)));
+ Text[] lines = ansi.new Text(format(summaryLine, params)).splitLines();
+ for (Text line : lines) { table.addRowValues(line); }
}
table.toString(sb);
}
return sb;
}
+ private static String format(String formatString, Object... params) {
+ return formatString == null ? "" : String.format(formatString, params);
+ }
/** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
* specified declaratively with the {@link Command#customSynopsis()} annotation attribute or programmatically
* by setting the Help instance's {@link Help#customSynopsis} field.
@@ -3221,14 +3239,14 @@ public class CommandLine {
* @param params the parameters to use to format the header heading
* @return the formatted header heading */
public String headerHeading(Object... params) {
- return ansi().new Text(format(headerHeading, params)).toString();
+ return heading(ansi(), headerHeading, params);
}
/** Returns the text displayed before the synopsis text; the result of {@code String.format(synopsisHeading, params)}.
* @param params the parameters to use to format the synopsis heading
* @return the formatted synopsis heading */
public String synopsisHeading(Object... params) {
- return ansi().new Text(format(synopsisHeading, params)).toString();
+ return heading(ansi(), synopsisHeading, params);
}
/** Returns the text displayed before the description text; an empty string if there is no description,
@@ -3236,7 +3254,7 @@ public class CommandLine {
* @param params the parameters to use to format the description heading
* @return the formatted description heading */
public String descriptionHeading(Object... params) {
- return empty(descriptionHeading) ? "" : ansi().new Text(format(descriptionHeading, params)).toString();
+ return empty(descriptionHeading) ? "" : heading(ansi(), descriptionHeading, params);
}
/** Returns the text displayed before the positional parameter list; an empty string if there are no positional
@@ -3244,7 +3262,7 @@ public class CommandLine {
* @param params the parameters to use to format the parameter list heading
* @return the formatted parameter list heading */
public String parameterListHeading(Object... params) {
- return positionalParametersFields.isEmpty() ? "" : ansi().new Text(format(parameterListHeading, params)).toString();
+ return positionalParametersFields.isEmpty() ? "" : heading(ansi(), parameterListHeading, params);
}
/** Returns the text displayed before the option list; an empty string if there are no options,
@@ -3252,7 +3270,7 @@ public class CommandLine {
* @param params the parameters to use to format the option list heading
* @return the formatted option list heading */
public String optionListHeading(Object... params) {
- return optionFields.isEmpty() ? "" : ansi().new Text(format(optionListHeading, params)).toString();
+ return optionFields.isEmpty() ? "" : heading(ansi(), optionListHeading, params);
}
/** Returns the text displayed before the command list; an empty string if there are no commands,
@@ -3260,17 +3278,14 @@ public class CommandLine {
* @param params the parameters to use to format the command list heading
* @return the formatted command list heading */
public String commandListHeading(Object... params) {
- return commands.isEmpty() ? "" : ansi().new Text(format(commandListHeading, params)).toString();
+ return commands.isEmpty() ? "" : heading(ansi(), commandListHeading, params);
}
/** Returns the text displayed before the footer text; the result of {@code String.format(footerHeading, params)}.
* @param params the parameters to use to format the footer heading
* @return the formatted footer heading */
public String footerHeading(Object... params) {
- return ansi().new Text(format(footerHeading, params)).toString();
- }
- private String format(String formatString, Object[] params) {
- return formatString == null ? "" : String.format(formatString, params);
+ return heading(ansi(), footerHeading, params);
}
/** Returns a 2-column list with command names and the first line of their header or (if absent) description.
* @return a usage help section describing the added commands */
@@ -3441,27 +3456,25 @@ public class CommandLine {
static class DefaultOptionRenderer implements IOptionRenderer {
public String requiredMarker = " ";
public Object command;
+ private String sep;
+ private boolean showDefault;
public Text[][] render(Option option, Field field, IParamLabelRenderer paramLabelRenderer, ColorScheme scheme) {
String[] names = ShortestFirst.sort(option.names());
int shortOptionCount = names[0].length() == 2 ? 1 : 0;
String shortOption = shortOptionCount > 0 ? names[0] : "";
- Text paramLabelText = paramLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
+ sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
+
String longOption = join(names, shortOptionCount, names.length - shortOptionCount, ", ");
- String sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
+ Text longOptionText = createLongOptionText(field, paramLabelRenderer, scheme, longOption);
+
+ showDefault = command != null && !option.help() && !isBoolean(field.getType());
+ Object defaultValue = createDefaultValue(field);
- // if no long option, fill in the space between the short option name and the param label value
- if (paramLabelText.length > 0 && longOption.length() == 0) {
- sep = paramLabelRenderer.separator();
- // #181 paramLabelText may be =LABEL or [=LABEL...]
- int sepStart = paramLabelText.plainString().indexOf(sep);
- Text prefix = paramLabelText.substring(0, sepStart);
- paramLabelText = prefix.append(paramLabelText.substring(sepStart + sep.length()));
- }
- Text longOptionText = scheme.optionText(longOption);
- longOptionText = longOptionText.append(paramLabelText);
String requiredOption = option.required() ? requiredMarker : "";
+ return renderDescriptionLines(option, scheme, requiredOption, shortOption, longOptionText, defaultValue);
+ }
- boolean showDefault = command != null && !option.help() && !isBoolean(field.getType());
+ private Object createDefaultValue(Field field) {
Object defaultValue = null;
try {
defaultValue = field.get(command);
@@ -3476,22 +3489,57 @@ public class CommandLine {
} catch (Exception ex) {
showDefault = false;
}
- final int descriptionCount = Math.max(1, option.description().length);
- final int ROW_COUNT = showDefault ? descriptionCount + 1 : descriptionCount;
- final int COLUMN_COUNT = 5;
+ return defaultValue;
+ }
+
+ private Text createLongOptionText(Field field, IParamLabelRenderer renderer, ColorScheme scheme, String longOption) {
+ Text paramLabelText = renderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
+
+ // if no long option, fill in the space between the short option name and the param label value
+ if (paramLabelText.length > 0 && longOption.length() == 0) {
+ sep = renderer.separator();
+ // #181 paramLabelText may be =LABEL or [=LABEL...]
+ int sepStart = paramLabelText.plainString().indexOf(sep);
+ Text prefix = paramLabelText.substring(0, sepStart);
+ paramLabelText = prefix.append(paramLabelText.substring(sepStart + sep.length()));
+ }
+ Text longOptionText = scheme.optionText(longOption);
+ longOptionText = longOptionText.append(paramLabelText);
+ return longOptionText;
+ }
+
+ private Text[][] renderDescriptionLines(Option option,
+ ColorScheme scheme,
+ String requiredOption,
+ String shortOption,
+ Text longOptionText,
+ Object defaultValue) {
Text EMPTY = Ansi.EMPTY_TEXT;
- Text[][] result = new Text[ROW_COUNT][COLUMN_COUNT];
- result[0] = new Text[] { scheme.optionText(requiredOption), scheme.optionText(shortOption),
- scheme.ansi().new Text(sep), longOptionText, scheme.ansi().new Text(str(option.description(), 0)) };
+ List<Text[]> result = new ArrayList<Text[]>();
+ Text[] descriptionFirstLines = scheme.ansi().new Text(str(option.description(), 0)).splitLines();
+ if (descriptionFirstLines.length == 0) {
+ if (showDefault) {
+ descriptionFirstLines = new Text[]{scheme.ansi().new Text(" Default: " + defaultValue)};
+ showDefault = false; // don't show the default value twice
+ } else {
+ descriptionFirstLines = new Text[]{ EMPTY };
+ }
+ }
+ result.add(new Text[] { scheme.optionText(requiredOption), scheme.optionText(shortOption),
+ scheme.ansi().new Text(sep), longOptionText, 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 < option.description().length; i++) {
- result[i] = new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text(option.description()[i]) };
+ Text[] descriptionNextLines = scheme.ansi().new Text(option.description()[i]).splitLines();
+ for (Text line : descriptionNextLines) {
+ result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
+ }
}
if (showDefault) {
- Arrays.fill(result[result.length - 1], EMPTY);
- int row = empty(result[ROW_COUNT - 2][COLUMN_COUNT - 1]) ? ROW_COUNT - 2 : ROW_COUNT - 1;
- result[row][COLUMN_COUNT - 1] = scheme.ansi().new Text(" Default: " + defaultValue);
+ result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text(" Default: " + defaultValue) });
}
- return result;
+ return result.toArray(new Text[result.size()][]);
}
}
/** The MinimalOptionRenderer converts {@link Option Options} to a single row with two columns of text: an
@@ -3502,7 +3550,7 @@ public class CommandLine {
Text paramLabelText = parameterLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.optionParamStyles);
optionText = optionText.append(paramLabelText);
return new Text[][] {{ optionText,
- scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0]) }};
+ scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0]) }};
}
}
/** The MinimalParameterRenderer converts {@link Parameters Parameters} to a single row with two columns of
@@ -3546,14 +3594,21 @@ public class CommandLine {
Text label = paramLabelRenderer.renderParameterLabel(field, scheme.ansi(), scheme.parameterStyles);
Text requiredParameter = scheme.parameterText(Range.parameterArity(field).min > 0 ? requiredMarker : "");
- final int COLUMN_COUNT = 5;
- final Text EMPTY = Ansi.EMPTY_TEXT;
- Text[][] result = new Text[Math.max(1, params.description().length)][COLUMN_COUNT];
- result[0] = new Text[] { requiredParameter, EMPTY, EMPTY, label, scheme.ansi().new Text(str(params.description(), 0)) };
+ Text EMPTY = Ansi.EMPTY_TEXT;
+ List<Text[]> result = new ArrayList<Text[]>();
+ Text[] descriptionFirstLines = scheme.ansi().new Text(str(params.description(), 0)).splitLines();
+ if (descriptionFirstLines.length == 0) { descriptionFirstLines = new Text[]{ EMPTY }; }
+ 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 < params.description().length; i++) {
- result[i] = new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text(params.description()[i]) };
+ Text[] descriptionNextLines = scheme.ansi().new Text(params.description()[i]).splitLines();
+ for (Text line : descriptionNextLines) {
+ result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
+ }
}
- return result;
+ return result.toArray(new Text[result.size()][]);
}
}
/** When customizing online usage help for an option parameter or a positional parameter, a custom
@@ -3830,12 +3885,12 @@ public class CommandLine {
public TextTable(Ansi ansi) {
// "* -c, --create Creates a ...."
this(ansi, new Column[] {
- new Column(2, 0, TRUNCATE), // "*"
- new Column(2, 0, TRUNCATE), // "-c"
- new Column(1, 0, TRUNCATE), // ","
- new Column(optionsColumnWidth - 2 - 2 - 1 , 1, SPAN), // " --create"
- new Column(usageHelpWidth - optionsColumnWidth, 1, WRAP) // " Creates a ..."
- });
+ new Column(2, 0, TRUNCATE), // "*"
+ new Column(2, 0, TRUNCATE), // "-c"
+ new Column(1, 0, TRUNCATE), // ","
+ new Column(optionsColumnWidth - 2 - 2 - 1 , 1, SPAN), // " --create"
+ new Column(usageHelpWidth - optionsColumnWidth, 1, WRAP) // " Creates a ..."
+ });
}
/** Constructs a new TextTable with columns with the specified width, all SPANning multiple columns on
@@ -3976,7 +4031,6 @@ public class CommandLine {
private static int length(Text str) {
return str.length; // TODO count some characters as double length
}
- private char[] spaces(int length) { char[] result = new char[length]; Arrays.fill(result, ' '); return result; }
private int copy(BreakIterator line, Text text, Text columnValue, int offset) {
// Deceive the BreakIterator to ensure no line breaks after '-' character
@@ -4211,7 +4265,7 @@ public class CommandLine {
public String on() { return CSI + startCode + "m"; }
public String off() { return CSI + endCode + "m"; }
- /** Returns the concatenated ANSI escape codes for turning all specified styles on.
+ /** Returns the concatenated ANSI escape codes for turning all specified styles on.
* @param styles the styles to generate ANSI escape codes for
* @return the concatenated ANSI escape codes for turning all specified styles on */
public static String on(IStyle... styles) {
@@ -4221,7 +4275,7 @@ public class CommandLine {
}
return result.toString();
}
- /** Returns the concatenated ANSI escape codes for turning all specified styles off.
+ /** Returns the concatenated ANSI escape codes for turning all specified styles off.
* @param styles the styles to generate ANSI escape codes for
* @return the concatenated ANSI escape codes for turning all specified styles off */
public static String off(IStyle... styles) {
@@ -4231,25 +4285,25 @@ public class CommandLine {
}
return result.toString();
}
- /** Parses the specified style markup and returns the associated style.
- * The markup may be one of the Style enum value names, or it may be one of the Style enum value
- * names when {@code "fg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
+ /** Parses the specified style markup and returns the associated style.
+ * The markup may be one of the Style enum value names, or it may be one of the Style enum value
+ * names when {@code "fg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
* @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "fg_blue"},
* or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
- * @return the IStyle for the specified converter
- */
+ * @return the IStyle for the specified converter
+ */
public static IStyle fg(String str) {
try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
try { return Style.valueOf("fg_" + str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
return new Palette256Color(true, str);
}
- /** Parses the specified style markup and returns the associated style.
- * The markup may be one of the Style enum value names, or it may be one of the Style enum value
- * names when {@code "bg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
- * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "bg_blue"},
+ /** Parses the specified style markup and returns the associated style.
+ * The markup may be one of the Style enum value names, or it may be one of the Style enum value
+ * names when {@code "bg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
+ * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "bg_blue"},
* or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
- * @return the IStyle for the specified converter
- */
+ * @return the IStyle for the specified converter
+ */
public static IStyle bg(String str) {
try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
try { return Style.valueOf("bg_" + str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
@@ -4404,6 +4458,27 @@ public class CommandLine {
try { return super.clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException(e); }
}
+ public Text[] splitLines() {
+ List<Text> result = new ArrayList<Text>();
+ boolean trailingEmptyString = false;
+ int start = 0, end = 0;
+ for (int i = 0; i < plain.length(); i++, end = i) {
+ char c = plain.charAt(i);
+ boolean eol = c == '\n';
+ eol |= (c == '\r' && i + 1 < plain.length() && plain.charAt(i + 1) == '\n' && ++i > 0); // \r\n
+ eol |= c == '\r';
+ if (eol) {
+ result.add(this.substring(start, end));
+ trailingEmptyString = i == plain.length() - 1;
+ start = i + 1;
+ }
+ }
+ if (start < plain.length() || trailingEmptyString) {
+ result.add(this.substring(start, plain.length()));
+ }
+ return result.toArray(new Text[result.size()]);
+ }
+
/** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
* @param start index in the plain text where to start the substring
* @return a new Text instance that is a substring of this Text */
@@ -4536,7 +4611,7 @@ public class CommandLine {
if (tracer.level.isEnabled(this)) { tracer.stream.printf(prefix(msg), params); }
}
private String prefix(String msg) { return "[picocli " + this + "] " + msg; }
- static TraceLevel lookup(String key) { return key == null ? WARN : empty(key) ? INFO : valueOf(key); }
+ static TraceLevel lookup(String key) { return key == null ? WARN : empty(key) || "true".equalsIgnoreCase(key) ? INFO : valueOf(key); }
}
private static class Tracer {
TraceLevel level = TraceLevel.lookup(System.getProperty("picocli.trace"));
@@ -4569,11 +4644,11 @@ public class CommandLine {
private final CommandLine commandLine;
public ExecutionException(CommandLine commandLine, String msg) {
super(msg);
- this.commandLine = Objects.requireNonNull(commandLine, "commandLine");
+ this.commandLine = Assert.notNull(commandLine, "commandLine");
}
public ExecutionException(CommandLine commandLine, String msg, Exception ex) {
super(msg, ex);
- this.commandLine = Objects.requireNonNull(commandLine, "commandLine");
+ this.commandLine = Assert.notNull(commandLine, "commandLine");
}
/** Returns the {@code CommandLine} object for the (sub)command that could not be invoked.
* @return the {@code CommandLine} object for the (sub)command where invocation failed.
@@ -4597,7 +4672,7 @@ public class CommandLine {
* @since 2.0 */
public ParameterException(CommandLine commandLine, String msg) {
super(msg);
- this.commandLine = Objects.requireNonNull(commandLine, "commandLine");
+ this.commandLine = Assert.notNull(commandLine, "commandLine");
}
/** Constructs a new ParameterException with the specified CommandLine and error message.
* @param commandLine the command or subcommand whose input was invalid
@@ -4606,7 +4681,7 @@ public class CommandLine {
* @since 2.0 */
public ParameterException(CommandLine commandLine, String msg, Exception ex) {
super(msg, ex);
- this.commandLine = Objects.requireNonNull(commandLine, "commandLine");
+ this.commandLine = Assert.notNull(commandLine, "commandLine");
}
/** Returns the {@code CommandLine} object for the (sub)command whose input could not be parsed.
@@ -4643,8 +4718,8 @@ public class CommandLine {
}
private static String describe(Field field, String separator) {
String prefix = (field.isAnnotationPresent(Option.class))
- ? field.getAnnotation(Option.class).names()[0] + separator
- : "params[" + field.getAnnotation(Parameters.class).index() + "]" + separator;
+ ? field.getAnnotation(Option.class).names()[0] + separator
+ : "params[" + field.getAnnotation(Parameters.class).index() + "]" + separator;
return prefix + Help.DefaultParamLabelRenderer.renderParameterName(field);
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23bcd257/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java
new file mode 100644
index 0000000..c9b435e
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineArityTest.java
@@ -0,0 +1,934 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.logging.log4j.core.tools.picocli;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.sql.Time;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.UUID;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.apache.logging.log4j.core.tools.picocli.CommandLine.*;
+
+import static java.util.concurrent.TimeUnit.*;
+import static org.junit.Assert.*;
+import static org.apache.logging.log4j.core.tools.picocli.CommandLine.*;
+
+public class CommandLineArityTest {
+ @Before public void setUp() { System.clearProperty("picocli.trace"); }
+ @After public void tearDown() { System.clearProperty("picocli.trace"); }
+
+ private static void setTraceLevel(String level) {
+ System.setProperty("picocli.trace", level);
+ }
+ @Test
+ public void testArityConstructor_fixedRange() {
+ Range arity = new Range(1, 23, false, false, null);
+ assertEquals("min", 1, arity.min);
+ assertEquals("max", 23, arity.max);
+ assertEquals("1..23", arity.toString());
+ assertEquals(Range.valueOf("1..23"), arity);
+ }
+ @Test
+ public void testArityConstructor_variableRange() {
+ Range arity = new Range(1, Integer.MAX_VALUE, true, false, null);
+ assertEquals("min", 1, arity.min);
+ assertEquals("max", Integer.MAX_VALUE, arity.max);
+ assertEquals("1..*", arity.toString());
+ assertEquals(Range.valueOf("1..*"), arity);
+ }
+ @Test
+ public void testArityForOption_booleanFieldImplicitArity0() throws Exception {
+ Range arity = Range.optionArity(CommandLineTest.SupportedTypes.class.getDeclaredField("booleanField"));
+ assertEquals(Range.valueOf("0"), arity);
+ assertEquals("0", arity.toString());
+ }
+ @Test
+ public void testArityForOption_intFieldImplicitArity1() throws Exception {
+ Range arity = Range.optionArity(CommandLineTest.SupportedTypes.class.getDeclaredField("intField"));
+ assertEquals(Range.valueOf("1"), arity);
+ assertEquals("1", arity.toString());
+ }
+ @Test
+ public void testArityForOption_isExplicitlyDeclaredValue() throws Exception {
+ class Params {
+ @Option(names = "-timeUnitList", type = TimeUnit.class, arity = "3") List<TimeUnit> timeUnitList;
+ }
+ Range arity = Range.optionArity(Params.class.getDeclaredField("timeUnitList"));
+ assertEquals(Range.valueOf("3"), arity);
+ assertEquals("3", arity.toString());
+ }
+ @Test
+ public void testArityForOption_listFieldImplicitArity1() throws Exception {
+ class ImplicitList { @Option(names = "-a") List<Integer> listIntegers; }
+ Range arity = Range.optionArity(ImplicitList.class.getDeclaredField("listIntegers"));
+ assertEquals(Range.valueOf("1"), arity);
+ assertEquals("1", arity.toString());
+ }
+ @Test
+ public void testArityForOption_arrayFieldImplicitArity1() throws Exception {
+ class ImplicitList { @Option(names = "-a") int[] intArray; }
+ Range arity = Range.optionArity(ImplicitList.class.getDeclaredField("intArray"));
+ assertEquals(Range.valueOf("1"), arity);
+ assertEquals("1", arity.toString());
+ }
+ @Test
+ public void testArityForParameters_booleanFieldImplicitArity1() throws Exception {
+ class ImplicitBoolField { @Parameters boolean boolSingleValue; }
+ Range arity = Range.parameterArity(ImplicitBoolField.class.getDeclaredField("boolSingleValue"));
+ assertEquals(Range.valueOf("1"), arity);
+ assertEquals("1", arity.toString());
+ }
+ @Test
+ public void testArityForParameters_intFieldImplicitArity1() throws Exception {
+ class ImplicitSingleField { @Parameters int intSingleValue; }
+ Range arity = Range.parameterArity(ImplicitSingleField.class.getDeclaredField("intSingleValue"));
+ assertEquals(Range.valueOf("1"), arity);
+ assertEquals("1", arity.toString());
+ }
+ @Test
+ public void testArityForParameters_listFieldImplicitArity0_1() throws Exception {
+ class Params {
+ @Parameters(type = Integer.class) List<Integer> list;
+ }
+ Range arity = Range.parameterArity(Params.class.getDeclaredField("list"));
+ assertEquals(Range.valueOf("0..1"), arity);
+ assertEquals("0..1", arity.toString());
+ }
+ @Test
+ public void testArityForParameters_arrayFieldImplicitArity0_1() throws Exception {
+ class Args {
+ @Parameters File[] inputFiles;
+ }
+ Range arity = Range.parameterArity(Args.class.getDeclaredField("inputFiles"));
+ assertEquals(Range.valueOf("0..1"), arity);
+ assertEquals("0..1", arity.toString());
+ }
+ @Test
+ public void testArrayOptionsWithArity0_nConsumeAllArguments() {
+ final double[] DEFAULT_PARAMS = new double[] {1, 2};
+ class ArrayOptionsArity0_nAndParameters {
+ @Parameters double[] doubleParams = DEFAULT_PARAMS;
+ @Option(names = "-doubles", arity = "0..*") double[] doubleOptions;
+ }
+ ArrayOptionsArity0_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionsArity0_nAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001);
+ assertArrayEquals(DEFAULT_PARAMS, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionsWithArity1_nConsumeAllArguments() {
+ class ArrayOptionsArity1_nAndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-doubles", arity = "1..*") double[] doubleOptions;
+ }
+ ArrayOptionsArity1_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionsArity1_nAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001);
+ assertArrayEquals(null, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionsWithArity2_nConsumeAllArguments() {
+ class ArrayOptionsArity2_nAndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-doubles", arity = "2..*") double[] doubleOptions;
+ }
+ ArrayOptionsArity2_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionsArity2_nAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001);
+ assertArrayEquals(null, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionArity2_nConsumesAllArgumentsUpToClusteredOption() {
+ class ArrayOptionsArity2_nAndParameters {
+ @Parameters String[] stringParams;
+ @Option(names = "-s", arity = "2..*") String[] stringOptions;
+ @Option(names = "-v") boolean verbose;
+ @Option(names = "-f") File file;
+ }
+ ArrayOptionsArity2_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionsArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 -vfFILE 5.5".split(" "));
+ assertArrayEquals(Arrays.toString(params.stringOptions),
+ new String[] {"1.1", "2.2", "3.3", "4.4"}, params.stringOptions);
+ assertTrue(params.verbose);
+ assertEquals(new File("FILE"), params.file);
+ assertArrayEquals(new String[] {"5.5"}, params.stringParams);
+ }
+
+ @Test
+ public void testArrayOptionArity2_nConsumesAllArgumentIncludingQuotedSimpleOption() {
+ class ArrayOptionArity2_nAndParameters {
+ @Parameters String[] stringParams;
+ @Option(names = "-s", arity = "2..*") String[] stringOptions;
+ @Option(names = "-v") boolean verbose;
+ @Option(names = "-f") File file;
+ }
+ ArrayOptionArity2_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 \"-v\" \"-f\" \"FILE\" 5.5".split(" "));
+ assertArrayEquals(Arrays.toString(params.stringOptions),
+ new String[] {"1.1", "2.2", "3.3", "4.4", "-v", "-f", "FILE", "5.5"}, params.stringOptions);
+ assertFalse("verbose", params.verbose);
+ assertNull("file", params.file);
+ assertArrayEquals(null, params.stringParams);
+ }
+
+ @Test
+ public void testArrayOptionArity2_nConsumesAllArgumentIncludingQuotedClusteredOption() {
+ class ArrayOptionArity2_nAndParameters {
+ @Parameters String[] stringParams;
+ @Option(names = "-s", arity = "2..*") String[] stringOptions;
+ @Option(names = "-v") boolean verbose;
+ @Option(names = "-f") File file;
+ }
+ ArrayOptionArity2_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 \"-vfFILE\" 5.5".split(" "));
+ assertArrayEquals(Arrays.toString(params.stringOptions),
+ new String[] {"1.1", "2.2", "3.3", "4.4", "-vfFILE", "5.5"}, params.stringOptions);
+ assertFalse("verbose", params.verbose);
+ assertNull("file", params.file);
+ assertArrayEquals(null, params.stringParams);
+ }
+
+ @Test
+ public void testArrayOptionArity2_nConsumesAllArgumentsUpToNextSimpleOption() {
+ class ArrayOptionArity2_nAndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-s", arity = "2..*") String[] stringOptions;
+ @Option(names = "-v") boolean verbose;
+ @Option(names = "-f") File file;
+ }
+ ArrayOptionArity2_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 -v -f=FILE 5.5".split(" "));
+ assertArrayEquals(Arrays.toString(params.stringOptions),
+ new String[] {"1.1", "2.2", "3.3", "4.4"}, params.stringOptions);
+ assertTrue(params.verbose);
+ assertEquals(new File("FILE"), params.file);
+ assertArrayEquals(new double[] {5.5}, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionArity2_nConsumesAllArgumentsUpToNextOptionWithAttachment() {
+ class ArrayOptionArity2_nAndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-s", arity = "2..*") String[] stringOptions;
+ @Option(names = "-v") boolean verbose;
+ @Option(names = "-f") File file;
+ }
+ ArrayOptionArity2_nAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2_nAndParameters(), "-s 1.1 2.2 3.3 4.4 -f=FILE -v 5.5".split(" "));
+ assertArrayEquals(Arrays.toString(params.stringOptions),
+ new String[] {"1.1", "2.2", "3.3", "4.4"}, params.stringOptions);
+ assertTrue(params.verbose);
+ assertEquals(new File("FILE"), params.file);
+ assertArrayEquals(new double[] {5.5}, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionArityNConsumeAllArguments() {
+ class ArrayOptionArityNAndParameters {
+ @Parameters char[] charParams;
+ @Option(names = "-chars", arity = "*") char[] charOptions;
+ }
+ ArrayOptionArityNAndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArityNAndParameters(), "-chars a b c d".split(" "));
+ assertArrayEquals(Arrays.toString(params.charOptions),
+ new char[] {'a', 'b', 'c', 'd'}, params.charOptions);
+ assertArrayEquals(null, params.charParams);
+ }
+ @Test
+ public void testMissingRequiredParams() {
+ class Example {
+ @Parameters(index = "1", arity = "0..1") String optional;
+ @Parameters(index = "0") String mandatory;
+ }
+ try { CommandLine.populateCommand(new Example(), new String[] {"mandatory"}); }
+ catch (MissingParameterException ex) { fail(); }
+
+ try {
+ CommandLine.populateCommand(new Example(), new String[0]);
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameter: <mandatory>", ex.getMessage());
+ }
+ }
+ @Test
+ public void testMissingRequiredParams1() {
+ class Tricky1 {
+ @Parameters(index = "2") String anotherMandatory;
+ @Parameters(index = "1", arity = "0..1") String optional;
+ @Parameters(index = "0") String mandatory;
+ }
+ try {
+ CommandLine.populateCommand(new Tricky1(), new String[0]);
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameters: <mandatory>, <anotherMandatory>", ex.getMessage());
+ }
+ try {
+ CommandLine.populateCommand(new Tricky1(), new String[] {"firstonly"});
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameter: <anotherMandatory>", ex.getMessage());
+ }
+ }
+ @Test
+ public void testMissingRequiredParams2() {
+ class Tricky2 {
+ @Parameters(index = "2", arity = "0..1") String anotherOptional;
+ @Parameters(index = "1", arity = "0..1") String optional;
+ @Parameters(index = "0") String mandatory;
+ }
+ try { CommandLine.populateCommand(new Tricky2(), new String[] {"mandatory"}); }
+ catch (MissingParameterException ex) { fail(); }
+
+ try {
+ CommandLine.populateCommand(new Tricky2(), new String[0]);
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameter: <mandatory>", ex.getMessage());
+ }
+ }
+ @Test
+ public void testMissingRequiredParamsWithOptions() {
+ class Tricky3 {
+ @Option(names="-v") boolean more;
+ @Option(names="-t") boolean any;
+ @Parameters(index = "1") String alsoMandatory;
+ @Parameters(index = "0") String mandatory;
+ }
+ try {
+ CommandLine.populateCommand(new Tricky3(), new String[] {"-t", "-v", "mandatory"});
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameter: <alsoMandatory>", ex.getMessage());
+ }
+
+ try {
+ CommandLine.populateCommand(new Tricky3(), new String[] { "-t", "-v"});
+ fail("Should not accept missing two mandatory parameters");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameters: <mandatory>, <alsoMandatory>", ex.getMessage());
+ }
+ }
+ @Test
+ public void testMissingRequiredParamWithOption() {
+ class Tricky3 {
+ @Option(names="-t") boolean any;
+ @Parameters(index = "0") String mandatory;
+ }
+ try {
+ CommandLine.populateCommand(new Tricky3(), new String[] {"-t"});
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameter: <mandatory>", ex.getMessage());
+ }
+ }
+ @Test
+ public void testNoMissingRequiredParamErrorIfHelpOptionSpecified() {
+ class App {
+ @Parameters(hidden = true) // "hidden": don't show this parameter in usage help message
+ List<String> allParameters; // no "index" attribute: captures _all_ arguments (as Strings)
+
+ @Parameters(index = "0") InetAddress host;
+ @Parameters(index = "1") int port;
+ @Parameters(index = "2..*") File[] files;
+
+ @Option(names = "-?", help = true) boolean help;
+ }
+ CommandLine.populateCommand(new App(), new String[] {"-?"});
+ try {
+ CommandLine.populateCommand(new App(), new String[0]);
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameters: <host>, <port>", ex.getMessage());
+ }
+ }
+ @Test
+ public void testNoMissingRequiredParamErrorWithLabelIfHelpOptionSpecified() {
+ class App {
+ @Parameters(hidden = true) // "hidden": don't show this parameter in usage help message
+ List<String> allParameters; // no "index" attribute: captures _all_ arguments (as Strings)
+
+ @Parameters(index = "0", paramLabel = "HOST") InetAddress host;
+ @Parameters(index = "1", paramLabel = "PORT") int port;
+ @Parameters(index = "2..*", paramLabel = "FILES") File[] files;
+
+ @Option(names = "-?", help = true) boolean help;
+ }
+ CommandLine.populateCommand(new App(), new String[] {"-?"});
+ try {
+ CommandLine.populateCommand(new App(), new String[0]);
+ fail("Should not accept missing mandatory parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameters: HOST, PORT", ex.getMessage());
+ }
+ }
+
+ private static class BooleanOptionsArity0_nAndParameters {
+ @Parameters String[] params;
+ @Option(names = "-bool", arity = "0..*") boolean bool;
+ @Option(names = {"-v", "-other"}, arity="0..*") boolean vOrOther;
+ @Option(names = "-r") boolean rBoolean;
+ }
+ @Test
+ public void testBooleanOptionsArity0_nConsume1ArgumentIfPossible() { // ignores varargs
+ BooleanOptionsArity0_nAndParameters
+ params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool false false true".split(" "));
+ assertFalse(params.bool);
+ assertArrayEquals(new String[]{ "false", "true"}, params.params);
+ }
+ @Test
+ public void testBooleanOptionsArity0_nRequiresNoArgument() { // ignores varargs
+ BooleanOptionsArity0_nAndParameters
+ params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool".split(" "));
+ assertTrue(params.bool);
+ }
+ @Test
+ public void testBooleanOptionsArity0_nConsume0ArgumentsIfNextArgIsOption() { // ignores varargs
+ BooleanOptionsArity0_nAndParameters
+ params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool -other".split(" "));
+ assertTrue(params.bool);
+ assertTrue(params.vOrOther);
+ }
+ @Test
+ public void testBooleanOptionsArity0_nConsume0ArgumentsIfNextArgIsParameter() { // ignores varargs
+ BooleanOptionsArity0_nAndParameters
+ params = CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool 123 -other".split(" "));
+ assertTrue(params.bool);
+ assertTrue(params.vOrOther);
+ assertArrayEquals(new String[]{ "123"}, params.params);
+ }
+ @Test
+ public void testBooleanOptionsArity0_nFailsIfAttachedParamNotABoolean() { // ignores varargs
+ try {
+ CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-bool=123 -other".split(" "));
+ fail("was able to assign 123 to boolean");
+ } catch (CommandLine.ParameterException ex) {
+ assertEquals("'123' is not a boolean for option '-bool'", ex.getMessage());
+ }
+ }
+ @Test
+ public void testBooleanOptionsArity0_nShortFormFailsIfAttachedParamNotABoolean() { // ignores varargs
+ try {
+ CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-rv234 -bool".split(" "));
+ fail("Expected exception");
+ } catch (UnmatchedArgumentException ok) {
+ assertEquals("Unmatched argument [-234]", ok.getMessage());
+ }
+ }
+ @Test
+ public void testBooleanOptionsArity0_nShortFormFailsIfAttachedParamNotABooleanWithUnmatchedArgsAllowed() { // ignores varargs
+ setTraceLevel("OFF");
+ CommandLine cmd = new CommandLine(new BooleanOptionsArity0_nAndParameters()).setUnmatchedArgumentsAllowed(true);
+ cmd.parse("-rv234 -bool".split(" "));
+ assertEquals(Arrays.asList("-234"), cmd.getUnmatchedArguments());
+ }
+ @Test
+ public void testBooleanOptionsArity0_nShortFormFailsIfAttachedWithSepParamNotABoolean() { // ignores varargs
+ try {
+ CommandLine.populateCommand(new BooleanOptionsArity0_nAndParameters(), "-rv=234 -bool".split(" "));
+ fail("was able to assign 234 to boolean");
+ } catch (CommandLine.ParameterException ex) {
+ assertEquals("'234' is not a boolean for option '-v'", ex.getMessage());
+ }
+ }
+
+ private static class BooleanOptionsArity1_nAndParameters {
+ @Parameters boolean[] boolParams;
+ @Option(names = "-bool", arity = "1..*") boolean aBoolean;
+ }
+ @Test
+ public void testBooleanOptionsArity1_nConsume1Argument() { // ignores varargs
+ BooleanOptionsArity1_nAndParameters
+ params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool false false true".split(" "));
+ assertFalse(params.aBoolean);
+ assertArrayEquals(new boolean[]{ false, true}, params.boolParams);
+
+ params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool true false true".split(" "));
+ assertTrue(params.aBoolean);
+ assertArrayEquals(new boolean[]{ false, true}, params.boolParams);
+ }
+ @Test
+ public void testBooleanOptionsArity1_nCaseInsensitive() { // ignores varargs
+ BooleanOptionsArity1_nAndParameters
+ params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool fAlsE false true".split(" "));
+ assertFalse(params.aBoolean);
+ assertArrayEquals(new boolean[]{ false, true}, params.boolParams);
+
+ params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool FaLsE false true".split(" "));
+ assertFalse(params.aBoolean);
+ assertArrayEquals(new boolean[]{ false, true}, params.boolParams);
+
+ params = CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool tRuE false true".split(" "));
+ assertTrue(params.aBoolean);
+ assertArrayEquals(new boolean[]{ false, true}, params.boolParams);
+ }
+ @Test
+ public void testBooleanOptionsArity1_nErrorIfValueNotTrueOrFalse() { // ignores varargs
+ try {
+ CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool abc".split(" "));
+ fail("Invalid format abc was accepted for boolean");
+ } catch (CommandLine.ParameterException expected) {
+ assertEquals("'abc' is not a boolean for option '-bool'", expected.getMessage());
+ }
+ }
+ @Test
+ public void testBooleanOptionsArity1_nErrorIfValueMissing() {
+ try {
+ CommandLine.populateCommand(new BooleanOptionsArity1_nAndParameters(), "-bool".split(" "));
+ fail("Missing param was accepted for boolean with arity=1");
+ } catch (CommandLine.ParameterException expected) {
+ assertEquals("Missing required parameter for option '-bool' at index 0 (<aBoolean>)", expected.getMessage());
+ }
+ }
+
+ @Test
+ public void testBooleanOptionArity0Consumes0Arguments() {
+ class BooleanOptionArity0AndParameters {
+ @Parameters boolean[] boolParams;
+ @Option(names = "-bool", arity = "0") boolean aBoolean;
+ }
+ BooleanOptionArity0AndParameters
+ params = CommandLine.populateCommand(new BooleanOptionArity0AndParameters(), "-bool true false true".split(" "));
+ assertTrue(params.aBoolean);
+ assertArrayEquals(new boolean[]{true, false, true}, params.boolParams);
+ }
+ @Test(expected = MissingParameterException.class)
+ public void testSingleValueFieldDefaultMinArityIs1() {
+ CommandLine.populateCommand(new CommandLineTest.SupportedTypes(), "-Long");
+ }
+ @Test
+ public void testSingleValueFieldDefaultMinArityIsOne() {
+ try {
+ CommandLine.populateCommand(new CommandLineTest.SupportedTypes(), "-Long", "-boolean");
+ fail("should fail");
+ } catch (CommandLine.ParameterException ex) {
+ assertEquals("Could not convert '-boolean' to Long for option '-Long'" +
+ ": java.lang.NumberFormatException: For input string: \"-boolean\"", ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testIntOptionArity1_nConsumes1Argument() { // ignores varargs
+ class IntOptionArity1_nAndParameters {
+ @Parameters int[] intParams;
+ @Option(names = "-int", arity = "1..*") int anInt;
+ }
+ IntOptionArity1_nAndParameters
+ params = CommandLine.populateCommand(new IntOptionArity1_nAndParameters(), "-int 23 42 7".split(" "));
+ assertEquals(23, params.anInt);
+ assertArrayEquals(new int[]{ 42, 7}, params.intParams);
+ }
+
+ @Test
+ public void testArrayOptionsWithArity0Consume0Arguments() {
+ class OptionsArray0ArityAndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-doubles", arity = "0") double[] doubleOptions;
+ }
+ OptionsArray0ArityAndParameters
+ params = CommandLine.populateCommand(new OptionsArray0ArityAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[0], params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{1.1, 2.2, 3.3, 4.4}, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionWithArity1Consumes1Argument() {
+ class Options1ArityAndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-doubles", arity = "1") double[] doubleOptions;
+ }
+ Options1ArityAndParameters
+ params = CommandLine.populateCommand(new Options1ArityAndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1}, params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{2.2, 3.3, 4.4}, params.doubleParams, 0.000001);
+
+ // repeated occurrence
+ params = CommandLine.populateCommand(new Options1ArityAndParameters(), "-doubles 1.1 -doubles 2.2 -doubles 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, 3.3}, params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{4.4}, params.doubleParams, 0.000001);
+
+ }
+
+ private static class ArrayOptionArity2AndParameters {
+ @Parameters double[] doubleParams;
+ @Option(names = "-doubles", arity = "2") double[] doubleOptions;
+ }
+ @Test
+ public void testArrayOptionWithArity2Consumes2Arguments() {
+ ArrayOptionArity2AndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles 1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, }, params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{3.3, 4.4}, params.doubleParams, 0.000001);
+
+ // repeated occurrence
+ params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles 1.1 2.2 -doubles 3.3 4.4 0".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, 3.3, 4.4 }, params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{ 0.0 }, params.doubleParams, 0.000001);
+ }
+ @Test
+ public void testArrayOptionsWithArity2Consume2ArgumentsEvenIfFirstIsAttached() {
+ ArrayOptionArity2AndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles=1.1 2.2 3.3 4.4".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, }, params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{3.3, 4.4}, params.doubleParams, 0.000001);
+
+ // repeated occurrence
+ params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles=1.1 2.2 -doubles=3.3 4.4 0".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1.1, 2.2, 3.3, 4.4}, params.doubleOptions, 0.000001);
+ assertArrayEquals(new double[]{0}, params.doubleParams, 0.000001);
+ }
+ /** Arity should not limit the total number of values put in an array or collection #191 */
+ @Test
+ public void testArrayOptionsWithArity2MayContainMoreThan2Values() {
+ ArrayOptionArity2AndParameters
+ params = CommandLine.populateCommand(new ArrayOptionArity2AndParameters(), "-doubles=1 2 -doubles 3 4 -doubles 5 6".split(" "));
+ assertArrayEquals(Arrays.toString(params.doubleOptions),
+ new double[] {1, 2, 3, 4, 5, 6 }, params.doubleOptions, 0.000001);
+ assertArrayEquals(null, params.doubleParams, 0.000001);
+ }
+
+ @Test
+ public void testArrayOptionWithoutArityConsumesOneArgument() { // #192
+ class OptionsNoArityAndParameters {
+ @Parameters char[] charParams;
+ @Option(names = "-chars") char[] charOptions;
+ }
+ OptionsNoArityAndParameters
+ params = CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars a b c d".split(" "));
+ assertArrayEquals(Arrays.toString(params.charOptions),
+ new char[] {'a', }, params.charOptions);
+ assertArrayEquals(Arrays.toString(params.charParams), new char[] {'b', 'c', 'd'}, params.charParams);
+
+ // repeated occurrence
+ params = CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars a -chars b c d".split(" "));
+ assertArrayEquals(Arrays.toString(params.charOptions),
+ new char[] {'a', 'b', }, params.charOptions);
+ assertArrayEquals(Arrays.toString(params.charParams), new char[] {'c', 'd'}, params.charParams);
+
+ try {
+ CommandLine.populateCommand(new OptionsNoArityAndParameters(), "-chars".split(" "));
+ fail("expected MissingParameterException");
+ } catch (MissingParameterException ok) {
+ assertEquals("Missing required parameter for option '-chars' (<charOptions>)", ok.getMessage());
+ }
+ }
+
+ @Test
+ public void testArrayParametersWithDefaultArity() {
+ class ArrayParamsDefaultArity {
+ @Parameters
+ List<String> params;
+ }
+ ArrayParamsDefaultArity params = CommandLine.populateCommand(new ArrayParamsDefaultArity(), "a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsDefaultArity(), "a");
+ assertEquals(Arrays.asList("a"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsDefaultArity());
+ assertEquals(null, params.params);
+ }
+
+ @Test
+ public void testArrayParametersWithArityMinusOneToN() {
+ class ArrayParamsNegativeArity {
+ @Parameters(arity = "-1..*")
+ List<String> params;
+ }
+ ArrayParamsNegativeArity params = CommandLine.populateCommand(new ArrayParamsNegativeArity(), "a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsNegativeArity(), "a");
+ assertEquals(Arrays.asList("a"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsNegativeArity());
+ assertEquals(null, params.params);
+ }
+
+ @Test
+ public void testArrayParametersArity0_n() {
+ class ArrayParamsArity0_n {
+ @Parameters(arity = "0..*")
+ List<String> params;
+ }
+ ArrayParamsArity0_n params = CommandLine.populateCommand(new ArrayParamsArity0_n(), "a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsArity0_n(), "a");
+ assertEquals(Arrays.asList("a"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsArity0_n());
+ assertEquals(null, params.params);
+ }
+
+ @Test
+ public void testArrayParametersArity1_n() {
+ class ArrayParamsArity1_n {
+ @Parameters(arity = "1..*")
+ List<String> params;
+ }
+ ArrayParamsArity1_n params = CommandLine.populateCommand(new ArrayParamsArity1_n(), "a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), params.params);
+
+ params = CommandLine.populateCommand(new ArrayParamsArity1_n(), "a");
+ assertEquals(Arrays.asList("a"), params.params);
+
+ try {
+ params = CommandLine.populateCommand(new ArrayParamsArity1_n());
+ fail("Should not accept input with missing parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameters at positions 0..*: <params>", ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testArrayParametersArity2_n() {
+ class ArrayParamsArity2_n {
+ @Parameters(arity = "2..*")
+ List<String> params;
+ }
+ ArrayParamsArity2_n params = CommandLine.populateCommand(new ArrayParamsArity2_n(), "a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), params.params);
+
+ try {
+ params = CommandLine.populateCommand(new ArrayParamsArity2_n(), "a");
+ fail("Should not accept input with missing parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("positional parameter at index 0..* (<params>) requires at least 2 values, but only 1 were specified: [a]", ex.getMessage());
+ }
+
+ try {
+ params = CommandLine.populateCommand(new ArrayParamsArity2_n());
+ fail("Should not accept input with missing parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("positional parameter at index 0..* (<params>) requires at least 2 values, but none were specified.", ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testNonVarargArrayParametersWithNegativeArityConsumesZeroArguments() {
+ class NonVarArgArrayParamsNegativeArity {
+ @Parameters(arity = "-1")
+ List<String> params;
+ }
+ try {
+ CommandLine.populateCommand(new NonVarArgArrayParamsNegativeArity(), "a", "b", "c");
+ fail("Expected UnmatchedArgumentException");
+ } catch (UnmatchedArgumentException ex) {
+ assertEquals("Unmatched arguments [a, b, c]", ex.getMessage());
+ }
+ try {
+ CommandLine.populateCommand(new NonVarArgArrayParamsNegativeArity(), "a");
+ fail("Expected UnmatchedArgumentException");
+ } catch (UnmatchedArgumentException ex) {
+ assertEquals("Unmatched argument [a]", ex.getMessage());
+ }
+ NonVarArgArrayParamsNegativeArity params = CommandLine.populateCommand(new NonVarArgArrayParamsNegativeArity());
+ assertEquals(null, params.params);
+ }
+
+ @Test
+ public void testNonVarargArrayParametersWithArity0() {
+ class NonVarArgArrayParamsZeroArity {
+ @Parameters(arity = "0")
+ List<String> params;
+ }
+ try {
+ CommandLine.populateCommand(new NonVarArgArrayParamsZeroArity(), "a", "b", "c");
+ fail("Expected UnmatchedArgumentException");
+ } catch (UnmatchedArgumentException ex) {
+ assertEquals("Unmatched arguments [a, b, c]", ex.getMessage());
+ }
+ try {
+ CommandLine.populateCommand(new NonVarArgArrayParamsZeroArity(), "a");
+ fail("Expected UnmatchedArgumentException");
+ } catch (UnmatchedArgumentException ex) {
+ assertEquals("Unmatched argument [a]", ex.getMessage());
+ }
+ NonVarArgArrayParamsZeroArity params = CommandLine.populateCommand(new NonVarArgArrayParamsZeroArity());
+ assertEquals(null, params.params);
+ }
+
+ @Test
+ public void testNonVarargArrayParametersWithArity1() {
+ class NonVarArgArrayParamsArity1 {
+ @Parameters(arity = "1")
+ List<String> params;
+ }
+ NonVarArgArrayParamsArity1 actual = CommandLine.populateCommand(new NonVarArgArrayParamsArity1(), "a", "b", "c");
+ assertEquals(Arrays.asList("a", "b", "c"), actual.params);
+
+ NonVarArgArrayParamsArity1 params = CommandLine.populateCommand(new NonVarArgArrayParamsArity1(), "a");
+ assertEquals(Arrays.asList("a"), params.params);
+
+ try {
+ params = CommandLine.populateCommand(new NonVarArgArrayParamsArity1());
+ fail("Should not accept input with missing parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameter: <params>", ex.getMessage());
+ }
+ }
+
+ @Test
+ public void testNonVarargArrayParametersWithArity2() {
+ class NonVarArgArrayParamsArity2 {
+ @Parameters(arity = "2")
+ List<String> params;
+ }
+ NonVarArgArrayParamsArity2 params = null;
+ try {
+ CommandLine.populateCommand(new NonVarArgArrayParamsArity2(), "a", "b", "c");
+ fail("expected MissingParameterException");
+ } catch (MissingParameterException ex) {
+ assertEquals("positional parameter at index 0..* (<params>) requires at least 2 values, but only 1 were specified: [c]", ex.getMessage());
+ }
+
+ try {
+ params = CommandLine.populateCommand(new NonVarArgArrayParamsArity2(), "a");
+ fail("Should not accept input with missing parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("positional parameter at index 0..* (<params>) requires at least 2 values, but only 1 were specified: [a]", ex.getMessage());
+ }
+
+ try {
+ params = CommandLine.populateCommand(new NonVarArgArrayParamsArity2());
+ fail("Should not accept input with missing parameter");
+ } catch (MissingParameterException ex) {
+ assertEquals("positional parameter at index 0..* (<params>) requires at least 2 values, but none were specified.", ex.getMessage());
+ }
+ }
+ @Test
+ public void testMixPositionalParamsWithOptions_ParamsUnboundedArity_isGreedy() {
+ class Arg {
+ @Parameters(arity = "1..*") List<String> parameters;
+ @Option(names = "-o") List<String> options;
+ }
+ Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3", "p4");
+ assertEquals(Arrays.asList("p1", "p2", "-o", "v2", "p3", "p4"), result.parameters);
+ assertEquals(Arrays.asList("v1"), result.options);
+
+ Arg result2 = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "-o", "v2", "p3");
+ assertEquals(Arrays.asList("p1", "-o", "v2", "p3"), result2.parameters);
+ assertEquals(Arrays.asList("v1"), result2.options);
+
+ try {
+ CommandLine.populateCommand(new Arg(), "-o", "v1", "-o", "v2");
+ fail("Expected MissingParameterException");
+ } catch (MissingParameterException ex) {
+ assertEquals("Missing required parameters at positions 0..*: <parameters>", ex.getMessage());
+ }
+ }
+
+ @Test
+ public void test130MixPositionalParamsWithOptions() {
+ @CommandLine.Command(name = "test-command", description = "tests help from a command script")
+ class Arg {
+
+ @Parameters(description = "some parameters")
+ List<String> parameters;
+
+ @Option(names = {"-cp", "--codepath"}, description = "the codepath")
+ List<String> codepath;
+ }
+ Arg result = CommandLine.populateCommand(new Arg(), "--codepath", "/usr/x.jar", "placeholder", "-cp", "/bin/y.jar", "another");
+ assertEquals(Arrays.asList("/usr/x.jar", "/bin/y.jar"), result.codepath);
+ assertEquals(Arrays.asList("placeholder", "another"), result.parameters);
+ }
+
+ @Test
+ public void test130MixPositionalParamsWithOptions1() {
+ class Arg {
+ @Parameters List<String> parameters;
+ @Option(names = "-o") List<String> options;
+ }
+ Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3");
+ assertEquals(Arrays.asList("v1", "v2"), result.options);
+ assertEquals(Arrays.asList("p1", "p2", "p3"), result.parameters);
+ }
+
+ @Test
+ public void test130MixPositionalParamsWithOptionsArity() {
+ class Arg {
+ @Parameters(arity = "2") List<String> parameters;
+ @Option(names = "-o") List<String> options;
+ }
+ Arg result = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3", "p4");
+ assertEquals(Arrays.asList("v1", "v2"), result.options);
+ assertEquals(Arrays.asList("p1", "p2", "p3", "p4"), result.parameters);
+
+ Arg result2 = CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "-o", "v2", "p3");
+ assertEquals(Arrays.asList("v1"), result2.options);
+ assertEquals(Arrays.asList("p1", "-o", "v2", "p3"), result2.parameters);
+
+ try {
+ CommandLine.populateCommand(new Arg(), "-o", "v1", "p1", "p2", "-o", "v2", "p3");
+ fail("Expected MissingParameterException");
+ } catch (MissingParameterException ex) {
+ assertEquals("positional parameter at index 0..* (<parameters>) requires at least 2 values, but only 1 were specified: [p3]", ex.getMessage());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/23bcd257/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java
index d0bb609..3651b22 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/tools/picocli/CommandLineHelpTest.java
@@ -2190,7 +2190,98 @@ public class CommandLineHelpTest {
assertEquals(ansi.new Text("@|bold abc|@@|underline DE|@"), txt2.substring(0,5));
assertEquals(ansi.new Text("@|bold bc|@@|underline DE|@"), txt2.substring(1,5));
}
-
+ @Test
+ public void testTextSplitLines() {
+ Help.Ansi ansi = Help.Ansi.ON;
+ Text[] all = {
+ ansi.new Text("@|bold 012\n34|@").append("5\nAA\n6").append("@|underline 78\n90|@"),
+ ansi.new Text("@|bold 012\r34|@").append("5\rAA\r6").append("@|underline 78\r90|@"),
+ ansi.new Text("@|bold 012\r\n34|@").append("5\r\nAA\r\n6").append("@|underline 78\r\n90|@"),
+ };
+ for (Text text : all) {
+ Text[] lines = text.splitLines();
+ int i = 0;
+ assertEquals(ansi.new Text("@|bold 012|@"), lines[i++]);
+ assertEquals(ansi.new Text("@|bold 34|@5"), lines[i++]);
+ assertEquals(ansi.new Text("AA"), lines[i++]);
+ assertEquals(ansi.new Text("6@|underline 78|@"), lines[i++]);
+ assertEquals(ansi.new Text("@|underline 90|@"), lines[i++]);
+ }
+ }
+ @Test
+ public void testTextSplitLinesStartEnd() {
+ Help.Ansi ansi = Help.Ansi.ON;
+ Text[] all = {
+ ansi.new Text("\n@|bold 012\n34|@").append("5\nAA\n6").append("@|underline 78\n90|@\n"),
+ ansi.new Text("\r@|bold 012\r34|@").append("5\rAA\r6").append("@|underline 78\r90|@\r"),
+ ansi.new Text("\r\n@|bold 012\r\n34|@").append("5\r\nAA\r\n6").append("@|underline 78\r\n90|@\r\n"),
+ };
+ for (Text text : all) {
+ Text[] lines = text.splitLines();
+ int i = 0;
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text("@|bold 012|@"), lines[i++]);
+ assertEquals(ansi.new Text("@|bold 34|@5"), lines[i++]);
+ assertEquals(ansi.new Text("AA"), lines[i++]);
+ assertEquals(ansi.new Text("6@|underline 78|@"), lines[i++]);
+ assertEquals(ansi.new Text("@|underline 90|@"), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ }
+ }
+ @Test
+ public void testTextSplitLinesStartEndIntermediate() {
+ Help.Ansi ansi = Help.Ansi.ON;
+ Text[] all = {
+ ansi.new Text("\n@|bold 012\n\n\n34|@").append("5\n\n\nAA\n\n\n6").append("@|underline 78\n90|@\n"),
+ ansi.new Text("\r@|bold 012\r\r\r34|@").append("5\r\r\rAA\r\r\r6").append("@|underline 78\r90|@\r"),
+ ansi.new Text("\r\n@|bold 012\r\n\r\n\r\n34|@").append("5\r\n\r\n\r\nAA\r\n\r\n\r\n6").append("@|underline 78\r\n90|@\r\n"),
+ };
+ for (Text text : all) {
+ Text[] lines = text.splitLines();
+ int i = 0;
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text("@|bold 012|@"), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text("@|bold 34|@5"), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text("AA"), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ assertEquals(ansi.new Text("6@|underline 78|@"), lines[i++]);
+ assertEquals(ansi.new Text("@|underline 90|@"), lines[i++]);
+ assertEquals(ansi.new Text(""), lines[i++]);
+ }
+ }
+ @Test
+ public void testEmbeddedNewLinesInUsageSections() throws UnsupportedEncodingException {
+ @Command(description = "first line\nsecond line\nthird line", headerHeading = "headerHeading1\nheaderHeading2",
+ header = "header1\nheader2", descriptionHeading = "descriptionHeading1\ndescriptionHeading2",
+ footerHeading = "footerHeading1\nfooterHeading2", footer = "footer1\nfooter2")
+ class App {
+ @Option(names = {"-v", "--verbose"}, description = "optionDescription1\noptionDescription2") boolean v;
+ @Parameters(description = "paramDescription1\nparamDescription2") String file;
+ }
+ String actual = usageString(new App(), Help.Ansi.OFF);
+ String expected = String.format("" +
+ "headerHeading1%n" +
+ "headerHeading2header1%n" +
+ "header2%n" +
+ "Usage: <main class> [-v] <file>%n" +
+ "descriptionHeading1%n" +
+ "descriptionHeading2first line%n" +
+ "second line%n" +
+ "third line%n" +
+ " <file> paramDescription1%n" +
+ " paramDescription2%n" +
+ " -v, --verbose optionDescription1%n" +
+ " optionDescription2%n" +
+ "footerHeading1%n" +
+ "footerHeading2footer1%n" +
+ "footer2%n");
+ assertEquals(expected, actual);
+ }
@Test
public void testTextWithMultipleStyledSections() {
assertEquals("\u001B[1m<main class>\u001B[21m\u001B[0m [\u001B[33m-v\u001B[39m\u001B[0m] [\u001B[33m-c\u001B[39m\u001B[0m [\u001B[3m<count>\u001B[23m\u001B[0m]]",