blob: 31dd4cec38bdf20111ba38261d4c6d43f80f03d3 [file] [log] [blame]
/*
* Copyright (C) 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.auto.value;
import com.google.auto.value.annotations.Empty;
import com.google.auto.value.annotations.GwtArrays;
import com.google.auto.value.annotations.StringValues;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.primitives.Ints;
import com.google.common.testing.EqualsTester;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import junit.framework.TestCase;
/**
* @author emcmanus@google.com (Éamonn McManus)
*/
public class AutoAnnotationTest extends TestCase {
@AutoAnnotation private static StringValues newStringValues(String[] value) {
return new AutoAnnotation_AutoAnnotationTest_newStringValues(value);
}
@Empty
@StringValues("oops")
class AnnotatedClass {}
public void testSimple() {
StringValues expectedStringValues = AnnotatedClass.class.getAnnotation(StringValues.class);
StringValues actualStringValues = newStringValues(new String[] {"oops"});
StringValues otherStringValues = newStringValues(new String[] {});
new EqualsTester()
.addEqualityGroup(expectedStringValues, actualStringValues)
.addEqualityGroup(otherStringValues)
.testEquals();
}
public void testArraysAreCloned() {
String[] array = {"Jekyll"};
StringValues stringValues = newStringValues(array);
array[0] = "Hyde";
assertEquals("Jekyll", stringValues.value()[0]);
stringValues.value()[0] = "Hyde";
assertEquals("Jekyll", stringValues.value()[0]);
}
public void testGwtArraysAreCloned() {
String[] strings = {"Jekyll"};
int[] ints = {2, 3, 5};
GwtArrays arrays = newGwtArrays(strings, ints);
assertEquals(ImmutableList.of("Jekyll"), ImmutableList.copyOf(arrays.strings()));
assertEquals(ImmutableList.of(2, 3, 5), Ints.asList(arrays.ints()));
strings[0] = "Hyde";
ints[0] = -1;
assertEquals(ImmutableList.of("Jekyll"), ImmutableList.copyOf(arrays.strings()));
assertEquals(ImmutableList.of(2, 3, 5), Ints.asList(arrays.ints()));
}
@AutoAnnotation private static GwtArrays newGwtArrays(String[] strings, int[] ints) {
return new AutoAnnotation_AutoAnnotationTest_newGwtArrays(strings, ints);
}
@AutoAnnotation private static StringValues newStringValuesVarArgs(String... value) {
return new AutoAnnotation_AutoAnnotationTest_newStringValuesVarArgs(value);
}
public void testSimpleVarArgs() {
StringValues expectedStringValues = AnnotatedClass.class.getAnnotation(StringValues.class);
StringValues actualStringValues = newStringValuesVarArgs("oops");
StringValues otherStringValues = newStringValuesVarArgs(new String[] {});
new EqualsTester()
.addEqualityGroup(expectedStringValues, actualStringValues)
.addEqualityGroup(otherStringValues)
.testEquals();
}
@AutoAnnotation private static Empty newEmpty() {
return new AutoAnnotation_AutoAnnotationTest_newEmpty();
}
public void testEmpty() {
Empty expectedEmpty = AnnotatedClass.class.getAnnotation(Empty.class);
Empty actualEmpty = newEmpty();
new EqualsTester()
.addEqualityGroup(expectedEmpty, actualEmpty)
.testEquals();
}
@Retention(RetentionPolicy.RUNTIME)
@interface Everything {
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();
}
@AutoAnnotation static Everything 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) {
return new AutoAnnotation_AutoAnnotationTest_newEverything(
aByte, aShort, anInt, aLong, aFloat, aDouble, aChar, aBoolean, aString, anEnum,
anAnnotation, bytes, shorts, ints, longs, floats, doubles, chars, booleans, strings, enums,
annotations);
}
@AutoAnnotation static Everything 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) {
return new AutoAnnotation_AutoAnnotationTest_newEverythingCollections(
aByte, aShort, anInt, aLong, aFloat, aDouble, aChar, aBoolean, aString, anEnum,
anAnnotation, bytes, shorts, ints, longs, floats, doubles, chars, booleans, strings, enums,
annotations);
}
@Everything(
aByte = 1,
aShort = 2,
anInt = 3,
aLong = -4,
aFloat = Float.NaN,
aDouble = Double.NaN,
aChar = '#',
aBoolean = true,
aString = "maybe\nmaybe not\n",
anEnum = RetentionPolicy.RUNTIME,
anAnnotation = @StringValues("whatever"),
bytes = {5, 6},
shorts = {},
ints = {7},
longs = {8, 9},
floats = {10, 11},
doubles = {Double.NEGATIVE_INFINITY, -12.0, Double.POSITIVE_INFINITY},
chars = {'?', '!', '\n'},
booleans = {false, true, false},
strings = {"ver", "vers", "vert", "verre", "vair"},
enums = {RetentionPolicy.CLASS, RetentionPolicy.RUNTIME},
annotations = {
@StringValues({}), @StringValues({"foo", "bar"})
}
)
private static class AnnotatedWithEverything {}
// Get an instance of @Everything via reflection on the class AnnotatedWithEverything,
// fabricate an instance using newEverything that is supposed to be equal to it, and
// fabricate another instance using newEverything that is supposed to be different.
private static final Everything EVERYTHING_FROM_REFLECTION =
AnnotatedWithEverything.class.getAnnotation(Everything.class);
private static final Everything EVERYTHING_FROM_AUTO = newEverything(
(byte) 1, (short) 2, 3, -4, Float.NaN, Double.NaN, '#', true,
"maybe\nmaybe not\n",
RetentionPolicy.RUNTIME,
newStringValues(new String[] {"whatever"}),
new byte[] {5, 6},
new short[] {},
new int[] {7},
new long[] {8, 9},
new float[] {10, 11},
new double[] {Double.NEGATIVE_INFINITY, -12.0, Double.POSITIVE_INFINITY},
new char[] {'?', '!', '\n'},
new boolean[] {false, true, false},
new String[] {"ver", "vers", "vert", "verre", "vair"},
new RetentionPolicy[] {RetentionPolicy.CLASS, RetentionPolicy.RUNTIME},
new StringValues[] {
newStringValues(new String[] {}),
newStringValues(new String[] {"foo", "bar"}),
});
private static final Everything EVERYTHING_FROM_AUTO_COLLECTIONS = newEverythingCollections(
(byte) 1, (short) 2, 3, -4, Float.NaN, Double.NaN, '#', true,
"maybe\nmaybe not\n",
RetentionPolicy.RUNTIME,
newStringValues(new String[] {"whatever"}),
Arrays.asList((byte) 5, (byte) 6),
Collections.<Short>emptyList(),
new ArrayList<Integer>(Collections.singleton(7)),
ImmutableSet.of(8L, 9L),
ImmutableSortedSet.of(10f, 11f),
new TreeSet<Double>(
ImmutableList.of(Double.NEGATIVE_INFINITY, -12.0, Double.POSITIVE_INFINITY)),
new LinkedHashSet<Character>(ImmutableList.of('?', '!', '\n')),
ImmutableList.of(false, true, false),
ImmutableList.of("ver", "vers", "vert", "verre", "vair"),
ImmutableSet.of(RetentionPolicy.CLASS, RetentionPolicy.RUNTIME),
ImmutableSet.of(
newStringValues(new String[] {}),
newStringValues(new String[] {"foo", "bar"})));
private static final Everything EVERYTHING_ELSE_FROM_AUTO = newEverything(
(byte) 0, (short) 0, 0, 0, 0, 0, '0', false, "", RetentionPolicy.SOURCE,
newStringValues(new String[] {""}),
new byte[0], new short[0], new int[0], new long[0], new float[0], new double[0],
new char[0], new boolean[0], new String[0], new RetentionPolicy[0], new StringValues[0]);
private static final Everything EVERYTHING_ELSE_FROM_AUTO_COLLECTIONS = newEverythingCollections(
(byte) 0, (short) 0, 0, 0, 0, 0, '0', false, "", RetentionPolicy.SOURCE,
newStringValues(new String[] {""}),
ImmutableList.<Byte>of(),
Collections.<Short>emptyList(),
new ArrayList<Integer>(),
Collections.<Long>emptySet(),
ImmutableSortedSet.<Float>of(),
new TreeSet<Double>(),
new LinkedHashSet<Character>(),
ImmutableSet.<Boolean>of(),
ImmutableList.<String>of(),
ImmutableSet.<RetentionPolicy>of(),
Collections.<StringValues>emptySet());
public void testEqualsAndHashCode() {
new EqualsTester()
.addEqualityGroup(
EVERYTHING_FROM_REFLECTION, EVERYTHING_FROM_AUTO, EVERYTHING_FROM_AUTO_COLLECTIONS)
.addEqualityGroup(EVERYTHING_ELSE_FROM_AUTO, EVERYTHING_ELSE_FROM_AUTO_COLLECTIONS)
.testEquals();
}
public static class IntList extends ArrayList<Integer> {
IntList(Collection<Integer> c) {
super(c);
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface IntArray {
int[] ints();
}
@IntArray(ints = {1, 2, 3})
private static class AnnotatedWithIntArray {}
@AutoAnnotation static IntArray newIntArray(IntList ints) {
return new AutoAnnotation_AutoAnnotationTest_newIntArray(ints);
}
/**
* Test that we can represent a primitive array member with a parameter whose type is a
* collection of the corresponding wrapper type, even if the wrapper type is not explicitly a type
* parameter. Specifically, if the member is an {@code int[]} then obviously we can represent it
* as a {@code List<Integer>}, but here we test that we can also represent it as an {@code
* IntList}, which is only a {@code List<Integer>} by virtue of inheritance. This is a separate
* test rather than just putting an {@code IntList} parameter into {@link
* #newEverythingCollections} because we want to check that we are still able to detect the
* primitive wrapper type even though it's hidden in this way. We need to generate a helper method
* for every primitive wrapper.
*/
public void testDerivedPrimitiveCollection() {
IntList intList = new IntList(ImmutableList.of(1, 2, 3));
IntArray actual = newIntArray(intList);
IntArray expected = AnnotatedWithIntArray.class.getAnnotation(IntArray.class);
assertEquals(expected, actual);
}
public void testToString() {
String expected = "@com.google.auto.value.AutoAnnotationTest.Everything("
+ "aByte=1, aShort=2, anInt=3, aLong=-4, aFloat=NaN, aDouble=NaN, aChar='#', "
+ "aBoolean=true, aString=\"maybe\\nmaybe not\\n\", anEnum=RUNTIME, "
+ "anAnnotation=@com.google.auto.value.annotations.StringValues([\"whatever\"]), "
+ "bytes=[5, 6], shorts=[], ints=[7], longs=[8, 9], floats=[10.0, 11.0], "
+ "doubles=[-Infinity, -12.0, Infinity], "
+ "chars=['?', '!', '\\n'], "
+ "booleans=[false, true, false], "
+ "strings=[\"ver\", \"vers\", \"vert\", \"verre\", \"vair\"], "
+ "enums=[CLASS, RUNTIME], "
+ "annotations=["
+ "@com.google.auto.value.annotations.StringValues([]), "
+ "@com.google.auto.value.annotations.StringValues([\"foo\", \"bar\"])"
+ "]"
+ ")";
assertEquals(expected, EVERYTHING_FROM_AUTO.toString());
assertEquals(expected, EVERYTHING_FROM_AUTO_COLLECTIONS.toString());
}
public void testStringQuoting() {
StringValues instance = newStringValues(
new String[] {
"",
"\r\n",
"hello, world",
"Éamonn",
"\007\uffef",
});
String expected = "@com.google.auto.value.annotations.StringValues("
+ "[\"\", \"\\r\\n\", \"hello, world\", \"Éamonn\", \"\\007\\uffef\"])";
assertEquals(expected, instance.toString());
}
@Retention(RetentionPolicy.RUNTIME)
@interface AnnotationsAnnotation {
Class<? extends Annotation>[] value();
}
@AnnotationsAnnotation(AnnotationsAnnotation.class)
static class AnnotatedWithAnnotationsAnnotation {}
@AutoAnnotation static AnnotationsAnnotation newAnnotationsAnnotation(
List<Class<? extends Annotation>> value) {
return new AutoAnnotation_AutoAnnotationTest_newAnnotationsAnnotation(value);
}
public void testGenericArray() {
AnnotationsAnnotation generated =
newAnnotationsAnnotation(
ImmutableList.<Class<? extends Annotation>>of(AnnotationsAnnotation.class));
AnnotationsAnnotation fromReflect =
AnnotatedWithAnnotationsAnnotation.class.getAnnotation(AnnotationsAnnotation.class);
assertEquals(fromReflect, generated);
}
@Retention(RetentionPolicy.RUNTIME)
@interface ClassesAnnotation {
Class<?>[] value();
}
@ClassesAnnotation(AnnotationsAnnotation.class)
static class AnnotatedWithClassesAnnotation {}
@AutoAnnotation static ClassesAnnotation newClassesAnnotation(
List<Class<?>> value) {
return new AutoAnnotation_AutoAnnotationTest_newClassesAnnotation(value);
}
public void testWildcardArray() {
ClassesAnnotation generated =
newClassesAnnotation(
Arrays.<Class<?>>asList(AnnotationsAnnotation.class));
ClassesAnnotation fromReflect =
AnnotatedWithClassesAnnotation.class.getAnnotation(ClassesAnnotation.class);
assertEquals(fromReflect, generated);
}
}