1   package com.lexicalscope.jewel.cli;
2   
3   import static org.hamcrest.MatcherAssert.assertThat;
4   import static org.hamcrest.Matchers.equalTo;
5   
6   import java.lang.reflect.ParameterizedType;
7   import java.lang.reflect.Type;
8   
9   import org.junit.Test;
10  
11  /**
12   * Tests {@link OptionSpecificationImpl} using a generic parameterized type as
13   * interface return type
14   * 
15   * @author Eduard Weissmann
16   */
17  public class TestOptionGenericTypes {
18      public static class SomeOtherType {}
19  
20      public static class MyGenericType<T> {
21          private final String stringValue;
22  
23          public MyGenericType(final String stringValue) {
24              this.stringValue = stringValue;
25          }
26  
27          String getStringValue() {
28              return stringValue;
29          }
30      }
31  
32      public static class MyGenericTypeWithTypeArgument<T> {
33          private final String stringValue;
34          private final Type type;
35  
36          public MyGenericTypeWithTypeArgument(final String stringValue, final Type type) {
37              this.stringValue = stringValue;
38              this.type = type;
39          }
40  
41          Type getType() {
42              return type;
43          }
44  
45          String getStringValue() {
46              return stringValue;
47          }
48      }
49  
50      public static class MyGenericTypeWithTwoConstructors<T> {
51          private final String stringValue;
52          private Type type;
53  
54          public MyGenericTypeWithTwoConstructors(final String stringValue) {
55              this.stringValue = stringValue;
56          }
57  
58          public MyGenericTypeWithTwoConstructors(final String stringValue, final Type type) {
59              this.stringValue = stringValue;
60              this.type = type;
61          }
62  
63          Type getType() {
64              return type;
65          }
66  
67          String getStringValue() {
68              return stringValue;
69          }
70      }
71  
72      @CommandLineInterface public interface CliWithGenericReturnType {
73          @Option MyGenericType<SomeOtherType> getOptionOne();
74          boolean isOptionOne();
75  
76          @Option MyGenericTypeWithTypeArgument<SomeOtherType> getOptionTwo();
77          boolean isOptionTwo();
78  
79          @Option MyGenericTypeWithTwoConstructors<SomeOtherType> getOptionThree();
80          boolean isOptionThree();
81      }
82  
83      @Test public void genericTypesCanBeUsedAsOptionValues() throws ArgumentValidationException {
84          final CliWithGenericReturnType parsedArguments = CliFactory.parseArguments(CliWithGenericReturnType.class,
85                  new String[] { "--optionOne", "my string" });
86  
87          assertThat(parsedArguments.getOptionOne().getStringValue(), equalTo("my string"));
88      }
89  
90      @Test public void genericTypeWithAConstructorTakingTypeIsPassedTheGenericReturnTypeOfTheMethod()
91              throws ArgumentValidationException {
92          final CliWithGenericReturnType parsedArguments = CliFactory.parseArguments(CliWithGenericReturnType.class,
93                  new String[] { "--optionTwo", "my string" });
94  
95          assertThat(parsedArguments.getOptionTwo().getStringValue(), equalTo("my string"));
96          assertThat(
97                  ((ParameterizedType) parsedArguments.getOptionTwo().getType()).getActualTypeArguments()[0],
98                  equalTo((Type) SomeOtherType.class));
99      }
100 
101     @Test public void stringConstructorIsPreferedToConstructorContainingType() throws ArgumentValidationException {
102         final CliWithGenericReturnType parsedArguments = CliFactory.parseArguments(CliWithGenericReturnType.class,
103                 new String[] { "--optionThree", "my string" });
104 
105         assertThat(parsedArguments.getOptionThree().getStringValue(), equalTo("my string"));
106         assertThat(parsedArguments.getOptionThree().getType(), equalTo(null));
107     }
108 }