Skip to content

Commit d4cead7

Browse files
Fix issue with groups not being reported in help output. (#411)
* Fix issue with groups not being reported in help output. AbstractHelpFormatter: * Swapped printHelp using Iterable<Option> with printHelp using Options. Effectively switching to using Options class to print the help. * Removed public String toSyntaxOptions(final Iterable<Option> options) as it was added in this version and should have only been used internally. HelpFormatterTest: * removed toSyntaxOptions using Iterable<Option> test. * added a printHelpTest with Iterable<Option> as previously we depended on printHelpTest with Option to test the code branch. * added verifyOptionGroupingOutput as a test to show that reported issue is corrected. * Don't break binary compatibility * Restore test Add test for toSyntaxOptions with iterable of options * fixed issues arising from reverting incompatible binary changes --------- Co-authored-by: Gary Gregory <[email protected]>
1 parent 1be4ff9 commit d4cead7

File tree

2 files changed

+115
-6
lines changed

2 files changed

+115
-6
lines changed

src/main/java/org/apache/commons/cli/help/AbstractHelpFormatter.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ public final String getSyntaxPrefix() {
293293
* @param autoUsage whether to print an automatically generated usage statement.
294294
* @throws IOException If the output could not be written to the {@link HelpAppendable}.
295295
*/
296-
public void printHelp(final String cmdLineSyntax, final String header, final Iterable<Option> options, final String footer, final boolean autoUsage)
296+
public void printHelp(final String cmdLineSyntax, final String header, final Options options, final String footer, final boolean autoUsage)
297297
throws IOException {
298298
if (Util.isEmpty(cmdLineSyntax)) {
299299
throw new IllegalArgumentException("cmdLineSyntax not provided");
@@ -306,7 +306,7 @@ public void printHelp(final String cmdLineSyntax, final String header, final Ite
306306
if (!Util.isEmpty(header)) {
307307
helpAppendable.appendParagraph(header);
308308
}
309-
helpAppendable.appendTable(getTableDefinition(options));
309+
helpAppendable.appendTable(getTableDefinition(options.getOptions()));
310310
if (!Util.isEmpty(footer)) {
311311
helpAppendable.appendParagraph(footer);
312312
}
@@ -317,14 +317,16 @@ public void printHelp(final String cmdLineSyntax, final String header, final Ite
317317
*
318318
* @param cmdLineSyntax the syntax for this application.
319319
* @param header the banner to display at the beginning of the help.
320-
* @param options the {@link Options} to print.
320+
* @param options the collection of {@link Option} objects to print.
321321
* @param footer the banner to display at the end of the help.
322322
* @param autoUsage whether to print an automatically generated usage statement.
323323
* @throws IOException If the output could not be written to the {@link HelpAppendable}.
324324
*/
325-
public final void printHelp(final String cmdLineSyntax, final String header, final Options options, final String footer, final boolean autoUsage)
325+
public void printHelp(final String cmdLineSyntax, final String header, final Iterable<Option> options, final String footer, final boolean autoUsage)
326326
throws IOException {
327-
printHelp(cmdLineSyntax, header, options.getOptions(), footer, autoUsage);
327+
Options optionsObject = new Options();
328+
options.forEach(optionsObject::addOption);
329+
printHelp(cmdLineSyntax, header, optionsObject, footer, autoUsage);
328330
}
329331

330332
/**
@@ -403,7 +405,11 @@ public final String toArgName(final String argName) {
403405

404406
/**
405407
* Return the string representation of the options as used in the syntax display.
406-
*
408+
* <p>
409+
* This is probably not the method you want. This method does not track the presence
410+
* of option groups. To display the option grouping use {@link #toSyntaxOptions(Options)} or
411+
* {@link #toSyntaxOptions(OptionGroup)} for individual groups.
412+
* </p>
407413
* @param options The collection of {@link Option} instances to create the string representation for.
408414
* @return the string representation of the options as used in the syntax display.
409415
*/

src/test/java/org/apache/commons/cli/help/HelpFormatterTest.java

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,85 @@ void testPrintHelp() throws IOException {
147147
assertEquals(0, sb.length(), "Should not write to output");
148148
}
149149

150+
@Test
151+
public void testPrintHelpWithIterableOptions() throws IOException {
152+
final StringBuilder sb = new StringBuilder();
153+
final TextHelpAppendable serializer = new TextHelpAppendable(sb);
154+
HelpFormatter formatter = HelpFormatter.builder().setHelpAppendable(serializer).get();
155+
156+
final List<Option> options = new ArrayList<>();
157+
options.add(Option.builder("a").since("1853").hasArg().desc("aaaa aaaa aaaa aaaa aaaa").build());
158+
159+
List<String> expected = new ArrayList<>();
160+
expected.add(" usage: commandSyntax [-a <arg>]");
161+
expected.add("");
162+
expected.add(" header");
163+
expected.add("");
164+
expected.add(" Options Since Description ");
165+
expected.add(" -a <arg> 1853 aaaa aaaa aaaa aaaa aaaa");
166+
expected.add("");
167+
expected.add(" footer");
168+
expected.add("");
169+
170+
formatter.printHelp("commandSyntax", "header", options, "footer", true);
171+
List<String> actual = IOUtils.readLines(new StringReader(sb.toString()));
172+
assertEquals(expected, actual);
173+
174+
formatter = HelpFormatter.builder().setShowSince(false).setHelpAppendable(serializer).get();
175+
expected = new ArrayList<>();
176+
expected.add(" usage: commandSyntax [-a <arg>]");
177+
expected.add("");
178+
expected.add(" header");
179+
expected.add("");
180+
expected.add(" Options Description ");
181+
expected.add(" -a <arg> aaaa aaaa aaaa aaaa aaaa");
182+
expected.add("");
183+
expected.add(" footer");
184+
expected.add("");
185+
186+
sb.setLength(0);
187+
formatter.printHelp("commandSyntax", "header", options, "footer", true);
188+
actual = IOUtils.readLines(new StringReader(sb.toString()));
189+
assertEquals(expected, actual);
190+
191+
sb.setLength(0);
192+
formatter.printHelp("commandSyntax", "header", options, "footer", false);
193+
expected.set(0, " usage: commandSyntax");
194+
actual = IOUtils.readLines(new StringReader(sb.toString()));
195+
assertEquals(expected, actual);
196+
197+
sb.setLength(0);
198+
formatter.printHelp("commandSyntax", "", options, "footer", false);
199+
expected.remove(3);
200+
expected.remove(2);
201+
actual = IOUtils.readLines(new StringReader(sb.toString()));
202+
assertEquals(expected, actual);
203+
204+
sb.setLength(0);
205+
formatter.printHelp("commandSyntax", null, options, "footer", false);
206+
actual = IOUtils.readLines(new StringReader(sb.toString()));
207+
assertEquals(expected, actual);
208+
209+
sb.setLength(0);
210+
formatter.printHelp("commandSyntax", null, options, "", false);
211+
expected.remove(6);
212+
expected.remove(5);
213+
actual = IOUtils.readLines(new StringReader(sb.toString()));
214+
assertEquals(expected, actual);
215+
216+
sb.setLength(0);
217+
formatter.printHelp("commandSyntax", null, options, null, false);
218+
actual = IOUtils.readLines(new StringReader(sb.toString()));
219+
assertEquals(expected, actual);
220+
221+
sb.setLength(0);
222+
final HelpFormatter fHelp = formatter;
223+
assertThrows(IllegalArgumentException.class, () -> fHelp.printHelp("", "header", options, "footer", true));
224+
assertEquals(0, sb.length(), "Should not write to output");
225+
assertThrows(IllegalArgumentException.class, () -> fHelp.printHelp(null, "header", options, "footer", true));
226+
assertEquals(0, sb.length(), "Should not write to output");
227+
}
228+
150229
/**
151230
* Tests example from the mailing list that caused an infinite loop.
152231
*
@@ -415,4 +494,28 @@ void testToSyntaxOptionOptionsTest() {
415494
"options with required group failed");
416495
}
417496

497+
@Test
498+
void verifyOptionGroupingOutput() throws IOException {
499+
// create options and groups
500+
final Option o1 = new Option("o1", "Descr");
501+
final Option o2 = new Option("o2", "Descr");
502+
503+
final Options options = new Options();
504+
options.addOption(o1);
505+
options.addOption(o2);
506+
507+
final OptionGroup group = new OptionGroup();
508+
group.addOption(o1);
509+
group.addOption(o2);
510+
options.addOptionGroup(group);
511+
512+
final StringBuilder output = new StringBuilder();
513+
//format options with new formatter
514+
final org.apache.commons.cli.help.HelpFormatter newFormatter =
515+
org.apache.commons.cli.help.HelpFormatter.builder().setShowSince(false)
516+
.setHelpAppendable(new TextHelpAppendable(output)).get();
517+
newFormatter.printHelp("Command", null, options, null, true);
518+
assertTrue(output.toString().contains("[-o1 | -o2]"));
519+
}
520+
418521
}

0 commit comments

Comments
 (0)