17dd252788645e940eada959bdde927426e2531c9Paul Duffin/*
27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2008 The Guava Authors
37dd252788645e940eada959bdde927426e2531c9Paul Duffin *
47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License.
67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at
77dd252788645e940eada959bdde927426e2531c9Paul Duffin *
87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
97dd252788645e940eada959bdde927426e2531c9Paul Duffin *
107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software
117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and
147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License.
157dd252788645e940eada959bdde927426e2531c9Paul Duffin */
167dd252788645e940eada959bdde927426e2531c9Paul Duffin
177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.collect.testing.features;
187dd252788645e940eada959bdde927426e2531c9Paul Duffin
197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport junit.framework.TestCase;
207dd252788645e940eada959bdde927426e2531c9Paul Duffin
217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.annotation.Annotation;
227dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.annotation.Inherited;
237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.annotation.Retention;
247dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.annotation.RetentionPolicy;
257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Method;
267dd252788645e940eada959bdde927426e2531c9Paul Duffin
277dd252788645e940eada959bdde927426e2531c9Paul Duffin/**
287dd252788645e940eada959bdde927426e2531c9Paul Duffin * Since annotations have some reusability issues that force copy and paste
297dd252788645e940eada959bdde927426e2531c9Paul Duffin * all over the place, it's worth having a test to ensure that all our Feature
307dd252788645e940eada959bdde927426e2531c9Paul Duffin * enums have their annotations correctly set up.
317dd252788645e940eada959bdde927426e2531c9Paul Duffin *
327dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author George van den Driessche
337dd252788645e940eada959bdde927426e2531c9Paul Duffin */
347dd252788645e940eada959bdde927426e2531c9Paul Duffinpublic class FeatureEnumTest extends TestCase {
357dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static void assertGoodTesterAnnotation(
367dd252788645e940eada959bdde927426e2531c9Paul Duffin      Class<? extends Annotation> annotationClass) {
377dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotNull(
387dd252788645e940eada959bdde927426e2531c9Paul Duffin        String.format("%s must be annotated with @TesterAnnotation.",
397dd252788645e940eada959bdde927426e2531c9Paul Duffin            annotationClass),
407dd252788645e940eada959bdde927426e2531c9Paul Duffin        annotationClass.getAnnotation(TesterAnnotation.class));
417dd252788645e940eada959bdde927426e2531c9Paul Duffin    final Retention retentionPolicy =
427dd252788645e940eada959bdde927426e2531c9Paul Duffin        annotationClass.getAnnotation(Retention.class);
437dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotNull(
447dd252788645e940eada959bdde927426e2531c9Paul Duffin        String.format("%s must have a @Retention annotation.", annotationClass),
457dd252788645e940eada959bdde927426e2531c9Paul Duffin        retentionPolicy);
467dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertEquals(
477dd252788645e940eada959bdde927426e2531c9Paul Duffin        String.format("%s must have RUNTIME RetentionPolicy.", annotationClass),
487dd252788645e940eada959bdde927426e2531c9Paul Duffin        RetentionPolicy.RUNTIME, retentionPolicy.value());
497dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertNotNull(
507dd252788645e940eada959bdde927426e2531c9Paul Duffin        String.format("%s must be inherited.", annotationClass),
517dd252788645e940eada959bdde927426e2531c9Paul Duffin        annotationClass.getAnnotation(Inherited.class));
527dd252788645e940eada959bdde927426e2531c9Paul Duffin
537dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (String propertyName : new String[]{"value", "absent"}) {
547dd252788645e940eada959bdde927426e2531c9Paul Duffin      Method method = null;
557dd252788645e940eada959bdde927426e2531c9Paul Duffin      try {
567dd252788645e940eada959bdde927426e2531c9Paul Duffin        method = annotationClass.getMethod(propertyName);
577dd252788645e940eada959bdde927426e2531c9Paul Duffin      } catch (NoSuchMethodException e) {
587dd252788645e940eada959bdde927426e2531c9Paul Duffin        fail(String.format("%s must have a property named '%s'.",
597dd252788645e940eada959bdde927426e2531c9Paul Duffin            annotationClass, propertyName));
607dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
617dd252788645e940eada959bdde927426e2531c9Paul Duffin      final Class<?> returnType = method.getReturnType();
627dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertTrue(String.format("%s.%s() must return an array.",
637dd252788645e940eada959bdde927426e2531c9Paul Duffin          annotationClass, propertyName),
647dd252788645e940eada959bdde927426e2531c9Paul Duffin          returnType.isArray());
657dd252788645e940eada959bdde927426e2531c9Paul Duffin      assertSame(String.format("%s.%s() must return an array of %s.",
667dd252788645e940eada959bdde927426e2531c9Paul Duffin          annotationClass, propertyName, annotationClass.getDeclaringClass()),
677dd252788645e940eada959bdde927426e2531c9Paul Duffin          annotationClass.getDeclaringClass(), returnType.getComponentType());
687dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
697dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
707dd252788645e940eada959bdde927426e2531c9Paul Duffin
717dd252788645e940eada959bdde927426e2531c9Paul Duffin  // This is public so that tests for Feature enums we haven't yet imagined
727dd252788645e940eada959bdde927426e2531c9Paul Duffin  // can reuse it.
737dd252788645e940eada959bdde927426e2531c9Paul Duffin  public static <E extends Enum<?> & Feature<?>> void assertGoodFeatureEnum(
747dd252788645e940eada959bdde927426e2531c9Paul Duffin      Class<E> featureEnumClass) {
757dd252788645e940eada959bdde927426e2531c9Paul Duffin    final Class<?>[] classes = featureEnumClass.getDeclaredClasses();
767dd252788645e940eada959bdde927426e2531c9Paul Duffin    for (Class<?> containedClass : classes) {
777dd252788645e940eada959bdde927426e2531c9Paul Duffin      if (containedClass.getSimpleName().equals("Require")) {
787dd252788645e940eada959bdde927426e2531c9Paul Duffin        if (containedClass.isAnnotation()) {
797dd252788645e940eada959bdde927426e2531c9Paul Duffin          assertGoodTesterAnnotation(asAnnotation(containedClass));
807dd252788645e940eada959bdde927426e2531c9Paul Duffin        } else {
817dd252788645e940eada959bdde927426e2531c9Paul Duffin          fail(String.format("Feature enum %s contains a class named " +
827dd252788645e940eada959bdde927426e2531c9Paul Duffin              "'Require' but it is not an annotation.", featureEnumClass));
837dd252788645e940eada959bdde927426e2531c9Paul Duffin        }
847dd252788645e940eada959bdde927426e2531c9Paul Duffin        return;
857dd252788645e940eada959bdde927426e2531c9Paul Duffin      }
867dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
877dd252788645e940eada959bdde927426e2531c9Paul Duffin    fail(String.format("Feature enum %s should contain an " +
887dd252788645e940eada959bdde927426e2531c9Paul Duffin        "annotation named 'Require'.", featureEnumClass));
897dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
907dd252788645e940eada959bdde927426e2531c9Paul Duffin
917dd252788645e940eada959bdde927426e2531c9Paul Duffin  @SuppressWarnings("unchecked")
927dd252788645e940eada959bdde927426e2531c9Paul Duffin  private static Class<? extends Annotation> asAnnotation(Class<?> clazz) {
937dd252788645e940eada959bdde927426e2531c9Paul Duffin    if (clazz.isAnnotation()) {
947dd252788645e940eada959bdde927426e2531c9Paul Duffin      return (Class<? extends Annotation>) clazz;
957dd252788645e940eada959bdde927426e2531c9Paul Duffin    } else {
967dd252788645e940eada959bdde927426e2531c9Paul Duffin      throw new IllegalArgumentException(
977dd252788645e940eada959bdde927426e2531c9Paul Duffin          String.format("%s is not an annotation.", clazz));
987dd252788645e940eada959bdde927426e2531c9Paul Duffin    }
997dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1007dd252788645e940eada959bdde927426e2531c9Paul Duffin
1017dd252788645e940eada959bdde927426e2531c9Paul Duffin  public void testFeatureEnums() throws Exception {
1027dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertGoodFeatureEnum(CollectionFeature.class);
1037dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertGoodFeatureEnum(ListFeature.class);
1047dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertGoodFeatureEnum(SetFeature.class);
1057dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertGoodFeatureEnum(CollectionSize.class);
1067dd252788645e940eada959bdde927426e2531c9Paul Duffin    assertGoodFeatureEnum(MapFeature.class);
1077dd252788645e940eada959bdde927426e2531c9Paul Duffin  }
1087dd252788645e940eada959bdde927426e2531c9Paul Duffin}
109