View Javadoc
1   /*
2    *    Copyright 2009-2026 the original author or authors.
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    *       https://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 jargs.gnu;
17  
18  import static org.junit.jupiter.api.Assertions.assertEquals;
19  import static org.junit.jupiter.api.Assertions.assertNotNull;
20  import static org.junit.jupiter.api.Assertions.assertThrows;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  
23  import java.util.List;
24  import java.util.Locale;
25  
26  import org.junit.jupiter.api.Test;
27  
28  class CmdLineParserTest {
29  
30      @Test
31      void testParseShortAndLongOptionsWithValues() throws Exception {
32          CmdLineParser parser = new CmdLineParser();
33          CmdLineParser.Option verbose = parser.addBooleanOption('v', "verbose");
34          CmdLineParser.Option count = parser.addIntegerOption('c', "count");
35          CmdLineParser.Option ratio = parser.addDoubleOption("ratio");
36          CmdLineParser.Option name = parser.addStringOption('n', "name");
37  
38          parser.parse(new String[] { "-v", "-c", "7", "--ratio=1.5", "--name", "sample" }, Locale.US);
39  
40          assertEquals(Boolean.TRUE, parser.getOptionValue(verbose));
41          assertEquals(7, parser.getOptionValue(count));
42          assertEquals(1.5d, (Double) parser.getOptionValue(ratio), 0.0001d);
43          assertEquals("sample", parser.getOptionValue(name));
44      }
45  
46      @Test
47      void testParseCombinedFlagsAndMultipleOccurrences() throws Exception {
48          CmdLineParser parser = new CmdLineParser();
49          CmdLineParser.Option alpha = parser.addBooleanOption('a', "alpha");
50          CmdLineParser.Option beta = parser.addBooleanOption('b', "beta");
51          CmdLineParser.Option include = parser.addStringOption('i', "include");
52  
53          parser.parse(new String[] { "-ab", "-i", "first", "--include=second" });
54  
55          assertEquals(Boolean.TRUE, parser.getOptionValue(alpha));
56          assertEquals(Boolean.TRUE, parser.getOptionValue(beta));
57          assertEquals(List.of("first", "second"), parser.getOptionValues(include));
58      }
59  
60      @Test
61      void testUnknownOptionAndSuboptionAreRejected() {
62          CmdLineParser parser = new CmdLineParser();
63          parser.addBooleanOption('a', "alpha");
64  
65          CmdLineParser.UnknownOptionException unknownOption = assertThrows(CmdLineParser.UnknownOptionException.class,
66                  () -> parser.parse(new String[] { "--unknown" }));
67          assertEquals("--unknown", unknownOption.getOptionName());
68  
69          CmdLineParser.UnknownSuboptionException unknownSuboption = assertThrows(
70                  CmdLineParser.UnknownSuboptionException.class, () -> parser.parse(new String[] { "-az" }));
71          assertEquals('z', unknownSuboption.getSuboption());
72          assertEquals("-az", unknownSuboption.getOptionName());
73      }
74  
75      @Test
76      void testNotFlagAndIllegalValueAreRejected() {
77          CmdLineParser parser = new CmdLineParser();
78          parser.addBooleanOption('a', "alpha");
79          parser.addStringOption('c', "config");
80          CmdLineParser.Option count = parser.addIntegerOption('n', "num");
81  
82          CmdLineParser.NotFlagException notFlag = assertThrows(CmdLineParser.NotFlagException.class,
83                  () -> parser.parse(new String[] { "-ac" }));
84          assertEquals('c', notFlag.getOptionChar());
85  
86          CmdLineParser.IllegalOptionValueException invalidValue = assertThrows(
87                  CmdLineParser.IllegalOptionValueException.class,
88                  () -> parser.parse(new String[] { "-n", "not-a-number" }));
89          assertEquals(count, invalidValue.getOption());
90          assertEquals("not-a-number", invalidValue.getValue());
91      }
92  
93      @Test
94      void testOptionConstructorsAndBooleanLongOnlyOption() throws Exception {
95          CmdLineParser parser = new CmdLineParser();
96          CmdLineParser.Option dryRun = parser.addBooleanOption("dry-run");
97          parser.parse(new String[] { "--dry-run" });
98  
99          assertTrue((Boolean) parser.getOptionValue(dryRun));
100 
101         IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
102                 () -> new CmdLineParser.Option.StringOption((String) null));
103         assertEquals("Null longForm not allowed", exception.getMessage());
104     }
105 
106     @Test
107     void testLongOptionShortAndLongForm() throws Exception {
108         CmdLineParser parser = new CmdLineParser();
109         CmdLineParser.Option sizeShort = parser.addLongOption('s', "size");
110         CmdLineParser.Option sizeLong = parser.addLongOption("max-size");
111 
112         parser.parse(new String[] { "-s", "100", "--max-size", "200" });
113 
114         assertEquals(100L, parser.getOptionValue(sizeShort));
115         assertEquals(200L, parser.getOptionValue(sizeLong));
116     }
117 
118     @Test
119     void testLongOptionIllegalValue() {
120         CmdLineParser parser = new CmdLineParser();
121         CmdLineParser.Option count = parser.addLongOption('n', "num");
122 
123         CmdLineParser.IllegalOptionValueException ex = assertThrows(CmdLineParser.IllegalOptionValueException.class,
124                 () -> parser.parse(new String[] { "-n", "not-a-long" }));
125         assertEquals(count, ex.getOption());
126         assertEquals("not-a-long", ex.getValue());
127     }
128 
129     @Test
130     void testDoubleDashEndsOptionParsing() throws Exception {
131         CmdLineParser parser = new CmdLineParser();
132         CmdLineParser.Option flag = parser.addBooleanOption('f', "flag");
133 
134         // after "--", "--flag" is treated as a plain argument, not an option
135         parser.parse(new String[] { "--", "--flag", "extra-arg" });
136 
137         // the flag must NOT have been set (it was not consumed as an option)
138         assertEquals(Boolean.FALSE, parser.getOptionValue(flag, Boolean.FALSE));
139         // args after -- are available as remaining args
140         assertTrue(parser.getRemainingArgs().contains("--flag"));
141         assertTrue(parser.getRemainingArgs().contains("extra-arg"));
142     }
143 
144     @Test
145     void testGetOptionValuesReturnsAllOccurrences() throws Exception {
146         CmdLineParser parser = new CmdLineParser();
147         CmdLineParser.Option include = parser.addStringOption('i', "include");
148 
149         parser.parse(new String[] { "-i", "one", "-i", "two", "--include", "three" });
150 
151         assertEquals(java.util.List.of("one", "two", "three"), parser.getOptionValues(include));
152     }
153 
154     @Test
155     void testExceptionMessageAndOptionAccessors() throws Exception {
156         CmdLineParser parser = new CmdLineParser();
157 
158         CmdLineParser.UnknownOptionException uoe = assertThrows(CmdLineParser.UnknownOptionException.class,
159                 () -> parser.parse(new String[] { "--bogus" }));
160         assertNotNull(uoe.getMessage());
161         assertEquals("--bogus", uoe.getOptionName());
162 
163         // IllegalOptionValueException getMessage
164         parser.addIntegerOption('n', "num");
165         CmdLineParser.IllegalOptionValueException ive = assertThrows(CmdLineParser.IllegalOptionValueException.class,
166                 () -> parser.parse(new String[] { "-n", "NaN" }));
167         assertNotNull(ive.getMessage());
168     }
169 }