001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.cli2.option;
018
019import java.io.BufferedReader;
020import java.io.IOException;
021import java.io.PrintWriter;
022import java.io.StringReader;
023import java.io.StringWriter;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.HashSet;
027import java.util.List;
028import java.util.Set;
029
030import org.apache.commons.cli2.CLITestCase;
031import org.apache.commons.cli2.CommandLine;
032import org.apache.commons.cli2.DisplaySetting;
033import org.apache.commons.cli2.Group;
034import org.apache.commons.cli2.OptionException;
035import org.apache.commons.cli2.builder.ArgumentBuilder;
036import org.apache.commons.cli2.builder.DefaultOptionBuilder;
037import org.apache.commons.cli2.builder.GroupBuilder;
038import org.apache.commons.cli2.commandline.Parser;
039import org.apache.commons.cli2.util.HelpFormatter;
040
041
042/**
043 * Test to exercise nested groups developed to demonstrate bug 32533
044 */
045public class NestedGroupTest extends CLITestCase {
046    private static final String[] EXPECTED_USAGE = new String[] {
047            "Usage:                                                                          ",
048            " [-h -k -e|-d -b|-3 -f <file>|-s <string>]                                      ",
049            "encryptionService                                                               ",
050            "  -h (--help)               Print this message                                  ",
051            "  -k (--key)                Encryption key                                      ",
052            "  Action                    Action                                              ",
053            "    -e (--encrypt)          Encrypt input                                       ",
054            "    -d (--decrypt)          Decrypt input                                       ",
055            "  Algorithm                 Encryption Algorithm                                ",
056            "    -b (--blowfish)         Blowfish                                            ",
057            "    -3 (--3DES)             Triple DES                                          ",
058            "  Input                     Input                                               ",
059            "    -f (--file) file        Input file                                          ",
060            "    -s (--string) string    Input string                                        "
061    };
062
063    final static DefaultOptionBuilder obuilder = new DefaultOptionBuilder();
064    final static ArgumentBuilder abuilder = new ArgumentBuilder();
065    final static GroupBuilder gbuilder = new GroupBuilder();
066
067    static Group buildActionGroup() {
068        return gbuilder.withName("Action").withDescription("Action")
069                       .withMinimum(1).withMaximum(1)
070                       .withOption(obuilder.withId(5).withShortName("e")
071                                           .withLongName("encrypt")
072                                           .withDescription("Encrypt input")
073                                           .create())
074                       .withOption(obuilder.withId(6).withShortName("d")
075                                           .withLongName("decrypt")
076                                           .withDescription("Decrypt input")
077                                           .create()).create();
078    }
079
080    static Group buildAlgorithmGroup() {
081        return gbuilder.withName("Algorithm")
082                       .withDescription("Encryption Algorithm").withMaximum(1)
083                       .withOption(obuilder.withId(0).withShortName("b")
084                                           .withLongName("blowfish")
085                                           .withDescription("Blowfish").create())
086                       .withOption(obuilder.withId(1).withShortName("3")
087                                           .withLongName("3DES")
088                                           .withDescription("Triple DES")
089                                           .create()).create();
090    }
091
092    static Group buildInputGroup() {
093        return gbuilder.withName("Input").withDescription("Input").withMinimum(1)
094                       .withMaximum(1)
095                       .withOption(obuilder.withId(2).withShortName("f")
096                                           .withLongName("file")
097                                           .withDescription("Input file")
098                                           .withArgument(abuilder.withName(
099                    "file").withMinimum(1).withMaximum(1).create()).create())
100                       .withOption(obuilder.withId(3).withShortName("s")
101                                           .withLongName("string")
102                                           .withDescription("Input string")
103                                           .withArgument(abuilder.withName(
104                    "string").withMinimum(1).withMaximum(1).create()).create())
105                       .create();
106    }
107
108    static Group buildEncryptionServiceGroup(Group[] nestedGroups) {
109        gbuilder.withName("encryptionService")
110                .withOption(obuilder.withId(4).withShortName("h")
111                                    .withLongName("help")
112                                    .withDescription("Print this message")
113                                    .create()).withOption(obuilder.withShortName(
114                "k").withLongName("key").withDescription("Encryption key")
115                                                                  .create());
116
117        for (int i = 0; i < nestedGroups.length; i++) {
118            gbuilder.withOption(nestedGroups[i]);
119        }
120
121        return gbuilder.create();
122    }
123
124    public void testNestedGroup()
125        throws OptionException {
126        final String[] args = {
127                "-eb",
128                "--file",
129                "/tmp/filename.txt"
130            };
131
132        Group[] nestedGroups = {
133                buildActionGroup(),
134                buildAlgorithmGroup(),
135                buildInputGroup()
136            };
137
138        Parser parser = new Parser();
139        parser.setGroup(buildEncryptionServiceGroup(nestedGroups));
140
141        CommandLine commandLine = parser.parse(args);
142
143        assertTrue("/tmp/filename.txt".equals(commandLine.getValue("-f")));
144        assertTrue(commandLine.hasOption("-e"));
145        assertTrue(commandLine.hasOption("-b"));
146        assertFalse(commandLine.hasOption("-d"));
147    }
148
149    public void testNestedGroupHelp() {
150        checkNestedGroupHelp(new HelpFormatter(), EXPECTED_USAGE);
151    }
152
153    public void testNestedGroupHelpOptional()
154    {
155        HelpFormatter helpFormatter = new HelpFormatter();
156        Set dispOptions = new HashSet(helpFormatter.getFullUsageSettings());
157        dispOptions.add(DisplaySetting.DISPLAY_OPTIONAL_CHILD_GROUP);
158        List expLines = new ArrayList(Arrays.asList(EXPECTED_USAGE));
159        expLines.set(1," [-h -k -e|-d [-b|-3] -f <file>|-s <string>]                                    ");
160        helpFormatter.setFullUsageSettings(dispOptions);
161        checkNestedGroupHelp(helpFormatter, (String[]) expLines
162                .toArray(new String[expLines.size()]));
163    }
164
165    private void checkNestedGroupHelp(HelpFormatter helpFormatter, String[] expected) {
166        Group[] nestedGroups = {
167                buildActionGroup(),
168                buildAlgorithmGroup(),
169                buildInputGroup()
170            };
171        helpFormatter.setGroup(buildEncryptionServiceGroup(nestedGroups));
172
173        final StringWriter out = new StringWriter();
174        helpFormatter.setPrintWriter(new PrintWriter(out));
175
176        try {
177            helpFormatter.print();
178
179            final BufferedReader bufferedReader = new BufferedReader(new StringReader(
180                        out.toString()));
181
182            List actual = new ArrayList(expected.length);
183            String input;
184
185            while ((input = bufferedReader.readLine()) != null) {
186                actual.add(input);
187            }
188
189            // Show they are the same number of lines
190            assertEquals("Help text lines should be " + expected.length,
191                actual.size(), expected.length);
192
193            for (int i = 0; i < expected.length; i++) {
194                if (!expected[i].equals(actual.get(i))) {
195                    for (int x = 0; x < expected.length; i++) {
196                        System.out.println("   " + expected[i]);
197                        System.out.println((expected[i].equals(actual.get(i))
198                            ? "== "
199                            : "!= ") + actual.get(i));
200                    }
201                }
202
203                assertEquals(expected[i], actual.get(i));
204            }
205        }
206        catch (IOException e) {
207            fail(e.getLocalizedMessage());
208        }
209    }
210}