You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2024/02/16 16:23:36 UTC

(commons-cli) branch master updated: CLI-324 Make adding OptionGroups and Options to existing Options easier (#230)

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 14a95d9  CLI-324 Make adding OptionGroups and Options to existing Options easier (#230)
14a95d9 is described below

commit 14a95d9e3a17b28d0030b51aef45464137efc74a
Author: Claude Warren <cl...@aiven.io>
AuthorDate: Fri Feb 16 17:23:31 2024 +0100

    CLI-324 Make adding OptionGroups and Options to existing Options easier (#230)
    
    * Fixes for CLI-324
    
    * added tests
    
    * reverted change of getOptionGroup to public and added documentation
    
    * added test cases and javadoc to explain functioning
---
 src/main/java/org/apache/commons/cli/Options.java  | 26 +++++-
 .../java/org/apache/commons/cli/OptionsTest.java   | 93 ++++++++++++++++++++++
 2 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/cli/Options.java b/src/main/java/org/apache/commons/cli/Options.java
index ee7ce14..6fff20b 100644
--- a/src/main/java/org/apache/commons/cli/Options.java
+++ b/src/main/java/org/apache/commons/cli/Options.java
@@ -54,6 +54,25 @@ public class Options implements Serializable {
     /** A map of the option groups */
     private final Map<String, OptionGroup> optionGroups = new LinkedHashMap<>();
 
+    /**
+     * Adds options to this option.  If any Option in {@code options} already exists
+     * in this Options an IllegalArgumentException is thrown
+     *
+     * @param options the options to add.
+     * @return The resulting Options instance.
+     * @since 1.7.0
+     */
+    public Options addOptions(final Options options) {
+        for (Option opt : options.getOptions()) {
+            if (hasOption(opt.getKey())) {
+                throw new IllegalArgumentException("Duplicate key: " + opt.getKey());
+            }
+            addOption(opt);
+        }
+        options.getOptionGroups().forEach(this::addOptionGroup);
+        return this;
+    }
+
     /**
      * Adds an option instance
      *
@@ -233,6 +252,11 @@ public class Options implements Serializable {
      * @return a Collection of OptionGroup instances.
      */
     Collection<OptionGroup> getOptionGroups() {
+        /* The optionGroups map will have duplicates in the values() results.  We
+         * use the HashSet to filter out duplicates and return a collection of
+         * OpitonGroup.  The decision to return a Collection rather than a set
+         * was probably to keep symmetry with the getOptions() method.
+         */
         return new HashSet<>(optionGroups.values());
     }
 
@@ -250,7 +274,7 @@ public class Options implements Serializable {
      *
      * @return read-only List of required options
      */
-    public List getRequiredOptions() {
+    public List<?> getRequiredOptions() {
         return Collections.unmodifiableList(requiredOpts);
     }
 
diff --git a/src/test/java/org/apache/commons/cli/OptionsTest.java b/src/test/java/org/apache/commons/cli/OptionsTest.java
index 3d7004f..1f93bc7 100644
--- a/src/test/java/org/apache/commons/cli/OptionsTest.java
+++ b/src/test/java/org/apache/commons/cli/OptionsTest.java
@@ -21,9 +21,15 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import org.junit.Test;
 
@@ -78,6 +84,93 @@ public class OptionsTest {
         assertEquals(2, options.getOptionGroups().size());
     }
 
+    @Test
+    public void testAddOptions() {
+        final Options options = new Options();
+
+        final OptionGroup group1 = new OptionGroup();
+        group1.addOption(Option.builder("a").build());
+        group1.addOption(Option.builder("b").build());
+
+        options.addOptionGroup(group1);
+
+        options.addOption(Option.builder("X").build());
+        options.addOption(Option.builder("y").build());
+
+        final Options underTest = new Options();
+        underTest.addOptions(options);
+
+        assertEquals(options.getOptionGroups(), underTest.getOptionGroups());
+        assertArrayEquals(options.getOptions().toArray(), underTest.getOptions().toArray());
+    }
+
+    @Test
+    public void testAddOptions2X() {
+        final Options options = new Options();
+
+        final OptionGroup group1 = new OptionGroup();
+        group1.addOption(Option.builder("a").build());
+        group1.addOption(Option.builder("b").build());
+
+        options.addOptionGroup(group1);
+
+        options.addOption(Option.builder("X").build());
+        options.addOption(Option.builder("y").build());
+
+        assertThrows(IllegalArgumentException.class, () -> options.addOptions(options));
+    }
+
+    @Test
+    public void testAddConflictingOptions() {
+        final Options options1 = new Options();
+        final OptionGroup group1 = new OptionGroup();
+        group1.addOption(Option.builder("a").build());
+        group1.addOption(Option.builder("b").build());
+        options1.addOptionGroup(group1);
+        options1.addOption(Option.builder("x").build());
+        options1.addOption(Option.builder("y").build());
+
+        final Options options2 = new Options();
+        final OptionGroup group2 = new OptionGroup();
+        group2.addOption(Option.builder("x").type(Integer.class).build());
+        group2.addOption(Option.builder("b").type(Integer.class).build());
+        options2.addOptionGroup(group2);
+        options2.addOption(Option.builder("c").build());
+
+        assertThrows(IllegalArgumentException.class, () -> options1.addOptions(options2));
+    }
+
+    @Test
+    public void testAddNonConflictingOptions() {
+        final Options options1 = new Options();
+        final OptionGroup group1 = new OptionGroup();
+        group1.addOption(Option.builder("a").build());
+        group1.addOption(Option.builder("b").build());
+        options1.addOptionGroup(group1);
+        options1.addOption(Option.builder("x").build());
+        options1.addOption(Option.builder("y").build());
+
+        final Options options2 = new Options();
+        final OptionGroup group2 = new OptionGroup();
+        group2.addOption(Option.builder("c").type(Integer.class).build());
+        group2.addOption(Option.builder("d").type(Integer.class).build());
+        options2.addOptionGroup(group2);
+        options1.addOption(Option.builder("e").build());
+        options1.addOption(Option.builder("f").build());
+
+        Options underTest = new Options();
+        underTest.addOptions(options1);
+        underTest.addOptions(options2);
+
+        List<OptionGroup> expected = Arrays.asList(group1, group2);
+        assertTrue(expected.size() == underTest.getOptionGroups().size() && expected.containsAll(underTest.getOptionGroups()));
+        Set<Option> expectOpt = new HashSet<>();
+        expectOpt.addAll(options1.getOptions());
+        expectOpt.addAll(options2.getOptions());
+        assertEquals(8, expectOpt.size());
+        assertTrue(expectOpt.size() == underTest.getOptions().size() && expectOpt.containsAll(underTest.getOptions()));
+    }
+
     @Test
     public void testHelpOptions() {
         OptionBuilder.withLongOpt("long-only1");