This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-cli.git


The following commit(s) were added to refs/heads/master by this push:
     new d4cead79 Fix issue with groups not being reported in help output. 
(#411)
d4cead79 is described below

commit d4cead7973eedc6f892f9c98ee3e3c1d16f88151
Author: Claude Warren <[email protected]>
AuthorDate: Wed Nov 5 13:28:04 2025 +0100

    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]>
---
 .../commons/cli/help/AbstractHelpFormatter.java    |  18 ++--
 .../apache/commons/cli/help/HelpFormatterTest.java | 103 +++++++++++++++++++++
 2 files changed, 115 insertions(+), 6 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/cli/help/AbstractHelpFormatter.java 
b/src/main/java/org/apache/commons/cli/help/AbstractHelpFormatter.java
index f8947c66..cc06c90a 100644
--- a/src/main/java/org/apache/commons/cli/help/AbstractHelpFormatter.java
+++ b/src/main/java/org/apache/commons/cli/help/AbstractHelpFormatter.java
@@ -293,7 +293,7 @@ public abstract class AbstractHelpFormatter {
      * @param autoUsage     whether to print an automatically generated usage 
statement.
      * @throws IOException If the output could not be written to the {@link 
HelpAppendable}.
      */
-    public void printHelp(final String cmdLineSyntax, final String header, 
final Iterable<Option> options, final String footer, final boolean autoUsage)
+    public void printHelp(final String cmdLineSyntax, final String header, 
final Options options, final String footer, final boolean autoUsage)
             throws IOException {
         if (Util.isEmpty(cmdLineSyntax)) {
             throw new IllegalArgumentException("cmdLineSyntax not provided");
@@ -306,7 +306,7 @@ public abstract class AbstractHelpFormatter {
         if (!Util.isEmpty(header)) {
             helpAppendable.appendParagraph(header);
         }
-        helpAppendable.appendTable(getTableDefinition(options));
+        helpAppendable.appendTable(getTableDefinition(options.getOptions()));
         if (!Util.isEmpty(footer)) {
             helpAppendable.appendParagraph(footer);
         }
@@ -317,14 +317,16 @@ public abstract class AbstractHelpFormatter {
      *
      * @param cmdLineSyntax the syntax for this application.
      * @param header        the banner to display at the beginning of the help.
-     * @param options       the {@link Options} to print.
+     * @param options       the collection of {@link Option} objects to print.
      * @param footer        the banner to display at the end of the help.
      * @param autoUsage     whether to print an automatically generated usage 
statement.
      * @throws IOException If the output could not be written to the {@link 
HelpAppendable}.
      */
-    public final void printHelp(final String cmdLineSyntax, final String 
header, final Options options, final String footer, final boolean autoUsage)
+    public void printHelp(final String cmdLineSyntax, final String header, 
final Iterable<Option> options, final String footer, final boolean autoUsage)
             throws IOException {
-        printHelp(cmdLineSyntax, header, options.getOptions(), footer, 
autoUsage);
+        Options optionsObject = new Options();
+        options.forEach(optionsObject::addOption);
+        printHelp(cmdLineSyntax, header, optionsObject, footer, autoUsage);
     }
 
     /**
@@ -403,7 +405,11 @@ public abstract class AbstractHelpFormatter {
 
     /**
      * Return the string representation of the options as used in the syntax 
display.
-     *
+     * <p>
+     *     This is probably not the method you want.  This method does not 
track the presence
+     *     of option groups.  To display the option grouping use {@link 
#toSyntaxOptions(Options)} or
+     *     {@link #toSyntaxOptions(OptionGroup)} for individual groups.
+     * </p>
      * @param options The collection of {@link Option} instances to create the 
string representation for.
      * @return the string representation of the options as used in the syntax 
display.
      */
diff --git a/src/test/java/org/apache/commons/cli/help/HelpFormatterTest.java 
b/src/test/java/org/apache/commons/cli/help/HelpFormatterTest.java
index 9d524033..7062daa5 100644
--- a/src/test/java/org/apache/commons/cli/help/HelpFormatterTest.java
+++ b/src/test/java/org/apache/commons/cli/help/HelpFormatterTest.java
@@ -147,6 +147,85 @@ class HelpFormatterTest {
         assertEquals(0, sb.length(), "Should not write to output");
     }
 
+    @Test
+    public void testPrintHelpWithIterableOptions() throws IOException {
+        final StringBuilder sb = new StringBuilder();
+        final TextHelpAppendable serializer = new TextHelpAppendable(sb);
+        HelpFormatter formatter = 
HelpFormatter.builder().setHelpAppendable(serializer).get();
+
+        final List<Option> options = new ArrayList<>();
+        options.add(Option.builder("a").since("1853").hasArg().desc("aaaa aaaa 
aaaa aaaa aaaa").build());
+
+        List<String> expected = new ArrayList<>();
+        expected.add(" usage:  commandSyntax [-a <arg>]");
+        expected.add("");
+        expected.add(" header");
+        expected.add("");
+        expected.add(" Options      Since           Description       ");
+        expected.add(" -a <arg>     1853      aaaa aaaa aaaa aaaa aaaa");
+        expected.add("");
+        expected.add(" footer");
+        expected.add("");
+
+        formatter.printHelp("commandSyntax", "header", options, "footer", 
true);
+        List<String> actual = IOUtils.readLines(new 
StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        formatter = 
HelpFormatter.builder().setShowSince(false).setHelpAppendable(serializer).get();
+        expected = new ArrayList<>();
+        expected.add(" usage:  commandSyntax [-a <arg>]");
+        expected.add("");
+        expected.add(" header");
+        expected.add("");
+        expected.add(" Options            Description       ");
+        expected.add(" -a <arg>     aaaa aaaa aaaa aaaa aaaa");
+        expected.add("");
+        expected.add(" footer");
+        expected.add("");
+
+        sb.setLength(0);
+        formatter.printHelp("commandSyntax", "header", options, "footer", 
true);
+        actual = IOUtils.readLines(new StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        sb.setLength(0);
+        formatter.printHelp("commandSyntax", "header", options, "footer", 
false);
+        expected.set(0, " usage:  commandSyntax");
+        actual = IOUtils.readLines(new StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        sb.setLength(0);
+        formatter.printHelp("commandSyntax", "", options, "footer", false);
+        expected.remove(3);
+        expected.remove(2);
+        actual = IOUtils.readLines(new StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        sb.setLength(0);
+        formatter.printHelp("commandSyntax", null, options, "footer", false);
+        actual = IOUtils.readLines(new StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        sb.setLength(0);
+        formatter.printHelp("commandSyntax", null, options, "", false);
+        expected.remove(6);
+        expected.remove(5);
+        actual = IOUtils.readLines(new StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        sb.setLength(0);
+        formatter.printHelp("commandSyntax", null, options, null, false);
+        actual = IOUtils.readLines(new StringReader(sb.toString()));
+        assertEquals(expected, actual);
+
+        sb.setLength(0);
+        final HelpFormatter fHelp = formatter;
+        assertThrows(IllegalArgumentException.class, () -> fHelp.printHelp("", 
"header", options, "footer", true));
+        assertEquals(0, sb.length(), "Should not write to output");
+        assertThrows(IllegalArgumentException.class, () -> 
fHelp.printHelp(null, "header", options, "footer", true));
+        assertEquals(0, sb.length(), "Should not write to output");
+    }
+
     /**
      * Tests example from the mailing list that caused an infinite loop.
      *
@@ -415,4 +494,28 @@ class HelpFormatterTest {
                 "options with required group failed");
     }
 
+    @Test
+    void verifyOptionGroupingOutput() throws IOException {
+         // create options and groups
+         final Option o1 = new Option("o1", "Descr");
+         final Option o2 = new Option("o2", "Descr");
+
+         final Options options = new Options();
+         options.addOption(o1);
+         options.addOption(o2);
+
+         final OptionGroup group = new OptionGroup();
+         group.addOption(o1);
+         group.addOption(o2);
+         options.addOptionGroup(group);
+
+         final StringBuilder output = new StringBuilder();
+         //format options with new formatter
+         final org.apache.commons.cli.help.HelpFormatter newFormatter =
+                 
org.apache.commons.cli.help.HelpFormatter.builder().setShowSince(false)
+        .setHelpAppendable(new TextHelpAppendable(output)).get();
+         newFormatter.printHelp("Command", null, options, null, true);
+         assertTrue(output.toString().contains("[-o1 | -o2]"));
+     }
+
 }

Reply via email to