View Javadoc
1   /*
2     Licensed to the Apache Software Foundation (ASF) under one or more
3     contributor license agreements.  See the NOTICE file distributed with
4     this work for additional information regarding copyright ownership.
5     The ASF licenses this file to You under the Apache License, Version 2.0
6     (the "License"); you may not use this file except in compliance with
7     the License.  You may obtain a copy of the License at
8   
9         https://www.apache.org/licenses/LICENSE-2.0
10  
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16   */
17  package org.apache.commons.cli.help;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertThrows;
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.function.BiFunction;
25  import java.util.function.Function;
26  import java.util.stream.Stream;
27  
28  import org.apache.commons.cli.DeprecatedAttributes;
29  import org.apache.commons.cli.Option;
30  import org.junit.jupiter.api.Test;
31  import org.junit.jupiter.params.ParameterizedTest;
32  import org.junit.jupiter.params.provider.Arguments;
33  import org.junit.jupiter.params.provider.MethodSource;
34  
35  /**
36   * Tests {@link OptionFormatter}.
37   */
38  class OptionFormatterTest {
39  
40      public static Stream<Arguments> deprecatedAttributesData() {
41          final List<Arguments> lst = new ArrayList<>();
42  
43          final DeprecatedAttributes.Builder daBuilder = DeprecatedAttributes.builder();
44          lst.add(Arguments.of(daBuilder.get(), "[Deprecated]"));
45  
46          daBuilder.setSince("now");
47          lst.add(Arguments.of(daBuilder.get(), "[Deprecated since now]"));
48  
49          daBuilder.setForRemoval(true);
50          lst.add(Arguments.of(daBuilder.get(), "[Deprecated for removal since now]"));
51  
52          daBuilder.setSince(null);
53          lst.add(Arguments.of(daBuilder.get(), "[Deprecated for removal]"));
54  
55          daBuilder.setForRemoval(false);
56          daBuilder.setDescription("Use something else");
57          lst.add(Arguments.of(daBuilder.get(), "[Deprecated. Use something else]"));
58  
59          daBuilder.setForRemoval(true);
60          lst.add(Arguments.of(daBuilder.get(), "[Deprecated for removal. Use something else]"));
61  
62          daBuilder.setForRemoval(false);
63          daBuilder.setSince("then");
64          lst.add(Arguments.of(daBuilder.get(), "[Deprecated since then. Use something else]"));
65  
66          daBuilder.setForRemoval(true);
67          lst.add(Arguments.of(daBuilder.get(), "[Deprecated for removal since then. Use something else]"));
68  
69          return lst.stream();
70      }
71  
72      private void assertEquivalent(final OptionFormatter formatter, final OptionFormatter formatter2) {
73          assertEquals(formatter.toSyntaxOption(), formatter2.toSyntaxOption());
74          assertEquals(formatter.toSyntaxOption(true), formatter2.toSyntaxOption(true));
75          assertEquals(formatter.toSyntaxOption(false), formatter2.toSyntaxOption(false));
76          assertEquals(formatter.getOpt(), formatter2.getOpt());
77          assertEquals(formatter.getLongOpt(), formatter2.getLongOpt());
78          assertEquals(formatter.getBothOpt(), formatter2.getBothOpt());
79          assertEquals(formatter.getDescription(), formatter2.getDescription());
80          assertEquals(formatter.getArgName(), formatter2.getArgName());
81          assertEquals(formatter.toOptional("foo"), formatter2.toOptional("foo"));
82      }
83  
84      @Test
85      void testAsOptional() {
86          OptionFormatter underTest;
87          final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
88  
89          underTest = OptionFormatter.from(option);
90          assertEquals("[what]", underTest.toOptional("what"));
91          assertEquals("", underTest.toOptional(""), "enpty string should return empty string");
92          assertEquals("", underTest.toOptional(null), "null should return empty string");
93  
94          underTest = OptionFormatter.builder().setOptionalDelimiters("-> ", " <-").build(option);
95          assertEquals("-> what <-", underTest.toOptional("what"));
96  
97      }
98  
99      @Test
100     void testAsSyntaxOption() {
101         OptionFormatter underTest;
102 
103         Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
104         underTest = OptionFormatter.from(option);
105         assertEquals("[-o <arg>]", underTest.toSyntaxOption(), "optional arg failed");
106 
107         option = Option.builder().option("o").longOpt("opt").hasArg().argName("other").get();
108         underTest = OptionFormatter.from(option);
109         assertEquals("[-o <other>]", underTest.toSyntaxOption(), "optional 'other' arg failed");
110 
111         option = Option.builder().option("o").longOpt("opt").hasArg().required().argName("other").get();
112         underTest = OptionFormatter.from(option);
113         assertEquals("-o <other>", underTest.toSyntaxOption(), "required 'other' arg failed");
114 
115         option = Option.builder().option("o").longOpt("opt").required().argName("other").get();
116         underTest = OptionFormatter.from(option);
117         assertEquals("-o", underTest.toSyntaxOption(), "required no arg failed");
118 
119         option = Option.builder().option("o").argName("other").get();
120         underTest = OptionFormatter.from(option);
121         assertEquals("[-o]", underTest.toSyntaxOption(), "optional no arg arg failed");
122 
123         option = Option.builder().longOpt("opt").hasArg().argName("other").get();
124         underTest = OptionFormatter.from(option);
125         assertEquals("[--opt <other>]", underTest.toSyntaxOption(), "optional longOpt 'other' arg failed");
126 
127         option = Option.builder().longOpt("opt").required().hasArg().argName("other").get();
128         underTest = OptionFormatter.from(option);
129         assertEquals("--opt <other>", underTest.toSyntaxOption(), "required longOpt 'other' arg failed");
130 
131         option = Option.builder().option("ot").longOpt("opt").hasArg().get();
132         underTest = OptionFormatter.from(option);
133         assertEquals("[-ot <arg>]", underTest.toSyntaxOption(), "optional multi char opt arg failed");
134     }
135 
136     @Test
137     void testCli343Part1() {
138         assertThrows(IllegalStateException.class, () -> Option.builder().required(false).build());
139         assertThrows(IllegalStateException.class, () -> Option.builder().required(false).get());
140     }
141 
142     @Test
143     void testCli343Part2() {
144         assertThrows(IllegalStateException.class, () -> Option.builder().desc("description").build());
145         assertThrows(IllegalStateException.class, () -> Option.builder().desc("description").get());
146     }
147 
148     @ParameterizedTest(name = "{index} {0}")
149     @MethodSource("deprecatedAttributesData")
150     void testComplexDeprecationFormat(final DeprecatedAttributes da, final String expected) {
151         final Option.Builder builder = Option.builder("o").deprecated(da);
152         final Option.Builder builderWithDesc = Option.builder("o").desc("The description").deprecated(da);
153 
154         assertEquals(expected, OptionFormatter.COMPLEX_DEPRECATED_FORMAT.apply(builder.get()));
155         assertEquals(expected + " The description", OptionFormatter.COMPLEX_DEPRECATED_FORMAT.apply(builderWithDesc.get()));
156     }
157 
158     @Test
159     void testCopyConstructor() {
160         final Function<Option, String> depFunc = o -> "Ooo Deprecated";
161         final BiFunction<OptionFormatter, Boolean, String> fmtFunc = (o, b) -> "Yep, it worked";
162         // @formatter:off
163         final OptionFormatter.Builder builder = OptionFormatter.builder()
164                 .setLongOptPrefix("l")
165                 .setOptPrefix("s")
166                 .setArgumentNameDelimiters("{", "}")
167                 .setDefaultArgName("Some Argument")
168                 .setOptSeparator(" and ")
169                 .setOptionalDelimiters("?>", "<?")
170                 .setSyntaxFormatFunction(fmtFunc)
171                 .setDeprecatedFormatFunction(depFunc);
172         // @formatter:on
173 
174         Option option = Option.builder("o").longOpt("opt").get();
175 
176         OptionFormatter formatter = builder.build(option);
177         OptionFormatter.Builder builder2 = new OptionFormatter.Builder(formatter);
178         assertEquivalent(formatter, builder2.build(option));
179 
180         option = Option.builder("o").longOpt("opt").deprecated().required().get();
181         formatter = builder.build(option);
182         builder2 = new OptionFormatter.Builder(formatter);
183         assertEquivalent(formatter, builder2.build(option));
184     }
185 
186     @Test
187     void testDefaultSyntaxFormat() {
188 
189         Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
190         OptionFormatter formatter = OptionFormatter.from(option);
191         assertEquals("[-o <arg>]", formatter.toSyntaxOption());
192         assertEquals("-o <arg>", formatter.toSyntaxOption(true));
193 
194         option = Option.builder().option("o").longOpt("opt").hasArg().required().get();
195         formatter = OptionFormatter.from(option);
196         assertEquals("-o <arg>", formatter.toSyntaxOption());
197         assertEquals("[-o <arg>]", formatter.toSyntaxOption(false));
198     }
199 
200     @Test
201     void testGetBothOpt() {
202         OptionFormatter underTest;
203 
204         Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
205         underTest = OptionFormatter.from(option);
206         assertEquals("-o, --opt", underTest.getBothOpt());
207 
208         option = Option.builder().longOpt("opt").hasArg().get();
209         underTest = OptionFormatter.from(option);
210         assertEquals("--opt", underTest.getBothOpt());
211 
212         option = Option.builder().option("o").hasArg().get();
213         underTest = OptionFormatter.from(option);
214         assertEquals("-o", underTest.getBothOpt());
215     }
216 
217     @Test
218     void testGetDescription() {
219         final Option normalOption = Option.builder().option("o").longOpt("one").hasArg().desc("The description").get();
220 
221         final Option deprecatedOption = Option.builder().option("o").longOpt("one").hasArg().desc("The description").deprecated().get();
222 
223         final Option deprecatedOptionWithAttributes = Option.builder().option("o").longOpt("one").hasArg().desc("The description")
224         .deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("now").setDescription("Use something else").get()).get();
225 
226         assertEquals("The description", OptionFormatter.from(normalOption).getDescription(), "normal option failure");
227         assertEquals("The description", OptionFormatter.from(deprecatedOption).getDescription(), "deprecated option failure");
228         assertEquals("The description", OptionFormatter.from(deprecatedOptionWithAttributes).getDescription(), "complex deprecated option failure");
229 
230         OptionFormatter.Builder builder = OptionFormatter.builder().setDeprecatedFormatFunction(OptionFormatter.SIMPLE_DEPRECATED_FORMAT);
231 
232         assertEquals("The description", builder.build(normalOption).getDescription(), "normal option failure");
233         assertEquals("[Deprecated] The description", builder.build(deprecatedOption).getDescription(), "deprecated option failure");
234         assertEquals("[Deprecated] The description", builder.build(deprecatedOptionWithAttributes).getDescription(), "complex deprecated option failure");
235 
236         builder = OptionFormatter.builder().setDeprecatedFormatFunction(OptionFormatter.COMPLEX_DEPRECATED_FORMAT);
237 
238         assertEquals("The description", builder.build(normalOption).getDescription(), "normal option failure");
239         assertEquals("[Deprecated] The description", builder.build(deprecatedOption).getDescription(), "deprecated option failure");
240         assertEquals("[Deprecated for removal since now. Use something else] The description", builder.build(deprecatedOptionWithAttributes).getDescription(),
241                 "complex deprecated option failure");
242     }
243 
244     @Test
245     void testSetArgumentNameDelimiters() {
246         final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
247         OptionFormatter.Builder builder = OptionFormatter.builder().setArgumentNameDelimiters("with argument named ", ".");
248         assertEquals("with argument named arg.", builder.build(option).getArgName());
249 
250         builder = OptionFormatter.builder().setArgumentNameDelimiters(null, "");
251         assertEquals("arg", builder.build(option).getArgName());
252 
253         builder = OptionFormatter.builder().setArgumentNameDelimiters("", null);
254         assertEquals("arg", builder.build(option).getArgName());
255 
256     }
257 
258     @Test
259     void testSetDefaultArgName() {
260         final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
261         OptionFormatter.Builder builder = OptionFormatter.builder().setDefaultArgName("foo");
262         assertEquals("<foo>", builder.build(option).getArgName());
263 
264         builder = OptionFormatter.builder().setDefaultArgName("");
265         assertEquals("<arg>", builder.build(option).getArgName());
266 
267         builder = OptionFormatter.builder().setDefaultArgName(null);
268         assertEquals("<arg>", builder.build(option).getArgName());
269     }
270 
271     @Test
272     void testSetLongOptPrefix() {
273         final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
274         OptionFormatter.Builder builder = OptionFormatter.builder().setLongOptPrefix("fo");
275         assertEquals("foopt", builder.build(option).getLongOpt());
276 
277         builder = OptionFormatter.builder().setLongOptPrefix("");
278         assertEquals("opt", builder.build(option).getLongOpt());
279 
280         builder = OptionFormatter.builder().setLongOptPrefix(null);
281         assertEquals("opt", builder.build(option).getLongOpt());
282     }
283 
284     @Test
285     void testSetOptArgumentSeparator() {
286         final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
287         OptionFormatter.Builder builder = OptionFormatter.builder().setOptArgSeparator(" with argument named ");
288         assertEquals("[-o with argument named <arg>]", builder.build(option).toSyntaxOption());
289 
290         builder = OptionFormatter.builder().setOptArgSeparator(null);
291         assertEquals("[-o<arg>]", builder.build(option).toSyntaxOption());
292 
293         builder = OptionFormatter.builder().setOptArgSeparator("=");
294         assertEquals("[-o=<arg>]", builder.build(option).toSyntaxOption());
295     }
296 
297     @Test
298     void testSetOptSeparator() {
299         final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
300         OptionFormatter.Builder builder = OptionFormatter.builder().setOptSeparator(" and ");
301         assertEquals("-o and --opt", builder.build(option).getBothOpt());
302 
303         builder = OptionFormatter.builder().setOptSeparator("");
304         assertEquals("-o--opt", builder.build(option).getBothOpt(), "Empty string should return default");
305 
306         builder = OptionFormatter.builder().setOptSeparator(null);
307         assertEquals("-o--opt", builder.build(option).getBothOpt(), "null string should return default");
308     }
309 
310     @Test
311     void testSetSyntaxFormatFunction() {
312         final BiFunction<OptionFormatter, Boolean, String> func = (o, b) -> "Yep, it worked";
313         final Option option = Option.builder().option("o").longOpt("opt").hasArg().get();
314 
315         OptionFormatter.Builder builder = OptionFormatter.builder().setSyntaxFormatFunction(func);
316         assertEquals("Yep, it worked", builder.build(option).toSyntaxOption());
317 
318         builder = OptionFormatter.builder().setSyntaxFormatFunction(null);
319         assertEquals("[-o <arg>]", builder.build(option).toSyntaxOption());
320     }
321 }