Skip to content

Commit f104dd0

Browse files
author
Oliver Heger
committed
CLI-123: Groups are now added to the command line if any of their child options are found. This makes it possible to test for the presence of a group and also validate minimum and maximum constraints when child groups are involved.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/cli/trunk@679530 13f79535-47bb-0310-9956-ffa450edef68
1 parent eed2561 commit f104dd0

6 files changed

Lines changed: 168 additions & 1 deletion

File tree

src/java/org/apache/commons/cli2/Option.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,25 @@ void appendUsage(
194194
* @return true iff the CommandLine will be invalid without this Option
195195
*/
196196
boolean isRequired();
197+
198+
/**
199+
* Returns the parent of this option. Options can be organized in a
200+
* hierarchical manner if they are added to groups. This method can be used
201+
* for obtaining the parent option of this option. The result may be
202+
* <b>null</b> if this option does not have a parent.
203+
*
204+
* @return the parent of this option
205+
*/
206+
Option getParent();
207+
208+
/**
209+
* Sets the parent of this option. This method is called when the option is
210+
* added to a group. Storing the parent of an option makes it possible to
211+
* keep track of hierarchical relations between options. For instance, if an
212+
* option is identified while parsing a command line, the group this option
213+
* belongs to can also be added to the command line.
214+
*
215+
* @param parent the parent option
216+
*/
217+
void setParent(Option parent);
197218
}

src/java/org/apache/commons/cli2/commandline/WriteableCommandLineImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ public void addOption(Option option) {
6969
for (Iterator i = option.getTriggers().iterator(); i.hasNext();) {
7070
nameToOption.put(i.next(), option);
7171
}
72+
73+
// ensure that all parent options are also added
74+
Option parent = option.getParent();
75+
while (parent != null && !options.contains(parent)) {
76+
options.add(parent);
77+
parent = parent.getParent();
78+
}
7279
}
7380

7481
public void addValue(final Option option,

src/java/org/apache/commons/cli2/option/GroupImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public GroupImpl(final List options,
8989
// process the options
9090
for (final Iterator i = options.iterator(); i.hasNext();) {
9191
final Option option = (Option) i.next();
92+
option.setParent(this);
9293

9394
if (option instanceof Argument) {
9495
i.remove();

src/java/org/apache/commons/cli2/option/OptionImpl.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
public abstract class OptionImpl implements Option {
3434
private final int id;
3535
private final boolean required;
36+
private Option parent;
3637

3738
/**
3839
* Creates an OptionImpl with the specified id
@@ -95,7 +96,9 @@ private boolean equals(Object left,
9596

9697
public int hashCode() {
9798
int hashCode = getId();
98-
hashCode = (hashCode * 37) + getPreferredName().hashCode();
99+
if (getPreferredName() != null) {
100+
hashCode = (hashCode * 37) + getPreferredName().hashCode();
101+
}
99102

100103
if (getDescription() != null) {
101104
hashCode = (hashCode * 37) + getDescription().hashCode();
@@ -123,6 +126,14 @@ public void defaults(final WriteableCommandLine commandLine) {
123126
// nothing to do normally
124127
}
125128

129+
public Option getParent() {
130+
return parent;
131+
}
132+
133+
public void setParent(Option parent) {
134+
this.parent = parent;
135+
}
136+
126137
protected void checkPrefixes(final Set prefixes) {
127138
// nothing to do if empty prefix list
128139
if (prefixes.isEmpty()) {

src/test/org/apache/commons/cli2/CommandLineTestCase.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ public final void testGetOptions_Order()
433433
final Iterator i = cl.getOptions().iterator();
434434

435435
assertSame(login, i.next());
436+
assertSame(group, i.next());
436437
assertSame(help, i.next());
437438
assertSame(targets, i.next());
438439
assertSame(targets, i.next());
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.cli2.bug;
18+
19+
import junit.framework.TestCase;
20+
21+
import org.apache.commons.cli2.CommandLine;
22+
import org.apache.commons.cli2.Group;
23+
import org.apache.commons.cli2.Option;
24+
import org.apache.commons.cli2.OptionException;
25+
import org.apache.commons.cli2.builder.ArgumentBuilder;
26+
import org.apache.commons.cli2.builder.DefaultOptionBuilder;
27+
import org.apache.commons.cli2.builder.GroupBuilder;
28+
import org.apache.commons.cli2.commandline.Parser;
29+
30+
/**
31+
* Group options are not added to the command line when child elements are
32+
* detected. This causes the validation of maximum and minimum to fail.
33+
*
34+
* @author Oliver Heger
35+
* @version $Id$
36+
*/
37+
public class BugCLI123Test extends TestCase {
38+
/** An option of the parent group. */
39+
private Option parentOption;
40+
41+
/** An option of the child group. */
42+
private Option childOption1;
43+
44+
/** Another option of the child group. */
45+
private Option childOption2;
46+
47+
/** The parent group. */
48+
private Group parentGroup;
49+
50+
/** The child group. */
51+
private Group childGroup;
52+
53+
/** The parser. */
54+
private Parser parser;
55+
56+
protected void setUp() throws Exception {
57+
super.setUp();
58+
final DefaultOptionBuilder obuilder = new DefaultOptionBuilder();
59+
final ArgumentBuilder abuilder = new ArgumentBuilder();
60+
final GroupBuilder gbuilder = new GroupBuilder();
61+
parentOption = obuilder.withLongName("parent").withShortName("p")
62+
.withArgument(abuilder.withName("name").create()).create();
63+
childOption1 = obuilder.withLongName("child").withShortName("c")
64+
.withArgument(abuilder.withName("c").create()).create();
65+
childOption2 = obuilder.withLongName("sub").withShortName("s")
66+
.withArgument(abuilder.withName("s").create()).create();
67+
childGroup = gbuilder.withName("childOptions").withMinimum(0)
68+
.withMaximum(2).withOption(childOption1).withOption(
69+
childOption2).create();
70+
parentGroup = gbuilder.withName("parentOptions").withMinimum(1)
71+
.withMaximum(1).withOption(parentOption).withOption(childGroup)
72+
.create();
73+
parser = new Parser();
74+
parser.setGroup(parentGroup);
75+
}
76+
77+
/**
78+
* A single option of the child group is specified.
79+
*/
80+
public void testSingleChildOption() throws OptionException {
81+
CommandLine cl = parser.parse(new String[] { "--child", "test" });
82+
assertTrue("Child option not found", cl.hasOption(childOption1));
83+
assertEquals("Wrong value for option", "test", cl
84+
.getValue(childOption1));
85+
assertTrue("Child group not found", cl.hasOption(childGroup));
86+
}
87+
88+
/**
89+
* Two options of the child group are specified.
90+
*/
91+
public void testMultipleChildOptions() throws OptionException {
92+
CommandLine cl = parser.parse(new String[] { "--child", "test",
93+
"--sub", "anotherTest" });
94+
assertTrue("Child option not found", cl.hasOption(childOption1));
95+
assertEquals("Wrong value for option", "test", cl
96+
.getValue(childOption1));
97+
assertTrue("Sub option not found", cl.hasOption(childOption2));
98+
assertEquals("Wrong value for sub option", "anotherTest", cl
99+
.getValue(childOption2));
100+
assertTrue("Child group not found", cl.hasOption(childGroup));
101+
}
102+
103+
/**
104+
* The option defined for the parent group is specified.
105+
*/
106+
public void testSingleParentOption() throws OptionException {
107+
CommandLine cl = parser.parse(new String[] { "--parent", "yes" });
108+
assertTrue("Parent option not found", cl.hasOption(parentOption));
109+
assertEquals("Wrong value for option", "yes", cl.getValue(parentOption));
110+
assertFalse("Found child group", cl.hasOption(childGroup));
111+
}
112+
113+
/**
114+
* The parent option and an option of the child group is specified. This
115+
* should cause an exception.
116+
*/
117+
public void testParentOptionAndChildOption() throws OptionException {
118+
try {
119+
parser.parse(new String[] { "--parent", "error", "--child",
120+
"exception" });
121+
fail("Maximum restriction for parent not verified!");
122+
} catch (OptionException oex) {
123+
// ok
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)