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