1 /*
2  * Copyright (C) 2023 The Android Open Source Project
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 
17 package com.android.tools.metalava.model.testsuite.annotationitem
18 
19 import com.android.tools.metalava.model.AnnotationItem
20 import com.android.tools.metalava.model.ClassItem
21 import com.android.tools.metalava.model.getAttributeValue
22 import com.android.tools.metalava.model.getAttributeValues
23 import com.android.tools.metalava.model.testsuite.BaseModelTest
24 import com.android.tools.metalava.testing.java
25 import kotlin.test.assertEquals
26 import org.junit.Test
27 
28 /** Common tests for implementations of [ClassItem]. */
29 class CommonAnnotationItemTest : BaseModelTest() {
30 
31     @Test
annotation with annotation valuesnull32     fun `annotation with annotation values`() {
33         runCodebaseTest(
34             signature(
35                 """
36                     // Signature format: 2.0
37                     package test.pkg {
38                       @test.pkg.Test.Anno(
39                         annotationValue = @test.pkg.Other("other"),
40                         annotationArrayValue = {@test.pkg.Other("other1"), @test.pkg.Other("other2")}
41                       )
42                       public class Test {
43                         ctor public Test();
44                       }
45 
46                       public @interface Test.Anno {
47                           method public Other annotationValue();
48                           method public Other[] annotationArrayValue();
49                       }
50                     }
51                 """
52             ),
53             java(
54                 """
55                     package test.pkg;
56 
57                     @Test.Anno(
58                       annotationValue = @test.pkg.Other("other"),
59                       annotationArrayValue = {@test.pkg.Other("other1"), @test.pkg.Other("other2")}
60                     )
61                     public class Test {
62                         public Test() {}
63 
64                         public @interface Anno {
65                           Other annotationValue();
66                           Other[] annotationArrayValue();
67                         }
68                     }
69 
70                     @interface Other {
71                         String value();
72                     }
73                 """
74             ),
75         ) {
76             val testClass = codebase.assertClass("test.pkg.Test")
77             val anno = testClass.modifiers.annotations().single()
78 
79             val other = anno.getAttributeValue<AnnotationItem>("annotationValue")!!
80             assertEquals("test.pkg.Other", other.qualifiedName)
81             other.assertAttributeValue("value", "other")
82 
83             val otherAsList = anno.getAttributeValues<AnnotationItem>("annotationValue")
84             assertEquals(listOf(other), otherAsList)
85 
86             val others = anno.getAttributeValues<AnnotationItem>("annotationArrayValue")!!
87             assertEquals(
88                 "other1, other2",
89                 others.mapNotNull { it.getAttributeValue("value") }.joinToString()
90             )
91         }
92     }
93 
94     @Test
annotation with boolean valuesnull95     fun `annotation with boolean values`() {
96         runCodebaseTest(
97             signature(
98                 """
99                     // Signature format: 2.0
100                     package test.pkg {
101                       @test.pkg.Test.Anno(
102                           booleanValue = true,
103                           booleanArrayValue = {true, false},
104                       )
105                       public class Test {
106                         ctor public Test();
107                       }
108 
109                       public @interface Test.Anno {
110                           method public boolean booleanValue();
111                           method public boolean[] booleanArrayValue();
112                       }
113                     }
114                 """
115             ),
116             java(
117                 """
118                     package test.pkg;
119 
120                     @Test.Anno(
121                       booleanValue = true,
122                       booleanArrayValue = {true, false}
123                     )
124                     public class Test {
125                         public Test() {}
126 
127                         public @interface Anno {
128                           boolean booleanValue();
129                           boolean[] booleanArrayValue();
130                         }
131                     }
132                 """
133             ),
134         ) {
135             val testClass = codebase.assertClass("test.pkg.Test")
136             val anno = testClass.modifiers.annotations().single()
137 
138             anno.assertAttributeValue("booleanValue", true)
139             anno.assertAttributeValues("booleanValue", listOf(true))
140             anno.assertAttributeValues("booleanArrayValue", listOf(true, false))
141         }
142     }
143 
144     @Test
annotation with char valuesnull145     fun `annotation with char values`() {
146         runCodebaseTest(
147             signature(
148                 """
149                     // Signature format: 2.0
150                     package test.pkg {
151                       @test.pkg.Test.Anno(
152                           charValue = 'a',
153                           charArrayValue = {'a', 'b'},
154                       )
155                       public class Test {
156                         ctor public Test();
157                       }
158 
159                       public @interface Test.Anno {
160                           method public char charValue();
161                           method public char[] charArrayValue();
162                       }
163                     }
164                 """
165             ),
166             java(
167                 """
168                     package test.pkg;
169 
170                     @Test.Anno(
171                       charValue = 'a',
172                       charArrayValue = {'a', 'b'}
173                     )
174                     public class Test {
175                         public Test() {}
176 
177                         public @interface Anno {
178                           char charValue();
179                           char[] charArrayValue();
180                         }
181                     }
182                 """
183             ),
184         ) {
185             val testClass = codebase.assertClass("test.pkg.Test")
186             val anno = testClass.modifiers.annotations().single()
187 
188             anno.assertAttributeValue("charValue", 'a')
189             anno.assertAttributeValues("charValue", listOf('a'))
190             anno.assertAttributeValues("charArrayValue", listOf('a', 'b'))
191         }
192     }
193 
194     @Test
annotation with class valuesnull195     fun `annotation with class values`() {
196         runCodebaseTest(
197             signature(
198                 """
199                     // Signature format: 2.0
200                     package test.pkg {
201                       @test.pkg.Test.Anno(
202                           classValue = test.pkg.Test,
203                           classArrayValue = {test.pkg.Test, Anno}
204                       )
205                       public class Test {
206                         ctor public Test();
207                       }
208 
209                       public @interface Test.Anno {
210                           method public Class<?> classValue();
211                           method public Class<?>[] classArrayValue();
212                       }
213                     }
214                 """
215             ),
216             java(
217                 """
218                     package test.pkg;
219 
220                     @Test.Anno(
221                       classValue = Test.class,
222                       classArrayValue = {Test.class, Anno.class}
223                     )
224                     public class Test {
225                         public Test() {}
226 
227                         public @interface Anno {
228                           Class<?> classValue();
229                           Class<?>[] classArrayValue();
230                         }
231                     }
232                 """
233             ),
234         ) {
235             val testClass = codebase.assertClass("test.pkg.Test")
236             val anno = testClass.modifiers.annotations().single()
237 
238             // A class value can be retrieved as a string.
239             anno.assertAttributeValue("classValue", "test.pkg.Test")
240             anno.assertAttributeValues("classValue", listOf("test.pkg.Test"))
241             anno.assertAttributeValues("classArrayValue", listOf("test.pkg.Test", "Anno"))
242         }
243     }
244 
245     @Test
annotation with number valuesnull246     fun `annotation with number values`() {
247         runCodebaseTest(
248             signature(
249                 """
250                     // Signature format: 2.0
251                     package test.pkg {
252                       @test.pkg.Test.Anno(
253                           byteValue = 1,
254                           byteArrayValue = {1, 2},
255 
256                           doubleValue = 1.5,
257                           doubleArrayValue = {1.5, 2.5},
258 
259                           floatValue = 0.5F,
260                           floatArrayValue = {0.5F, 1.5F},
261 
262                           intValue = 1,
263                           intArrayValue = {1, 2, 3},
264 
265                           longValue = 2,
266                           longArrayValue = {2, 4},
267 
268                           shortValue = 3,
269                           shortArrayValue = {3, 5},
270                       )
271                       public class Test {
272                         ctor public Test();
273                       }
274 
275                       public @interface Test.Anno {
276                           method public byte byteValue();
277                           method public byte[] byteArrayValue();
278 
279                           method public double doubleValue();
280                           method public double[] doubleArrayValue();
281 
282                           method public float floatValue();
283                           method public float[] floatArrayValue();
284 
285                           method public int intValue();
286                           method public int[] intArrayValue();
287 
288                           method public long longValue();
289                           method public long[] longArrayValue();
290 
291                           method public short shortValue();
292                           method public short[] shortArrayValue();
293                       }
294                     }
295                 """
296             ),
297             java(
298                 """
299                     package test.pkg;
300 
301                     @Test.Anno(
302                       byteValue = 1,
303                       byteArrayValue = {1, 2},
304 
305                       doubleValue = 1.5,
306                       doubleArrayValue = {1.5, 2.5},
307 
308                       floatValue = 0.5F,
309                       floatArrayValue = {0.5F, 1.5F},
310 
311                       intValue = 1,
312                       intArrayValue = {1, 2, 3},
313 
314                       longValue = 2L,
315                       longArrayValue = {2L, 4L},
316 
317                       shortValue = 3,
318                       shortArrayValue = {3, 5}
319                     )
320                     public class Test {
321                         public Test() {}
322 
323                         public @interface Anno {
324                           byte byteValue();
325                           byte[] byteArrayValue();
326 
327                           double doubleValue();
328                           double[] doubleArrayValue();
329 
330                           float floatValue();
331                           float[] floatArrayValue();
332 
333                           int intValue();
334                           int[] intArrayValue();
335 
336                           long longValue();
337                           long[] longArrayValue();
338 
339                           short shortValue();
340                           short[] shortArrayValue();
341                         }
342                     }
343                 """
344             ),
345         ) {
346             val testClass = codebase.assertClass("test.pkg.Test")
347             val anno = testClass.modifiers.annotations().single()
348 
349             anno.assertAttributeValue("byteValue", 1.toByte())
350             anno.assertAttributeValues("byteValue", byteArrayOf(1).toList())
351             anno.assertAttributeValues("byteArrayValue", byteArrayOf(1, 2).toList())
352 
353             anno.assertAttributeValue("doubleValue", 1.5)
354             anno.assertAttributeValues("doubleValue", listOf(1.5))
355             anno.assertAttributeValues("doubleArrayValue", listOf(1.5, 2.5))
356 
357             anno.assertAttributeValue("floatValue", 0.5F)
358             anno.assertAttributeValues("floatValue", listOf(0.5F))
359             anno.assertAttributeValues("floatArrayValue", listOf(0.5F, 1.5F))
360 
361             anno.assertAttributeValue("intValue", 1)
362             anno.assertAttributeValues("intValue", listOf(1))
363             anno.assertAttributeValues("intArrayValue", listOf(1, 2, 3))
364 
365             anno.assertAttributeValue("longValue", 2L)
366             anno.assertAttributeValues("longValue", listOf(2L))
367             anno.assertAttributeValues("longArrayValue", listOf(2L, 4L))
368 
369             anno.assertAttributeValue("shortValue", 3.toShort())
370             anno.assertAttributeValues("shortValue", listOf(3.toShort()))
371             anno.assertAttributeValues("shortArrayValue", shortArrayOf(3, 5).toList())
372         }
373     }
374 
375     @Test
annotation with string valuesnull376     fun `annotation with string values`() {
377         runCodebaseTest(
378             signature(
379                 """
380                     // Signature format: 2.0
381                     package test.pkg {
382                       @test.pkg.Test.Anno(
383                           stringValue = "string",
384                           stringArrayValue = {"string1", "string2"},
385                       )
386                       public class Test {
387                         ctor public Test();
388                       }
389 
390                       public @interface Test.Anno {
391                           method public String stringValue();
392                           method public String[] stringArrayValue();
393                       }
394                     }
395                 """
396             ),
397             java(
398                 """
399                     package test.pkg;
400 
401                     @Test.Anno(
402                       stringValue = "string",
403                       stringArrayValue = {"string1", "string2"}
404                     )
405                     public class Test {
406                         public Test() {}
407 
408                         public @interface Anno {
409                           String stringValue();
410                           String[] stringArrayValue();
411                         }
412                     }
413                 """
414             ),
415         ) {
416             val testClass = codebase.assertClass("test.pkg.Test")
417             val anno = testClass.modifiers.annotations().single()
418 
419             anno.assertAttributeValue("stringValue", "string")
420             anno.assertAttributeValues("stringValue", listOf("string"))
421             anno.assertAttributeValues("stringArrayValue", listOf("string1", "string2"))
422         }
423     }
424 
425     @Test
annotation array values with single elementnull426     fun `annotation array values with single element`() {
427         runCodebaseTest(
428             signature(
429                 """
430                     // Signature format: 2.0
431                     package test.pkg {
432                       @test.pkg.Test.Anno("string")
433                       public class Test {
434                         ctor public Test();
435                       }
436 
437                       public @interface Test.Anno {
438                           method public String[] value();
439                       }
440                     }
441                 """
442             ),
443             java(
444                 """
445                     package test.pkg;
446 
447                     @Test.Anno("string")
448                     public class Test {
449                         public Test() {}
450 
451                         public @interface Anno {
452                           String[] value();
453                         }
454                     }
455                 """
456             ),
457         ) {
458             val testClass = codebase.assertClass("test.pkg.Test")
459             val anno = testClass.modifiers.annotations().single()
460 
461             // It is expected to be not of array type
462             anno.assertAttributeValue("value", "string")
463         }
464     }
465 
466     @Test
annotation array values with single array elementnull467     fun `annotation array values with single array element`() {
468         runCodebaseTest(
469             signature(
470                 """
471                     // Signature format: 2.0
472                     package test.pkg {
473                       @test.pkg.Test.Anno({"string"})
474                       public class Test {
475                         ctor public Test();
476                       }
477 
478                       public @interface Test.Anno {
479                           method public String[] value();
480                       }
481                     }
482                 """
483             ),
484             java(
485                 """
486                     package test.pkg;
487 
488                     @Test.Anno({"string"})
489                     public class Test {
490                         public Test() {}
491 
492                         public @interface Anno {
493                           String[] value();
494                         }
495                     }
496                 """
497             ),
498         ) {
499             val testClass = codebase.assertClass("test.pkg.Test")
500             val anno = testClass.modifiers.annotations().single()
501 
502             // It is expected to be of array type
503             anno.assertAttributeValues("value", listOf("string"))
504         }
505     }
506 
507     @Test
annotation with enum valuesnull508     fun `annotation with enum values`() {
509         runCodebaseTest(
510             signature(
511                 """
512                     // Signature format: 2.0
513                     package test.pkg {
514                       @test.pkg.Test.Anno(
515                           enumValue = test.pkg.Enum.ENUM1,
516                           enumArrayValue = {test.pkg.Enum.ENUM1, test.pkg.Enum.ENUM2},
517                       )
518                       public class Test {
519                         ctor public Test();
520                       }
521 
522                       public @interface Test.Anno {
523                           method public Enum stringValue();
524                           method public Enum[] stringArrayValue();
525                       }
526 
527                       public enum Enum {
528                         enum_constant public test.pkg.Enum ENUM1;
529                         enum_constant public test.pkg.Enum ENUM2;
530                       }
531                     }
532                 """
533             ),
534             java(
535                 """
536                     package test.pkg;
537 
538                     @Test.Anno(
539                       enumValue = Enum.ENUM1,
540                       enumArrayValue = {Enum.ENUM1,Enum.ENUM2}
541                     )
542                     public class Test {
543                         public Test() {}
544 
545                         public @interface Anno {
546                           Enum enumValue();
547                           Enum[] enumArrayValue();
548                         }
549                     }
550 
551                     public enum Enum {
552                       ENUM1,
553                       ENUM2,
554                     }
555                 """
556             ),
557         ) {
558             val testClass = codebase.assertClass("test.pkg.Test")
559             val anno = testClass.modifiers.annotations().single()
560 
561             anno.assertAttributeValue("enumValue", "test.pkg.Enum.ENUM1")
562             anno.assertAttributeValues("enumValue", listOf("test.pkg.Enum.ENUM1"))
563             anno.assertAttributeValues(
564                 "enumArrayValue",
565                 listOf("test.pkg.Enum.ENUM1", "test.pkg.Enum.ENUM2")
566             )
567         }
568     }
569 
570     @Test
annotation with constant literal valuesnull571     fun `annotation with constant literal values`() {
572         runCodebaseTest(
573             signature(
574                 """
575                     // Signature format: 2.0
576                     package test.pkg {
577                       @test.pkg.Test.Anno(test.pkg.Test.FIELD)
578                       public class Test {
579                         ctor public Test();
580                         field public static final int FIELD = 5;
581                       }
582 
583                       public @interface Test.Anno {
584                          method public Int value();
585                       }
586                     }
587                 """
588             ),
589             java(
590                 """
591                     package test.pkg;
592 
593                     @Test.Anno(Test.FIELD)
594                     public class Test {
595                         public Test() {}
596 
597                         public static final int FIELD = 5;
598 
599                         public @interface Anno {
600                           int value();
601                         }
602                     }
603                 """
604             ),
605         ) {
606             val testClass = codebase.assertClass("test.pkg.Test")
607             val anno = testClass.modifiers.annotations().single()
608 
609             anno.assertAttributeValue("value", 5)
610         }
611     }
612 
613     @Test
annotation toSource() with annotation valuesnull614     fun `annotation toSource() with annotation values`() {
615         runCodebaseTest(
616             signature(
617                 """
618                     // Signature format: 2.0
619                     package test.pkg {
620                       @test.pkg.Test.Anno(
621                         annotationValue = @test.pkg.Other("other"),
622                         annotationArrayValue = {@test.pkg.Other("other1"), @test.pkg.Other("other2")}
623                       )
624                       public class Test {
625                         ctor public Test();
626                       }
627 
628                       public @interface Test.Anno {
629                           method public Other annotationValue();
630                           method public Other[] annotationArrayValue();
631                       }
632                     }
633                 """
634             ),
635             java(
636                 """
637                     package test.pkg;
638 
639                     @Test.Anno(
640                       annotationValue = @test.pkg.Other("other"),
641                       annotationArrayValue = {@test.pkg.Other("other1"), @test.pkg.Other("other2")}
642                     )
643                     public class Test {
644                         public Test() {}
645 
646                         public @interface Anno {
647                           Other annotationValue();
648                           Other[] annotationArrayValue();
649                         }
650                     }
651 
652                     @interface Other {
653                         String value();
654                     }
655                 """
656             ),
657         ) {
658             val testClass = codebase.assertClass("test.pkg.Test")
659             val anno = testClass.modifiers.annotations().single()
660 
661             val toSource =
662                 "@test.pkg.Test.Anno(annotationValue=@test.pkg.Other(\"other\"), annotationArrayValue={@test.pkg.Other(\"other1\"), @test.pkg.Other(\"other2\")})"
663             assertEquals(toSource, anno.toSource())
664         }
665     }
666 
667     @Test
annotation toSource() with boolean valuesnull668     fun `annotation toSource() with boolean values`() {
669         runCodebaseTest(
670             signature(
671                 """
672                     // Signature format: 2.0
673                     package test.pkg {
674                       @test.pkg.Test.Anno(
675                           booleanValue = true,
676                           booleanArrayValue = {true, false},
677                       )
678                       public class Test {
679                         ctor public Test();
680                       }
681 
682                       public @interface Test.Anno {
683                           method public boolean booleanValue();
684                           method public boolean[] booleanArrayValue();
685                       }
686                     }
687                 """
688             ),
689             java(
690                 """
691                     package test.pkg;
692 
693                     @Test.Anno(
694                       booleanValue = true,
695                       booleanArrayValue = {true, false}
696                     )
697                     public class Test {
698                         public Test() {}
699 
700                         public @interface Anno {
701                           boolean booleanValue();
702                           boolean[] booleanArrayValue();
703                         }
704                     }
705                 """
706             ),
707         ) {
708             val testClass = codebase.assertClass("test.pkg.Test")
709             val anno = testClass.modifiers.annotations().single()
710 
711             val toSource = "@test.pkg.Test.Anno(booleanValue=true, booleanArrayValue={true, false})"
712             assertEquals(toSource, anno.toSource())
713         }
714     }
715 
716     @Test
annotation toSource() with char valuesnull717     fun `annotation toSource() with char values`() {
718         runCodebaseTest(
719             signature(
720                 """
721                     // Signature format: 2.0
722                     package test.pkg {
723                       @test.pkg.Test.Anno(
724                           charValue = 'a',
725                           charArrayValue = {'a', '\uFF00'},
726                       )
727                       public class Test {
728                         ctor public Test();
729                       }
730 
731                       public @interface Test.Anno {
732                           method public char charValue();
733                           method public char[] charArrayValue();
734                       }
735                     }
736                 """
737             ),
738             java(
739                 """
740                     package test.pkg;
741 
742                     @Test.Anno(
743                       charValue = 'a',
744                       charArrayValue = {'a', '\uFF00'}
745                     )
746                     public class Test {
747                         public Test() {}
748 
749                         public @interface Anno {
750                           char charValue();
751                           char[] charArrayValue();
752                         }
753                     }
754                 """
755             ),
756         ) {
757             val testClass = codebase.assertClass("test.pkg.Test")
758             val anno = testClass.modifiers.annotations().single()
759 
760             val toSource = "@test.pkg.Test.Anno(charValue='a', charArrayValue={'a', '\\uff00'})"
761             assertEquals(toSource, anno.toSource())
762         }
763     }
764 
765     @Test
annotation toSource() with class valuesnull766     fun `annotation toSource() with class values`() {
767         runCodebaseTest(
768             signature(
769                 """
770                     // Signature format: 2.0
771                     package test.pkg {
772                       @test.pkg.Test.Anno(
773                           classValue = test.pkg.Test,
774                           classArrayValue = {test.pkg.Test, Anno}
775                       )
776                       public class Test {
777                         ctor public Test();
778                       }
779 
780                       public @interface Test.Anno {
781                           method public Class<?> classValue();
782                           method public Class<?>[] classArrayValue();
783                       }
784                     }
785                 """
786             ),
787             java(
788                 """
789                     package test.pkg;
790 
791                     @Test.Anno(
792                       classValue = Test.class,
793                       classArrayValue = {Test.class, Anno.class}
794                     )
795                     public class Test {
796                         public Test() {}
797 
798                         public @interface Anno {
799                           Class<?> classValue();
800                           Class<?>[] classArrayValue();
801                         }
802                     }
803                 """
804             ),
805         ) {
806             val testClass = codebase.assertClass("test.pkg.Test")
807             val anno = testClass.modifiers.annotations().single()
808 
809             val toSource =
810                 "@test.pkg.Test.Anno(classValue=Test.class, classArrayValue={Test.class, Anno.class})"
811             assertEquals(toSource, anno.toSource())
812         }
813     }
814 
815     @Test
annotation toSource() with number valuesnull816     fun `annotation toSource() with number values`() {
817         runCodebaseTest(
818             signature(
819                 """
820                     // Signature format: 2.0
821                     package test.pkg {
822                       @test.pkg.Test.Anno(
823                           byteValue = 1,
824                           byteArrayValue = {1, 2},
825 
826                           doubleValue = 1.5,
827                           doubleArrayValue = {1.5, 2.5},
828 
829                           floatValue = 0.5F,
830                           floatArrayValue = {0.5F, 1.5F},
831 
832                           intValue = 1,
833                           intArrayValue = {1, 2, 3},
834 
835                           longValue = 2,
836                           longArrayValue = {2, 4},
837 
838                           shortValue = 3,
839                           shortArrayValue = {3, 5},
840                       )
841                       public class Test {
842                         ctor public Test();
843                       }
844 
845                       public @interface Test.Anno {
846                           method public byte byteValue();
847                           method public byte[] byteArrayValue();
848 
849                           method public double doubleValue();
850                           method public double[] doubleArrayValue();
851 
852                           method public float floatValue();
853                           method public float[] floatArrayValue();
854 
855                           method public int intValue();
856                           method public int[] intArrayValue();
857 
858                           method public long longValue();
859                           method public long[] longArrayValue();
860 
861                           method public short shortValue();
862                           method public short[] shortArrayValue();
863                       }
864                     }
865                 """
866             ),
867             java(
868                 """
869                     package test.pkg;
870 
871                     @Test.Anno(
872                       byteValue = 1,
873                       byteArrayValue = {1, 2},
874 
875                       doubleValue = 1.5,
876                       doubleArrayValue = {1.5, 2.5},
877 
878                       floatValue = 0.5F,
879                       floatArrayValue = {0.5F, 1.5F},
880 
881                       intValue = 1,
882                       intArrayValue = {1, 2, 3},
883 
884                       longValue = 2L,
885                       longArrayValue = {2L, 4L},
886 
887                       shortValue = 3,
888                       shortArrayValue = {3, 5}
889                     )
890                     public class Test {
891                         public Test() {}
892 
893                         public @interface Anno {
894                           byte byteValue();
895                           byte[] byteArrayValue();
896 
897                           double doubleValue();
898                           double[] doubleArrayValue();
899 
900                           float floatValue();
901                           float[] floatArrayValue();
902 
903                           int intValue();
904                           int[] intArrayValue();
905 
906                           long longValue();
907                           long[] longArrayValue();
908 
909                           short shortValue();
910                           short[] shortArrayValue();
911                         }
912                     }
913                 """
914             ),
915         ) {
916             val testClass = codebase.assertClass("test.pkg.Test")
917             val anno = testClass.modifiers.annotations().single()
918 
919             val toSource =
920                 "@test.pkg.Test.Anno(byteValue=1, byteArrayValue={1, 2}, doubleValue=1.5, doubleArrayValue={1.5, 2.5}, floatValue=0.5f, floatArrayValue={0.5f, 1.5f}, intValue=1, intArrayValue={1, 2, 3}, longValue=2L, longArrayValue={2L, 4L}, shortValue=3, shortArrayValue={3, 5})"
921             assertEquals(toSource, anno.toSource())
922         }
923     }
924 
925     @Test
annotation toSource() with string valuesnull926     fun `annotation toSource() with string values`() {
927         runCodebaseTest(
928             signature(
929                 """
930                     // Signature format: 2.0
931                     package test.pkg {
932                       @test.pkg.Test.Anno(
933                           stringValue = "string",
934                           stringArrayValue = {"string1", "string2"},
935                       )
936                       public class Test {
937                         ctor public Test();
938                       }
939 
940                       public @interface Test.Anno {
941                           method public String stringValue();
942                           method public String[] stringArrayValue();
943                       }
944                     }
945                 """
946             ),
947             java(
948                 """
949                     package test.pkg;
950 
951                     @Test.Anno(
952                       stringValue = "string",
953                       stringArrayValue = {"string1", "string2"}
954                     )
955                     public class Test {
956                         public Test() {}
957 
958                         public @interface Anno {
959                           String stringValue();
960                           String[] stringArrayValue();
961                         }
962                     }
963                 """
964             ),
965         ) {
966             val testClass = codebase.assertClass("test.pkg.Test")
967             val anno = testClass.modifiers.annotations().single()
968 
969             val toSource =
970                 "@test.pkg.Test.Anno(stringValue=\"string\", stringArrayValue={\"string1\", \"string2\"})"
971             assertEquals(toSource, anno.toSource())
972         }
973     }
974 
975     @Test
annotation toSource() for array values with single elementnull976     fun `annotation toSource() for array values with single element`() {
977         runCodebaseTest(
978             signature(
979                 """
980                     // Signature format: 2.0
981                     package test.pkg {
982                       @test.pkg.Test.Anno("string")
983                       public class Test {
984                         ctor public Test();
985                       }
986 
987                       public @interface Test.Anno {
988                           method public String[] value();
989                       }
990                     }
991                 """
992             ),
993             java(
994                 """
995                     package test.pkg;
996 
997                     @Test.Anno("string")
998                     public class Test {
999                         public Test() {}
1000 
1001                         public @interface Anno {
1002                           String[] value();
1003                         }
1004                     }
1005                 """
1006             ),
1007         ) {
1008             val testClass = codebase.assertClass("test.pkg.Test")
1009             val anno = testClass.modifiers.annotations().single()
1010 
1011             val toSource = "@test.pkg.Test.Anno(\"string\")"
1012             assertEquals(toSource, anno.toSource())
1013         }
1014     }
1015 
1016     @Test
annotation toSource() for array values with single array elementnull1017     fun `annotation toSource() for array values with single array element`() {
1018         runCodebaseTest(
1019             signature(
1020                 """
1021                     // Signature format: 2.0
1022                     package test.pkg {
1023                       @test.pkg.Test.Anno({"string"})
1024                       public class Test {
1025                         ctor public Test();
1026                       }
1027 
1028                       public @interface Test.Anno {
1029                           method public String[] value();
1030                       }
1031                     }
1032                 """
1033             ),
1034             java(
1035                 """
1036                     package test.pkg;
1037 
1038                     @Test.Anno({"string"})
1039                     public class Test {
1040                         public Test() {}
1041 
1042                         public @interface Anno {
1043                           String[] value();
1044                         }
1045                     }
1046                 """
1047             ),
1048         ) {
1049             val testClass = codebase.assertClass("test.pkg.Test")
1050             val anno = testClass.modifiers.annotations().single()
1051 
1052             val toSource = "@test.pkg.Test.Anno({\"string\"})"
1053             assertEquals(toSource, anno.toSource())
1054         }
1055     }
1056 
1057     @Test
annotation toSource() with enum valuesnull1058     fun `annotation toSource() with enum values`() {
1059         runCodebaseTest(
1060             signature(
1061                 """
1062                     // Signature format: 2.0
1063                     package test.pkg {
1064                       @test.pkg.Test.Anno(
1065                           enumValue = test.pkg.Enum.ENUM1,
1066                           enumArrayValue = {test.pkg.Enum.ENUM1, test.pkg.Enum.ENUM2},
1067                       )
1068                       public class Test {
1069                         ctor public Test();
1070                       }
1071 
1072                       public @interface Test.Anno {
1073                           method public Enum stringValue();
1074                           method public Enum[] stringArrayValue();
1075                       }
1076 
1077                       public enum Enum {
1078                         enum_constant public test.pkg.Enum ENUM1;
1079                         enum_constant public test.pkg.Enum ENUM2;
1080                       }
1081                     }
1082                 """
1083             ),
1084             java(
1085                 """
1086                     package test.pkg;
1087 
1088                     @Test.Anno(
1089                       enumValue = Enum.ENUM1,
1090                       enumArrayValue = {Enum.ENUM1,Enum.ENUM2}
1091                     )
1092                     public class Test {
1093                         public Test() {}
1094 
1095                         public @interface Anno {
1096                           Enum enumValue();
1097                           Enum[] enumArrayValue();
1098                         }
1099                     }
1100 
1101                     public enum Enum {
1102                       ENUM1,
1103                       ENUM2,
1104                     }
1105                 """
1106             ),
1107         ) {
1108             val testClass = codebase.assertClass("test.pkg.Test")
1109             val anno = testClass.modifiers.annotations().single()
1110 
1111             val toSource =
1112                 "@test.pkg.Test.Anno(enumValue=test.pkg.Enum.ENUM1, enumArrayValue={test.pkg.Enum.ENUM1, test.pkg.Enum.ENUM2})"
1113             assertEquals(toSource, anno.toSource())
1114         }
1115     }
1116 
1117     @Test
annotation toSource() with constant literal valuesnull1118     fun `annotation toSource() with constant literal values`() {
1119         runCodebaseTest(
1120             signature(
1121                 """
1122                     // Signature format: 2.0
1123                     package test.pkg {
1124                       @test.pkg.Test.Anno(test.pkg.Test.FIELD)
1125                       public class Test {
1126                         ctor public Test();
1127                         field public static final int FIELD = 5;
1128                       }
1129 
1130                       public @interface Test.Anno {
1131                          method public Int value();
1132                       }
1133                     }
1134                 """
1135             ),
1136             java(
1137                 """
1138                     package test.pkg;
1139 
1140                     @Test.Anno(Test.FIELD)
1141                     public class Test {
1142                         public Test() {}
1143 
1144                         public static final int FIELD = 5;
1145 
1146                         public @interface Anno {
1147                           int value();
1148                         }
1149                     }
1150                 """
1151             ),
1152         ) {
1153             val testClass = codebase.assertClass("test.pkg.Test")
1154             val anno = testClass.modifiers.annotations().single()
1155 
1156             val toSource = "@test.pkg.Test.Anno(test.pkg.Test.FIELD)"
1157             assertEquals(toSource, anno.toSource())
1158         }
1159     }
1160 
1161     @Test
annotation toSource() with compound expression valuesnull1162     fun `annotation toSource() with compound expression values`() {
1163         runCodebaseTest(
1164             signature(
1165                 """
1166                     // Signature format: 2.0
1167                     package test.pkg {
1168                       @test.pkg.Test.Anno(value=test.pkg.Test.FIELD1+test.pkg.Test.FIELD2, name="FirstName"+"LastName", id=1+test.pkg.FIELD1)
1169                       public class Test {
1170                         ctor public Test();
1171                         field public static final int FIELD1 = 5;
1172                         field public static final int FIELD2 = 7;
1173                       }
1174 
1175                       public @interface Test.Anno {
1176                           method public int value();
1177                           method public String name();
1178                           method public int id();
1179                       }
1180                     }
1181                 """
1182             ),
1183             java(
1184                 """
1185                     package test.pkg;
1186 
1187                     @Test.Anno(value = Test.FIELD1+Test.FIELD2, name = "FirstName"+"LastName", id = 1+Test.FIELD1)
1188                     public class Test {
1189                         public Test() {}
1190 
1191                         public static final int FIELD1 = 5;
1192                         public static final int FIELD2 = 7;
1193 
1194                         public @interface Anno {
1195                             int value();
1196                             String name();
1197                             int id();
1198                         }
1199                     }
1200                 """
1201             ),
1202         ) {
1203             val testClass = codebase.assertClass("test.pkg.Test")
1204             val anno = testClass.modifiers.annotations().single()
1205 
1206             anno.assertAttributeValue("value", 12)
1207             anno.assertAttributeValue("name", "FirstNameLastName")
1208             anno.assertAttributeValue("id", 6)
1209             val toSource =
1210                 "@test.pkg.Test.Anno(value=test.pkg.Test.FIELD1 + test.pkg.Test.FIELD2, name=\"FirstName\" + \"LastName\", id=1 + test.pkg.Test.FIELD1)"
1211             assertEquals(toSource, anno.toSource())
1212         }
1213     }
1214 
1215     @Test
annotation with negative number valuesnull1216     fun `annotation with negative number values`() {
1217         runCodebaseTest(
1218             signature(
1219                 """
1220                     // Signature format: 2.0
1221                     package test.pkg {
1222                       @test.pkg.Test.Anno(
1223                           doubleValue = -1.5,
1224                           floatValue = -0.5F,
1225                           intValue = -1,
1226                           longValue = -2,
1227                           shortValue = -3,
1228                       )
1229                       public class Test {
1230                         ctor public Test();
1231                       }
1232 
1233                       public @interface Test.Anno {
1234                           method public double doubleValue();
1235                           method public float floatValue();
1236                           method public int intValue();
1237                           method public long longValue();
1238                           method public short shortValue();
1239                       }
1240                     }
1241                 """
1242             ),
1243             java(
1244                 """
1245                     package test.pkg;
1246 
1247                     @Test.Anno(
1248                       doubleValue = -1.5,
1249                       floatValue = -0.5F,
1250                       intValue = -1,
1251                       longValue = -2L,
1252                       shortValue = -3,
1253                     )
1254                     public class Test {
1255                         public Test() {}
1256 
1257                         public @interface Anno {
1258                           double doubleValue();
1259                           float floatValue();
1260                           int intValue();
1261                           long longValue();
1262                           short shortValue();
1263                         }
1264                     }
1265                 """
1266             ),
1267         ) {
1268             val testClass = codebase.assertClass("test.pkg.Test")
1269             val anno = testClass.modifiers.annotations().single()
1270 
1271             anno.assertAttributeValue("doubleValue", -1.5)
1272             anno.assertAttributeValue("floatValue", -0.5F)
1273             anno.assertAttributeValue("intValue", -1)
1274             anno.assertAttributeValue("longValue", -2L)
1275             anno.assertAttributeValue("shortValue", -3.toShort())
1276 
1277             val toSource =
1278                 "@test.pkg.Test.Anno(doubleValue=-1.5, floatValue=-0.5F, intValue=0xffffffff, longValue=-2L, shortValue=0xfffffffd)"
1279             assertEquals(toSource, anno.toSource())
1280         }
1281     }
1282 
1283     @Test
annotation with type cast valuesnull1284     fun `annotation with type cast values`() {
1285         runCodebaseTest(
1286             signature(
1287                 """
1288                     // Signature format: 2.0
1289                     package test.pkg {
1290                       @test.pkg.Test.Anno((int)5.6)
1291                       public class Test {
1292                         ctor public Test();
1293                       }
1294 
1295                       public @interface Test.Anno {
1296                           method public int value();
1297                       }
1298                     }
1299                 """
1300             ),
1301             java(
1302                 """
1303                     package test.pkg;
1304 
1305                     @Test.Anno((int)5.6f)
1306                     public class Test {
1307                         public Test() {}
1308 
1309                         public @interface Anno {
1310                           int value();
1311                         }
1312                     }
1313                 """
1314             ),
1315         ) {
1316             val testClass = codebase.assertClass("test.pkg.Test")
1317             val anno = testClass.modifiers.annotations().single()
1318 
1319             anno.assertAttributeValue("value", 5)
1320             assertEquals("@test.pkg.Test.Anno(0x5)", anno.toSource())
1321         }
1322     }
1323 
1324     @Test
annotation with infinity valuesnull1325     fun `annotation with infinity values`() {
1326         runCodebaseTest(
1327             signature(
1328                 """
1329                     // Signature format: 2.0
1330                     package test.pkg {
1331                       @test.pkg.Test.Anno({java.lang.Double.POSITIVE_INFINITY,java.lang.Double.POSITIVE_INFINITY})
1332                       public class Test {
1333                         ctor public Test();
1334                       }
1335 
1336                       public @interface Test.Anno {
1337                           method public double [] value();
1338                       }
1339                     }
1340                 """
1341             ),
1342             java(
1343                 """
1344                     package test.pkg;
1345 
1346                     @Test.Anno({Double.POSITIVE_INFINITY,Double.NEGATIVE_INFINITY})
1347                     public class Test {
1348                         public Test() {}
1349 
1350                         public @interface Anno {
1351                           double [] value();
1352                         }
1353                     }
1354                 """
1355             ),
1356         ) {
1357             val testClass = codebase.assertClass("test.pkg.Test")
1358             val anno = testClass.modifiers.annotations().single()
1359 
1360             anno.assertAttributeValues("value", listOf(2147483647, -2147483648))
1361             assertEquals(
1362                 "@test.pkg.Test.Anno({java.lang.Double.POSITIVE_INFINITY, java.lang.Double.NEGATIVE_INFINITY})",
1363                 anno.toSource()
1364             )
1365         }
1366     }
1367 
assertAttributeValuenull1368     inline fun <reified T : Any> AnnotationItem.assertAttributeValue(
1369         attributeName: String,
1370         expected: T
1371     ) {
1372         assertEquals(
1373             expected,
1374             getAttributeValue(attributeName),
1375             message = "getAttributeValue($attributeName)"
1376         )
1377     }
1378 
assertAttributeValuesnull1379     inline fun <reified T : Any> AnnotationItem.assertAttributeValues(
1380         attributeName: String,
1381         expected: List<T>
1382     ) {
1383         assertEquals(
1384             expected,
1385             getAttributeValues(attributeName),
1386             message = "getAttributeValues($attributeName)"
1387         )
1388     }
1389 }
1390