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 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 void testAddValue() {
105 final Option option = new Option("f", null);
106 assertThrows(UnsupportedOperationException.class, () -> option.addValue(""));
107 assertThrows(IllegalStateException.class, () -> option.processValue(""));
108 }
109
110 @Test
111 void testBuilderDeprecatedBuildEmpty() {
112 assertThrows(IllegalStateException.class, () -> Option.builder().build());
113 }
114
115 @Test
116 void testBuilderEmpty() {
117 assertThrows(IllegalStateException.class, () -> Option.builder().get());
118 }
119
120 @Test
121 void testBuilderInsufficientParams1() {
122 assertThrows(IllegalStateException.class, () -> Option.builder().desc("desc").get());
123 }
124
125 @Test
126 void testBuilderInsufficientParams2() {
127 assertThrows(IllegalStateException.class, () -> Option.builder(null).desc("desc").get());
128 }
129
130 @Test
131 void testBuilderInvalidOptionName0() {
132 assertThrows(IllegalStateException.class, () -> Option.builder().option(null).get());
133 assertThrows(IllegalArgumentException.class, () -> Option.builder().option(""));
134 assertThrows(IllegalArgumentException.class, () -> Option.builder().option(" "));
135 }
136
137 @Test
138 void testBuilderInvalidOptionName1() {
139 assertThrows(IllegalArgumentException.class, () -> Option.builder().option("invalid?"));
140 }
141
142 @Test
143 void testBuilderInvalidOptionName2() {
144 assertThrows(IllegalArgumentException.class, () -> Option.builder().option("invalid@"));
145 }
146
147 @Test
148 void testBuilderInvalidOptionName3() {
149 assertThrows(IllegalArgumentException.class, () -> Option.builder("invalid?"));
150 }
151
152 @Test
153 void testBuilderInvalidOptionName4() {
154 assertThrows(IllegalArgumentException.class, () -> Option.builder("invalid@"));
155 }
156
157 @Test
158 void testBuilderMethods() {
159 final char defaultSeparator = (char) 0;
160
161 checkOption(Option.builder("a").desc("desc").get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, String.class, null,
162 null, null);
163 checkOption(Option.builder("a").desc("desc").get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, String.class, null,
164 null, null);
165 checkOption(Option.builder("a").desc("desc").longOpt("aaa").get(), "a", "desc", "aaa", Option.UNINITIALIZED, null, false, false, defaultSeparator,
166 String.class, null, null, null);
167 checkOption(Option.builder("a").desc("desc").hasArg(true).get(), "a", "desc", null, 1, null, false, false, defaultSeparator, String.class, null, null,
168 null);
169 checkOption(Option.builder("a").desc("desc").hasArg(false).get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
170 String.class, null, null, null);
171 checkOption(Option.builder("a").desc("desc").hasArg(true).get(), "a", "desc", null, 1, null, false, false, defaultSeparator, String.class, null, null,
172 null);
173 checkOption(Option.builder("a").desc("desc").numberOfArgs(3).get(), "a", "desc", null, 3, null, false, false, defaultSeparator, String.class, null,
174 null, null);
175 checkOption(Option.builder("a").desc("desc").required(true).get(), "a", "desc", null, Option.UNINITIALIZED, null, true, false, defaultSeparator,
176 String.class, null, null, null);
177 checkOption(Option.builder("a").desc("desc").required(false).get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
178 String.class, null, null, null);
179
180 checkOption(Option.builder("a").desc("desc").argName("arg1").get(), "a", "desc", null, Option.UNINITIALIZED, "arg1", false, false, defaultSeparator,
181 String.class, null, null, null);
182 checkOption(Option.builder("a").desc("desc").optionalArg(false).get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
183 String.class, null, null, null);
184 checkOption(Option.builder("a").desc("desc").optionalArg(true).get(), "a", "desc", null, 1, null, false, true, defaultSeparator, String.class, null,
185 null, null);
186 checkOption(Option.builder("a").desc("desc").valueSeparator(':').get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, ':',
187 String.class, null, null, null);
188 checkOption(Option.builder("a").desc("desc").type(Integer.class).get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
189 Integer.class, null, null, null);
190 checkOption(Option.builder("a").desc("desc").type(null).get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator,
191 String.class, null, null, null);
192 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).get(), "a", "desc", null, Option.UNINITIALIZED, null, false, false,
193 defaultSeparator, Integer.class, null, null, null);
194
195 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).deprecated().get(), "a", "desc", null, Option.UNINITIALIZED, null, false,
196 false, defaultSeparator, Integer.class, "", false, "");
197 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).deprecated(DeprecatedAttributes.builder().get()).get(), "a", "desc", null,
198 Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "", false, "");
199 checkOption(Option.builder().option("a").desc("desc").type(Integer.class).deprecated(DeprecatedAttributes.builder().setDescription("X").get()).get(),
200 "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "X", false, "");
201 checkOption(
202 Option.builder().option("a").desc("desc").type(Integer.class)
203 .deprecated(DeprecatedAttributes.builder().setDescription("X").setForRemoval(true).get()).get(),
204 "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "X", true, "");
205 checkOption(
206 Option.builder().option("a").desc("desc").type(Integer.class)
207 .deprecated(DeprecatedAttributes.builder().setDescription("X").setForRemoval(true).setSince("2.0").get()).get(),
208 "a", "desc", null, Option.UNINITIALIZED, null, false, false, defaultSeparator, Integer.class, "X", true, "2.0");
209 }
210
211 @Test
212 void testClear() {
213 final TestOption option = new TestOption("x", true, "");
214 assertTrue(option.getValuesList().isEmpty());
215 option.addValue("a");
216 assertEquals(1, option.getValuesList().size());
217 option.clearValues();
218 assertTrue(option.getValuesList().isEmpty());
219 }
220
221
222 @Test
223 void testClone() {
224 final TestOption a = new TestOption("a", true, "");
225 final TestOption b = (TestOption) a.clone();
226 assertEquals(a, b);
227 assertNotSame(a, b);
228 a.setDescription("a");
229 assertEquals("", b.getDescription());
230 b.setArgs(2);
231 b.addValue("b1");
232 b.addValue("b2");
233 assertEquals(1, a.getArgs());
234 assertTrue(a.getValuesList().isEmpty());
235 assertEquals(2, b.getValues().length);
236 }
237
238 @Test
239 void testEquals() {
240 final Option option1a = new Option("1", null);
241 final Option option1b = new Option("1", null);
242 final Option option2 = new Option("2", null);
243 assertEquals(option1a, option1a);
244 assertEquals(option1a, option1b);
245 assertEquals(option1b, option1a);
246 assertNotEquals(option1a, option2);
247 assertNotEquals(option1b, option2);
248 assertNotEquals(option2, option1a);
249 assertNotEquals(option2, "");
250 }
251
252 @Test
253 void testGetValue() {
254 final Option option = new Option("f", null);
255 option.setArgs(Option.UNLIMITED_VALUES);
256
257 assertEquals("default", option.getValue("default"));
258 assertNull(option.getValue(0));
259
260 option.processValue("foo");
261
262 assertEquals("foo", option.getValue());
263 assertEquals("foo", option.getValue(0));
264 assertEquals("foo", option.getValue("default"));
265 }
266
267 @Test
268 void testHasArgName() {
269 final Option option = new Option("f", null);
270
271 option.setArgName(null);
272 assertFalse(option.hasArgName());
273
274 option.setArgName("");
275 assertFalse(option.hasArgName());
276
277 option.setArgName("file");
278 assertTrue(option.hasArgName());
279 }
280
281 @Test
282 void testHasArgs() {
283 final Option option = new Option("f", null);
284
285 option.setArgs(0);
286 assertFalse(option.hasArgs());
287
288 option.setArgs(1);
289 assertFalse(option.hasArgs());
290
291 option.setArgs(10);
292 assertTrue(option.hasArgs());
293
294 option.setArgs(Option.UNLIMITED_VALUES);
295 assertTrue(option.hasArgs());
296
297 option.setArgs(Option.UNINITIALIZED);
298 assertFalse(option.hasArgs());
299 }
300
301 @Test
302 void testHashCode() {
303 assertNotEquals(Option.builder("test").get().hashCode(), Option.builder("test2").get().hashCode());
304 assertNotEquals(Option.builder("test").get().hashCode(), Option.builder().longOpt("test").get().hashCode());
305 assertNotEquals(Option.builder("test").get().hashCode(), Option.builder("test").longOpt("long test").get().hashCode());
306 }
307
308 @Test
309 public void testProcessValue() {
310 final Option option = new Option("D", true, "Define property");
311 option.setValueSeparator('=');
312 final NullPointerException exception = assertThrows(NullPointerException.class, () -> option.processValue(null));
313 assertTrue(exception.getMessage().contains("value"));
314 }
315
316 @Test
317 void testSerialization() throws IOException, ClassNotFoundException {
318 final Option option = Option.builder("o").type(TypeHandlerTest.Instantiable.class).get();
319 assertEquals(Converter.DEFAULT, option.getConverter());
320 Option roundtrip = roundTrip(option);
321 assertEquals(Converter.DEFAULT, roundtrip.getConverter());
322
323
324 option.setConverter(Converter.DATE);
325 roundtrip = roundTrip(option);
326 assertEquals(Converter.DEFAULT, roundtrip.getConverter());
327
328
329
330 assertEquals(Converter.DATE, option.getConverter());
331 roundtrip = roundTrip(option);
332 assertEquals(Converter.DEFAULT, roundtrip.getConverter());
333 }
334
335 @Test
336 void testSubclass() {
337 final Option option = new DefaultOption("f", "file", "myfile.txt");
338 final Option clone = (Option) option.clone();
339 assertEquals("myfile.txt", clone.getValue());
340 assertEquals(DefaultOption.class, clone.getClass());
341 }
342
343 @Test
344 void testTypeClass() {
345 final Option option = new Option("f", null);
346 assertEquals(String.class, option.getType());
347 option.setType(CharSequence.class);
348 assertEquals(CharSequence.class, option.getType());
349 }
350
351 @Test
352 void testTypeObject() {
353 final Option option = new Option("f", null);
354 assertEquals(String.class, option.getType());
355 @SuppressWarnings("cast")
356 final Object type = CharSequence.class;
357 option.setType(type);
358 assertEquals(CharSequence.class, option.getType());
359 }
360 }