1/*
2 * Copyright (C) 2008 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.collect.testing.features;
18
19import static com.google.common.truth.Truth.assertThat;
20
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Sets;
23
24import junit.framework.TestCase;
25
26import java.lang.annotation.Inherited;
27import java.lang.annotation.Retention;
28import java.lang.annotation.RetentionPolicy;
29import java.lang.reflect.Method;
30import java.util.Collections;
31import java.util.Set;
32
33/**
34 * @author George van den Driessche
35 */
36// Enum values use constructors with generic varargs.
37@SuppressWarnings("unchecked")
38public class FeatureUtilTest extends TestCase {
39  interface ExampleBaseInterface {
40    void behave();
41  }
42
43  interface ExampleDerivedInterface extends ExampleBaseInterface {
44    void misbehave();
45  }
46
47  enum ExampleBaseFeature implements Feature<ExampleBaseInterface> {
48    BASE_FEATURE_1,
49    BASE_FEATURE_2;
50
51    @Override
52    public Set<Feature<? super ExampleBaseInterface>> getImpliedFeatures() {
53      return Collections.emptySet();
54    }
55
56    @Retention(RetentionPolicy.RUNTIME)
57    @Inherited
58    @TesterAnnotation
59    @interface Require {
60      ExampleBaseFeature[] value() default {};
61      ExampleBaseFeature[] absent() default {};
62    }
63  }
64
65  enum ExampleDerivedFeature implements Feature<ExampleDerivedInterface>{
66    DERIVED_FEATURE_1,
67    DERIVED_FEATURE_2(ExampleBaseFeature.BASE_FEATURE_1),
68    DERIVED_FEATURE_3,
69
70    COMPOUND_DERIVED_FEATURE(
71        DERIVED_FEATURE_1,
72        DERIVED_FEATURE_2,
73        ExampleBaseFeature.BASE_FEATURE_2);
74
75    private Set<Feature<? super ExampleDerivedInterface>> implied;
76
77    ExampleDerivedFeature(
78        Feature<? super ExampleDerivedInterface> ... implied) {
79      this.implied = ImmutableSet.copyOf(implied);
80    }
81
82    @Override
83    public Set<Feature<? super ExampleDerivedInterface>> getImpliedFeatures() {
84      return implied;
85    }
86
87    @Retention(RetentionPolicy.RUNTIME)
88    @Inherited
89    @TesterAnnotation
90    @interface Require {
91      ExampleDerivedFeature[] value() default {};
92      ExampleDerivedFeature[] absent() default {};
93    }
94  }
95
96  @Retention(RetentionPolicy.RUNTIME)
97  @interface NonTesterAnnotation {
98  }
99
100  @ExampleBaseFeature.Require({ExampleBaseFeature.BASE_FEATURE_1})
101  private static abstract class ExampleBaseInterfaceTester extends TestCase {
102    protected final void doNotActuallyRunThis() {
103      fail("Nobody's meant to actually run this!");
104    }
105  }
106
107  @NonTesterAnnotation
108  @ExampleDerivedFeature.Require({ExampleDerivedFeature.DERIVED_FEATURE_2})
109  private static class ExampleDerivedInterfaceTester
110      extends ExampleBaseInterfaceTester {
111    // Exists to test that our framework doesn't run it:
112    @SuppressWarnings("unused")
113    @ExampleDerivedFeature.Require({
114        ExampleDerivedFeature.DERIVED_FEATURE_1,
115        ExampleDerivedFeature.DERIVED_FEATURE_2})
116    public void testRequiringTwoExplicitDerivedFeatures() throws Exception {
117      doNotActuallyRunThis();
118    }
119
120    // Exists to test that our framework doesn't run it:
121    @SuppressWarnings("unused")
122    @ExampleDerivedFeature.Require({
123        ExampleDerivedFeature.DERIVED_FEATURE_1,
124        ExampleDerivedFeature.DERIVED_FEATURE_3})
125    public void testRequiringAllThreeDerivedFeatures() {
126      doNotActuallyRunThis();
127    }
128
129    // Exists to test that our framework doesn't run it:
130    @SuppressWarnings("unused")
131    @ExampleBaseFeature.Require(absent = {ExampleBaseFeature.BASE_FEATURE_1})
132    public void testRequiringConflictingFeatures() throws Exception {
133      doNotActuallyRunThis();
134    }
135  }
136
137  @ExampleDerivedFeature.Require(
138      absent = {ExampleDerivedFeature.DERIVED_FEATURE_2})
139  private static class ExampleDerivedInterfaceTester_Conflict
140      extends ExampleBaseInterfaceTester {
141  }
142
143  public void testTestFeatureEnums() throws Exception {
144    // Haha! Let's test our own test rig!
145    FeatureEnumTest.assertGoodFeatureEnum(
146        FeatureUtilTest.ExampleBaseFeature.class);
147    FeatureEnumTest.assertGoodFeatureEnum(
148        FeatureUtilTest.ExampleDerivedFeature.class);
149  }
150
151  public void testAddImpliedFeatures_returnsSameSetInstance() throws Exception {
152    Set<Feature<?>> features = Sets.<Feature<?>>newHashSet(
153        ExampleBaseFeature.BASE_FEATURE_1);
154    assertSame(features, FeatureUtil.addImpliedFeatures(features));
155  }
156
157  public void testAddImpliedFeatures_addsImpliedFeatures() throws Exception {
158    Set<Feature<?>> features;
159
160    features = Sets.<Feature<?>>newHashSet(
161        ExampleDerivedFeature.DERIVED_FEATURE_1);
162    assertThat(FeatureUtil.addImpliedFeatures(features)).has().item(
163        ExampleDerivedFeature.DERIVED_FEATURE_1);
164
165    features = Sets.<Feature<?>>newHashSet(
166        ExampleDerivedFeature.DERIVED_FEATURE_2);
167    assertThat(FeatureUtil.addImpliedFeatures(features)).has().exactly(
168        ExampleDerivedFeature.DERIVED_FEATURE_2,
169        ExampleBaseFeature.BASE_FEATURE_1);
170
171    features = Sets.<Feature<?>>newHashSet(
172        ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE);
173    assertThat(FeatureUtil.addImpliedFeatures(features)).has().exactly(
174        ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE,
175        ExampleDerivedFeature.DERIVED_FEATURE_1,
176        ExampleDerivedFeature.DERIVED_FEATURE_2,
177        ExampleBaseFeature.BASE_FEATURE_1,
178        ExampleBaseFeature.BASE_FEATURE_2);
179  }
180
181  public void testImpliedFeatures_returnsNewSetInstance() throws Exception {
182    Set<Feature<?>> features = Sets.<Feature<?>>newHashSet(
183        ExampleBaseFeature.BASE_FEATURE_1);
184    assertNotSame(features, FeatureUtil.impliedFeatures(features));
185  }
186
187  public void testImpliedFeatures_returnsImpliedFeatures() throws Exception {
188    Set<Feature<?>> features;
189
190    features = Sets.<Feature<?>>newHashSet(
191        ExampleDerivedFeature.DERIVED_FEATURE_1);
192    assertTrue(FeatureUtil.impliedFeatures(features).isEmpty());
193
194    features = Sets.<Feature<?>>newHashSet(
195        ExampleDerivedFeature.DERIVED_FEATURE_2);
196    assertThat(FeatureUtil.impliedFeatures(features)).has().item(
197        ExampleBaseFeature.BASE_FEATURE_1);
198
199    features = Sets.<Feature<?>>newHashSet(
200        ExampleDerivedFeature.COMPOUND_DERIVED_FEATURE);
201    assertThat(FeatureUtil.impliedFeatures(features)).has().exactly(
202        ExampleDerivedFeature.DERIVED_FEATURE_1,
203        ExampleDerivedFeature.DERIVED_FEATURE_2,
204        ExampleBaseFeature.BASE_FEATURE_1,
205        ExampleBaseFeature.BASE_FEATURE_2);
206  }
207
208  public void testBuildTesterRequirements_class() throws Exception {
209    assertEquals(FeatureUtil.buildTesterRequirements(
210            ExampleBaseInterfaceTester.class),
211        new TesterRequirements(
212            Sets.<Feature<?>>newHashSet(ExampleBaseFeature.BASE_FEATURE_1),
213            Collections.<Feature<?>>emptySet()));
214
215    assertEquals(FeatureUtil.buildTesterRequirements(
216            ExampleDerivedInterfaceTester.class),
217        new TesterRequirements(
218            Sets.<Feature<?>>newHashSet(
219                ExampleBaseFeature.BASE_FEATURE_1,
220                ExampleDerivedFeature.DERIVED_FEATURE_2),
221            Collections.<Feature<?>>emptySet()));
222  }
223
224  public void testBuildTesterRequirements_method() throws Exception {
225    assertEquals(FeatureUtil.buildTesterRequirements(
226        ExampleDerivedInterfaceTester.class.getMethod(
227            "testRequiringTwoExplicitDerivedFeatures")),
228        new TesterRequirements(
229            Sets.<Feature<?>>newHashSet(
230                ExampleBaseFeature.BASE_FEATURE_1,
231                ExampleDerivedFeature.DERIVED_FEATURE_1,
232                ExampleDerivedFeature.DERIVED_FEATURE_2),
233            Collections.<Feature<?>>emptySet()));
234    assertEquals(FeatureUtil.buildTesterRequirements(
235        ExampleDerivedInterfaceTester.class.getMethod(
236            "testRequiringAllThreeDerivedFeatures")),
237        new TesterRequirements(
238            Sets.<Feature<?>>newHashSet(
239                ExampleBaseFeature.BASE_FEATURE_1,
240                ExampleDerivedFeature.DERIVED_FEATURE_1,
241                ExampleDerivedFeature.DERIVED_FEATURE_2,
242                ExampleDerivedFeature.DERIVED_FEATURE_3),
243            Collections.<Feature<?>>emptySet()));
244  }
245
246  public void testBuildTesterRequirements_classClassConflict()
247      throws Exception {
248    try {
249      FeatureUtil.buildTesterRequirements(
250          ExampleDerivedInterfaceTester_Conflict.class);
251      fail("Expected ConflictingRequirementsException");
252    } catch (ConflictingRequirementsException e) {
253      assertThat(e.getConflicts()).has().item(
254          ExampleBaseFeature.BASE_FEATURE_1);
255      assertEquals(ExampleDerivedInterfaceTester_Conflict.class, e.getSource());
256    }
257  }
258
259  public void testBuildTesterRequirements_methodClassConflict()
260      throws Exception {
261    final Method method = ExampleDerivedInterfaceTester.class
262        .getMethod("testRequiringConflictingFeatures");
263    try {
264      FeatureUtil.buildTesterRequirements(method);
265      fail("Expected ConflictingRequirementsException");
266    } catch (ConflictingRequirementsException e) {
267      assertThat(e.getConflicts()).has().item(
268          ExampleBaseFeature.BASE_FEATURE_1);
269      assertEquals(method, e.getSource());
270    }
271  }
272
273  public void testBuildDeclaredTesterRequirements() throws Exception {
274    assertEquals(FeatureUtil.buildDeclaredTesterRequirements(
275        ExampleDerivedInterfaceTester.class
276            .getMethod("testRequiringTwoExplicitDerivedFeatures")),
277        new TesterRequirements(FeatureUtil.addImpliedFeatures(
278            Sets.<Feature<?>>newHashSet(
279                ExampleDerivedFeature.DERIVED_FEATURE_1,
280                ExampleDerivedFeature.DERIVED_FEATURE_2)),
281            Collections.<Feature<?>>emptySet()));
282  }
283
284}
285