Skip to content

Commit 249ba6c

Browse files
author
Robert James Oxspring
committed
Nested group handling improved
Applied the test from the bug and implemented an alternate fix PR: 32533 Submitted by: David Morris git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/cli/trunk@155218 13f79535-47bb-0310-9956-ffa450edef68
1 parent f24d0ef commit 249ba6c

3 files changed

Lines changed: 256 additions & 1 deletion

File tree

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,21 @@ public void process(
178178
// narrow the search
179179
final Collection values = optionMap.tailMap(arg).values();
180180

181-
for (Iterator i = values.iterator(); i.hasNext();) {
181+
boolean foundMemberOption = false;
182+
for (Iterator i = values.iterator(); i.hasNext() && !foundMemberOption;) {
182183
final Option option = (Option) i.next();
183184

184185
if (option.canProcess(arg)) {
186+
foundMemberOption = true;
185187
arguments.previous();
186188
option.process(commandLine, arguments);
187189
}
188190
}
191+
// back track and abort this group if necessary
192+
if(!foundMemberOption) {
193+
arguments.previous();
194+
return;
195+
}
189196
} // [END argument may be anonymous
190197

191198
// [START argument is NOT anonymous
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2004 The Apache Software Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.commons.cli2.bug;
17+
18+
import org.apache.commons.cli2.Argument;
19+
import org.apache.commons.cli2.Group;
20+
import org.apache.commons.cli2.Option;
21+
import org.apache.commons.cli2.OptionException;
22+
import org.apache.commons.cli2.builder.ArgumentBuilder;
23+
import org.apache.commons.cli2.builder.DefaultOptionBuilder;
24+
import org.apache.commons.cli2.builder.GroupBuilder;
25+
import org.apache.commons.cli2.commandline.Parser;
26+
27+
import junit.framework.TestCase;
28+
29+
/**
30+
* @author roxspring
31+
*/
32+
public class Bug32533Test extends TestCase {
33+
34+
public void testBlah() throws OptionException {
35+
36+
Option a1 = new DefaultOptionBuilder().withLongName("a1").create();
37+
Option b1 = new DefaultOptionBuilder().withLongName("b1").create();
38+
Option c1 = new DefaultOptionBuilder().withLongName("c1").create();
39+
40+
Group b = new GroupBuilder().withOption(b1).create();
41+
Group c = new GroupBuilder().withOption(c1).create();
42+
Group a = new GroupBuilder().withOption(a1).withOption(b).withOption(c).create();
43+
44+
Parser parser = new Parser();
45+
parser.setGroup(a);
46+
parser.parse(new String[]{"--a1","--b1"});
47+
}
48+
49+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/**
2+
* Copyright 2003-2004 The Apache Software Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.commons.cli2.option;
17+
18+
import org.apache.commons.cli2.CLITestCase;
19+
import org.apache.commons.cli2.CommandLine;
20+
import org.apache.commons.cli2.Group;
21+
import org.apache.commons.cli2.OptionException;
22+
import org.apache.commons.cli2.builder.ArgumentBuilder;
23+
import org.apache.commons.cli2.builder.DefaultOptionBuilder;
24+
import org.apache.commons.cli2.builder.GroupBuilder;
25+
import org.apache.commons.cli2.commandline.Parser;
26+
import org.apache.commons.cli2.util.HelpFormatter;
27+
28+
import java.io.BufferedReader;
29+
import java.io.IOException;
30+
import java.io.PrintWriter;
31+
import java.io.StringReader;
32+
import java.io.StringWriter;
33+
34+
import java.util.ArrayList;
35+
import java.util.List;
36+
37+
38+
/**
39+
* Test to exercise nested groups developed to demonstrate bug 32533
40+
*/
41+
public class NestedGroupTest extends CLITestCase {
42+
final static DefaultOptionBuilder obuilder = new DefaultOptionBuilder();
43+
final static ArgumentBuilder abuilder = new ArgumentBuilder();
44+
final static GroupBuilder gbuilder = new GroupBuilder();
45+
46+
static Group buildActionGroup() {
47+
return gbuilder.withName("Action").withDescription("Action")
48+
.withMinimum(1).withMaximum(1)
49+
.withOption(obuilder.withId(5).withShortName("e")
50+
.withLongName("encrypt")
51+
.withDescription("Encrypt input")
52+
.create())
53+
.withOption(obuilder.withId(6).withShortName("d")
54+
.withLongName("decrypt")
55+
.withDescription("Decrypt input")
56+
.create()).create();
57+
}
58+
59+
static Group buildAlgorithmGroup() {
60+
return gbuilder.withName("Algorithm")
61+
.withDescription("Encryption Algorithm").withMaximum(1)
62+
.withOption(obuilder.withId(0).withShortName("b")
63+
.withLongName("blowfish")
64+
.withDescription("Blowfish").create())
65+
.withOption(obuilder.withId(1).withShortName("3")
66+
.withLongName("3DES")
67+
.withDescription("Triple DES")
68+
.create()).create();
69+
}
70+
71+
static Group buildInputGroup() {
72+
return gbuilder.withName("Input").withDescription("Input").withMinimum(1)
73+
.withMaximum(1)
74+
.withOption(obuilder.withId(2).withShortName("f")
75+
.withLongName("file")
76+
.withDescription("Input file")
77+
.withArgument(abuilder.withName(
78+
"file").withMinimum(1).withMaximum(1).create()).create())
79+
.withOption(obuilder.withId(3).withShortName("s")
80+
.withLongName("string")
81+
.withDescription("Input string")
82+
.withArgument(abuilder.withName(
83+
"string").withMinimum(1).withMaximum(1).create()).create())
84+
.create();
85+
}
86+
87+
static Group buildEncryptionServiceGroup(Group[] nestedGroups) {
88+
gbuilder.withName("encryptionService")
89+
.withOption(obuilder.withId(4).withShortName("h")
90+
.withLongName("help")
91+
.withDescription("Print this message")
92+
.create()).withOption(obuilder.withShortName(
93+
"k").withLongName("key").withDescription("Encryption key")
94+
.create());
95+
96+
for (int i = 0; i < nestedGroups.length; i++) {
97+
gbuilder.withOption(nestedGroups[i]);
98+
}
99+
100+
return gbuilder.create();
101+
}
102+
103+
public void testNestedGroup()
104+
throws OptionException {
105+
final String[] args = {
106+
"-eb",
107+
"--file",
108+
"/tmp/filename.txt"
109+
};
110+
111+
Group[] nestedGroups = {
112+
buildActionGroup(),
113+
buildAlgorithmGroup(),
114+
buildInputGroup()
115+
};
116+
117+
Parser parser = new Parser();
118+
parser.setGroup(buildEncryptionServiceGroup(nestedGroups));
119+
120+
CommandLine commandLine = parser.parse(args);
121+
122+
assertTrue("/tmp/filename.txt".equals(
123+
(String) commandLine.getValue("-f")));
124+
assertTrue(commandLine.hasOption("-e"));
125+
assertTrue(commandLine.hasOption("-b"));
126+
assertFalse(commandLine.hasOption("-d"));
127+
}
128+
129+
public void testNestedGroupHelp()
130+
throws OptionException {
131+
final String[] args = {
132+
"-eb",
133+
"--file",
134+
"/tmp/filename.txt"
135+
};
136+
137+
Group[] nestedGroups = {
138+
buildActionGroup(),
139+
buildAlgorithmGroup(),
140+
buildInputGroup()
141+
};
142+
143+
HelpFormatter helpFormatter = new HelpFormatter();
144+
helpFormatter.setGroup(buildEncryptionServiceGroup(nestedGroups));
145+
146+
final StringWriter out = new StringWriter();
147+
helpFormatter.setPrintWriter(new PrintWriter(out));
148+
149+
try {
150+
helpFormatter.print();
151+
152+
final BufferedReader bufferedReader = new BufferedReader(new StringReader(
153+
out.toString()));
154+
final String[] expected = new String[] {
155+
"Usage: ",
156+
" [-h -k -e|-d -b|-3 -f <file>|-s <string>] ",
157+
"encryptionService ",
158+
" -h (--help) Print this message ",
159+
" -k (--key) Encryption key ",
160+
" Action Action ",
161+
" -e (--encrypt) Encrypt input ",
162+
" -d (--decrypt) Decrypt input ",
163+
" Algorithm Encryption Algorithm ",
164+
" -b (--blowfish) Blowfish ",
165+
" -3 (--3DES) Triple DES ",
166+
" Input Input ",
167+
" -f (--file) file Input file ",
168+
" -s (--string) string Input string "
169+
};
170+
171+
List actual = new ArrayList(expected.length);
172+
String input;
173+
174+
while ((input = bufferedReader.readLine()) != null) {
175+
actual.add(input);
176+
}
177+
178+
// Show they are the same number of lines
179+
assertEquals("Help text lines should be " + expected.length,
180+
actual.size(), expected.length);
181+
182+
for (int i = 0; i < expected.length; i++) {
183+
if (!expected[i].equals(actual.get(i))) {
184+
for (int x = 0; x < expected.length; i++) {
185+
System.out.println(" " + expected[i]);
186+
System.out.println((expected[i].equals(actual.get(i))
187+
? "== "
188+
: "!= ") + actual.get(i));
189+
}
190+
}
191+
192+
assertEquals(expected[i], actual.get(i));
193+
}
194+
}
195+
catch (IOException e) {
196+
fail(e.getLocalizedMessage());
197+
}
198+
}
199+
}

0 commit comments

Comments
 (0)