1   package com.lexicalscope.jewel.cli.validation;
2   
3   import static com.lexicalscope.fluentreflection.FluentReflection.type;
4   import static com.lexicalscope.jewel.cli.ValidationFailureMatcher.validationError;
5   import static com.lexicalscope.jewel.cli.parser.DefaultArgumentParserFactory.createDefaultArgumentParser;
6   import static org.hamcrest.Matchers.contains;
7   import static org.junit.Assert.*;
8   
9   import java.util.List;
10  
11  import org.junit.Test;
12  
13  import com.lexicalscope.jewel.cli.ArgumentCollectionBuilder;
14  import com.lexicalscope.jewel.cli.ArgumentValidationException;
15  import com.lexicalscope.jewel.cli.InterfaceOptionsSpecificationParser;
16  import com.lexicalscope.jewel.cli.Option;
17  import com.lexicalscope.jewel.cli.Unparsed;
18  import com.lexicalscope.jewel.cli.ValidationErrorBuilderImpl;
19  import com.lexicalscope.jewel.cli.ValidationFailureType;
20  import com.lexicalscope.jewel.cli.examples.RmExample;
21  
22  public class TestArgumentValidatorImpl2 {
23      public interface NoValue {
24          @Option boolean getName0();
25  
26          @Option boolean getName1();
27      }
28  
29      public interface SingleValue {
30          @Option String getName();
31      }
32  
33      public interface MultipleValue {
34          @Option List<String> getName();
35  
36          @Unparsed List<String> getUnparsed();
37      }
38  
39      public interface ExtraValue {
40          @Option List<String> getName0();
41  
42          @Option String getName1();
43  
44          @Unparsed List<String> getUnparsed();
45      }
46  
47      public interface OptionalOption {
48          @Option String getName0();
49  
50          @Option String getName1();
51          boolean isName1();
52      }
53  
54      public interface OptionAndUnparsed {
55          @Option String getName0();
56  
57          @Unparsed List<String> getRemainingArguments();
58      }
59  
60      @Test public void testMissingOption() {
61          try {
62              validate(new String[] { "--name1", "value" }, OptionalOption.class);
63              fail();
64          } catch (final ArgumentValidationException e) {
65              assertThat(e.getValidationFailures(), contains(validationError(ValidationFailureType.MissingOption)));
66          }
67      }
68  
69      @Test public void testMultipleValue() throws ArgumentValidationException {
70          validate(new String[] { "--name", "a", "b" }, MultipleValue.class);
71      }
72  
73      @Test public void testMultipleValueEndOfArguments() throws ArgumentValidationException {
74          final OptionCollectionImpl validated =
75                  validate(new String[] { "--name", "a", "b", "--", "c", "d" }, MultipleValue.class);
76          assertEquals(2, validated.getUnparsed().size());
77          assertEquals(2, validated.getValues("name").size());
78      }
79  
80      @Test public void testMultipleValueNotEndOfArguments() throws ArgumentValidationException {
81          final OptionCollectionImpl validated =
82                  validate(
83                          new String[] { "--name0", "a", "b", "--name1", "c", "d", "e", "--", "f", "g" },
84                          ExtraValue.class);
85          assertEquals(4, validated.getUnparsed().size());
86          assertEquals(2, validated.getValues("name0").size());
87          assertEquals(1, validated.getValues("name1").size());
88      }
89  
90      @Test public void testAdjacentShortOptions() throws ArgumentValidationException {
91          final OptionCollectionImpl validated = validate(new String[] { "-vrf", "./" }, RmExample.class);
92          assertEquals(1, validated.getUnparsed().size());
93      }
94  
95      @Test public void testSingleValue() throws ArgumentValidationException {
96          validate(new String[] { "--name", "a" }, MultipleValue.class);
97      }
98  
99      @Test public void testExtraOption() {
100         try {
101             validate(new String[] { "--name1", "value", "wrong", "--name0" }, ExtraValue.class);
102             fail();
103         } catch (final ArgumentValidationException e) {
104             assertThat(e.getValidationFailures(), contains(validationError(ValidationFailureType.UnexpectedAdditionalValue)));
105         }
106     }
107 
108     @Test public void testMissingValue() {
109         try {
110             validate(new String[] { "--name" }, SingleValue.class);
111             fail();
112         } catch (final ArgumentValidationException e) {
113             assertThat(e.getValidationFailures(), contains(validationError(ValidationFailureType.MissingValue)));
114         }
115     }
116 
117     @Test public void testUnexpectedValue() {
118         try {
119             validate(new String[] { "--name1", "value", "--name0" }, NoValue.class);
120             fail();
121         } catch (final ArgumentValidationException e) {
122             assertThat(e.getValidationFailures(), contains(validationError(ValidationFailureType.UnexpectedValue)));
123         }
124     }
125 
126     @Test public void testMissingMultipleValue() throws ArgumentValidationException {
127         validate(new String[] { "--name" }, MultipleValue.class);
128         // TODO[tim]:support minimum/maximum value list lengths
129     }
130 
131     @Test public void testOptionAndUnparsed() throws ArgumentValidationException {
132         final OptionCollectionImpl validated =
133                 validate(new String[] { "--name0", "value0", "remaining0" }, OptionAndUnparsed.class);
134         assertEquals(1, validated.getUnparsed().size());
135     }
136 
137     private <O> OptionCollectionImpl validate(final String[] arguments, final Class<O> klass)
138             throws ArgumentValidationException {
139         final ArgumentValidatorImpl<O> impl =
140                 new ArgumentValidatorImpl<O>(
141                         InterfaceOptionsSpecificationParser.<O>createOptionsSpecificationImpl(type(klass)), new ValidationErrorBuilderImpl());
142 
143         final ArgumentCollectionBuilder parsedArguments = new ArgumentCollectionBuilder();
144         createDefaultArgumentParser().parseArguments(parsedArguments, arguments);
145 
146         return (OptionCollectionImpl) parsedArguments.processArguments(impl);
147     }
148 }