Skip to content

Commit 14a95d9

Browse files
authored
CLI-324 Make adding OptionGroups and Options to existing Options easier (apache#230)
* Fixes for CLI-324 * added tests * reverted change of getOptionGroup to public and added documentation * added test cases and javadoc to explain functioning
1 parent 4fd2152 commit 14a95d9

2 files changed

Lines changed: 118 additions & 1 deletion

File tree

src/main/java/org/apache/commons/cli/Options.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ public class Options implements Serializable {
5454
/** A map of the option groups */
5555
private final Map<String, OptionGroup> optionGroups = new LinkedHashMap<>();
5656

57+
/**
58+
* Adds options to this option. If any Option in {@code options} already exists
59+
* in this Options an IllegalArgumentException is thrown
60+
*
61+
* @param options the options to add.
62+
* @return The resulting Options instance.
63+
* @since 1.7.0
64+
*/
65+
public Options addOptions(final Options options) {
66+
for (Option opt : options.getOptions()) {
67+
if (hasOption(opt.getKey())) {
68+
throw new IllegalArgumentException("Duplicate key: " + opt.getKey());
69+
}
70+
addOption(opt);
71+
}
72+
options.getOptionGroups().forEach(this::addOptionGroup);
73+
return this;
74+
}
75+
5776
/**
5877
* Adds an option instance
5978
*
@@ -233,6 +252,11 @@ public OptionGroup getOptionGroup(final Option opt) {
233252
* @return a Collection of OptionGroup instances.
234253
*/
235254
Collection<OptionGroup> getOptionGroups() {
255+
/* The optionGroups map will have duplicates in the values() results. We
256+
* use the HashSet to filter out duplicates and return a collection of
257+
* OpitonGroup. The decision to return a Collection rather than a set
258+
* was probably to keep symmetry with the getOptions() method.
259+
*/
236260
return new HashSet<>(optionGroups.values());
237261
}
238262

@@ -250,7 +274,7 @@ public Collection<Option> getOptions() {
250274
*
251275
* @return read-only List of required options
252276
*/
253-
public List getRequiredOptions() {
277+
public List<?> getRequiredOptions() {
254278
return Collections.unmodifiableList(requiredOpts);
255279
}
256280

src/test/java/org/apache/commons/cli/OptionsTest.java

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ Licensed to the Apache Software Foundation (ASF) under one or more
2121
import static org.junit.Assert.assertNotNull;
2222
import static org.junit.Assert.assertTrue;
2323
import static org.junit.Assert.fail;
24+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
25+
import static org.junit.jupiter.api.Assertions.assertThrows;
2426

2527
import java.util.ArrayList;
28+
import java.util.Arrays;
2629
import java.util.Collection;
30+
import java.util.HashSet;
31+
import java.util.List;
32+
import java.util.Set;
2733

2834
import org.junit.Test;
2935

@@ -78,6 +84,93 @@ public void testGetOptionsGroups() {
7884
assertEquals(2, options.getOptionGroups().size());
7985
}
8086

87+
@Test
88+
public void testAddOptions() {
89+
final Options options = new Options();
90+
91+
final OptionGroup group1 = new OptionGroup();
92+
group1.addOption(Option.builder("a").build());
93+
group1.addOption(Option.builder("b").build());
94+
95+
options.addOptionGroup(group1);
96+
97+
options.addOption(Option.builder("X").build());
98+
options.addOption(Option.builder("y").build());
99+
100+
final Options underTest = new Options();
101+
underTest.addOptions(options);
102+
103+
assertEquals(options.getOptionGroups(), underTest.getOptionGroups());
104+
assertArrayEquals(options.getOptions().toArray(), underTest.getOptions().toArray());
105+
}
106+
107+
@Test
108+
public void testAddOptions2X() {
109+
final Options options = new Options();
110+
111+
final OptionGroup group1 = new OptionGroup();
112+
group1.addOption(Option.builder("a").build());
113+
group1.addOption(Option.builder("b").build());
114+
115+
options.addOptionGroup(group1);
116+
117+
options.addOption(Option.builder("X").build());
118+
options.addOption(Option.builder("y").build());
119+
120+
assertThrows(IllegalArgumentException.class, () -> options.addOptions(options));
121+
}
122+
123+
@Test
124+
public void testAddConflictingOptions() {
125+
final Options options1 = new Options();
126+
final OptionGroup group1 = new OptionGroup();
127+
group1.addOption(Option.builder("a").build());
128+
group1.addOption(Option.builder("b").build());
129+
options1.addOptionGroup(group1);
130+
options1.addOption(Option.builder("x").build());
131+
options1.addOption(Option.builder("y").build());
132+
133+
final Options options2 = new Options();
134+
final OptionGroup group2 = new OptionGroup();
135+
group2.addOption(Option.builder("x").type(Integer.class).build());
136+
group2.addOption(Option.builder("b").type(Integer.class).build());
137+
options2.addOptionGroup(group2);
138+
options2.addOption(Option.builder("c").build());
139+
140+
assertThrows(IllegalArgumentException.class, () -> options1.addOptions(options2));
141+
}
142+
143+
@Test
144+
public void testAddNonConflictingOptions() {
145+
final Options options1 = new Options();
146+
final OptionGroup group1 = new OptionGroup();
147+
group1.addOption(Option.builder("a").build());
148+
group1.addOption(Option.builder("b").build());
149+
options1.addOptionGroup(group1);
150+
options1.addOption(Option.builder("x").build());
151+
options1.addOption(Option.builder("y").build());
152+
153+
final Options options2 = new Options();
154+
final OptionGroup group2 = new OptionGroup();
155+
group2.addOption(Option.builder("c").type(Integer.class).build());
156+
group2.addOption(Option.builder("d").type(Integer.class).build());
157+
options2.addOptionGroup(group2);
158+
options1.addOption(Option.builder("e").build());
159+
options1.addOption(Option.builder("f").build());
160+
161+
Options underTest = new Options();
162+
underTest.addOptions(options1);
163+
underTest.addOptions(options2);
164+
165+
List<OptionGroup> expected = Arrays.asList(group1, group2);
166+
assertTrue(expected.size() == underTest.getOptionGroups().size() && expected.containsAll(underTest.getOptionGroups()));
167+
Set<Option> expectOpt = new HashSet<>();
168+
expectOpt.addAll(options1.getOptions());
169+
expectOpt.addAll(options2.getOptions());
170+
assertEquals(8, expectOpt.size());
171+
assertTrue(expectOpt.size() == underTest.getOptions().size() && expectOpt.containsAll(underTest.getOptions()));
172+
}
173+
81174
@Test
82175
public void testHelpOptions() {
83176
OptionBuilder.withLongOpt("long-only1");

0 commit comments

Comments
 (0)