1
+ package io .swagger .v3 .core .converting ;
2
+
3
+ import io .swagger .v3 .core .converter .AnnotatedType ;
4
+ import org .testng .annotations .Test ;
5
+
6
+ import java .lang .annotation .Annotation ;
7
+ import java .lang .annotation .ElementType ;
8
+ import java .lang .annotation .Retention ;
9
+ import java .lang .annotation .RetentionPolicy ;
10
+ import java .lang .annotation .Target ;
11
+ import java .lang .reflect .Type ;
12
+ import java .util .HashSet ;
13
+ import java .util .Set ;
14
+
15
+ import static org .testng .Assert .assertEquals ;
16
+ import static org .testng .Assert .assertNotEquals ;
17
+ import static org .testng .Assert .assertTrue ;
18
+
19
+ public class AnnotatedTypeTest {
20
+
21
+ @ Retention (RetentionPolicy .RUNTIME )
22
+ @ Target (ElementType .TYPE )
23
+ @interface TestAnnA {}
24
+
25
+ @ Retention (RetentionPolicy .RUNTIME )
26
+ @ Target (ElementType .TYPE )
27
+ @interface TestAnnB {}
28
+
29
+ @ TestAnnA
30
+ @ TestAnnB
31
+ @ Deprecated
32
+ private static class AnnotationHolder {}
33
+
34
+ private Annotation getAnnotationInstance (Class <? extends Annotation > clazz ) {
35
+ return AnnotationHolder .class .getAnnotation (clazz );
36
+ }
37
+
38
+ /**
39
+ * Tests that equals() and hashCode() are order-insensitive for context annotations.
40
+ */
41
+ @ Test
42
+ public void testEqualsAndHashCode_shouldBeOrderInsensitiveForAnnotations () {
43
+ Annotation annA = getAnnotationInstance (TestAnnA .class );
44
+ Annotation annB = getAnnotationInstance (TestAnnB .class );
45
+ AnnotatedType type1 = new AnnotatedType (String .class ).ctxAnnotations (new Annotation []{annA , annB });
46
+ AnnotatedType type2 = new AnnotatedType (String .class ).ctxAnnotations (new Annotation []{annB , annA });
47
+ assertEquals (type1 , type2 , "Objects should be equal even if annotation order is different." );
48
+ assertEquals (type1 .hashCode (), type2 .hashCode (), "Hash codes should be equal even if annotation order is different." );
49
+ }
50
+
51
+ /**
52
+ * Tests that JDK/internal annotations are filtered out for equals() and hashCode() comparison.
53
+ */
54
+ @ Test
55
+ public void testEqualsAndHashCode_shouldIgnoreJdkInternalAnnotations () {
56
+ Annotation annA = getAnnotationInstance (TestAnnA .class );
57
+ Annotation deprecated = getAnnotationInstance (Deprecated .class );
58
+ AnnotatedType typeWithUserAnn = new AnnotatedType (String .class ).ctxAnnotations (new Annotation []{annA });
59
+ AnnotatedType typeWithJdkAnn = new AnnotatedType (String .class ).ctxAnnotations (new Annotation []{annA , deprecated });
60
+ AnnotatedType typeWithOnlyJdkAnn = new AnnotatedType (String .class ).ctxAnnotations (new Annotation []{deprecated });
61
+ AnnotatedType typeWithNoAnn = new AnnotatedType (String .class );
62
+ assertEquals (typeWithUserAnn , typeWithJdkAnn , "JDK annotations should be ignored in equality comparison." );
63
+ assertEquals (typeWithUserAnn .hashCode (), typeWithJdkAnn .hashCode (), "JDK annotations should be ignored in hashCode calculation." );
64
+ assertEquals (typeWithOnlyJdkAnn , typeWithNoAnn , "An object with only JDK annotations should be equal to one with no annotations." );
65
+ assertEquals (typeWithOnlyJdkAnn .hashCode (), typeWithNoAnn .hashCode (), "The hash code of an object with only JDK annotations should be the same as one with no annotations." );
66
+ }
67
+
68
+ /**
69
+ * Tests that defensive copying prevents Set corruption from external array mutation.
70
+ */
71
+ @ Test
72
+ public void testImmutability_shouldPreventCorruptionInHashSet () {
73
+ Annotation annA = getAnnotationInstance (TestAnnA .class );
74
+ Annotation annB = getAnnotationInstance (TestAnnB .class );
75
+ Annotation [] originalAnnotations = new Annotation []{annA };
76
+ AnnotatedType type = new AnnotatedType (String .class ).ctxAnnotations (originalAnnotations );
77
+ Set <AnnotatedType > typeSet = new HashSet <>();
78
+ typeSet .add (type );
79
+ int initialHashCode = type .hashCode ();
80
+ originalAnnotations [0 ] = annB ;
81
+ assertEquals (initialHashCode , type .hashCode (), "Hash code must remain the same after mutating the external array." );
82
+ assertTrue (typeSet .contains (type ), "The Set must still contain the object after mutating the external array." );
83
+ }
84
+
85
+ /**
86
+ * Tests that an instance of a subclass can be equal to an instance of the parent class.
87
+ */
88
+ @ Test
89
+ public void testEqualsAndHashCode_shouldAllowSubclassEquality () {
90
+ class SubAnnotatedType extends AnnotatedType {
91
+ public SubAnnotatedType (Type type ) { super (type ); }
92
+ }
93
+ Annotation annA = getAnnotationInstance (TestAnnA .class );
94
+ Annotation [] annotations = {annA };
95
+ AnnotatedType parent = new AnnotatedType (Integer .class ).ctxAnnotations (annotations ).name ("number" );
96
+ SubAnnotatedType child = new SubAnnotatedType (Integer .class );
97
+ child .ctxAnnotations (annotations );
98
+ child .name ("number" );
99
+ AnnotatedType differentParent = new AnnotatedType (Long .class ).name ("number" );
100
+ assertEquals (parent , child , "Parent and child objects should be equal if their properties are the same." );
101
+ assertEquals (child , parent , "Equality comparison should be symmetric." );
102
+ assertEquals (parent .hashCode (), child .hashCode (), "Parent and child hash codes should be equal if their properties are the same." );
103
+ assertNotEquals (parent , differentParent , "Objects with different properties should not be equal." );
104
+ }
105
+ }
0 commit comments