1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.cli;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotEquals;
23 import static org.junit.jupiter.api.Assertions.assertNotSame;
24 import static org.junit.jupiter.api.Assertions.assertNull;
25 import static org.junit.jupiter.api.Assertions.assertThrows;
26 import static org.junit.jupiter.api.Assertions.assertTrue;
27
28 import java.io.ByteArrayInputStream;
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 import java.io.ObjectInputStream;
32 import java.io.ObjectOutputStream;
33
34 import org.junit.jupiter.api.Test;
35
36 public class OptionTest {
37
38 private static final class DefaultOption extends Option {
39 private static final long serialVersionUID = 1L;
40
41 private final String defaultValue;
42
43 DefaultOption(final String opt, final String description, final String defaultValue) throws IllegalArgumentException {
44 super(opt, true, description);
45 this.defaultValue = defaultValue;
46 }
47
48 @Override
49 public String getValue() {
50 return super.getValue() != null ? super.getValue() : defaultValue;
51 }
52 }
53
54 private static final class TestOption extends Option {
55 private static final long serialVersionUID = 1L;
56
57 TestOption(final String opt, final boolean hasArg, final String description) throws IllegalArgumentException {
58 super(opt, hasArg, description);
59 }
60
61 @Override
62 public boolean addValue(final String value) {
63 processValue(value);
64 return true;
65 }
66 }
67
68 private static void checkOption(final Option option, final String opt, final String description, final String longOpt, final int numArgs,
69 final String argName, final boolean required, final boolean optionalArg, final char valueSeparator, final Class<?> cls, final String deprecatedDesc,
70 final Boolean deprecatedForRemoval, final String deprecatedSince) {
71 assertEquals(opt, option.getOpt());
72 assertEquals(description, option.getDescription());
73 assertEquals(longOpt, option.getLongOpt());
74 assertEquals(numArgs, option.getArgs());
75 assertEquals(argName, option.getArgName());
76 assertEquals(required, option.isRequired());
77
78 assertEquals(optionalArg, option.hasOptionalArg());
79 assertEquals(numArgs > 0, option.hasArg());
80 assertEquals(numArgs > 0, option.acceptsArg());
81 assertEquals(valueSeparator, option.getValueSeparator());
82 assertEquals(cls, option.getType());
83 if (deprecatedDesc != null) {
84 assertEquals(deprecatedDesc, option.getDeprecated().getDescription());
85 }
86 if (deprecatedForRemoval != null) {
87 assertEquals(deprecatedForRemoval, option.getDeprecated().isForRemoval());
88 }
89 if (deprecatedSince != null) {
90 assertEquals(deprecatedSince, option.getDeprecated().getSince());
91 }
92 }
93
94 private Option roundTrip(final Option o) throws IOException, ClassNotFoundException {
95 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
96 final ObjectOutputStream oos = new ObjectOutputStream(baos);
97 oos.writeObject(o);
98 final ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
99 final ObjectInputStream ois = new ObjectInputStream(bais);
100 return (Option) ois.readObject();
101 }
102
103 @Test
104 public void testAddValue() {
105 final Option option = new Option("f", null);
106 assertThrows(UnsupportedOperationException.class, () -> option.addValue(""));
107 assertThrows(IllegalArgumentException.class, () -> option.processValue(""));
108 }
109
110 @Test
111 public void testBuilderEmpty() {
112 assertThrows(IllegalArgumentException.class, () -> Option.builder().build());
113 }
114
115 @Test
116 public void testBuilderInsufficientParams1() {
117 assertThrows(IllegalArgumentException.class, () -> Option.builder().desc("desc").build());
118 }
119
120 @Test
121 public void testBuilderInsufficientParams2() {
122 assertThrows(IllegalArgumentException.class, () -> Option.builder(null).desc("desc").build());
123 }
124
125 @Test
126 public void testBuilderInvalidOptionName0() {
127 assertThrows(IllegalArgumentException.class, () -> Option.builder().option(null).build());
128 assertThrows(IllegalArgumentException.class, () -> Option.builder().option(""));
129 assertThrows(IllegalArgumentException.class, () -> Option.builder().option(" "));
130 }
131
132 @Test
133 public void testBuilderInvalidOptionName1() {
134 assertThrows(IllegalArgumentException.class, () -> Option.builder().option("invalid?"));
135 }
136
137 @Test
138 public void testBuilderInvalidOptionName2() {
139 assertThrows(IllegalArgumentException.class, () -> Option.builder().option("invalid@"));
140 }
141
142 @Test
143 public void testBuilderInvalidOptionName3() {
144 assertThrows(IllegalArgumentException.class, () -> Option.builder("invalid?"));
145 }
146
147 @Test
148 public void testBuilderInvalidOptionName4() {
149 assertThrows(IllegalArgumentException.class, () -> Option.builder("invalid@"));
150 }
151
152 @Test
153 public void testBuilderMethods() {
154 final char defaultSeparator = (char) 0;
155
156 checkOption(Option.builder("a").desc("desc").build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, String.class, null,
157 null, null);
158 checkOption(Option.builder("a").desc("desc").build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, String.class, null,
159 null, null);
160 checkOption(Option.builder("a").desc("desc").longOpt("aaa").build(), "a", "desc", "aaa", Option.UNINITIALIZED, null, false, false, defaultSeparator,
161 String.class, null, null, null);
162 checkOption(Option.builder("a").desc("desc").hasArg(true).build(), "a", "desc", null, 1, null, false, false, defaultSeparator, String.class, null, null,
163 null);
164 checkOption(Option.builder("a").desc("desc").hasArg(false).build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
165 String.class, null, null, null);
166 checkOption(Option.builder("a").desc("desc").hasArg(true).build(), "a", "desc", null, 1, null, false, false, defaultSeparator, String.class, null, null,
167 null);
168 checkOption(Option.builder("a").desc("desc").numberOfArgs(3).build(), "a", "desc", null, 3, null, false, false, defaultSeparator, String.class, null,
169 null, null);
170 checkOption(Option.builder("a").desc("desc").required(true).build(), "a", "desc", null, Option.UNINITIALIZED, null, true, false, defaultSeparator,
171 String.class, null, null, null);
172 checkOption(Option.builder("a").desc("desc").required(false).build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
173 String.class, null, null, null);
174
175 checkOption(Option.builder("a").desc("desc").argName("arg1").build(), "a", "desc", null, Option.UNINITIALIZED, "arg1", false, false, defaultSeparator,
176 String.class, null, null, null);
177 checkOption(Option.builder("a").desc("desc").optionalArg(false).build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
178 String.class, null, null, null);
179 checkOption(Option.builder("a").desc("desc").optionalArg(true).build(), "a", "desc", null, 1, null, false, true, defaultSeparator, String.class, null,
180 null, null);
181 checkOption(Option.builder("a").desc("desc").valueSeparator(':').build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, ':',
182 String.class, null, null, null);
183 checkOption(Option.builder("a").desc("desc").type(Integer.class).build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
184 Integer.class, null, null, null);
185 checkOption(Option.builder("a").desc("desc").type(null).build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
186 String.class, null, null, null);
187 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).build(), "a", "desc", null, Option.UNINITIALIZED, null, false, false,
188 defaultSeparator, Integer.class, null, null, null);
189
190 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).deprecated().build(), "a", "desc", null, Option.UNINITIALIZED, null, false,
191 false, defaultSeparator, Integer.class, "", false, "");
192 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).deprecated(DeprecatedAttributes.builder().get()).build(), "a", "desc", null,
193 Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "", false, "");
194 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).deprecated(DeprecatedAttributes.builder().setDescription("X").get()).build(),
195 "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "X", false, "");
196 checkOption(
197 Option.builder().option("a").desc("desc").type(Integer.class)
198 .deprecated(DeprecatedAttributes.builder().setDescription("X").setForRemoval(true).get()).build(),
199 "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "X", true, "");
200 checkOption(
201 Option.builder().option("a").desc("desc").type(Integer.class)
202 .deprecated(DeprecatedAttributes.builder().setDescription("X").setForRemoval(true).setSince("2.0").get()).build(),
203 "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "X", true, "2.0");
204 }
205
206 @Test
207 public void testClear() {
208 final TestOption option = new TestOption("x", true, "");
209 assertEquals(0, option.getValuesList().size());
210 option.addValue("a");
211 assertEquals(1, option.getValuesList().size());
212 option.clearValues();
213 assertEquals(0, option.getValuesList().size());
214 }
215
216
217 @Test
218 public void testClone() {
219 final TestOption a = new TestOption("a", true, "");
220 final TestOption b = (TestOption) a.clone();
221 assertEquals(a, b);
222 assertNotSame(a, b);
223 a.setDescription("a");
224 assertEquals("", b.getDescription());
225 b.setArgs(2);
226 b.addValue("b1");
227 b.addValue("b2");
228 assertEquals(1, a.getArgs());
229 assertEquals(0, a.getValuesList().size());
230 assertEquals(2, b.getValues().length);
231 }
232
233 @Test
234 public void testEquals() {
235 final Option option1a = new Option("1", null);
236 final Option option1b = new Option("1", null);
237 final Option option2 = new Option("2", null);
238 assertEquals(option1a, option1a);
239 assertEquals(option1a, option1b);
240 assertEquals(option1b, option1a);
241 assertNotEquals(option1a, option2);
242 assertNotEquals(option1b, option2);
243 assertNotEquals(option2, option1a);
244 assertNotEquals(option2, "");
245 }
246
247 @Test
248 public void testGetValue() {
249 final Option option = new Option("f", null);
250 option.setArgs(Option.UNLIMITED_VALUES);
251
252 assertEquals("default", option.getValue("default"));
253 assertNull(option.getValue(0));
254
255 option.processValue("foo");
256
257 assertEquals("foo", option.getValue());
258 assertEquals("foo", option.getValue(0));
259 assertEquals("foo", option.getValue("default"));
260 }
261
262 @Test
263 public void testHasArgName() {
264 final Option option = new Option("f", null);
265
266 option.setArgName(null);
267 assertFalse(option.hasArgName());
268
269 option.setArgName("");
270 assertFalse(option.hasArgName());
271
272 option.setArgName("file");
273 assertTrue(option.hasArgName());
274 }
275
276 @Test
277 public void testHasArgs() {
278 final Option option = new Option("f", null);
279
280 option.setArgs(0);
281 assertFalse(option.hasArgs());
282
283 option.setArgs(1);
284 assertFalse(option.hasArgs());
285
286 option.setArgs(10);
287 assertTrue(option.hasArgs());
288
289 option.setArgs(Option.UNLIMITED_VALUES);
290 assertTrue(option.hasArgs());
291
292 option.setArgs(Option.UNINITIALIZED);
293 assertFalse(option.hasArgs());
294 }
295
296 @Test
297 public void testHashCode() {
298 assertNotEquals(Option.builder("test").build().hashCode(), Option.builder("test2").build().hashCode());
299 assertNotEquals(Option.builder("test").build().hashCode(), Option.builder().longOpt("test").build().hashCode());
300 assertNotEquals(Option.builder("test").build().hashCode(), Option.builder("test").longOpt("long test").build().hashCode());
301 }
302
303 @Test
304 public void testSerialization() throws IOException, ClassNotFoundException {
305 final Option option = Option.builder("o").type(TypeHandlerTest.Instantiable.class).build();
306 assertEquals(Converter.DEFAULT, option.getConverter());
307 Option roundtrip = roundTrip(option);
308 assertEquals(Converter.DEFAULT, roundtrip.getConverter());
309
310
311 option.setConverter(Converter.DATE);
312 roundtrip = roundTrip(option);
313 assertEquals(Converter.DEFAULT, roundtrip.getConverter());
314
315
316
317 assertEquals(Converter.DATE, option.getConverter());
318 roundtrip = roundTrip(option);
319 assertEquals(Converter.DEFAULT, roundtrip.getConverter());
320 }
321
322 @Test
323 public void testSubclass() {
324 final Option option = new DefaultOption("f", "file", "myfile.txt");
325 final Option clone = (Option) option.clone();
326 assertEquals("myfile.txt", clone.getValue());
327 assertEquals(DefaultOption.class, clone.getClass());
328 }
329
330 @Test
331 public void testTypeClass() {
332 final Option option = new Option("f", null);
333 assertEquals(String.class, option.getType());
334 option.setType(CharSequence.class);
335 assertEquals(CharSequence.class, option.getType());
336 }
337
338 @Test
339 public void testTypeObject() {
340 final Option option = new Option("f", null);
341 assertEquals(String.class, option.getType());
342 @SuppressWarnings("cast")
343 final Object type = CharSequence.class;
344 option.setType(type);
345 assertEquals(CharSequence.class, option.getType());
346 }
347 }