1 /*
2  * Copyright (C) 2017 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
18 
19 import com.android.tools.metalava.model.text.FileFormat
20 import com.android.tools.metalava.testing.java
21 import org.junit.Test
22 
23 class NullabilityAnnotationsValidatorTest : DriverTest() {
24 
25     @Test
Empty report when all expected annotations presentnull26     fun `Empty report when all expected annotations present`() {
27         check(
28             sourceFiles =
29                 arrayOf(
30                     java(
31                         """
32                         package test.pkg;
33 
34                         public interface Appendable {
35                             Appendable append(CharSequence csq) throws IOException;
36                         }
37 
38                         public interface List<T> {
39                             T get(int index);
40                         }
41 
42                         // This is not annotated at all, shouldn't complain about this.
43                         public interface NotAnnotated {
44                             NotAnnotated combine(NotAnnotated other);
45                         }
46                     """
47                     ),
48                     libcoreNonNullSource,
49                     libcoreNullableSource,
50                     libcoreNullFromTypeParamSource
51                 ),
52             format = FileFormat.V2,
53             mergeJavaStubAnnotations =
54                 """
55                 package test.pkg;
56 
57                 import libcore.util.NonNull;
58                 import libcore.util.Nullable;
59                 import libcore.util.NullFromTypeParam;
60 
61                 public interface Appendable {
62                     @NonNull Appendable append(@Nullable java.lang.CharSequence csq);
63                 }
64 
65                 public interface List<T> {
66                     @NullFromTypeParam T get(int index);
67                 }
68                 """,
69             extraArguments = arrayOf(ARG_VALIDATE_NULLABILITY_FROM_MERGED_STUBS),
70             validateNullability = setOf()
71         )
72     }
73 
74     @Test
Missing parameter annotationnull75     fun `Missing parameter annotation`() {
76         check(
77             sourceFiles =
78                 arrayOf(
79                     java(
80                         """
81                         package test.pkg;
82 
83                         public interface Appendable {
84                             Appendable append(CharSequence csq) throws IOException;
85                         }
86 
87                         public interface List<T> {
88                             T get(int index);
89                         }
90                     """
91                     ),
92                     libcoreNonNullSource,
93                     libcoreNullFromTypeParamSource
94                 ),
95             format = FileFormat.V2,
96             mergeJavaStubAnnotations =
97                 """
98                 package test.pkg;
99 
100                 import libcore.util.NonNull;
101                 import libcore.util.NullFromTypeParam;
102 
103                 public interface Appendable {
104                     @NonNull Appendable append(java.lang.CharSequence csq);
105                 }
106 
107                 public interface List<T> {
108                     @NullFromTypeParam T get(int index);
109                 }
110                 """,
111             extraArguments = arrayOf(ARG_VALIDATE_NULLABILITY_FROM_MERGED_STUBS),
112             validateNullability =
113                 setOf(
114                     "WARNING: method test.pkg.Appendable.append(CharSequence), parameter csq, MISSING"
115                 )
116         )
117     }
118 
119     @Test
Missing return type annotationsnull120     fun `Missing return type annotations`() {
121         check(
122             sourceFiles =
123                 arrayOf(
124                     java(
125                         """
126                         package test.pkg;
127 
128                         public interface Appendable {
129                             Appendable append(CharSequence csq) throws IOException;
130                         }
131 
132                         public interface List<T> {
133                             T get(int index);
134                         }
135                     """
136                     ),
137                     libcoreNullableSource
138                 ),
139             format = FileFormat.V2,
140             mergeJavaStubAnnotations =
141                 """
142                 package test.pkg;
143 
144                 import libcore.util.Nullable;
145 
146                 public interface Appendable {
147                     Appendable append(@Nullable java.lang.CharSequence csq);
148                 }
149 
150                 public interface List<T> {
151                 }
152                 """,
153             extraArguments = arrayOf(ARG_VALIDATE_NULLABILITY_FROM_MERGED_STUBS),
154             validateNullability =
155                 setOf(
156                     "WARNING: method test.pkg.Appendable.append(CharSequence), return value, MISSING",
157                     "WARNING: method test.pkg.List.get(int), return value, MISSING"
158                 )
159         )
160     }
161 
162     @Test
Error from annotation on primitivenull163     fun `Error from annotation on primitive`() {
164         check(
165             sourceFiles =
166                 arrayOf(
167                     java(
168                         """
169                         package test.pkg;
170 
171                         public interface Appendable {
172                             Appendable append(CharSequence csq) throws IOException;
173                         }
174 
175                         public interface List<T> {
176                             T get(int index);
177                         }
178                     """
179                     ),
180                     libcoreNonNullSource,
181                     libcoreNullableSource,
182                     libcoreNullFromTypeParamSource
183                 ),
184             format = FileFormat.V2,
185             mergeJavaStubAnnotations =
186                 """
187                 package test.pkg;
188 
189                 import libcore.util.NonNull;
190                 import libcore.util.Nullable;
191                 import libcore.util.NullFromTypeParam;
192 
193                 public interface Appendable {
194                     @NonNull Appendable append(@Nullable java.lang.CharSequence csq);
195                 }
196 
197                 public interface List<T> {
198                     @NullFromTypeParam T get(@NonNull int index);
199                 }
200                 """,
201             extraArguments = arrayOf(ARG_VALIDATE_NULLABILITY_FROM_MERGED_STUBS),
202             validateNullability =
203                 setOf("ERROR: method test.pkg.List.get(int), parameter index, ON_PRIMITIVE")
204         )
205     }
206 
207     @Test
Error from NullFromTypeParam not on type paramnull208     fun `Error from NullFromTypeParam not on type param`() {
209         check(
210             sourceFiles =
211                 arrayOf(
212                     java(
213                         """
214                         package test.pkg;
215 
216                         public interface Appendable {
217                             Appendable append(CharSequence csq) throws IOException;
218                         }
219 
220                         public interface List<T> {
221                             T get(int index);
222                         }
223                     """
224                     ),
225                     libcoreNullableSource,
226                     libcoreNullFromTypeParamSource
227                 ),
228             format = FileFormat.V2,
229             mergeJavaStubAnnotations =
230                 """
231                 package test.pkg;
232 
233                 import libcore.util.Nullable;
234                 import libcore.util.NullFromTypeParam;
235 
236                 public interface Appendable {
237                     @NullFromTypeParam Appendable append(@Nullable java.lang.CharSequence csq);
238                 }
239 
240                 public interface List<T> {
241                     @NullFromTypeParam T get(int index);
242                 }
243                 """,
244             extraArguments = arrayOf(ARG_VALIDATE_NULLABILITY_FROM_MERGED_STUBS),
245             validateNullability =
246                 setOf(
247                     "ERROR: method test.pkg.Appendable.append(CharSequence), return value, BAD_TYPE_PARAM"
248                 )
249         )
250     }
251 
252     @Test
Using class listnull253     fun `Using class list`() {
254         check(
255             sourceFiles =
256                 arrayOf(
257                     java(
258                         """
259                         package test.pkg;
260 
261                         import libcore.util.Nullable;
262 
263                         // This will be validated. It is missing an annotation on its return type.
264                         public interface Appendable {
265                             Appendable append(@Nullable CharSequence csq) throws IOException;
266                         }
267 
268                         // This is missing an annotation on its return type, but will not be validated.
269                         public interface List<T> {
270                             T get(int index);
271                         }
272                     """
273                     ),
274                     libcoreNullableSource
275                 ),
276             format = FileFormat.V2,
277             extraArguments = arrayOf(ARG_VALIDATE_NULLABILITY_FROM_MERGED_STUBS),
278             validateNullabilityFromList =
279                 """
280                 # a comment, then a blank line, then the class to validate
281 
282                 test.pkg.Appendable
283             """,
284             validateNullability =
285                 setOf(
286                     "WARNING: method test.pkg.Appendable.append(CharSequence), return value, MISSING"
287                 )
288         )
289     }
290 }
291