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.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.when;
27
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.io.OutputStreamWriter;
31 import java.io.PrintWriter;
32 import java.io.StringWriter;
33 import java.io.UncheckedIOException;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.stream.Stream;
37
38 import org.apache.commons.cli.HelpFormatter.Builder;
39 import org.junit.jupiter.api.Test;
40 import org.junit.jupiter.params.ParameterizedTest;
41 import org.junit.jupiter.params.provider.Arguments;
42 import org.junit.jupiter.params.provider.MethodSource;
43 import org.junit.jupiter.params.provider.ValueSource;
44
45
46
47
48 class HelpFormatterTest {
49
50 private static final String EOL = System.lineSeparator();
51
52 static Stream<Arguments> deprecatedOptionsProvider() {
53 final List<Arguments> lst = new ArrayList<>();
54 Option option = Option.builder("a").longOpt("aaa").desc("dddd dddd dddd")
55 .deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("now")
56 .setDescription("Why why why").get()).get();
57
58 HelpFormatter hf = HelpFormatter.builder().get();
59 lst.add(Arguments.of(hf, option, "[Deprecated] dddd dddd dddd"));
60
61 hf = HelpFormatter.builder().setShowDeprecated(false).get();
62 lst.add(Arguments.of(hf, option, "dddd dddd dddd"));
63
64 hf = HelpFormatter.builder().setShowDeprecated(true).get();
65 lst.add(Arguments.of(hf, option, "[Deprecated] dddd dddd dddd"));
66
67 hf = HelpFormatter.builder().setShowDeprecated(o -> String.format("%s [%s]", HelpFormatter.getDescription(o), o.getDeprecated())).get();
68 lst.add(Arguments.of(hf, option, "dddd dddd dddd [Deprecated for removal since now: Why why why]"));
69
70 option = Option.builder("a").longOpt("aaa")
71 .deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("now")
72 .setDescription("Why why why").get()).get();
73
74 hf = HelpFormatter.builder().get();
75 lst.add(Arguments.of(hf, option, "[Deprecated]"));
76
77 hf = HelpFormatter.builder().setShowDeprecated(false).get();
78 lst.add(Arguments.of(hf, option, ""));
79
80 hf = HelpFormatter.builder().setShowDeprecated(true).get();
81 lst.add(Arguments.of(hf, option, "[Deprecated]"));
82
83 hf = HelpFormatter.builder().setShowDeprecated(o -> String.format("%s [%s]", HelpFormatter.getDescription(o), o.getDeprecated())).get();
84 lst.add(Arguments.of(hf, option, "[Deprecated for removal since now: Why why why]"));
85
86 return lst.stream();
87 }
88
89 @Test
90 void testAccessors() {
91 final HelpFormatter formatter = new HelpFormatter();
92
93 formatter.setArgName("argname");
94 assertEquals("argname", formatter.getArgName(), "arg name");
95
96 formatter.setDescPadding(3);
97 assertEquals(3, formatter.getDescPadding(), "desc padding");
98
99 formatter.setLeftPadding(7);
100 assertEquals(7, formatter.getLeftPadding(), "left padding");
101
102 formatter.setLongOptPrefix("~~");
103 assertEquals("~~", formatter.getLongOptPrefix(), "long opt prefix");
104
105 formatter.setNewLine("\n");
106 assertEquals("\n", formatter.getNewLine(), "new line");
107
108 formatter.setOptPrefix("~");
109 assertEquals("~", formatter.getOptPrefix(), "opt prefix");
110
111 formatter.setSyntaxPrefix("-> ");
112 assertEquals("-> ", formatter.getSyntaxPrefix(), "syntax prefix");
113
114 formatter.setWidth(80);
115 assertEquals(80, formatter.getWidth(), "width");
116 }
117
118 @Test
119 void testAutomaticUsage() {
120 final HelpFormatter hf = new HelpFormatter();
121 Options options;
122 String expected = "usage: app [-a]";
123 final ByteArrayOutputStream out = new ByteArrayOutputStream();
124 final PrintWriter pw = new PrintWriter(out);
125
126 options = new Options().addOption("a", false, "aaaa aaaa aaaa aaaa aaaa");
127 hf.printUsage(pw, 60, "app", options);
128 pw.flush();
129 assertEquals(expected, out.toString().trim(), "simple auto usage");
130 out.reset();
131
132 expected = "usage: app [-a] [-b]";
133 options = new Options().addOption("a", false, "aaaa aaaa aaaa aaaa aaaa").addOption("b", false, "bbb");
134 hf.printUsage(pw, 60, "app", options);
135 pw.flush();
136 assertEquals(expected, out.toString().trim(), "simple auto usage");
137 out.reset();
138 }
139
140 @Test
141 void testDefaultArgName() {
142 final Option option = Option.builder("f").hasArg().required(true).get();
143
144 final Options options = new Options();
145 options.addOption(option);
146
147 final StringWriter out = new StringWriter();
148
149 final HelpFormatter formatter = new HelpFormatter();
150 formatter.setArgName("argument");
151 formatter.printUsage(new PrintWriter(out), 80, "app", options);
152
153 assertEquals("usage: app -f <argument>" + EOL, out.toString());
154 }
155
156 @ParameterizedTest
157 @ValueSource(ints = { -100, -1, 0 })
158 void testDeprecatedFindWrapPosZeroWidth(final int width) {
159 final int pos = new HelpFormatter().findWrapPos("Hello World", width, 0);
160 assertEquals(width, pos);
161 }
162
163 @ParameterizedTest
164 @ValueSource(ints = { -100, -1, 0 })
165 void testDeprecatedPrintOptionsZeroWidth(final int width) {
166 final Options options = new Options();
167 options.addOption("h", "help", false, "Show help");
168 final StringWriter out = new StringWriter();
169 final PrintWriter pw = new PrintWriter(out);
170 new HelpFormatter().printOptions(pw, width, options, 1, 3);
171 final String result = out.toString();
172 assertNotNull(result);
173 }
174
175 @Test
176 void testFindWrapPos() {
177 final HelpFormatter hf = new HelpFormatter();
178
179 String text = "This is a test.";
180
181 assertEquals(7, hf.findWrapPos(text, 8, 0), "wrap position");
182
183
184 assertEquals(-1, hf.findWrapPos(text, 8, 8), "wrap position 2");
185
186
187 text = "aaaa aa";
188 assertEquals(3, hf.findWrapPos(text, 3, 0), "wrap position 3");
189
190
191 text = "aaaaaa aaaaaa";
192 assertEquals(6, hf.findWrapPos(text, 6, 0), "wrap position 4");
193 assertEquals(-1, hf.findWrapPos(text, 6, 7), "wrap position 4");
194
195 text = "aaaaaa\n aaaaaa";
196 assertEquals(7, hf.findWrapPos(text, 6, 0), "wrap position 5");
197
198 text = "aaaaaa\t aaaaaa";
199 assertEquals(7, hf.findWrapPos(text, 6, 0), "wrap position 6");
200 }
201
202 @Test
203 void testHeaderStartingWithLineSeparator0() {
204
205 final Options options = new Options();
206 final HelpFormatter formatter = new HelpFormatter();
207 final String header = EOL + "Header";
208 final String footer = "Footer";
209 final StringWriter out = new StringWriter();
210 formatter.printHelp(new PrintWriter(out), 80, "foobar", header, options, 2, 2, footer, true);
211
212 assertEquals(
213 "usage: foobar" + EOL +
214 EOL +
215 "Header" + EOL +
216 EOL +
217 "Footer" + EOL,
218 out.toString());
219
220 }
221
222 @Test
223 void testHeaderStartingWithLineSeparator1() {
224
225 final Options options = new Options();
226 final String header = EOL + "Header";
227 final String footer = "Footer";
228 final Builder builder = HelpFormatter.builder();
229 StringWriter out = new StringWriter();
230 builder.setPrintWriter(new PrintWriter(out)).get().printHelp(new PrintWriter(out), 80, "foobar", header, options, 2, 2, footer, true);
231
232 assertEquals(
233 "usage: foobar" + EOL +
234 "" + EOL +
235 "Header" + EOL +
236 "" + EOL +
237 "Footer" + EOL,
238 out.toString());
239
240 out = new StringWriter();
241 builder.setPrintWriter(new PrintWriter(out)).get().printHelp("foobar", header, options, footer);
242
243 assertEquals(
244 "usage: foobar" + EOL +
245 EOL +
246 "Header" + EOL +
247 EOL +
248 "Footer" + EOL,
249 out.toString());
250
251 out = new StringWriter();
252 builder.setPrintWriter(new PrintWriter(out)).get().printHelp(80, "foobar", header, options, footer);
253
254 assertEquals(
255 "usage: foobar" + EOL +
256 EOL +
257 "Header" + EOL +
258 EOL +
259 "Footer" + EOL,
260 out.toString());
261
262 out = new StringWriter();
263 builder.setPrintWriter(new PrintWriter(out)).get().printHelp("foobar", header, options, footer, false);
264
265 assertEquals(
266 "usage: foobar" + EOL +
267 EOL +
268 "Header" + EOL +
269 EOL +
270 "Footer" + EOL,
271 out.toString());
272
273 out = new StringWriter();
274 builder.setPrintWriter(new PrintWriter(out)).get().printHelp("foobar", header, options, footer, true);
275
276 assertEquals(
277 "usage: foobar" + EOL +
278 EOL +
279 "Header" + EOL +
280 EOL +
281 "Footer" + EOL,
282 out.toString());
283
284 out = new StringWriter();
285 builder.setPrintWriter(new PrintWriter(out)).get().printHelp("foobar", options, false);
286
287 assertEquals(
288 "usage: foobar" + EOL +
289 "" + EOL,
290 out.toString());
291
292 }
293
294 @Test
295 void testHelpWithLongOptSeparator() {
296 final Options options = new Options();
297 options.addOption("f", true, "the file");
298 options.addOption(Option.builder("s").longOpt("size").desc("the size").hasArg().argName("SIZE").get());
299 options.addOption(Option.builder().longOpt("age").desc("the age").hasArg().get());
300
301 final HelpFormatter formatter = new HelpFormatter();
302 assertEquals(HelpFormatter.DEFAULT_LONG_OPT_SEPARATOR, formatter.getLongOptSeparator());
303 formatter.setLongOptSeparator("=");
304 assertEquals("=", formatter.getLongOptSeparator());
305
306 final StringWriter out = new StringWriter();
307
308 formatter.printHelp(new PrintWriter(out), 80, "create", "header", options, 2, 2, "footer");
309
310
311 assertEquals(
312 "usage: create" + EOL +
313 "header" + EOL +
314 " --age=<arg> the age" + EOL +
315 " -f <arg> the file" + EOL +
316 " -s,--size=<SIZE> the size" + EOL +
317 "footer" + EOL,
318 out.toString());
319
320 }
321
322 @Test
323 void testIndentedHeaderAndFooter() {
324
325 final Options options = new Options();
326 final HelpFormatter formatter = new HelpFormatter();
327 final String header = " Header1\n Header2";
328 final String footer = " Footer1\n Footer2";
329 final StringWriter out = new StringWriter();
330 formatter.printHelp(new PrintWriter(out), 80, "foobar", header, options, 2, 2, footer, true);
331
332 assertEquals(
333 "usage: foobar" + EOL +
334 " Header1" + EOL +
335 " Header2" + EOL +
336 "" + EOL +
337 " Footer1" + EOL +
338 " Footer2" + EOL,
339 out.toString());
340
341 }
342
343 @Test
344 void testOptionWithoutShortFormat() {
345
346 final Options options = new Options();
347 options.addOption(new Option("a", "aaa", false, "aaaaaaa"));
348 options.addOption(new Option(null, "bbb", false, "bbbbbbb"));
349 options.addOption(new Option("c", null, false, "ccccccc"));
350
351 final HelpFormatter formatter = new HelpFormatter();
352 final StringWriter out = new StringWriter();
353 formatter.printHelp(new PrintWriter(out), 80, "foobar", "", options, 2, 2, "", true);
354
355 assertEquals(
356 "usage: foobar [-a] [--bbb] [-c]" + EOL +
357 " -a,--aaa aaaaaaa" + EOL +
358 " --bbb bbbbbbb" + EOL +
359 " -c ccccccc" + EOL,
360 out.toString());
361
362 }
363
364 @Test
365 void testOptionWithoutShortFormat2() {
366
367 final Option help = new Option("h", "help", false, "print this message");
368 final Option version = new Option("v", "version", false, "print version information");
369 final Option newRun = new Option("n", "new", false, "Create NLT cache entries only for new items");
370 final Option trackerRun = new Option("t", "tracker", false, "Create NLT cache entries only for tracker items");
371
372 final Option timeLimit = Option.builder("l")
373 .longOpt("limit")
374 .hasArg()
375 .valueSeparator()
376 .desc("Set time limit for execution, in mintues").get();
377 final Option age = Option.builder("a").longOpt("age")
378 .hasArg()
379 .valueSeparator()
380 .desc("Age (in days) of cache item before being recomputed").get();
381 final Option server = Option.builder("s").longOpt("server")
382 .hasArg()
383 .valueSeparator()
384 .desc("The NLT server address").get();
385 final Option numResults = Option.builder("r").longOpt("results")
386 .hasArg()
387 .valueSeparator()
388 .desc("Number of results per item").get();
389 final Option configFile = Option.builder().longOpt("config")
390 .hasArg()
391 .valueSeparator()
392 .desc("Use the specified configuration file").get();
393
394
395 final Options mOptions = new Options();
396 mOptions.addOption(help);
397 mOptions.addOption(version);
398 mOptions.addOption(newRun);
399 mOptions.addOption(trackerRun);
400 mOptions.addOption(timeLimit);
401 mOptions.addOption(age);
402 mOptions.addOption(server);
403 mOptions.addOption(numResults);
404 mOptions.addOption(configFile);
405
406 final HelpFormatter formatter = new HelpFormatter();
407 final String eol = System.lineSeparator();
408 final StringWriter out = new StringWriter();
409 formatter.printHelp(new PrintWriter(out), 80, "commandline", "header", mOptions, 2, 2, "footer", true);
410
411 assertEquals(
412 "usage: commandline [-a <arg>] [--config <arg>] [-h] [-l <arg>] [-n] [-r <arg>]" + eol +
413 " [-s <arg>] [-t] [-v]" + eol +
414 "header" + eol +
415 " -a,--age <arg> Age (in days) of cache item before being recomputed" + eol +
416 " --config <arg> Use the specified configuration file" + eol +
417 " -h,--help print this message" + eol +
418 " -l,--limit <arg> Set time limit for execution, in mintues" + eol +
419 " -n,--new Create NLT cache entries only for new items" + eol +
420 " -r,--results <arg> Number of results per item" + eol +
421 " -s,--server <arg> The NLT server address" + eol +
422 " -t,--tracker Create NLT cache entries only for tracker items" + eol +
423 " -v,--version print version information" + eol +
424 "footer" + eol,
425 out.toString());
426
427 }
428
429 @ParameterizedTest
430 @MethodSource("deprecatedOptionsProvider")
431 void testPrintDeprecatedOptions(final HelpFormatter hf, final Option option, final String expectedTxt) {
432 final StringBuffer sb = new StringBuffer();
433
434 final int leftPad = 1;
435 final int descPad = 3;
436 final String lpad = hf.createPadding(leftPad);
437 final String dpad = hf.createPadding(descPad);
438 Options options;
439 final StringBuilder expected = new StringBuilder().append(lpad).append("-a,--aaa");
440
441 options = new Options().addOption(option);
442 if (expectedTxt.length() > 0) {
443 expected.append(dpad).append(expectedTxt);
444 }
445 hf.renderOptions(sb, 160, options, leftPad, descPad);
446 assertEquals(expected.toString(), sb.toString());
447 }
448
449 @Test
450 void testPrintHelpNewlineFooter() {
451 final HelpFormatter formatter = new HelpFormatter();
452 final ByteArrayOutputStream out = new ByteArrayOutputStream();
453 final PrintWriter pw = new PrintWriter(out);
454
455 final Options options = new Options();
456 options.addOption("a", "b");
457
458 formatter.printHelp(
459 pw,
460 80,
461 "test" + EOL,
462 "header" + EOL,
463 options,
464 0,
465 0,
466 EOL
467 );
468 final String expected = "usage: test" + EOL +
469 "header" + EOL +
470 "-ab" + EOL +
471 EOL;
472 pw.flush();
473 assertEquals(expected, out.toString(), "footer newline");
474 }
475
476 @Test
477 void testPrintHelpNewlineHeader() {
478 final HelpFormatter formatter = new HelpFormatter();
479 final ByteArrayOutputStream out = new ByteArrayOutputStream();
480 final PrintWriter pw = new PrintWriter(out);
481
482 final Options options = new Options();
483 options.addOption("a", "b");
484
485 formatter.printHelp(
486 pw,
487 80,
488 "test" + EOL,
489 EOL,
490 options,
491 0,
492 0,
493 "footer" + EOL
494 );
495 final String expected = "usage: test" + EOL +
496 EOL +
497 "-ab" + EOL +
498 "footer" + EOL;
499 pw.flush();
500 assertEquals(expected, out.toString(), "header newline");
501 }
502
503 @Test
504 void testPrintHelpWithEmptySyntax() {
505 final HelpFormatter formatter = new HelpFormatter();
506 assertThrows(IllegalArgumentException.class, () -> formatter.printHelp(null, new Options()), "null command line syntax should be rejected");
507 assertThrows(IllegalArgumentException.class, () -> formatter.printHelp(null, new Options(), true), "null command line syntax should be rejected");
508 assertThrows(IllegalArgumentException.class, () -> formatter.printHelp(null, new Options(), false), "null command line syntax should be rejected");
509 assertThrows(IllegalArgumentException.class, () -> formatter.printHelp("", new Options(), true), "null command line syntax should be rejected");
510 assertThrows(IllegalArgumentException.class, () -> formatter.printHelp("", new Options(), false), "null command line syntax should be rejected");
511 }
512
513 @Test
514 void testPrintHelpWithSince() {
515 final String [] expected = {"usage: Command syntax", "Header", "Options Since Description",
516 " -n,--no-since - Description for n", " -W,--with-since 1.19.0 Descripton for W", "footer"};
517 final Options options = new Options()
518 .addOption(Option.builder("W").longOpt("with-since").since("1.19.0").desc("Descripton for W").get())
519 .addOption(Option.builder("n").longOpt("no-since").desc("Description for n").get());
520
521 final HelpFormatter formatter = HelpFormatter.builder().setShowSince(true).get();
522 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
523 try (PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos))) {
524 formatter.printHelp(pw, 80, "Command syntax", "Header", options, 2, 5, "footer", false);
525 }
526 assertArrayEquals(expected, baos.toString().split(System.lineSeparator()));
527 }
528
529 @Test
530 void testPrintOptionGroupUsage() {
531 final OptionGroup optionGroup = new OptionGroup();
532 optionGroup.addOption(Option.builder("a").get());
533 optionGroup.addOption(Option.builder("b").get());
534 optionGroup.addOption(Option.builder("c").get());
535
536 final Options options = new Options();
537 options.addOptionGroup(optionGroup);
538
539 final StringWriter out = new StringWriter();
540
541 final HelpFormatter formatter = new HelpFormatter();
542 formatter.printUsage(new PrintWriter(out), 80, "app", options);
543
544 assertEquals("usage: app [-a | -b | -c]" + EOL, out.toString());
545 }
546
547 @Test
548 void testPrintOptions() {
549 final StringBuffer sb = new StringBuffer();
550 final HelpFormatter hf = new HelpFormatter();
551 final int leftPad = 1;
552 final int descPad = 3;
553 final String lpad = hf.createPadding(leftPad);
554 final String dpad = hf.createPadding(descPad);
555 Options options;
556 String expected;
557
558 options = new Options().addOption("a", false, "aaaa aaaa aaaa aaaa aaaa");
559 expected = lpad + "-a" + dpad + "aaaa aaaa aaaa aaaa aaaa";
560 hf.renderOptions(sb, 60, options, leftPad, descPad);
561 assertEquals(expected, sb.toString(), "simple non-wrapped option");
562
563 int nextLineTabStop = leftPad + descPad + "-a".length();
564 expected = lpad + "-a" + dpad + "aaaa aaaa aaaa" + EOL + hf.createPadding(nextLineTabStop) + "aaaa aaaa";
565 sb.setLength(0);
566 hf.renderOptions(sb, nextLineTabStop + 17, options, leftPad, descPad);
567 assertEquals(expected, sb.toString(), "simple wrapped option");
568
569 options = new Options().addOption("a", "aaa", false, "dddd dddd dddd dddd");
570 expected = lpad + "-a,--aaa" + dpad + "dddd dddd dddd dddd";
571 sb.setLength(0);
572 hf.renderOptions(sb, 60, options, leftPad, descPad);
573 assertEquals(expected, sb.toString(), "long non-wrapped option");
574
575 nextLineTabStop = leftPad + descPad + "-a,--aaa".length();
576 expected = lpad + "-a,--aaa" + dpad + "dddd dddd" + EOL + hf.createPadding(nextLineTabStop) + "dddd dddd";
577 sb.setLength(0);
578 hf.renderOptions(sb, 25, options, leftPad, descPad);
579 assertEquals(expected, sb.toString(), "long wrapped option");
580
581 options = new Options().addOption("a", "aaa", false, "dddd dddd dddd dddd").addOption("b", false, "feeee eeee eeee eeee");
582 expected = lpad + "-a,--aaa" + dpad + "dddd dddd" + EOL + hf.createPadding(nextLineTabStop) + "dddd dddd" + EOL + lpad + "-b " + dpad
583 + "feeee eeee" + EOL + hf.createPadding(nextLineTabStop) + "eeee eeee";
584 sb.setLength(0);
585 hf.renderOptions(sb, 25, options, leftPad, descPad);
586 assertEquals(expected, sb.toString(), "multiple wrapped options");
587 }
588
589 @Test
590 void testPrintOptionWithEmptyArgNameUsage() {
591 final Option option = new Option("f", true, null);
592 option.setArgName("");
593 option.setRequired(true);
594
595 final Options options = new Options();
596 options.addOption(option);
597
598 final StringWriter out = new StringWriter();
599
600 final HelpFormatter formatter = new HelpFormatter();
601 formatter.printUsage(new PrintWriter(out), 80, "app", options);
602
603 assertEquals("usage: app -f" + EOL, out.toString());
604 }
605
606 @Test
607 void testPrintRequiredOptionGroupUsage() {
608 final OptionGroup optionGroup = new OptionGroup();
609 optionGroup.addOption(Option.builder("a").get());
610 optionGroup.addOption(Option.builder("b").get());
611 optionGroup.addOption(Option.builder("c").get());
612 optionGroup.setRequired(true);
613
614 final Options options = new Options();
615 options.addOptionGroup(optionGroup);
616
617 final StringWriter out = new StringWriter();
618
619 final HelpFormatter formatter = new HelpFormatter();
620 formatter.printUsage(new PrintWriter(out), 80, "app", options);
621
622 assertEquals("usage: app -a | -b | -c" + EOL, out.toString());
623 }
624
625
626 @Test
627 void testPrintSortedUsage() {
628 final Options opts = new Options();
629 opts.addOption(new Option("a", "first"));
630 opts.addOption(new Option("b", "second"));
631 opts.addOption(new Option("c", "third"));
632
633 final HelpFormatter helpFormatter = new HelpFormatter();
634 helpFormatter.setOptionComparator((opt1, opt2) -> opt2.getKey().compareToIgnoreCase(opt1.getKey()));
635
636 final StringWriter out = new StringWriter();
637 helpFormatter.printUsage(new PrintWriter(out), 80, "app", opts);
638
639 assertEquals("usage: app [-c] [-b] [-a]" + EOL, out.toString());
640 }
641
642 @Test
643 void testPrintSortedUsageWithNullComparator() {
644 final Options opts = new Options();
645 opts.addOption(new Option("c", "first"));
646 opts.addOption(new Option("b", "second"));
647 opts.addOption(new Option("a", "third"));
648
649 final HelpFormatter helpFormatter = new HelpFormatter();
650 helpFormatter.setOptionComparator(null);
651
652 final StringWriter out = new StringWriter();
653 helpFormatter.printUsage(new PrintWriter(out), 80, "app", opts);
654
655 assertEquals("usage: app [-c] [-b] [-a]" + EOL, out.toString());
656 }
657
658
659
660 @Test
661 void testPrintUsage() {
662 final Option optionA = new Option("a", "first");
663 final Option optionB = new Option("b", "second");
664 final Option optionC = new Option("c", "third");
665 final Options opts = new Options();
666 opts.addOption(optionA);
667 opts.addOption(optionB);
668 opts.addOption(optionC);
669 final HelpFormatter helpFormatter = new HelpFormatter();
670 final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
671 try (PrintWriter printWriter = new PrintWriter(bytesOut)) {
672 helpFormatter.printUsage(printWriter, 80, "app", opts);
673 }
674 assertEquals("usage: app [-a] [-b] [-c]" + EOL, bytesOut.toString());
675 }
676
677 @Test
678 void testRenderSince() throws IOException {
679 final String[] expected = {"Options Since Description", " -n,--no-since - Description for n",
680 " -W,--with-since 1.19.0 Descripton for W"};
681 final Options options = new Options()
682 .addOption(Option.builder("W").longOpt("with-since").since("1.19.0").desc("Descripton for W").get())
683 .addOption(Option.builder("n").longOpt("no-since").desc("Description for n").get());
684 final HelpFormatter formatter = HelpFormatter.builder().setShowSince(true).get();
685
686 final StringBuffer sb = new StringBuffer();
687 formatter.renderOptions(sb, 50, options, 2, 5);
688 assertArrayEquals(expected, sb.toString().split(System.lineSeparator()));
689
690 final HelpFormatter spy = spy(formatter);
691 when(spy.appendOptions(sb, 50, options, 2, 5)).thenThrow(IOException.class);
692 assertThrows(UncheckedIOException.class, () -> spy.renderOptions(sb, 50, options, 2, 5));
693 }
694
695 @Test
696 void testRenderWrappedTextMultiLine() {
697
698 final int width = 16;
699 final int padding = 0;
700
701 final String expected = "aaaa aaaa aaaa" + EOL +
702 "aaaaaa" + EOL +
703 "aaaaa";
704
705
706 final StringBuffer sb = new StringBuffer();
707 new HelpFormatter().renderWrappedText(sb, width, padding, expected);
708 assertEquals(expected, sb.toString(), "multi line text");
709 }
710
711 @Test
712 void testRenderWrappedTextMultiLinePadded() {
713
714 final int width = 16;
715 final int padding = 4;
716
717 final String text = "aaaa aaaa aaaa" + EOL +
718 "aaaaaa" + EOL +
719 "aaaaa";
720 final String expected = "aaaa aaaa aaaa" + EOL +
721 " aaaaaa" + EOL +
722 " aaaaa";
723
724
725 final StringBuffer sb = new StringBuffer();
726 new HelpFormatter().renderWrappedText(sb, width, padding, text);
727 assertEquals(expected, sb.toString(), "multi-line padded text");
728 }
729
730 @Test
731 void testRenderWrappedTextSingleLine() throws IOException {
732
733 final int width = 12;
734 final int padding = 0;
735 final String text = "This is a test.";
736 final String expected = "This is a" + EOL + "test.";
737
738 final StringBuffer sb = new StringBuffer();
739 new HelpFormatter().renderWrappedText(sb, width, padding, text);
740 assertEquals(expected, sb.toString(), "single line text");
741
742 final HelpFormatter spy = spy(new HelpFormatter());
743 when(spy.appendWrappedText(sb, width, padding, text)).thenThrow(IOException.class);
744 assertThrows(UncheckedIOException.class, () -> spy.renderWrappedText(sb, width, padding, text));
745
746 }
747
748 @Test
749 void testRenderWrappedTextSingleLinePadded() {
750
751 final int width = 12;
752 final int padding = 4;
753 final String text = "This is a test.";
754 final String expected = "This is a" + EOL + " test.";
755
756 final StringBuffer sb = new StringBuffer();
757 new HelpFormatter().renderWrappedText(sb, width, padding, text);
758 assertEquals(expected, sb.toString(), "single line padded text");
759 }
760
761 @Test
762 void testRenderWrappedTextSingleLinePadded2() {
763
764 final int width = 53;
765 final int padding = 24;
766
767 final String text = " -p,--period <PERIOD> PERIOD is time duration of form " +
768 "DATE[-DATE] where DATE has form YYYY[MM[DD]]";
769 final String expected = " -p,--period <PERIOD> PERIOD is time duration of" + EOL +
770 " form DATE[-DATE] where DATE" + EOL +
771 " has form YYYY[MM[DD]]";
772
773
774 final StringBuffer sb = new StringBuffer();
775 new HelpFormatter().renderWrappedText(sb, width, padding, text);
776 assertEquals(expected, sb.toString(), "single line padded text 2");
777 }
778
779 @Test
780 void testRenderWrappedTextWordCut() {
781 final int width = 7;
782 final int padding = 0;
783 final String text = "Thisisatest.";
784 final String expected = "Thisisa" + EOL + "test.";
785
786 final StringBuffer sb = new StringBuffer();
787 new HelpFormatter().renderWrappedText(sb, width, padding, text);
788 assertEquals(expected, sb.toString(), "cut and wrap");
789 }
790
791 @Test
792 void testRtrim() {
793 final HelpFormatter formatter = new HelpFormatter();
794
795 assertNull(formatter.rtrim(null));
796 assertEquals("", formatter.rtrim(""));
797 assertEquals(" foo", formatter.rtrim(" foo "));
798 }
799
800 @Test
801 void testUsageWithLongOptSeparator() {
802 final Options options = new Options();
803 options.addOption("f", true, "the file");
804 options.addOption(Option.builder("s").longOpt("size").desc("the size").hasArg().argName("SIZE").get());
805 options.addOption(Option.builder().longOpt("age").desc("the age").hasArg().get());
806
807 final HelpFormatter formatter = new HelpFormatter();
808 formatter.setLongOptSeparator("=");
809
810 final StringWriter out = new StringWriter();
811
812 formatter.printUsage(new PrintWriter(out), 80, "create", options);
813
814 assertEquals("usage: create [--age=<arg>] [-f <arg>] [-s <SIZE>]", out.toString().trim());
815 }
816 }