001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.cli2.option;
018
019import java.text.ParseException;
020
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collections;
024import java.util.HashSet;
025import java.util.Iterator;
026import java.util.List;
027import java.util.ListIterator;
028import java.util.Set;
029
030import org.apache.commons.cli2.Argument;
031import org.apache.commons.cli2.DisplaySetting;
032import org.apache.commons.cli2.HelpLine;
033import org.apache.commons.cli2.Option;
034import org.apache.commons.cli2.OptionException;
035import org.apache.commons.cli2.WriteableCommandLine;
036import org.apache.commons.cli2.builder.ArgumentBuilder;
037import org.apache.commons.cli2.builder.GroupBuilder;
038import org.apache.commons.cli2.commandline.WriteableCommandLineImpl;
039import org.apache.commons.cli2.resource.ResourceConstants;
040import org.apache.commons.cli2.resource.ResourceHelper;
041import org.apache.commons.cli2.validation.DateValidator;
042import org.apache.commons.cli2.validation.DateValidatorTest;
043
044/**
045 * @author Rob Oxspring
046 */
047public class ArgumentTest
048    extends ArgumentTestCase {
049    private ResourceHelper resources = ResourceHelper.getResourceHelper();
050
051    public static Argument buildUsernameArgument() {
052        return new ArgumentImpl("username", "The user to connect as", 1, 1, '\0', '\0', null,
053                                ArgumentImpl.DEFAULT_CONSUME_REMAINING, null, 0);
054    }
055
056    public static Argument buildHostArgument() {
057        return new ArgumentImpl("host", "The host name", 2, 3, '\0', ',', null, null, null, 0);
058    }
059
060    public static Argument buildPathArgument() {
061        return new ArgumentImpl("path", "The place to look for files", 1, Integer.MAX_VALUE, '=',
062                                ';', null, ArgumentImpl.DEFAULT_CONSUME_REMAINING, null, 0);
063    }
064
065    public static Argument buildDateLimitArgument() {
066        return new ArgumentImpl("limit", "the last acceptable date", 0, 1, '=', '\0',
067                                new DateValidator(DateValidatorTest.YYYY_MM_DD), null, null, 0);
068    }
069
070    public static Argument buildTargetsArgument() {
071        return new ArgumentImpl("target", "The targets ant should build", 0, Integer.MAX_VALUE,
072                                '\0', ',', null, null, null, 0);
073    }
074
075    public static Argument buildSizeArgument() {
076        List defaults = new ArrayList();
077        defaults.add("10");
078
079        return new ArgumentImpl("size", "The number of units", 1, 1, '\0', '\0', null,
080                                ArgumentImpl.DEFAULT_CONSUME_REMAINING, defaults, 0);
081    }
082
083    public static Argument buildBoundsArgument() {
084        List defaults = new ArrayList();
085        defaults.add("5");
086        defaults.add("10");
087
088        return new ArgumentImpl("size", "The number of units", 2, 2, '\0', '\0', null,
089                                ArgumentImpl.DEFAULT_CONSUME_REMAINING, defaults, 0);
090    }
091
092    public void testNew() {
093        try {
094            new ArgumentImpl("limit", "the last acceptable date", 10, 5, '=', '\0',
095                             new DateValidator(DateValidatorTest.YYYY_MM_DD), null, null, 0);
096        } catch (IllegalArgumentException e) {
097            assertEquals(resources.getMessage("Argument.minimum.exceeds.maximum"), e.getMessage());
098        }
099
100        {
101            ArgumentImpl arg =
102                new ArgumentImpl(null, "the last acceptable date", 5, 5, '=', '\0',
103                                 new DateValidator(DateValidatorTest.YYYY_MM_DD), null, null, 0);
104            assertEquals("wrong arg name", "arg", arg.getPreferredName());
105        }
106
107        {
108            List defaults = new ArrayList();
109
110            try {
111                new ArgumentImpl(null, "the last acceptable date", 1, 1, '=', '\0',
112                                 new DateValidator(DateValidatorTest.YYYY_MM_DD), null, defaults, 0);
113            } catch (IllegalArgumentException exp) {
114                assertEquals(resources.getMessage("Argument.too.few.defaults"), exp.getMessage());
115            }
116        }
117
118        try {
119            List defaults = new ArrayList();
120            defaults.add("1");
121            defaults.add("2");
122
123            new ArgumentImpl(null, "the last acceptable date", 1, 1, '=', '\0',
124                             new DateValidator(DateValidatorTest.YYYY_MM_DD), null, defaults, 0);
125        } catch (IllegalArgumentException exp) {
126            assertEquals(resources.getMessage("Argument.too.many.defaults"), exp.getMessage());
127        }
128    }
129
130    /*
131     * (non-Javadoc)
132     *
133     * @see org.apache.commons.cli2.ArgumentTestCase#testProcessValues()
134     */
135    public void testProcessValues()
136        throws OptionException {
137        final Argument option = buildUsernameArgument();
138        final List args = list("rob");
139        final WriteableCommandLine commandLine = commandLine(option, args);
140        final ListIterator iterator = args.listIterator();
141        option.processValues(commandLine, iterator, option);
142
143        assertFalse(iterator.hasNext());
144        assertTrue(commandLine.hasOption(option));
145        assertTrue(commandLine.hasOption("username"));
146        assertEquals("rob", commandLine.getValue(option));
147    }
148
149    public void testProcessValues_BoundaryQuotes()
150        throws OptionException {
151        final Argument option = buildUsernameArgument();
152        final List args = list("\"rob\"");
153        final WriteableCommandLine commandLine = commandLine(option, args);
154        final ListIterator iterator = args.listIterator();
155        option.processValues(commandLine, iterator, option);
156
157        assertFalse(iterator.hasNext());
158        assertTrue(commandLine.hasOption(option));
159        assertTrue(commandLine.hasOption("username"));
160        assertEquals("rob", commandLine.getValue(option));
161    }
162
163    public void testProcessValues_SpareValues()
164        throws OptionException {
165        final Argument option = buildUsernameArgument();
166        final List args = list("rob", "secret");
167        final WriteableCommandLine commandLine = commandLine(option, args);
168        final ListIterator iterator = args.listIterator();
169        option.processValues(commandLine, iterator, option);
170
171        assertTrue(iterator.hasNext());
172        assertTrue(commandLine.hasOption(option));
173        assertTrue(commandLine.hasOption("username"));
174        assertEquals("rob", commandLine.getValue(option));
175    }
176
177    public void testProcessValues_Optional() {
178        final Argument option = buildTargetsArgument();
179        final List args = list();
180        final WriteableCommandLine commandLine = commandLine(option, args);
181        final ListIterator iterator = args.listIterator();
182
183        try {
184            option.processValues(commandLine, iterator, option);
185        } catch (final OptionException mve) {
186            assertEquals(option, mve.getOption());
187            assertEquals("Missing value(s) target [target ...]", mve.getMessage());
188        }
189
190        assertFalse(iterator.hasNext());
191        assertFalse(commandLine.hasOption(option));
192        assertFalse(commandLine.hasOption("username"));
193        assertTrue(commandLine.getValues(option).isEmpty());
194    }
195
196    public void testProcessValues_Multiple()
197        throws OptionException {
198        final Argument option = buildTargetsArgument();
199        final List args = list("compile", "test", "docs");
200        final WriteableCommandLine commandLine = commandLine(option, args);
201        final ListIterator iterator = args.listIterator();
202        option.processValues(commandLine, iterator, option);
203
204        assertFalse(iterator.hasNext());
205        assertTrue(commandLine.hasOption(option));
206        assertTrue(commandLine.hasOption("target"));
207        assertFalse(commandLine.getValues(option).isEmpty());
208        assertListContentsEqual(args, commandLine.getValues(option));
209    }
210
211    public void testProcessValues_Contracted()
212        throws OptionException {
213        final Argument option = buildTargetsArgument();
214        final List args = list("compile,test,javadoc", "checkstyle,jdepend");
215        final WriteableCommandLine commandLine = commandLine(option, args);
216        final ListIterator iterator = args.listIterator();
217        option.processValues(commandLine, iterator, option);
218
219        assertFalse(iterator.hasNext());
220        assertTrue(commandLine.hasOption(option));
221        assertTrue(commandLine.hasOption("target"));
222        assertListContentsEqual(list("compile", "test", "javadoc", "checkstyle", "jdepend"),
223                                commandLine.getValues(option));
224    }
225
226    public void testProcessValues_ContractedTooFew() {
227        final Argument option = buildHostArgument();
228        final List args = list("box1");
229        final WriteableCommandLine commandLine = commandLine(option, args);
230        final ListIterator iterator = args.listIterator();
231
232        try {
233            option.processValues(commandLine, iterator, option);
234            option.validate(commandLine);
235            fail("Expected MissingValueException");
236        } catch (OptionException mve) {
237            assertSame(option, mve.getOption());
238        }
239    }
240
241    public void testProcessValues_ContractedTooMany() {
242        final Argument option = buildHostArgument();
243        final List args = list("box1,box2,box3,box4");
244        final WriteableCommandLine commandLine = commandLine(option, args);
245        final ListIterator iterator = args.listIterator();
246
247        try {
248            option.processValues(commandLine, iterator, option);
249            option.validate(commandLine);
250            fail("Expected MissingValueException");
251        } catch (OptionException mve) {
252            assertSame(option, mve.getOption());
253        }
254    }
255
256    /*
257     * (non-Javadoc)
258     *
259     * @see org.apache.commons.cli2.OptionTestCase#testCanProcess()
260     */
261    public void testCanProcess() {
262        final Argument option = buildTargetsArgument();
263        assertTrue(option.canProcess(new WriteableCommandLineImpl(option, null), "any value"));
264    }
265
266    /*
267     * (non-Javadoc)
268     *
269     * @see org.apache.commons.cli2.OptionTestCase#testPrefixes()
270     */
271    public void testPrefixes() {
272        final Argument option = buildTargetsArgument();
273        assertTrue(option.getPrefixes().isEmpty());
274    }
275
276    /*
277     * (non-Javadoc)
278     *
279     * @see org.apache.commons.cli2.OptionTestCase#testProcess()
280     */
281    public void testProcess()
282        throws OptionException {
283        final Argument option = buildPathArgument();
284        final List args = list("-path=/lib;/usr/lib;/usr/local/lib");
285        final WriteableCommandLine commandLine = commandLine(option, args);
286        final ListIterator iterator = args.listIterator();
287        option.process(commandLine, iterator);
288
289        assertFalse(iterator.hasNext());
290        assertTrue(commandLine.hasOption(option));
291        assertTrue(commandLine.hasOption("path"));
292        assertListContentsEqual(list("-path=/lib", "/usr/lib", "/usr/local/lib"),
293                                commandLine.getValues(option));
294    }
295
296    /*
297     * (non-Javadoc)
298     *
299     * @see org.apache.commons.cli2.OptionTestCase#testTriggers()
300     */
301    public void testTriggers() {
302        final Argument option = buildTargetsArgument();
303        assertTrue(option.getTriggers().isEmpty());
304    }
305
306    /*
307     * (non-Javadoc)
308     *
309     * @see org.apache.commons.cli2.OptionTestCase#testValidate()
310     */
311    public void testValidate()
312        throws OptionException {
313        final Argument option = buildUsernameArgument();
314        final WriteableCommandLine commandLine = commandLine(option, list());
315
316        commandLine.addValue(option, "rob");
317
318        option.validate(commandLine);
319    }
320
321    public void testValidate_Minimum() {
322        final Argument option = buildUsernameArgument();
323        final WriteableCommandLine commandLine = commandLine(option, list());
324
325        try {
326            option.validate(commandLine);
327            fail("UnexpectedValue");
328        } catch (OptionException mve) {
329            assertEquals(option, mve.getOption());
330        }
331    }
332
333    public void testRequired() {
334        {
335            final Argument arg = buildBoundsArgument();
336
337            assertTrue("not required", arg.isRequired());
338        }
339
340        {
341            final Argument arg = buildTargetsArgument();
342
343            assertFalse("should not be required", arg.isRequired());
344        }
345    }
346
347    public void testValidate_Maximum() {
348        final Argument option = buildUsernameArgument();
349        final WriteableCommandLine commandLine = commandLine(option, list());
350
351        commandLine.addValue(option, "rob");
352        commandLine.addValue(option, "oxspring");
353
354        try {
355            option.validate(commandLine);
356            fail("UnexpectedValue");
357        } catch (OptionException uve) {
358            assertEquals(option, uve.getOption());
359        }
360    }
361
362    public void testValidate_Validator()
363        throws OptionException, ParseException {
364        final Argument option = buildDateLimitArgument();
365        final WriteableCommandLine commandLine = commandLine(option, list());
366
367        commandLine.addValue(option, "2004-01-01");
368
369        option.validate(commandLine, option);
370        assertContentsEqual(Arrays.asList(new Object[] {
371                                              DateValidatorTest.YYYY_MM_DD.parse("2004-01-01")
372                                          }), commandLine.getValues(option));
373    }
374
375    public void testValidate_ValidatorInvalidDate()
376        throws OptionException, ParseException {
377        final Argument option = buildDateLimitArgument();
378        final WriteableCommandLine commandLine = commandLine(option, list());
379
380        commandLine.addValue(option, "12-12-2004");
381
382        try {
383            option.validate(commandLine, option);
384        } catch (OptionException exp) {
385            OptionException e =
386                new OptionException(option, ResourceConstants.ARGUMENT_UNEXPECTED_VALUE,
387                                    "12-12-2004");
388            assertEquals("wrong exception message", e.getMessage(), exp.getMessage());
389        }
390    }
391
392    /*
393     * (non-Javadoc)
394     *
395     * @see org.apache.commons.cli2.OptionTestCase#testAppendUsage()
396     */
397    public void testAppendUsage() {
398        final Option option = buildUsernameArgument();
399        final StringBuffer buffer = new StringBuffer();
400        option.appendUsage(buffer, DisplaySetting.ALL, null);
401
402        assertEquals("<username>", buffer.toString());
403    }
404
405    public void testAppendUsage_Infinite() {
406        final Option option = buildTargetsArgument();
407        final StringBuffer buffer = new StringBuffer();
408        option.appendUsage(buffer, DisplaySetting.ALL, null);
409
410        assertEquals("[<target1> [<target2> ...]]", buffer.toString());
411    }
412
413    public void testAppendUsage_InfiniteNoOptional() {
414        final Option option = buildTargetsArgument();
415        final StringBuffer buffer = new StringBuffer();
416        final Set settings = new HashSet(DisplaySetting.ALL);
417        settings.remove(DisplaySetting.DISPLAY_OPTIONAL);
418        option.appendUsage(buffer, settings, null);
419
420        assertEquals("<target1> [<target2> ...]", buffer.toString());
421    }
422
423    public void testAppendUsage_InfiniteNoNumbering() {
424        final Option option = buildTargetsArgument();
425        final StringBuffer buffer = new StringBuffer();
426        final Set settings = new HashSet(DisplaySetting.ALL);
427        settings.remove(DisplaySetting.DISPLAY_ARGUMENT_NUMBERED);
428        option.appendUsage(buffer, settings, null);
429
430        assertEquals("[<target> [<target> ...]]", buffer.toString());
431    }
432
433    public void testAppendUsage_Minimum() {
434        final Option option = buildHostArgument();
435        final StringBuffer buffer = new StringBuffer();
436        option.appendUsage(buffer, DisplaySetting.ALL, null);
437
438        assertEquals("<host1> <host2> [<host3>]", buffer.toString());
439    }
440
441    /*
442     * (non-Javadoc)
443     *
444     * @see org.apache.commons.cli2.OptionTestCase#testGetPreferredName()
445     */
446    public void testGetPreferredName() {
447        final Option option = buildPathArgument();
448        assertEquals("path", option.getPreferredName());
449    }
450
451    /*
452     * (non-Javadoc)
453     *
454     * @see org.apache.commons.cli2.OptionTestCase#testGetDescription()
455     */
456    public void testGetDescription() {
457        final Option option = buildHostArgument();
458        assertEquals("The host name", option.getDescription());
459    }
460
461    /*
462     * (non-Javadoc)
463     *
464     * @see org.apache.commons.cli2.OptionTestCase#testHelpLines()
465     */
466    public void testHelpLines() {
467        final Option option = buildHostArgument();
468        final List lines = option.helpLines(0, DisplaySetting.ALL, null);
469        final Iterator i = lines.iterator();
470
471        final HelpLine line1 = (HelpLine) i.next();
472        assertEquals(0, line1.getIndent());
473        assertEquals(option, line1.getOption());
474
475        assertFalse(i.hasNext());
476    }
477
478    public void testCanProcess_ConsumeRemaining() {
479        final Option option = buildUsernameArgument();
480
481        assertTrue(option.canProcess(new WriteableCommandLineImpl(option, null), "--"));
482    }
483
484    public void testProcess_ConsumeRemaining()
485        throws OptionException {
486        final Option option = buildPathArgument();
487        final List args = list("options", "--", "--ignored", "-Dprop=val");
488        final WriteableCommandLine commandLine = commandLine(option, args);
489        final ListIterator iterator = args.listIterator();
490
491        option.process(commandLine, iterator);
492
493        final List values = commandLine.getValues(option);
494        assertTrue(values.contains("options"));
495        assertTrue(values.contains("--ignored"));
496        assertTrue(values.contains("-Dprop=val"));
497        assertEquals(3, values.size());
498        assertFalse(iterator.hasNext());
499    }
500
501    public void testProcess_ConsumeNothing() {
502        final Option option = buildPathArgument();
503        final List args = list("--");
504        final WriteableCommandLine commandLine = commandLine(option, args);
505        final ListIterator iterator = args.listIterator();
506
507        try {
508            option.process(commandLine, iterator);
509            option.validate(commandLine);
510            fail("Missing Value!");
511        } catch (OptionException mve) {
512            assertEquals(option, mve.getOption());
513            assertEquals("Missing value(s) path [path ...]", mve.getMessage());
514        }
515
516        assertTrue(commandLine.getValues(option).isEmpty());
517        assertFalse(iterator.hasNext());
518    }
519
520    //    public void testProcess_DefinedDefaultValue() throws OptionException {
521    //        final Option size = buildSizeArgument();
522    //        final List args = list();
523    //        final WriteableCommandLine commandLine = commandLine(size, args);
524    //        final ListIterator iterator = args.listIterator();
525    //
526    //        size.process(commandLine, iterator);
527    //
528    //        assertEquals("10", commandLine.getValue(size));
529    //    }
530    //
531    //    public void testProcess_DefinedDefaultValues() throws OptionException {
532    //        final Option bounds = buildBoundsArgument();
533    //        final List args = list();
534    //        final WriteableCommandLine commandLine = commandLine(bounds, args);
535    //        final ListIterator iterator = args.listIterator();
536    //
537    //        bounds.process(commandLine, iterator);
538    //
539    //        List values = new ArrayList();
540    //        values.add("5");
541    //        values.add("10");
542    //        assertEquals(values, commandLine.getValues(bounds));
543    //    }
544    public void testProcess_InterrogatedDefaultValue()
545        throws OptionException {
546        final Option size = buildSizeArgument();
547        final List args = list();
548        final WriteableCommandLine commandLine = commandLine(size, args);
549        final ListIterator iterator = args.listIterator();
550
551        size.process(commandLine, iterator);
552
553        assertEquals(new Integer(20), commandLine.getValue(size, new Integer(20)));
554    }
555
556    public void testTooFewDefaults() {
557        List defaults = new ArrayList();
558        defaults.add("5");
559
560        try {
561            new ArgumentImpl("size", "The number of units", 2, 2, '\0', '\0', null,
562                             ArgumentImpl.DEFAULT_CONSUME_REMAINING, defaults, 0);
563        } catch (IllegalArgumentException exp) {
564            assertEquals("wrong exception message",
565                         ResourceHelper.getResourceHelper().getMessage(ResourceConstants.ARGUMENT_TOO_FEW_DEFAULTS),
566                         exp.getMessage());
567        }
568    }
569
570    public void testTooManyDefaults() {
571        List defaults = new ArrayList();
572        defaults.add("5");
573        defaults.add("10");
574        defaults.add("15");
575
576        try {
577            new ArgumentImpl("size", "The number of units", 2, 2, '\0', '\0', null,
578                             ArgumentImpl.DEFAULT_CONSUME_REMAINING, defaults, 0);
579        } catch (IllegalArgumentException exp) {
580            assertEquals("wrong exception message",
581                         ResourceHelper.getResourceHelper().getMessage(ResourceConstants.ARGUMENT_TOO_MANY_DEFAULTS),
582                         exp.getMessage());
583        }
584    }
585
586    public void testProcess_InterrogatedDefaultValues()
587        throws OptionException {
588        final Option bounds = buildBoundsArgument();
589        final List args = list();
590        final WriteableCommandLine commandLine = commandLine(bounds, args);
591        final ListIterator iterator = args.listIterator();
592
593        bounds.process(commandLine, iterator);
594
595        // test with values
596        List values = new ArrayList();
597        values.add("50");
598        values.add("100");
599        assertEquals(values, commandLine.getValues(bounds, values));
600
601        // test without values
602        assertEquals(Collections.EMPTY_LIST, commandLine.getValues(bounds, null));
603    }
604
605    public void testProcess_StripBoundaryQuotes()
606        throws OptionException {
607        final Option bounds = buildBoundsArgument();
608        final List args = list();
609        final WriteableCommandLine commandLine = commandLine(bounds, args);
610        final ListIterator iterator = args.listIterator();
611
612        bounds.process(commandLine, iterator);
613
614        List values = new ArrayList();
615        values.add("50\"");
616        values.add("\"100");
617        assertEquals(values, commandLine.getValues(bounds, values));
618    }
619
620    public void testSourceDestArgument() {
621        final ArgumentBuilder abuilder = new ArgumentBuilder();
622        final GroupBuilder gbuilder = new GroupBuilder();
623        final Argument inputfiles =
624            abuilder.withName("input").withMinimum(0).withMaximum(0).create();
625        final Argument bad_outputfile =
626            abuilder.withName("output").withMinimum(1).withMaximum(2).create();
627
628        try {
629            final Argument targets = new SourceDestArgument(inputfiles, bad_outputfile);
630        } catch (final IllegalArgumentException exp) {
631            assertEquals("wrong exception message",
632                         ResourceHelper.getResourceHelper().getMessage(ResourceConstants.SOURCE_DEST_MUST_ENFORCE_VALUES),
633                         exp.getMessage());
634        }
635
636        final Argument outputfile =
637            abuilder.withName("output").withMinimum(1).withMaximum(1).create();
638
639        final Argument targets = new SourceDestArgument(inputfiles, outputfile);
640        final StringBuffer buffer = new StringBuffer("test content");
641        targets.appendUsage(buffer, Collections.EMPTY_SET, null);
642
643        assertTrue("buffer not added", buffer.toString().startsWith("test content"));
644        assertFalse("space added", buffer.charAt(12) == ' ');
645    }
646}