• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.google.doclava.javadoc;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 
22 import javax.lang.model.element.ExecutableElement;
23 import javax.lang.model.element.PackageElement;
24 import javax.lang.model.element.TypeElement;
25 import javax.lang.model.element.VariableElement;
26 import javax.lang.model.type.ArrayType;
27 import jdk.javadoc.doclet.DocletEnvironment;
28 import org.junit.Before;
29 import org.junit.BeforeClass;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.JUnit4;
32 
33 @RunWith(JUnit4.class)
34 public abstract class BaseTest {
35 
36     protected static RootDocImpl rootDoc;
37     protected static DocletEnvironment docletEnv;
38     protected Context context;
39 
40     /**
41      * @implNote While marked with {@link BeforeClass}, the actual initialization happens only once
42      * across multiple runs by test subclasses, which results are stored in a singleton manner.
43      */
44     @BeforeClass
beforeClass()45     public static void beforeClass() {
46         if (docletEnv != null && rootDoc != null) {
47             return;
48         }
49 
50         var doclet = new EmptyDoclet("src/test/resources");
51         docletEnv = doclet.getEnvironment();
52 
53         rootDoc = new RootDocImpl(docletEnv);
54     }
55 
56     @Before
setUp()57     public void setUp() {
58         context = new Context(docletEnv);
59     }
60 
61     // TypeElements (ANNOTATION_TYPE, CLASS, ENUM, INTERFACE, or RECORD).
62     static class CLASS {
63 
64         static final TypeElement publicAbstractClass = initTypeElement(
65                 "com.example.classes.AbstractEmptyClass");
66         static final TypeElement publicAbstractInterface = initTypeElement(
67                 "com.example.classes.AbstractEmptyInterface");
68 
69         static final TypeElement publicAnnotation = initTypeElement(
70                 "com.example.classes.PublicAnnotation");
71         static final TypeElement publicClass = initTypeElement("com.example.classes.PublicClass");
72         static final TypeElement publicEnum = initTypeElement("com.example.classes.PublicEnum");
73         static final TypeElement publicInterface = initTypeElement(
74                 "com.example.classes.PublicInterface");
75 
76         static final TypeElement simpleEnum = initTypeElement("com.example.classes.SimpleEnum");
77 
78         static final TypeElement publicClassWithNests = initTypeElement(
79                 "com.example.classes.PublicClassWithNests");
80         static final TypeElement publicClassWithNests$Nest1 = initTypeElement(
81                 "com.example.classes.PublicClassWithNests.Nest1");
82         static final TypeElement publicClassWithNests$Nest1$Nest2 = initTypeElement(
83                 "com.example.classes.PublicClassWithNests.Nest1.Nest2");
84         static final TypeElement publicClassWithNests$Nest1$Nest2$Nest3 = initTypeElement(
85                 "com.example.classes.PublicClassWithNests.Nest1.Nest2.Nest3");
86         static final TypeElement innerClasses = initTypeElement(
87                 "com.example.classes.InnerClasses");
88 
89         static final TypeElement parametrizedAnnotation = initTypeElement(
90                 "com.example.classes.ParametrizedAnnotation");
91 
92         static final TypeElement tags = initTypeElement("com.example.classes.Tags");
93         static final TypeElement tags$See = initTypeElement("com.example.classes.Tags.See");
94         static final TypeElement tags$Throws = initTypeElement("com.example.classes.Tags.Throws");
95         static final TypeElement tags$Various = initTypeElement("com.example.classes.Tags.Various");
96 
97         static final TypeElement constructors = initTypeElement(
98                 "com.example.constructors.Constructors");
99 
100         static final TypeElement packagePrivateClass = initTypeElement(
101                 "com.example.classes.PackagePrivateClass");
102 
103         static final TypeElement implementsSerializable = initTypeElement(
104                 "com.example.classes.ImplementsSerializable");
105         static final TypeElement implementsExternalizable = initTypeElement(
106                 "com.example.classes.ImplementsExternalizable");
107 
108         static final TypeElement annotatedClass = initTypeElement(
109                 "com.example.classes.AnnotatedClass");
110 
111         static final TypeElement javaUtilMap = initTypeElement("java.util.Map");
112 
113         static final TypeElement fieldsAccessModifiers = initTypeElement(
114                 "com.example.classes.FieldsAccessModifiers");
115         static final TypeElement methodsAccessModifiers = initTypeElement(
116                 "com.example.classes.MethodsAccessModifiers");
117     }
118 
119     static class GENERIC {
120 
121         static final TypeElement box = initTypeElement("com.example.classes.Tags.Box");
122     }
123 
124     static class ARRAY {
125 
126         static final ArrayType int_1 = (ArrayType) initVariableElement(
127                 "com.example.fields.Arrays", "arr_int_1").asType();
128         static final ArrayType string_2 = (ArrayType) initVariableElement(
129                 "com.example.fields.Arrays", "arr_String_2").asType();
130         static final ArrayType T_3 = (ArrayType) initVariableElement(
131                 "com.example.fields.Arrays", "arr_T_3").asType();
132         static final ArrayType ListOfStrings_4 = (ArrayType) initVariableElement(
133                 "com.example.fields.Arrays", "arr_ListOfString_4").asType();
134         static final ArrayType override_5 = (ArrayType) initVariableElement(
135                 "com.example.fields.Arrays", "arr_Override_5").asType();
136     }
137 
138     static class INTERFACE {
139 
140         static final TypeElement serializable = initTypeElement("java.io.Serializable");
141         static final TypeElement extendsSerializable = initTypeElement(
142                 "com.example.classes.ExtendsSerializable");
143         static final TypeElement extendsExternalizable = initTypeElement(
144                 "com.example.classes.ExtendsExternalizable");
145     }
146 
147     static class INSTANCE {
148 
149         static final TypeElement javaLangObject = initTypeElement("java.lang.Object");
150         static final TypeElement javaLangError = initTypeElement("java.lang.Error");
151         static final TypeElement javaLangException = initTypeElement("java.lang.Exception");
152         static final TypeElement javaLangString = initTypeElement("java.lang.String");
153         static final TypeElement javaLangThrowable = initTypeElement("java.lang.Throwable");
154     }
155 
156     static class PACKAGE {
157 
158         static PackageElement comExamplePackages = initPackageElement("com.example.packages");
159     }
160 
161     static class ANNOTATION_METHOD {
162 
163         /**
164          * <pre>
165          * public @interface AllDefaultAnnotation {
166          *     boolean bool() default true;
167          *     byte byt() default (byte)1;
168          *     char ch() default 'a';
169          *     double dbl() default 3.1d;
170          *     float flt() default 4.1f;
171          *     int integer() default 5;
172          *     long lng() default 6L;
173          *     short shrt() default (short)7;
174          *     String str() default "qwe";
175          *     Class<?> cls() default PublicClass.class;
176          *     SimpleEnum enm() default SimpleEnum.A;
177          *     Class<?> annotation() default Override.class;
178          *     String[] arrayOfStrings() default { "abc", "def", "ghi" };
179          * }
180          * </pre>
181          */
182         static class WITH_DEFAULT {
183 
184             static final ExecutableElement returningBool = initExecutableElement(
185                     "com.example.classes.AllDefaultAnnotation", "bool()");
186             static final ExecutableElement returningByte = initExecutableElement(
187                     "com.example.classes.AllDefaultAnnotation", "byt()");
188             static final ExecutableElement returningChar = initExecutableElement(
189                     "com.example.classes.AllDefaultAnnotation", "ch()");
190             static final ExecutableElement returningDouble = initExecutableElement(
191                     "com.example.classes.AllDefaultAnnotation", "dbl()");
192             static final ExecutableElement returningFloat = initExecutableElement(
193                     "com.example.classes.AllDefaultAnnotation", "flt()");
194             static final ExecutableElement returningInteger = initExecutableElement(
195                     "com.example.classes.AllDefaultAnnotation", "integer()");
196             static final ExecutableElement returningLond = initExecutableElement(
197                     "com.example.classes.AllDefaultAnnotation", "lng()");
198             static final ExecutableElement returningShort = initExecutableElement(
199                     "com.example.classes.AllDefaultAnnotation", "shrt()");
200             static final ExecutableElement returningString = initExecutableElement(
201                     "com.example.classes.AllDefaultAnnotation", "str()");
202             static final ExecutableElement returningClass = initExecutableElement(
203                     "com.example.classes.AllDefaultAnnotation", "cls()");
204             static final ExecutableElement returningEnum = initExecutableElement(
205                     "com.example.classes.AllDefaultAnnotation", "enm()");
206             static final ExecutableElement returningAnnotation = initExecutableElement(
207                     "com.example.classes.AllDefaultAnnotation", "annotation()");
208             static final ExecutableElement returningArrayOfString = initExecutableElement(
209                     "com.example.classes.AllDefaultAnnotation", "arrayOfStrings()");
210         }
211 
212         static final TypeElement allDefaultAnnotation = initTypeElement(
213                 "com.example.classes.AllDefaultAnnotation");
214         static final ExecutableElement annotationMethod = initExecutableElement(
215                 "com.example.classes.ParametrizedAnnotation", "primitiveI()");
216         static final ExecutableElement annotationMethodWithDefault = initExecutableElement(
217                 "com.example.classes.ParametrizedAnnotation", "primitiveDefaultL()");
218     }
219 
220     static class CONSTRUCTOR {
221 
222         static final ExecutableElement empty = initExecutableElement(
223                 "com.example.constructors.Constructors", "Constructors()");
224         static final ExecutableElement arg1_int = initExecutableElement(
225                 "com.example.constructors.Constructors", "Constructors(int)");
226         static final ExecutableElement arg1_String = initExecutableElement(
227                 "com.example.constructors.Constructors", "Constructors(java.lang.String)");
228         static final ExecutableElement arg2_int_String = initExecutableElement(
229                 "com.example.constructors.Constructors", "Constructors(int,java.lang.String)");
230 
231         static final ExecutableElement paramTag_arg2_T_int = initExecutableElement(
232                 "com.example.classes.Tags.Box", "Box(T,int)");
233     }
234 
235     static class METHOD {
236 
237         static class OF_CLASS {
238 
239             static final ExecutableElement public_void_arg0 = initExecutableElement(
240                     "com.example.methods.OfClass", "public_void_arg0()");
241             static final ExecutableElement private_int_arg0 = initExecutableElement(
242                     "com.example.methods.OfClass", "private_int_arg0()");
243             static final ExecutableElement packagePrivate_String_arg2_int_String = initExecutableElement(
244                     "com.example.methods.OfClass",
245                     "packagePrivate_String_arg2_int_String(int,java.lang.String)");
246             static final ExecutableElement public_abstract_void_arg0 = initExecutableElement(
247                     "com.example.methods.OfClass", "public_abstract_void_arg0()");
248             static final ExecutableElement override_public_String_toString0 = initExecutableElement(
249                     "com.example.methods.OfClass", "toString()");
250             static final ExecutableElement void_arg1_annotatedObject = initExecutableElement(
251                     "com.example.methods.OfClass",
252                     "void_arg1_annotatedObject(@com.example.classes.UniversalAnnotation java.lang.Object)");
253         }
254 
255         static class OF_INTERFACE {
256 
257             static final ExecutableElement public_void_arg0 = initExecutableElement(
258                     "com.example.methods.OfInterface", "public_void_arg0()");
259             static final ExecutableElement public_default_String_arg0 = initExecutableElement(
260                     "com.example.methods.OfInterface", "public_default_String_arg0()");
261         }
262 
263         static class OVERRIDES {
264 
265             static final ExecutableElement A_name = initExecutableElement(
266                     "com.example.methods.override.A", "name()");
267             static final ExecutableElement B_name = initExecutableElement(
268                     "com.example.methods.override.B", "name()");
269             static final ExecutableElement C_name = initExecutableElement(
270                     "com.example.methods.override.C", "name()");
271             static final ExecutableElement D_name = initExecutableElement(
272                     "com.example.methods.override.D", "name()");
273         }
274 
275         static class PARAMETER {
276 
277             static final VariableElement Object_annotatedWith_UniversalAnnotation = initMethodParam(
278                     "com.example.methods.OfClass",
279                     "void_arg1_annotatedObject(@com.example.classes.UniversalAnnotation java.lang.Object)",
280                     "obj");
281         }
282     }
283 
284     static class FIELD {
285 
286         static final VariableElement public_int = initVariableElement(
287                 "com.example.fields.Fields", "public_int");
288         static final VariableElement public_transient_volatile_Object = initVariableElement(
289                 "com.example.fields.Fields", "public_transient_volatile_Object");
290         static final VariableElement public_final_int = initVariableElement(
291                 "com.example.fields.Fields", "public_final_int");
292         static final VariableElement public_final_String = initVariableElement(
293                 "com.example.fields.Fields", "public_final_String");
294 
295         static class ACCESS_MODIFIERS {
296 
297             static final VariableElement public_int = initVariableElement(
298                     "com.example.fields.FieldsAccessModifiers", "public_int");
299             static final VariableElement private_int = initVariableElement(
300                     "com.example.fields.FieldsAccessModifiers", "private_int");
301             static final VariableElement protected_float = initVariableElement(
302                     "com.example.fields.FieldsAccessModifiers", "protected_float");
303             static final VariableElement packagePrivate_long = initVariableElement(
304                     "com.example.fields.FieldsAccessModifiers", "packagePrivate_long");
305         }
306     }
307 
initTypeElement(String name)308     protected static TypeElement initTypeElement(String name) {
309         var e = docletEnv.getElementUtils().getTypeElement(name);
310         assertNotNull(e);
311         return e;
312     }
313 
initPackageElement(String name)314     private static PackageElement initPackageElement(String name) {
315         var e = docletEnv.getElementUtils().getPackageElement(name);
316         assertNotNull(e);
317         return e;
318     }
319 
initMethodParam(String containingType, String methodSignature, String parameterName)320     private static VariableElement initMethodParam(String containingType, String methodSignature,
321             String parameterName) {
322         ExecutableElement method = initExecutableElement(containingType, methodSignature);
323         var params = method.getParameters()
324                 .stream()
325                 .filter(param -> param.getSimpleName().toString().equals(parameterName))
326                 .toList();
327 
328         assertEquals(1, params.size());
329         return params.get(0);
330     }
331 
initVariableElement(String containingType, String name)332     private static VariableElement initVariableElement(String containingType, String name) {
333         var t = initTypeElement(containingType);
334         var fields = t.getEnclosedElements()
335                 .stream()
336                 .filter(e -> e instanceof VariableElement)
337                 .map(e -> (VariableElement) e)
338                 .filter(ve -> name.equals(ve.getSimpleName().toString()))
339                 .toList();
340 
341         assertEquals(1, fields.size());
342         return fields.get(0);
343     }
344 
345     /**
346      * Finds ExecutableElement in the environment by class type and element signature. Signature
347      * should be in the following format: {@code methodName(type1[,type2...])}, types are specified
348      * in a fully qualified form. For example:
349      *
350      * <ul>
351      *     <li>{@code Constructor()}</li>
352      *     <li>{@code Constructor(int)}</li>
353      *     <li>{@code update(java.lang.String,float)}</li>
354      * </ul>
355      *
356      * @param type fully qualified class name
357      * @param signature signature of executable element
358      * @return ExecutableElement
359      */
initExecutableElement(String type, String signature)360     private static ExecutableElement initExecutableElement(String type, String signature) {
361         var t = initTypeElement(type);
362         var methods = t.getEnclosedElements()
363                 .stream()
364                 .filter(e -> e instanceof ExecutableElement)
365                 .map(e -> (ExecutableElement) e)
366                 .filter(exe -> signature.equals(exe.toString()))
367                 .toList();
368 
369         assertEquals(1, methods.size());
370         return methods.get(0);
371     }
372 }
373