• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google LLC
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 package com.google.auto.value;
17 
18 import static org.junit.Assert.assertEquals;
19 
20 import com.google.auto.value.annotations.Empty;
21 import com.google.auto.value.annotations.GwtArrays;
22 import com.google.auto.value.annotations.StringValues;
23 import com.google.common.collect.ImmutableCollection;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.ImmutableSortedSet;
27 import com.google.common.primitives.Ints;
28 import com.google.common.testing.EqualsTester;
29 import java.lang.annotation.Annotation;
30 import java.lang.annotation.Retention;
31 import java.lang.annotation.RetentionPolicy;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.Collections;
36 import java.util.LinkedHashSet;
37 import java.util.List;
38 import java.util.Set;
39 import java.util.SortedSet;
40 import java.util.TreeSet;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.junit.runners.JUnit4;
44 
45 /** @author emcmanus@google.com (Éamonn McManus) */
46 @RunWith(JUnit4.class)
47 public class AutoAnnotationTest {
48   @AutoAnnotation
newStringValues(String[] value)49   private static StringValues newStringValues(String[] value) {
50     return new AutoAnnotation_AutoAnnotationTest_newStringValues(value);
51   }
52 
53   @Empty
54   @StringValues("oops")
55   static class AnnotatedClass {}
56 
57   @Test
testSimple()58   public void testSimple() {
59     StringValues expectedStringValues = AnnotatedClass.class.getAnnotation(StringValues.class);
60     StringValues actualStringValues = newStringValues(new String[] {"oops"});
61     StringValues otherStringValues = newStringValues(new String[] {});
62     new EqualsTester()
63         .addEqualityGroup(expectedStringValues, actualStringValues)
64         .addEqualityGroup(otherStringValues)
65         .testEquals();
66   }
67 
68   @Test
testArraysAreCloned()69   public void testArraysAreCloned() {
70     String[] array = {"Jekyll"};
71     StringValues stringValues = newStringValues(array);
72     array[0] = "Hyde";
73     assertEquals("Jekyll", stringValues.value()[0]);
74     stringValues.value()[0] = "Hyde";
75     assertEquals("Jekyll", stringValues.value()[0]);
76   }
77 
78   @Test
testGwtArraysAreCloned()79   public void testGwtArraysAreCloned() {
80     String[] strings = {"Jekyll"};
81     int[] ints = {2, 3, 5};
82     GwtArrays arrays = newGwtArrays(strings, ints);
83     assertEquals(ImmutableList.of("Jekyll"), ImmutableList.copyOf(arrays.strings()));
84     assertEquals(ImmutableList.of(2, 3, 5), Ints.asList(arrays.ints()));
85     strings[0] = "Hyde";
86     ints[0] = -1;
87     assertEquals(ImmutableList.of("Jekyll"), ImmutableList.copyOf(arrays.strings()));
88     assertEquals(ImmutableList.of(2, 3, 5), Ints.asList(arrays.ints()));
89   }
90 
91   @AutoAnnotation
newGwtArrays(String[] strings, int[] ints)92   private static GwtArrays newGwtArrays(String[] strings, int[] ints) {
93     return new AutoAnnotation_AutoAnnotationTest_newGwtArrays(strings, ints);
94   }
95 
96   @AutoAnnotation
newStringValuesVarArgs(String... value)97   private static StringValues newStringValuesVarArgs(String... value) {
98     return new AutoAnnotation_AutoAnnotationTest_newStringValuesVarArgs(value);
99   }
100 
101   @Test
testSimpleVarArgs()102   public void testSimpleVarArgs() {
103     StringValues expectedStringValues = AnnotatedClass.class.getAnnotation(StringValues.class);
104     StringValues actualStringValues = newStringValuesVarArgs("oops");
105     StringValues otherStringValues = newStringValuesVarArgs(new String[] {});
106     new EqualsTester()
107         .addEqualityGroup(expectedStringValues, actualStringValues)
108         .addEqualityGroup(otherStringValues)
109         .testEquals();
110   }
111 
112   @AutoAnnotation
newEmpty()113   private static Empty newEmpty() {
114     return new AutoAnnotation_AutoAnnotationTest_newEmpty();
115   }
116 
117   @Test
testEmpty()118   public void testEmpty() {
119     Empty expectedEmpty = AnnotatedClass.class.getAnnotation(Empty.class);
120     Empty actualEmpty = newEmpty();
121     new EqualsTester().addEqualityGroup(expectedEmpty, actualEmpty).testEquals();
122   }
123 
124   @Retention(RetentionPolicy.RUNTIME)
125   @interface Everything {
aByte()126     byte aByte();
127 
aShort()128     short aShort();
129 
anInt()130     int anInt();
131 
aLong()132     long aLong();
133 
aFloat()134     float aFloat();
135 
aDouble()136     double aDouble();
137 
aChar()138     char aChar();
139 
aBoolean()140     boolean aBoolean();
141 
aString()142     String aString();
143 
anEnum()144     RetentionPolicy anEnum();
145 
anAnnotation()146     StringValues anAnnotation();
147 
bytes()148     byte[] bytes();
149 
shorts()150     short[] shorts();
151 
ints()152     int[] ints();
153 
longs()154     long[] longs();
155 
floats()156     float[] floats();
157 
doubles()158     double[] doubles();
159 
chars()160     char[] chars();
161 
booleans()162     boolean[] booleans();
163 
strings()164     String[] strings();
165 
enums()166     RetentionPolicy[] enums();
167 
annotations()168     StringValues[] annotations();
169   }
170 
171   @AutoAnnotation
newEverything( byte aByte, short aShort, int anInt, long aLong, float aFloat, double aDouble, char aChar, boolean aBoolean, String aString, RetentionPolicy anEnum, StringValues anAnnotation, byte[] bytes, short[] shorts, int[] ints, long[] longs, float[] floats, double[] doubles, char[] chars, boolean[] booleans, String[] strings, RetentionPolicy[] enums, StringValues[] annotations)172   static Everything newEverything(
173       byte aByte,
174       short aShort,
175       int anInt,
176       long aLong,
177       float aFloat,
178       double aDouble,
179       char aChar,
180       boolean aBoolean,
181       String aString,
182       RetentionPolicy anEnum,
183       StringValues anAnnotation,
184       byte[] bytes,
185       short[] shorts,
186       int[] ints,
187       long[] longs,
188       float[] floats,
189       double[] doubles,
190       char[] chars,
191       boolean[] booleans,
192       String[] strings,
193       RetentionPolicy[] enums,
194       StringValues[] annotations) {
195     return new AutoAnnotation_AutoAnnotationTest_newEverything(
196         aByte,
197         aShort,
198         anInt,
199         aLong,
200         aFloat,
201         aDouble,
202         aChar,
203         aBoolean,
204         aString,
205         anEnum,
206         anAnnotation,
207         bytes,
208         shorts,
209         ints,
210         longs,
211         floats,
212         doubles,
213         chars,
214         booleans,
215         strings,
216         enums,
217         annotations);
218   }
219 
220   @AutoAnnotation
newEverythingCollections( byte aByte, short aShort, int anInt, long aLong, float aFloat, double aDouble, char aChar, boolean aBoolean, String aString, RetentionPolicy anEnum, StringValues anAnnotation, Collection<Byte> bytes, List<Short> shorts, ArrayList<Integer> ints, Set<Long> longs, SortedSet<Float> floats, TreeSet<Double> doubles, LinkedHashSet<Character> chars, ImmutableCollection<Boolean> booleans, ImmutableList<String> strings, ImmutableSet<RetentionPolicy> enums, Set<StringValues> annotations)221   static Everything newEverythingCollections(
222       byte aByte,
223       short aShort,
224       int anInt,
225       long aLong,
226       float aFloat,
227       double aDouble,
228       char aChar,
229       boolean aBoolean,
230       String aString,
231       RetentionPolicy anEnum,
232       StringValues anAnnotation,
233       Collection<Byte> bytes,
234       List<Short> shorts,
235       ArrayList<Integer> ints,
236       Set<Long> longs,
237       SortedSet<Float> floats,
238       TreeSet<Double> doubles,
239       LinkedHashSet<Character> chars,
240       ImmutableCollection<Boolean> booleans,
241       ImmutableList<String> strings,
242       ImmutableSet<RetentionPolicy> enums,
243       Set<StringValues> annotations) {
244     return new AutoAnnotation_AutoAnnotationTest_newEverythingCollections(
245         aByte,
246         aShort,
247         anInt,
248         aLong,
249         aFloat,
250         aDouble,
251         aChar,
252         aBoolean,
253         aString,
254         anEnum,
255         anAnnotation,
256         bytes,
257         shorts,
258         ints,
259         longs,
260         floats,
261         doubles,
262         chars,
263         booleans,
264         strings,
265         enums,
266         annotations);
267   }
268 
269   @Everything(
270       aByte = 1,
271       aShort = 2,
272       anInt = 3,
273       aLong = -4,
274       aFloat = Float.NaN,
275       aDouble = Double.NaN,
276       aChar = '#',
277       aBoolean = true,
278       aString = "maybe\nmaybe not\n",
279       anEnum = RetentionPolicy.RUNTIME,
280       anAnnotation = @StringValues("whatever"),
281       bytes = {5, 6},
282       shorts = {},
283       ints = {7},
284       longs = {8, 9},
285       floats = {10, 11},
286       doubles = {Double.NEGATIVE_INFINITY, -12.0, Double.POSITIVE_INFINITY},
287       chars = {'?', '!', '\n'},
288       booleans = {false, true, false},
289       strings = {"ver", "vers", "vert", "verre", "vair"},
290       enums = {RetentionPolicy.CLASS, RetentionPolicy.RUNTIME},
291       annotations = {@StringValues({}), @StringValues({"foo", "bar"})})
292   private static class AnnotatedWithEverything {}
293 
294   // Get an instance of @Everything via reflection on the class AnnotatedWithEverything,
295   // fabricate an instance using newEverything that is supposed to be equal to it, and
296   // fabricate another instance using newEverything that is supposed to be different.
297   private static final Everything EVERYTHING_FROM_REFLECTION =
298       AnnotatedWithEverything.class.getAnnotation(Everything.class);
299   private static final Everything EVERYTHING_FROM_AUTO =
300       newEverything(
301           (byte) 1,
302           (short) 2,
303           3,
304           -4,
305           Float.NaN,
306           Double.NaN,
307           '#',
308           true,
309           "maybe\nmaybe not\n",
310           RetentionPolicy.RUNTIME,
311           newStringValues(new String[] {"whatever"}),
312           new byte[] {5, 6},
313           new short[] {},
314           new int[] {7},
315           new long[] {8, 9},
316           new float[] {10, 11},
317           new double[] {Double.NEGATIVE_INFINITY, -12.0, Double.POSITIVE_INFINITY},
318           new char[] {'?', '!', '\n'},
319           new boolean[] {false, true, false},
320           new String[] {"ver", "vers", "vert", "verre", "vair"},
321           new RetentionPolicy[] {RetentionPolicy.CLASS, RetentionPolicy.RUNTIME},
322           new StringValues[] {
323             newStringValues(new String[] {}), newStringValues(new String[] {"foo", "bar"}),
324           });
325   private static final Everything EVERYTHING_FROM_AUTO_COLLECTIONS =
326       newEverythingCollections(
327           (byte) 1,
328           (short) 2,
329           3,
330           -4,
331           Float.NaN,
332           Double.NaN,
333           '#',
334           true,
335           "maybe\nmaybe not\n",
336           RetentionPolicy.RUNTIME,
337           newStringValues(new String[] {"whatever"}),
338           Arrays.asList((byte) 5, (byte) 6),
339           Collections.<Short>emptyList(),
340           new ArrayList<Integer>(Collections.singleton(7)),
341           ImmutableSet.of(8L, 9L),
342           ImmutableSortedSet.of(10f, 11f),
343           new TreeSet<Double>(
344               ImmutableList.of(Double.NEGATIVE_INFINITY, -12.0, Double.POSITIVE_INFINITY)),
345           new LinkedHashSet<Character>(ImmutableList.of('?', '!', '\n')),
346           ImmutableList.of(false, true, false),
347           ImmutableList.of("ver", "vers", "vert", "verre", "vair"),
348           ImmutableSet.of(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME),
349           ImmutableSet.of(
350               newStringValues(new String[] {}), newStringValues(new String[] {"foo", "bar"})));
351   private static final Everything EVERYTHING_ELSE_FROM_AUTO =
352       newEverything(
353           (byte) 0,
354           (short) 0,
355           0,
356           0,
357           0,
358           0,
359           '0',
360           false,
361           "",
362           RetentionPolicy.SOURCE,
363           newStringValues(new String[] {""}),
364           new byte[0],
365           new short[0],
366           new int[0],
367           new long[0],
368           new float[0],
369           new double[0],
370           new char[0],
371           new boolean[0],
372           new String[0],
373           new RetentionPolicy[0],
374           new StringValues[0]);
375   private static final Everything EVERYTHING_ELSE_FROM_AUTO_COLLECTIONS =
376       newEverythingCollections(
377           (byte) 0,
378           (short) 0,
379           0,
380           0,
381           0,
382           0,
383           '0',
384           false,
385           "",
386           RetentionPolicy.SOURCE,
387           newStringValues(new String[] {""}),
388           ImmutableList.<Byte>of(),
389           Collections.<Short>emptyList(),
390           new ArrayList<Integer>(),
391           Collections.<Long>emptySet(),
392           ImmutableSortedSet.<Float>of(),
393           new TreeSet<Double>(),
394           new LinkedHashSet<Character>(),
395           ImmutableSet.<Boolean>of(),
396           ImmutableList.<String>of(),
397           ImmutableSet.<RetentionPolicy>of(),
398           Collections.<StringValues>emptySet());
399 
400   @Test
testEqualsAndHashCode()401   public void testEqualsAndHashCode() {
402     new EqualsTester()
403         .addEqualityGroup(
404             EVERYTHING_FROM_REFLECTION, EVERYTHING_FROM_AUTO, EVERYTHING_FROM_AUTO_COLLECTIONS)
405         .addEqualityGroup(EVERYTHING_ELSE_FROM_AUTO, EVERYTHING_ELSE_FROM_AUTO_COLLECTIONS)
406         .testEquals();
407   }
408 
409   public static class IntList extends ArrayList<Integer> {
IntList(Collection<Integer> c)410     IntList(Collection<Integer> c) {
411       super(c);
412     }
413   }
414 
415   @Retention(RetentionPolicy.RUNTIME)
416   @interface IntArray {
ints()417     int[] ints();
418   }
419 
420   @IntArray(ints = {1, 2, 3})
421   private static class AnnotatedWithIntArray {}
422 
423   @AutoAnnotation
newIntArray(IntList ints)424   static IntArray newIntArray(IntList ints) {
425     return new AutoAnnotation_AutoAnnotationTest_newIntArray(ints);
426   }
427 
428   /**
429    * Test that we can represent a primitive array member with a parameter whose type is a collection
430    * of the corresponding wrapper type, even if the wrapper type is not explicitly a type parameter.
431    * Specifically, if the member is an {@code int[]} then obviously we can represent it as a {@code
432    * List<Integer>}, but here we test that we can also represent it as an {@code IntList}, which is
433    * only a {@code List<Integer>} by virtue of inheritance. This is a separate test rather than just
434    * putting an {@code IntList} parameter into {@link #newEverythingCollections} because we want to
435    * check that we are still able to detect the primitive wrapper type even though it's hidden in
436    * this way. We need to generate a helper method for every primitive wrapper.
437    */
438   @Test
testDerivedPrimitiveCollection()439   public void testDerivedPrimitiveCollection() {
440     IntList intList = new IntList(ImmutableList.of(1, 2, 3));
441     IntArray actual = newIntArray(intList);
442     IntArray expected = AnnotatedWithIntArray.class.getAnnotation(IntArray.class);
443     assertEquals(expected, actual);
444   }
445 
446   @Test
testToString()447   public void testToString() {
448     String expected =
449         "@com.google.auto.value.AutoAnnotationTest.Everything("
450             + "aByte=1, aShort=2, anInt=3, aLong=-4, aFloat=NaN, aDouble=NaN, aChar='#', "
451             + "aBoolean=true, aString=\"maybe\\nmaybe not\\n\", anEnum=RUNTIME, "
452             + "anAnnotation=@com.google.auto.value.annotations.StringValues([\"whatever\"]), "
453             + "bytes=[5, 6], shorts=[], ints=[7], longs=[8, 9], floats=[10.0, 11.0], "
454             + "doubles=[-Infinity, -12.0, Infinity], "
455             + "chars=['?', '!', '\\n'], "
456             + "booleans=[false, true, false], "
457             + "strings=[\"ver\", \"vers\", \"vert\", \"verre\", \"vair\"], "
458             + "enums=[CLASS, RUNTIME], "
459             + "annotations=["
460             + "@com.google.auto.value.annotations.StringValues([]), "
461             + "@com.google.auto.value.annotations.StringValues([\"foo\", \"bar\"])"
462             + "]"
463             + ")";
464     assertEquals(expected, EVERYTHING_FROM_AUTO.toString());
465     assertEquals(expected, EVERYTHING_FROM_AUTO_COLLECTIONS.toString());
466   }
467 
468   @Test
testStringQuoting()469   public void testStringQuoting() {
470     StringValues instance =
471         newStringValues(
472             new String[] {
473               "", "\r\n", "hello, world", "Éamonn", "\007\uffef",
474             });
475     String expected =
476         "@com.google.auto.value.annotations.StringValues("
477             + "[\"\", \"\\r\\n\", \"hello, world\", \"Éamonn\", \"\\007\\uffef\"])";
478     assertEquals(expected, instance.toString());
479   }
480 
481   @Retention(RetentionPolicy.RUNTIME)
482   @interface AnnotationsAnnotation {
value()483     Class<? extends Annotation>[] value();
484   }
485 
486   @AnnotationsAnnotation(AnnotationsAnnotation.class)
487   static class AnnotatedWithAnnotationsAnnotation {}
488 
489   @AutoAnnotation
newAnnotationsAnnotation(List<Class<? extends Annotation>> value)490   static AnnotationsAnnotation newAnnotationsAnnotation(List<Class<? extends Annotation>> value) {
491     return new AutoAnnotation_AutoAnnotationTest_newAnnotationsAnnotation(value);
492   }
493 
494   @Test
testGenericArray()495   public void testGenericArray() {
496     AnnotationsAnnotation generated =
497         newAnnotationsAnnotation(
498             ImmutableList.<Class<? extends Annotation>>of(AnnotationsAnnotation.class));
499     AnnotationsAnnotation fromReflect =
500         AnnotatedWithAnnotationsAnnotation.class.getAnnotation(AnnotationsAnnotation.class);
501     assertEquals(fromReflect, generated);
502   }
503 
504   @Retention(RetentionPolicy.RUNTIME)
505   @interface ClassesAnnotation {
value()506     Class<?>[] value();
507   }
508 
509   @ClassesAnnotation(AnnotationsAnnotation.class)
510   static class AnnotatedWithClassesAnnotation {}
511 
512   @AutoAnnotation
newClassesAnnotation(List<Class<?>> value)513   static ClassesAnnotation newClassesAnnotation(List<Class<?>> value) {
514     return new AutoAnnotation_AutoAnnotationTest_newClassesAnnotation(value);
515   }
516 
517   @Test
testWildcardArray()518   public void testWildcardArray() {
519     ClassesAnnotation generated =
520         newClassesAnnotation(Arrays.<Class<?>>asList(AnnotationsAnnotation.class));
521     ClassesAnnotation fromReflect =
522         AnnotatedWithClassesAnnotation.class.getAnnotation(ClassesAnnotation.class);
523     assertEquals(fromReflect, generated);
524   }
525 
526   @Retention(RetentionPolicy.RUNTIME)
527   @interface IntegersAnnotation {
one()528     int one() default Integer.MAX_VALUE;
529 
two()530     int two() default Integer.MAX_VALUE;
531 
three()532     int three();
533   }
534 
535   @IntegersAnnotation(three = 23)
536   static class AnnotatedWithIntegersAnnotation {}
537 
538   @AutoAnnotation
newIntegersAnnotation(int three)539   static IntegersAnnotation newIntegersAnnotation(int three) {
540     return new AutoAnnotation_AutoAnnotationTest_newIntegersAnnotation(three);
541   }
542 
543   @Test
testConstantOverflowInHashCode()544   public void testConstantOverflowInHashCode() {
545     IntegersAnnotation generated = newIntegersAnnotation(23);
546     IntegersAnnotation fromReflect =
547         AnnotatedWithIntegersAnnotation.class.getAnnotation(IntegersAnnotation.class);
548     new EqualsTester().addEqualityGroup(generated, fromReflect).testEquals();
549   }
550 
551   @Retention(RetentionPolicy.RUNTIME)
552   @interface EverythingWithDefaults {
aByte()553     byte aByte() default 5;
554 
aShort()555     short aShort() default 17;
556 
anInt()557     int anInt() default 23;
558 
aLong()559     long aLong() default 1729;
560 
aFloat()561     float aFloat() default 5;
562 
aDouble()563     double aDouble() default 17;
564 
aChar()565     char aChar() default 'x';
566 
aBoolean()567     boolean aBoolean() default true;
568 
aString()569     String aString() default "whatever";
570 
anEnum()571     RetentionPolicy anEnum() default RetentionPolicy.CLASS;
572     // We don't yet support defaulting annotation values.
573     // StringValues anAnnotation() default @StringValues({"foo", "bar"});
bytes()574     byte[] bytes() default {1, 2};
575 
shorts()576     short[] shorts() default {3, 4};
577 
ints()578     int[] ints() default {5, 6};
579 
longs()580     long[] longs() default {7, 8};
581 
floats()582     float[] floats() default {9, 10};
583 
doubles()584     double[] doubles() default {11, 12};
585 
chars()586     char[] chars() default {'D', 'E'};
587 
booleans()588     boolean[] booleans() default {true, false};
589 
strings()590     String[] strings() default {"vrai", "faux"};
591 
enums()592     RetentionPolicy[] enums() default {RetentionPolicy.SOURCE, RetentionPolicy.CLASS};
593     // We don't yet support defaulting annotation values.
594     // StringValues[] annotations() default {
595     //   @StringValues({"foo", "bar"}), @StringValues({"baz", "buh"})
596     // };
597   }
598 
599   @EverythingWithDefaults
600   static class AnnotatedWithEverythingWithDefaults {}
601 
602   @AutoAnnotation
newEverythingWithDefaults()603   static EverythingWithDefaults newEverythingWithDefaults() {
604     return new AutoAnnotation_AutoAnnotationTest_newEverythingWithDefaults();
605   }
606 
607   @Test
testDefaultedValues()608   public void testDefaultedValues() {
609     EverythingWithDefaults generated = newEverythingWithDefaults();
610     EverythingWithDefaults fromReflect =
611         AnnotatedWithEverythingWithDefaults.class.getAnnotation(EverythingWithDefaults.class);
612     new EqualsTester().addEqualityGroup(generated, fromReflect).testEquals();
613   }
614 }
615