blob: a05f8b58fb5de611028c06ea1143c44434b070c2 [file] [log] [blame]
/*
* Copyright (C) 2012 The Guava Authors
*
* 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 static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Objects;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.testing.EqualsTester;
import com.google.common.testing.SerializableTester;
import junit.framework.TestCase;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
/**
* @author emcmanus@google.com (Éamonn McManus)
*/
public class AutoValueTest extends TestCase {
// TODO(user): add tests for exotic locales
@AutoValue
abstract static class Simple {
public abstract String publicString();
protected abstract int protectedInt();
abstract Map<String, Long> packageMap();
public static Simple create(String s, int i, Map<String, Long> m) {
return new AutoValue_AutoValueTest_Simple(s, i, m);
}
}
public void testSimple() throws Exception {
Simple instance1a = Simple.create("example", 23, ImmutableMap.of("twenty-three", 23L));
Simple instance1b = Simple.create("example", 23, ImmutableMap.of("twenty-three", 23L));
Simple instance2 = Simple.create("", 0, ImmutableMap.<String, Long>of());
assertEquals("example", instance1a.publicString());
assertEquals(23, instance1a.protectedInt());
assertEquals(ImmutableMap.of("twenty-three", 23L), instance1a.packageMap());
Objects.ToStringHelper toStringHelper = Objects.toStringHelper(Simple.class);
toStringHelper.add("publicString", "example");
toStringHelper.add("protectedInt", 23);
toStringHelper.add("packageMap", ImmutableMap.of("twenty-three", 23L));
assertEquals(toStringHelper.toString(), instance1a.toString());
new EqualsTester()
.addEqualityGroup(instance1a, instance1b)
.addEqualityGroup(instance2)
.testEquals();
}
@AutoValue
abstract static class Empty {
public static Empty create() {
return new AutoValue_AutoValueTest_Empty();
}
}
public void testEmpty() throws Exception {
Empty instance = Empty.create();
assertEquals("Empty{}", instance.toString());
assertEquals(instance, instance);
assertEquals(instance, Empty.create());
}
@AutoValue
abstract static class SimpleWithGetters {
abstract int getFoo();
abstract boolean isBar();
abstract boolean getOtherBar();
abstract String getPackage(); // package is a reserved word
abstract String getPackage0();
abstract String getHTMLPage();
static SimpleWithGetters create(
int foo, boolean bar, boolean otherBar, String pkg, String pkg0, String htmlPage) {
return new AutoValue_AutoValueTest_SimpleWithGetters(foo, bar, otherBar, pkg, pkg0, htmlPage);
}
}
public void testGetters() {
SimpleWithGetters instance = SimpleWithGetters.create(23, true, false, "foo", "bar", "<html>");
assertEquals(
"SimpleWithGetters{"
+ "foo=23, bar=true, otherBar=false, package=foo, package0=bar, HTMLPage=<html>}",
instance.toString());
}
@AutoValue
abstract static class NotAllGetters {
abstract int getFoo();
abstract boolean bar();
static NotAllGetters create(int foo, boolean bar) {
return new AutoValue_AutoValueTest_NotAllGetters(foo, bar);
}
}
public void testNotGetters() {
NotAllGetters instance = NotAllGetters.create(23, true);
assertEquals("NotAllGetters{getFoo=23, bar=true}", instance.toString());
}
@AutoValue
abstract static class GettersAndConcreteNonGetters {
abstract int getFoo();
abstract byte[] getBytes();
boolean hasNoBytes() {
return getBytes().length == 0;
}
static GettersAndConcreteNonGetters create(int foo, byte[] bytes) {
return new AutoValue_AutoValueTest_GettersAndConcreteNonGetters(foo, bytes);
}
}
public void testGettersAndConcreteNonGetters() {
GettersAndConcreteNonGetters instance = GettersAndConcreteNonGetters.create(23, new byte[] {1});
assertFalse(instance.hasNoBytes());
assertEquals("GettersAndConcreteNonGetters{foo=23, bytes=[1]}", instance.toString());
}
@AutoValue
public abstract static class Serialize implements Serializable {
public abstract int integer();
public abstract String string();
public abstract BigInteger bigInteger();
public static Serialize create(int integer, String string, BigInteger bigInteger) {
return new AutoValue_AutoValueTest_Serialize(integer, string, bigInteger);
}
}
public void testSerialize() throws Exception {
Serialize instance = Serialize.create(23, "23", BigInteger.valueOf(23));
assertEquals(instance, SerializableTester.reserialize(instance));
}
@AutoValue
public abstract static class SerializeWithVersionUID implements Serializable {
private static final long serialVersionUID = 4294967297L;
public abstract int integer();
public abstract String string();
public static SerializeWithVersionUID create(int integer, String string) {
return new AutoValue_AutoValueTest_SerializeWithVersionUID(integer, string);
}
}
public void testSerializeWithVersionUID() throws Exception {
SerializeWithVersionUID instance = SerializeWithVersionUID.create(23, "23");
assertEquals(instance, SerializableTester.reserialize(instance));
long serialVersionUID =
ObjectStreamClass.lookup(AutoValue_AutoValueTest_SerializeWithVersionUID.class)
.getSerialVersionUID();
assertEquals(4294967297L, serialVersionUID);
}
@AutoValue
abstract static class LongProperty {
public abstract long longProperty();
public static LongProperty create(long longProperty) {
return new AutoValue_AutoValueTest_LongProperty(longProperty);
}
}
public void testLongHashCode() {
long longValue = 0x1234567887654321L;
LongProperty longProperty = LongProperty.create(longValue);
assertEquals(singlePropertyHash(longValue), longProperty.hashCode());
}
@AutoValue
abstract static class IntProperty {
public abstract int intProperty();
public static IntProperty create(int intProperty) {
return new AutoValue_AutoValueTest_IntProperty(intProperty);
}
}
public void testIntHashCode() {
int intValue = 0x12345678;
IntProperty intProperty = IntProperty.create(intValue);
assertEquals(singlePropertyHash(intValue), intProperty.hashCode());
}
@AutoValue
abstract static class ShortProperty {
public abstract short shortProperty();
public static ShortProperty create(short shortProperty) {
return new AutoValue_AutoValueTest_ShortProperty(shortProperty);
}
}
public void testShortHashCode() {
short shortValue = 0x1234;
ShortProperty shortProperty = ShortProperty.create(shortValue);
assertEquals(singlePropertyHash(shortValue), shortProperty.hashCode());
}
@AutoValue
abstract static class ByteProperty {
public abstract byte byteProperty();
public static ByteProperty create(byte byteProperty) {
return new AutoValue_AutoValueTest_ByteProperty(byteProperty);
}
}
public void testByteHashCode() {
byte byteValue = 123;
ByteProperty byteProperty = ByteProperty.create(byteValue);
assertEquals(singlePropertyHash(byteValue), byteProperty.hashCode());
}
@AutoValue
abstract static class CharProperty {
public abstract char charProperty();
public static CharProperty create(char charProperty) {
return new AutoValue_AutoValueTest_CharProperty(charProperty);
}
}
public void testCharHashCode() {
char charValue = 123;
CharProperty charProperty = CharProperty.create(charValue);
assertEquals(singlePropertyHash(charValue), charProperty.hashCode());
}
@AutoValue
abstract static class BooleanProperty {
public abstract boolean booleanProperty();
public static BooleanProperty create(boolean booleanProperty) {
return new AutoValue_AutoValueTest_BooleanProperty(booleanProperty);
}
}
public void testBooleanHashCode() {
for (boolean booleanValue : new boolean[] {false, true}) {
BooleanProperty booleanProperty = BooleanProperty.create(booleanValue);
assertEquals(singlePropertyHash(booleanValue), booleanProperty.hashCode());
}
}
@AutoValue
abstract static class FloatProperty {
public abstract float floatProperty();
public static FloatProperty create(float floatProperty) {
return new AutoValue_AutoValueTest_FloatProperty(floatProperty);
}
}
public void testFloatHashCode() {
float floatValue = 123456f;
FloatProperty floatProperty = FloatProperty.create(floatValue);
assertEquals(singlePropertyHash(floatValue), floatProperty.hashCode());
}
@AutoValue
abstract static class DoubleProperty {
public abstract double doubleProperty();
public static DoubleProperty create(double doubleProperty) {
return new AutoValue_AutoValueTest_DoubleProperty(doubleProperty);
}
}
public void testDoubleHashCode() {
double doubleValue = 12345678901234567890d;
DoubleProperty doubleProperty = DoubleProperty.create(doubleValue);
assertEquals(singlePropertyHash(doubleValue), doubleProperty.hashCode());
}
public void testFloatingEquality() {
FloatProperty floatZero = FloatProperty.create(0.0f);
FloatProperty floatMinusZero = FloatProperty.create(-0.0f);
FloatProperty floatNaN = FloatProperty.create(Float.NaN);
DoubleProperty doubleZero = DoubleProperty.create(0.0);
DoubleProperty doubleMinusZero = DoubleProperty.create(-0.0);
DoubleProperty doubleNaN = DoubleProperty.create(Double.NaN);
new EqualsTester()
.addEqualityGroup(floatZero)
.addEqualityGroup(floatMinusZero)
.addEqualityGroup(floatNaN)
.addEqualityGroup(doubleZero)
.addEqualityGroup(doubleMinusZero)
.addEqualityGroup(doubleNaN)
.testEquals();
}
private static int singlePropertyHash(Object property) {
return 1000003 ^ property.hashCode();
}
abstract static class Super {
public abstract Object superObject();
public abstract boolean superBoolean();
// The above two are out of alphabetical order to test EclipseHack.
}
@AutoValue
public abstract static class Sub extends Super {
public abstract int subInt();
public static Sub create(Object superObject, boolean superBoolean, int subInt) {
return new AutoValue_AutoValueTest_Sub(superObject, superBoolean, subInt);
}
}
// The @AutoValue class can inherit abstract methods from its superclass.
public void testSuperclass() throws Exception {
Sub instance = Sub.create("blim", true, 1729);
assertEquals("blim", instance.superObject());
assertTrue(instance.superBoolean());
assertEquals(1729, instance.subInt());
assertEquals(instance, instance);
assertEqualsNullIsFalse(instance);
}
abstract static class NonPublicSuper {
abstract Object superObject();
}
// The properties in this subclass are not in alphabetical order, which enables us to test that
// everything works correctly when Eclipse sorts them into the order
// [superObject, subInt, subString], since it sorts per class.
@AutoValue
abstract static class NonPublicSub extends NonPublicSuper {
abstract String subString();
abstract int subInt();
static NonPublicSub create(Object superObject, String subString, int subInt) {
return new AutoValue_AutoValueTest_NonPublicSub(superObject, subString, subInt);
}
}
public void testNonPublicInheritedGetters() throws Exception {
NonPublicSub instance = NonPublicSub.create("blim", "blam", 1729);
assertEquals("blim", instance.superObject());
assertEquals("blam", instance.subString());
assertEquals(1729, instance.subInt());
assertEquals(instance, instance);
assertEqualsNullIsFalse(instance);
}
@SuppressWarnings("ObjectEqualsNull")
private void assertEqualsNullIsFalse(Object instance) {
assertFalse(instance.equals(null));
}
@AutoValue
abstract static class NullableProperties {
@Nullable abstract String nullableString();
abstract int randomInt();
static NullableProperties create(@Nullable String nullableString, int randomInt) {
return new AutoValue_AutoValueTest_NullableProperties(nullableString, randomInt);
}
}
public void testNullablePropertiesCanBeNull() throws Exception {
NullableProperties instance = NullableProperties.create(null, 23);
assertNull(instance.nullableString());
assertEquals(23, instance.randomInt());
assertEquals("NullableProperties{nullableString=null, randomInt=23}", instance.toString());
}
@AutoValue
abstract static class AlternativeNullableProperties {
@interface Nullable {}
@AlternativeNullableProperties.Nullable abstract String nullableString();
abstract int randomInt();
static AlternativeNullableProperties create(@Nullable String nullableString, int randomInt) {
return new AutoValue_AutoValueTest_AlternativeNullableProperties(nullableString, randomInt);
}
}
public void testNullableCanBeFromElsewhere() throws Exception {
AlternativeNullableProperties instance = AlternativeNullableProperties.create(null, 23);
assertNull(instance.nullableString());
assertEquals(23, instance.randomInt());
assertEquals(
"AlternativeNullableProperties{nullableString=null, randomInt=23}", instance.toString());
}
@AutoValue
abstract static class NonNullableProperties {
abstract String nonNullableString();
abstract int randomInt();
static NonNullableProperties create(String nonNullableString, int randomInt) {
return new AutoValue_AutoValueTest_NonNullableProperties(nonNullableString, randomInt);
}
}
public void testNonNullablePropertiesCannotBeNull() throws Exception {
try {
NonNullableProperties.create(null, 23);
fail("Object creation succeeded but should not have");
} catch (NullPointerException expected) {
}
NonNullableProperties instance = NonNullableProperties.create("nonnull", 23);
assertEquals("nonnull", instance.nonNullableString());
assertEquals(23, instance.randomInt());
}
static class Nested {
@AutoValue
abstract static class Doubly {
@Nullable abstract String nullableString();
abstract int randomInt();
static Doubly create(String nullableString, int randomInt) {
return new AutoValue_AutoValueTest_Nested_Doubly(nullableString, randomInt);
}
}
}
public void testDoublyNestedClass() throws Exception {
Nested.Doubly instance = Nested.Doubly.create(null, 23);
assertNull(instance.nullableString());
assertEquals(23, instance.randomInt());
assertEquals("Doubly{nullableString=null, randomInt=23}", instance.toString());
}
static interface NestedInInterface {
@AutoValue
abstract class Doubly {
abstract String string();
abstract Map<String, Integer> map();
static Doubly create(String string, Map<String, Integer> map) {
return new AutoValue_AutoValueTest_NestedInInterface_Doubly(string, map);
}
}
}
public void testClassNestedInInterface() throws Exception {
Map<String, Integer> map = ImmutableMap.of("vingt-et-un", 21);
NestedInInterface.Doubly instance = NestedInInterface.Doubly.create("foo", map);
assertEquals("foo", instance.string());
assertEquals(map, instance.map());
}
@AutoValue
abstract static class NullableNonNullable {
@Nullable abstract String nullableString();
@Nullable abstract String otherNullableString();
abstract String nonNullableString();
static NullableNonNullable create(
String nullableString, String otherNullableString, String nonNullableString) {
return new AutoValue_AutoValueTest_NullableNonNullable(
nullableString, otherNullableString, nonNullableString);
}
}
public void testEqualsWithNullable() throws Exception {
NullableNonNullable everythingNull =
NullableNonNullable.create(null, null, "nonNullableString");
NullableNonNullable somethingNull =
NullableNonNullable.create(null, "otherNullableString", "nonNullableString");
NullableNonNullable nothingNull =
NullableNonNullable.create("nullableString", "otherNullableString", "nonNullableString");
NullableNonNullable nothingNullAgain =
NullableNonNullable.create("nullableString", "otherNullableString", "nonNullableString");
new EqualsTester()
.addEqualityGroup(everythingNull)
.addEqualityGroup(somethingNull)
.addEqualityGroup(nothingNull, nothingNullAgain)
.testEquals();
}
@AutoValue
abstract static class GenericProperties {
abstract Map<String, Integer> simpleMap();
abstract Map<String, Map<String, Integer>> hairyMap();
static GenericProperties create(
Map<String, Integer> simpleMap, Map<String, Map<String, Integer>> hairyMap) {
return new AutoValue_AutoValueTest_GenericProperties(simpleMap, hairyMap);
}
}
public void testGenericProperties() throws Exception {
GenericProperties instance1 = GenericProperties.create(
ImmutableMap.of("twenty-three", 23),
ImmutableMap.of("very", (Map<String, Integer>) ImmutableMap.of("hairy", 17)));
GenericProperties instance2 = GenericProperties.create(
ImmutableMap.of("seventeen", 17),
ImmutableMap.of("very", (Map<String, Integer>) ImmutableMap.of("hairy", 23)));
new EqualsTester()
.addEqualityGroup(instance1)
.addEqualityGroup(instance2)
.testEquals();
assertEquals(
ImmutableMap.of("very", (Map<String, Integer>) ImmutableMap.of("hairy", 23)),
instance2.hairyMap());
}
@AutoValue
abstract static class GenericClass<K, V> {
abstract K key();
abstract Map<K, V> map();
static <K, V> GenericClass<K, V> create(K key, Map<K, V> map) {
return new AutoValue_AutoValueTest_GenericClass<K, V>(key, map);
}
}
public void testGenericClass() throws Exception {
GenericClass<String, Boolean> instance =
GenericClass.create("whatever", ImmutableMap.of("no", false));
assertEquals(instance, instance);
assertEquals("whatever", instance.key());
assertEquals(ImmutableMap.of("no", false), instance.map());
}
@AutoValue
abstract static class GenericClassSimpleBounds<K extends Number, V extends K> {
abstract K key();
abstract Map<K, V> map();
static <K extends Number, V extends K> GenericClassSimpleBounds<K, V> create(
K key, Map<K, V> map) {
return new AutoValue_AutoValueTest_GenericClassSimpleBounds<K, V>(key, map);
}
}
public void testGenericClassWithSimpleBounds() throws Exception {
GenericClassSimpleBounds<Integer, Integer> instance =
GenericClassSimpleBounds.create(23, ImmutableMap.of(17, 23));
assertEquals(instance, instance);
assertEquals(23, (int) instance.key());
assertEquals(ImmutableMap.of(17, 23), instance.map());
}
@AutoValue
abstract static class GenericClassHairyBounds<K extends List<V> & Comparable<K>, V> {
abstract K key();
abstract Map<K, V> map();
static <K extends List<V> & Comparable<K>, V> GenericClassHairyBounds<K, V> create(
K key, Map<K, V> map) {
return new AutoValue_AutoValueTest_GenericClassHairyBounds<K, V>(key, map);
}
}
public void testGenericClassWithHairyBounds() throws Exception {
class ComparableList<E> extends ArrayList<E> implements Comparable<ComparableList<E>> {
@Override public int compareTo(ComparableList<E> list) {
throw new UnsupportedOperationException();
}
}
ComparableList<String> emptyList = new ComparableList<String>();
GenericClassHairyBounds<ComparableList<String>, String> instance =
GenericClassHairyBounds.create(emptyList, ImmutableMap.of(emptyList, "23"));
assertEquals(instance, instance);
assertEquals(emptyList, instance.key());
assertEquals(ImmutableMap.of(emptyList, "23"), instance.map());
}
interface Mergeable<M extends Mergeable<M>> {
M merge(M other);
}
@AutoValue
abstract static class Delta<M extends Mergeable<M>> {
abstract M meta();
static <M extends Mergeable<M>> Delta<M> create(M meta) {
return new AutoValue_AutoValueTest_Delta<M>(meta);
}
}
public void testRecursiveGeneric() {
class MergeableImpl implements Mergeable<MergeableImpl> {
@Override public MergeableImpl merge(MergeableImpl other) {
return this;
}
}
MergeableImpl mergeable = new MergeableImpl();
Delta<MergeableImpl> instance = Delta.create(mergeable);
assertSame(mergeable, instance.meta());
}
@AutoValue
abstract static class ExplicitToString {
abstract String string();
static ExplicitToString create(String string) {
return new AutoValue_AutoValueTest_ExplicitToString(string);
}
@Override
public String toString() {
return "Bazinga{" + string() + "}";
}
}
// We should not generate a toString() method if there already is a non-default one.
public void testExplicitToString() throws Exception {
ExplicitToString instance = ExplicitToString.create("foo");
assertEquals("Bazinga{foo}", instance.toString());
}
abstract static class NonAutoExplicitToString {
abstract String string();
@Override
public String toString() {
return "Bazinga{" + string() + "}";
}
}
@AutoValue
abstract static class InheritedExplicitToString extends NonAutoExplicitToString {
static InheritedExplicitToString create(String string) {
return new AutoValue_AutoValueTest_InheritedExplicitToString(string);
}
}
// We should not generate a toString() method if we already inherit a non-default one.
public void testInheritedExplicitToString() throws Exception {
InheritedExplicitToString instance = InheritedExplicitToString.create("foo");
assertEquals("Bazinga{foo}", instance.toString());
}
@AutoValue
abstract static class AbstractToString {
abstract String string();
static AbstractToString create(String string) {
return new AutoValue_AutoValueTest_AbstractToString(string);
}
@Override
public abstract String toString();
}
// We should generate a toString() method if the parent class has an abstract one.
// That allows users to cancel a toString() from a parent class if they want.
public void testAbstractToString() throws Exception {
AbstractToString instance = AbstractToString.create("foo");
assertEquals("AbstractToString{string=foo}", instance.toString());
}
abstract static class NonAutoAbstractToString {
abstract String string();
@Override
public abstract String toString();
}
@AutoValue
abstract static class SubAbstractToString extends NonAutoAbstractToString {
static SubAbstractToString create(String string) {
return new AutoValue_AutoValueTest_SubAbstractToString(string);
}
}
// We should generate a toString() method if the parent class inherits an abstract one.
public void testInheritedAbstractToString() throws Exception {
SubAbstractToString instance = SubAbstractToString.create("foo");
assertEquals("SubAbstractToString{string=foo}", instance.toString());
}
@AutoValue
abstract static class ExplicitHashCode {
abstract String string();
static ExplicitHashCode create(String string) {
return new AutoValue_AutoValueTest_ExplicitHashCode(string);
}
@Override
public int hashCode() {
return 1234;
}
}
public void testExplicitHashCode() throws Exception {
ExplicitHashCode instance = ExplicitHashCode.create("foo");
assertEquals(1234, instance.hashCode());
}
@AutoValue
abstract static class ExplicitEquals {
int equalsCount;
static ExplicitEquals create() {
return new AutoValue_AutoValueTest_ExplicitEquals();
}
@Override
public boolean equals(Object o) {
equalsCount++;
return super.equals(o);
}
}
public void testExplicitEquals() throws Exception {
ExplicitEquals instance = ExplicitEquals.create();
assertEquals(0, instance.equalsCount);
assertTrue(instance.equals(instance));
assertEquals(1, instance.equalsCount);
Method equals = instance.getClass().getMethod("equals", Object.class);
assertNotSame(ExplicitEquals.class, instance.getClass());
assertSame(ExplicitEquals.class, equals.getDeclaringClass());
}
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value();
}
@AutoValue
abstract static class PrimitiveArrays {
abstract boolean[] booleans();
@Nullable abstract int[] ints();
static PrimitiveArrays create(boolean[] booleans, int[] ints) {
// Real code would likely clone these parameters, but here we want to check that the
// generated constructor rejects a null value for booleans.
return new AutoValue_AutoValueTest_PrimitiveArrays(booleans, ints);
}
}
public void testPrimitiveArrays() {
PrimitiveArrays object0 = PrimitiveArrays.create(new boolean[0], new int[0]);
boolean[] booleans = {false, true, true, false};
int[] ints = {6, 28, 496, 8128, 33550336};
PrimitiveArrays object1 = PrimitiveArrays.create(booleans.clone(), ints.clone());
PrimitiveArrays object2 = PrimitiveArrays.create(booleans.clone(), ints.clone());
new EqualsTester()
.addEqualityGroup(object1, object2)
.addEqualityGroup(object0)
.testEquals();
// EqualsTester also exercises hashCode(). We clone the arrays above to ensure that using the
// default Object.hashCode() will fail.
String expectedString = "PrimitiveArrays{booleans=" + Arrays.toString(booleans) + ", "
+ "ints=" + Arrays.toString(ints) + "}";
assertEquals(expectedString, object1.toString());
// Check that getters clone the arrays so callers can't change them.
object1.ints()[0]++;
assertTrue(Arrays.equals(ints, object1.ints()));
}
public void testNullablePrimitiveArrays() {
PrimitiveArrays object0 = PrimitiveArrays.create(new boolean[0], null);
boolean[] booleans = {false, true, true, false};
PrimitiveArrays object1 = PrimitiveArrays.create(booleans.clone(), null);
PrimitiveArrays object2 = PrimitiveArrays.create(booleans.clone(), null);
new EqualsTester()
.addEqualityGroup(object1, object2)
.addEqualityGroup(object0)
.testEquals();
String expectedString = "PrimitiveArrays{booleans=" + Arrays.toString(booleans) + ", "
+ "ints=null}";
assertEquals(expectedString, object1.toString());
object1.booleans()[0] ^= true;
assertTrue(Arrays.equals(booleans, object1.booleans()));
}
public void testNotNullablePrimitiveArrays() {
try {
PrimitiveArrays.create(null, new int[0]);
fail("Construction with null value for non-@Nullable array should have failed");
} catch (NullPointerException e) {
assertTrue(e.getMessage().contains("booleans"));
}
}
// If users are mad enough to define their own Arrays class and have some properties of that
// class and others of primitive array type, then we can't import java.util.Arrays.
// This is unlikely.
@AutoValue
abstract static class AmbiguousArrays {
static class Arrays {}
abstract Arrays arrays();
abstract int[] ints();
static AmbiguousArrays create(Arrays arrays, int[] ints) {
return new AutoValue_AutoValueTest_AmbiguousArrays(arrays, ints);
}
}
public void testAmbiguousArrays() {
// If this test compiles at all then we presumably don't have the import problem above.
AmbiguousArrays object1 = AmbiguousArrays.create(new AmbiguousArrays.Arrays(), new int[0]);
assertNotNull(object1.arrays());
assertEquals(0, object1.ints().length);
}
static final class HashCodeObserver {
int hashCodeCount;
@Override
public boolean equals(Object obj) {
return obj instanceof HashCodeObserver;
}
@Override
public int hashCode() {
hashCodeCount++;
return 23;
}
}
@AutoValue
abstract static class MaybeCachedHashCode {
abstract HashCodeObserver hashCodeObserver();
abstract int randomInt();
static MaybeCachedHashCode create(HashCodeObserver hashCodeObserver, int randomInt) {
return new AutoValue_AutoValueTest_MaybeCachedHashCode(hashCodeObserver, randomInt);
}
}
public void testHashCodeNotCached() {
HashCodeObserver observer = new HashCodeObserver();
MaybeCachedHashCode maybeCached = MaybeCachedHashCode.create(observer, 17);
int hash1 = maybeCached.hashCode();
int hash2 = maybeCached.hashCode();
assertEquals(hash1, hash2);
assertEquals(2, observer.hashCodeCount);
}
@AutoValue
abstract static class Version implements Comparable<Version> {
abstract int major();
abstract int minor();
static Version create(int major, int minor) {
return new AutoValue_AutoValueTest_Version(major, minor);
}
@Override
public int compareTo(Version that) {
return ComparisonChain.start()
.compare(this.major(), that.major())
.compare(this.minor(), that.minor())
.result();
}
}
public void testComparisonChain() {
assertEquals(Version.create(1, 2), Version.create(1, 2));
Version[] versions = {Version.create(1, 2), Version.create(1, 3), Version.create(2, 1)};
for (int i = 0; i < versions.length; i++) {
for (int j = 0; j < versions.length; j++) {
int actual = Integer.signum(versions[i].compareTo(versions[j]));
int expected = Integer.signum(i - j);
assertEquals(actual, expected);
}
}
}
abstract static class LukesBase {
interface LukesVisitor<T> {
T visit(LukesSub s);
}
abstract <T> T accept(LukesVisitor<T> visitor);
@AutoValue abstract static class LukesSub extends LukesBase {
static LukesSub create() {
return new AutoValue_AutoValueTest_LukesBase_LukesSub();
}
@Override <T> T accept(LukesVisitor<T> visitor) {
return visitor.visit(this);
}
}
}
public void testVisitor() {
LukesBase.LukesVisitor<String> visitor = new LukesBase.LukesVisitor<String>() {
@Override public String visit(LukesBase.LukesSub s) {
return s.toString();
}
};
LukesBase.LukesSub sub = LukesBase.LukesSub.create();
assertEquals(sub.toString(), sub.accept(visitor));
}
@AutoValue
public abstract static class ComplexInheritance extends AbstractBase implements A, B {
public static ComplexInheritance create(String name) {
return new AutoValue_AutoValueTest_ComplexInheritance(name);
}
abstract String name();
}
static class AbstractBase implements Base {
@Override
public int answer() {
return 42;
}
}
interface A extends Base {}
interface B extends Base {}
interface Base {
int answer();
}
public void testComplexInheritance() {
ComplexInheritance complex = ComplexInheritance.create("fred");
assertEquals("fred", complex.name());
assertEquals(42, complex.answer());
}
@AutoValue
public abstract static class InheritTwice implements A, B {
public static InheritTwice create(int answer) {
return new AutoValue_AutoValueTest_InheritTwice(answer);
}
}
public void testInheritTwice() {
InheritTwice inheritTwice = InheritTwice.create(42);
assertEquals(42, inheritTwice.answer());
}
@AutoValue
public abstract static class Optional {
public abstract com.google.common.base.Optional<Object> getOptional();
public static Optional create(com.google.common.base.Optional<Object> opt) {
return new AutoValue_AutoValueTest_Optional(opt);
}
}
public void testAmbiguityFromAutoValueType() {
Optional autoOptional = Optional.create(com.google.common.base.Optional.absent());
assertEquals(com.google.common.base.Optional.absent(), autoOptional.getOptional());
}
static class BaseWithNestedType {
static class Optional {}
}
@AutoValue
public abstract static class InheritsNestedType extends BaseWithNestedType {
public abstract com.google.common.base.Optional<Object> getOptional();
public static InheritsNestedType create(com.google.common.base.Optional<Object> opt) {
return new AutoValue_AutoValueTest_InheritsNestedType(opt);
}
}
public void testAmbiguityFromInheritedType() {
InheritsNestedType inheritsNestedType =
InheritsNestedType.create(com.google.common.base.Optional.absent());
assertEquals(com.google.common.base.Optional.absent(), inheritsNestedType.getOptional());
}
abstract static class AbstractParent {
abstract int foo();
}
@AutoValue
abstract static class AbstractChild extends AbstractParent {
// The main point of this test is to ensure that we don't try to copy this @Override into the
// generated implementation alongside the @Override that we put on all implementation methods.
@Override
abstract int foo();
static AbstractChild create(int foo) {
return new AutoValue_AutoValueTest_AbstractChild(foo);
}
}
public void testOverrideNotDuplicated() {
AbstractChild instance = AbstractChild.create(23);
assertEquals(23, instance.foo());
}
@AutoValue
public abstract static class BasicWithBuilder {
public abstract int foo();
public static Builder builder() {
return new AutoValue_AutoValueTest_BasicWithBuilder.Builder();
}
@AutoValue.Builder
public interface Builder {
Builder foo(int foo);
BasicWithBuilder build();
}
}
public void testBasicWithBuilder() {
BasicWithBuilder x = BasicWithBuilder.builder().foo(23).build();
assertEquals(23, x.foo());
try {
BasicWithBuilder.builder().build();
fail("Expected exception for missing property");
} catch (IllegalStateException e) {
assertThat(e.getMessage()).contains("foo");
}
}
@AutoValue
public abstract static class EmptyWithBuilder {
public static Builder builder() {
return new AutoValue_AutoValueTest_EmptyWithBuilder.Builder();
}
@AutoValue.Builder
public interface Builder {
EmptyWithBuilder build();
}
}
public void testEmptyWithBuilder() {
EmptyWithBuilder x = EmptyWithBuilder.builder().build();
EmptyWithBuilder y = EmptyWithBuilder.builder().build();
assertEquals(x, y);
}
@AutoValue
public abstract static class TwoPropertiesWithBuilderClass {
public abstract String string();
public abstract int integer();
public static Builder builder() {
return new AutoValue_AutoValueTest_TwoPropertiesWithBuilderClass.Builder();
}
public static Builder builder(String string) {
return new AutoValue_AutoValueTest_TwoPropertiesWithBuilderClass.Builder()
.string(string);
}
@AutoValue.Builder
public abstract static class Builder {
public abstract Builder string(String x);
public abstract Builder integer(int x);
public abstract TwoPropertiesWithBuilderClass build();
}
}
public void testTwoPropertiesWithBuilderClass() {
TwoPropertiesWithBuilderClass a1 =
TwoPropertiesWithBuilderClass.builder().string("23").integer(17).build();
TwoPropertiesWithBuilderClass a2 =
TwoPropertiesWithBuilderClass.builder("23").integer(17).build();
TwoPropertiesWithBuilderClass a3 =
TwoPropertiesWithBuilderClass.builder().integer(17).string("23").build();
TwoPropertiesWithBuilderClass b =
TwoPropertiesWithBuilderClass.builder().string("17").integer(17).build();
new EqualsTester()
.addEqualityGroup(a1, a2, a3)
.addEqualityGroup(b)
.testEquals();
}
@AutoValue
public abstract static class ValidationWithBuilder {
public abstract String string();
public abstract int integer();
public static Builder builder() {
return new AutoValue_AutoValueTest_ValidationWithBuilder.Builder();
}
@AutoValue.Validate
void validate() {
if (string().isEmpty()) {
throw new IllegalStateException("String is empty");
}
if (integer() < 0) {
throw new IllegalStateException("Integer is negative");
}
}
@AutoValue.Builder
public interface Builder {
Builder string(String string);
Builder integer(int integer);
ValidationWithBuilder build();
}
}
public void testValidation() {
ValidationWithBuilder ok = ValidationWithBuilder.builder().string("foo").integer(17).build();
assertEquals("foo", ok.string());
assertEquals(17, ok.integer());
try {
ValidationWithBuilder.builder().string("").integer(17).build();
fail("Expected IllegalStateException for empty string");
} catch (IllegalStateException expected) {
assertThat(expected).hasMessage("String is empty");
}
try {
ValidationWithBuilder.builder().string("foo").integer(-17).build();
fail("Expected IllegalStateException for negative integer");
} catch (IllegalStateException expected) {
assertThat(expected).hasMessage("Integer is negative");
}
}
@AutoValue
public abstract static class GenericsWithBuilder<T extends Number & Comparable<T>, U extends T> {
public abstract List<T> list();
public abstract U u();
public static <T extends Number & Comparable<T>, U extends T> Builder<T, U> builder() {
return new AutoValue_AutoValueTest_GenericsWithBuilder.Builder<T, U>();
}
@AutoValue.Builder
public interface Builder<T extends Number & Comparable<T>, U extends T> {
Builder<T, U> list(List<T> list);
Builder<T, U> u(U u);
GenericsWithBuilder<T, U> build();
}
}
public void testBuilderGenerics() {
List<Integer> integers = ImmutableList.of(1, 2, 3);
GenericsWithBuilder<Integer, Integer> instance =
GenericsWithBuilder.<Integer, Integer>builder().list(integers).u(23).build();
assertEquals(integers, instance.list());
assertEquals((Integer) 23, instance.u());
}
@AutoValue
public abstract static class BuilderWithSet<T extends Comparable<T>> {
public abstract List<T> list();
public abstract T t();
public static <T extends Comparable<T>> Builder<T> builder() {
return new AutoValue_AutoValueTest_BuilderWithSet.Builder<T>();
}
@AutoValue.Builder
public interface Builder<T extends Comparable<T>> {
Builder<T> setList(List<T> list);
Builder<T> setT(T t);
BuilderWithSet<T> build();
}
}
public void testBuilderWithSet() {
List<Integer> integers = ImmutableList.of(1, 2, 3);
BuilderWithSet<Integer> instance =
BuilderWithSet.<Integer>builder().setList(integers).setT(23).build();
assertEquals(integers, instance.list());
assertEquals((Integer) 23, instance.t());
}
@AutoValue
public abstract static class BuilderWithSetAndGet {
public abstract List<Integer> getAList();
public abstract int getAnInt();
public static Builder builder() {
return new AutoValue_AutoValueTest_BuilderWithSetAndGet.Builder();
}
@AutoValue.Builder
public interface Builder {
Builder setAList(List<Integer> list);
Builder setAnInt(int i);
BuilderWithSetAndGet build();
}
}
public void testBuilderWithSetAndGet() {
List<Integer> integers = ImmutableList.of(1, 2, 3);
BuilderWithSetAndGet instance =
BuilderWithSetAndGet.builder().setAList(integers).setAnInt(23).build();
assertEquals(integers, instance.getAList());
assertEquals(23, instance.getAnInt());
}
@Retention(RetentionPolicy.RUNTIME)
@interface GwtCompatible {
boolean funky() default false;
}
@AutoValue
@GwtCompatible(funky = true)
abstract static class GwtCompatibleTest {
abstract int foo();
static GwtCompatibleTest create(int foo) {
return new AutoValue_AutoValueTest_GwtCompatibleTest(foo);
}
}
@AutoValue
@GwtCompatible
abstract static class GwtCompatibleTestNoArgs {
abstract String bar();
static GwtCompatibleTestNoArgs create(String bar) {
return new AutoValue_AutoValueTest_GwtCompatibleTestNoArgs(bar);
}
}
public void testGwtCompatibleInherited() {
GwtCompatibleTest test = GwtCompatibleTest.create(23);
GwtCompatible gwtCompatible = test.getClass().getAnnotation(GwtCompatible.class);
assertNotNull(gwtCompatible);
assertTrue(gwtCompatible.funky());
GwtCompatibleTestNoArgs testNoArgs = GwtCompatibleTestNoArgs.create("23");
GwtCompatible gwtCompatibleNoArgs = testNoArgs.getClass().getAnnotation(GwtCompatible.class);
assertNotNull(gwtCompatibleNoArgs);
assertFalse(gwtCompatibleNoArgs.funky());
}
@interface NestedAnnotation {
int anInt();
Class<?>[] aClassArray();
}
@Retention(RetentionPolicy.RUNTIME)
@interface HairyAnnotation {
String aString();
Class<? extends Number> aClass();
RetentionPolicy anEnum();
NestedAnnotation anAnnotation();
}
@AutoValue
abstract static class CopyAnnotation {
@HairyAnnotation(
aString = "hello",
aClass = Integer.class,
anEnum = RetentionPolicy.RUNTIME,
anAnnotation = @NestedAnnotation(
anInt = 73,
aClassArray = {String.class, Object.class}))
abstract String id();
static CopyAnnotation create(String id) {
return new AutoValue_AutoValueTest_CopyAnnotation(id);
}
}
public void testCopyAnnotations() throws Exception {
CopyAnnotation x = CopyAnnotation.create("id");
Class<?> c = x.getClass();
assertNotSame(CopyAnnotation.class, c);
Method methodInSubclass = c.getDeclaredMethod("id");
Method methodInSuperclass = CopyAnnotation.class.getDeclaredMethod("id");
assertNotSame(methodInSuperclass, methodInSubclass);
HairyAnnotation annotationInSubclass =
methodInSubclass.getAnnotation(HairyAnnotation.class);
HairyAnnotation annotationInSuperclass =
methodInSuperclass.getAnnotation(HairyAnnotation.class);
assertEquals(annotationInSuperclass, annotationInSubclass);
}
}