xref: /aosp_15_r20/tools/metalava/metalava/src/test/java/com/android/tools/metalava/lint/CheckBuilderTest.kt (revision 115816f9299ab6ddd6b9673b81f34e707f6bacab)
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.lint
18 
19 import com.android.tools.metalava.DriverTest
20 import com.android.tools.metalava.androidxNonNullSource
21 import com.android.tools.metalava.androidxNullableSource
22 import com.android.tools.metalava.testing.java
23 import org.junit.Test
24 
25 /** Tests for the [ApiLint.checkBuilder] method. */
26 class CheckBuilderTest : DriverTest() {
27 
28     @Test
Check buildersnull29     fun `Check builders`() {
30         check(
31             apiLint = "", // enabled
32             expectedIssues =
33                 """
34                 src/android/pkg/Bad.java:13: warning: Builder must be final: android.pkg.Bad.BadBuilder [StaticFinalBuilder]
35                 src/android/pkg/Bad.java:13: warning: Builder must be static: android.pkg.Bad.BadBuilder [StaticFinalBuilder]
36                 src/android/pkg/Bad.java:14: warning: Builder constructor arguments must be mandatory (i.e. not @Nullable): parameter badParameter in android.pkg.Bad.BadBuilder(String badParameter) [OptionalBuilderConstructorArgument]
37                 src/android/pkg/Bad.java:20: warning: android.pkg.Bad does not declare a `getWithoutMatchingGetters()` method matching method android.pkg.Bad.BadBuilder.addWithoutMatchingGetter(String) [MissingGetterMatchingBuilder]
38                 src/android/pkg/Bad.java:23: warning: android.pkg.Bad does not declare a `isWithoutMatchingGetter()` method matching method android.pkg.Bad.BadBuilder.setWithoutMatchingGetter(boolean) [MissingGetterMatchingBuilder]
39                 src/android/pkg/Bad.java:26: warning: android.pkg.Bad does not declare a `getPluralWithoutMatchingGetters()` method matching method android.pkg.Bad.BadBuilder.addPluralWithoutMatchingGetter(java.util.Collection<java.lang.String>) [MissingGetterMatchingBuilder]
40                 src/android/pkg/Bad.java:32: warning: android.pkg.Bad does not declare a getter method matching method android.pkg.Bad.BadBuilder.addPluralWithoutMatchingGetters(java.util.Collection<java.lang.String>) (expected one of: [getPluralWithoutMatchingGetters(), getPluralWithoutMatchingGetterses()]) [MissingGetterMatchingBuilder]
41                 src/android/pkg/Bad.java:38: warning: Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.pkg.Bad.BadBuilder.withBadSetterStyle(boolean) [BuilderSetStyle]
42                 src/android/pkg/Bad.java:41: warning: Builder setter must be @NonNull: method android.pkg.Bad.BadBuilder.setReturnsNullable(boolean) [SetterReturnsThis]
43                 src/android/pkg/Bad.java:43: warning: Getter should be on the built object, not the builder: method android.pkg.Bad.BadBuilder.getOnBuilder() [GetterOnBuilder]
44                 src/android/pkg/Bad.java:45: warning: android.pkg.Bad does not declare a `isNotReturningBuilder()` method matching method android.pkg.Bad.BadBuilder.setNotReturningBuilder(boolean) [MissingGetterMatchingBuilder]
45                 src/android/pkg/Bad.java:45: warning: Methods must return the builder object (return type android.pkg.Bad.BadBuilder instead of void): method android.pkg.Bad.BadBuilder.setNotReturningBuilder(boolean) [SetterReturnsThis]
46                 src/android/pkg/Bad.java:51: warning: android.pkg.Bad.NoBuildMethodBuilder does not declare a `build()` method, but builder classes are expected to [MissingBuildMethod]
47                 src/android/pkg/Bad.java:57: warning: Methods must return the builder object (return type android.pkg.Bad.BadGenericBuilder<T> instead of T): method android.pkg.Bad.BadGenericBuilder.setBoolean(boolean) [SetterReturnsThis]
48                 src/android/pkg/TopLevelBuilder.java:3: warning: android.pkg.TopLevelBuilder does not declare a `build()` method, but builder classes are expected to [MissingBuildMethod]
49                 src/android/pkg/TopLevelBuilder.java:3: warning: Builder should be defined as inner class: android.pkg.TopLevelBuilder [TopLevelBuilder]
50                 src/test/pkg/BadClass.java:6: warning: Builder must be final: test.pkg.BadClass.Builder [StaticFinalBuilder]
51                 src/test/pkg/BadInterface.java:6: warning: Builder must be final: test.pkg.BadInterface.Builder [StaticFinalBuilder]
52                 """,
53             sourceFiles =
54                 arrayOf(
55                     java(
56                         """
57                     package android.pkg;
58 
59                     public final class TopLevelBuilder {
60                     }
61                     """
62                     ),
63                     java(
64                         """
65                     package android.pkg;
66 
67                     import androidx.annotation.NonNull;
68                     import androidx.annotation.Nullable;
69 
70                     public class Ok {
71 
72                         public int getInt();
73                         @NonNull
74                         public List<String> getStrings();
75                         @NonNull
76                         public List<String> getProperties();
77                         @NonNull
78                         public List<String> getRays();
79                         @NonNull
80                         public List<String> getBuses();
81                         @NonNull
82                         public List<String> getTaxes();
83                         @NonNull
84                         public List<String> getMessages();
85                         public boolean isBoolean();
86                         public boolean hasBoolean2();
87                         public boolean shouldBoolean3();
88 
89                         public static final class OkBuilder {
90                             public OkBuilder(@NonNull String goodParameter, int goodParameter2) {}
91 
92                             @NonNull
93                             public Ok build() { return null; }
94 
95                             @NonNull
96                             public OkBuilder setInt(int value) { return this; }
97 
98                             @NonNull
99                             public OkBuilder addString(@NonNull String value) { return this; }
100 
101                             @NonNull
102                             public OkBuilder addProperty(@NonNull String value) { return this; }
103 
104                             @NonNull
105                             public OkBuilder addRay(@NonNull String value) { return this; }
106 
107                             @NonNull
108                             public OkBuilder addBus(@NonNull String value) { return this; }
109 
110                             @NonNull
111                             public OkBuilder addTax(@NonNull String value) { return this; }
112 
113                             @NonNull
114                             public OkBuilder addMessages(@NonNull Collection<String> value) {
115                                 return this;
116                             }
117 
118                             @NonNull
119                             public OkBuilder clearStrings() { return this; }
120 
121                             @NonNull
122                             public OkBuilder setBoolean(boolean v) { return this; }
123 
124                             @NonNull
125                             public OkBuilder setHasBoolean2(boolean v) { return this; }
126 
127                             @NonNull
128                             public OkBuilder setShouldBoolean3(boolean v) { return this; }
129 
130                             @NonNull
131                             public OkBuilder clear() { return this; }
132 
133                             @NonNull
134                             public OkBuilder clearAll() { return this; }
135                         }
136 
137                         public static final class GenericBuilder<B extends GenericBuilder> {
138                             @NonNull
139                             public B setBoolean(boolean value) { return this; }
140 
141                             @NonNull
142                             public Ok build() { return null; }
143                         }
144                     }
145                     """
146                     ),
147                     java(
148                         """
149                     package android.pkg;
150 
151                     import androidx.annotation.NonNull;
152 
153                     public class SubOk extends Ok {
154 
155                         public static final class Builder {
156                             public Builder() {}
157 
158                             @NonNull
159                             public SubOk build() { return null; }
160 
161                             @NonNull
162                             public Builder setInt(int value) { return this; }
163                         }
164                     }
165                     """
166                     ),
167                     java(
168                         """
169                     package android.pkg;
170 
171                     import androidx.annotation.NonNull;
172                     import androidx.annotation.Nullable;
173                     import java.util.Collection;
174 
175                     public class Bad {
176 
177                         public boolean isBoolean();
178                         public boolean getWithoutMatchingGetter();
179                         public boolean isReturnsNullable();
180 
181                         public class BadBuilder {
182                             public BadBuilder(@Nullable String badParameter) {}
183 
184                             @NonNull
185                             public Bad build() { return null; }
186 
187                             @NonNull
188                             public BadBuilder addWithoutMatchingGetter(@NonNull String value) { return this; }
189 
190                             @NonNull
191                             public BadBuilder setWithoutMatchingGetter(boolean v) { return this; }
192 
193                             @NonNull
194                             public BadBuilder addPluralWithoutMatchingGetter(
195                                 @NonNull Collection<String> value) {
196                                 return this;
197                             }
198 
199                             @NonNull
200                             public BadBuilder addPluralWithoutMatchingGetters(
201                                 @NonNull Collection<String> value) {
202                                 return this;
203                             }
204 
205                             @NonNull
206                             public BadBuilder withBadSetterStyle(boolean v) { return this; }
207 
208                             @Nullable
209                             public BadBuilder setReturnsNullable(boolean v) { return this; }
210 
211                             public boolean getOnBuilder() { return true; }
212 
213                             public void setNotReturningBuilder(boolean v) { return this; }
214 
215                             @NonNull
216                             public BadBuilder () { return this; }
217                         }
218 
219                         public static final class NoBuildMethodBuilder {
220                             public NoBuildMethodBuilder() {}
221                         }
222 
223                         public static final class BadGenericBuilder<T extends Bad> {
224                             @NonNull
225                             public T setBoolean(boolean value) { return this; }
226 
227                             @NonNull
228                             public Bad build() { return null; }
229                         }
230                     }
231                     """
232                     ),
233                     java(
234                         """
235                     package test.pkg;
236 
237                     import androidx.annotation.NonNull;
238 
239                     public class GoodInterface {
240                         public interface Builder extends java.lang.Runnable {
241                             @NonNull
242                             GoodInterface build();
243                         }
244                     }
245                         """
246                             .trimIndent()
247                     ),
248                     java(
249                         """
250                     package test.pkg;
251 
252                     import androidx.annotation.NonNull;
253 
254                     public class GoodClass {
255                         public static abstract class Builder extends Base {
256                             @NonNull
257                             public abstract GoodClass build();
258                         }
259                         public class Base {}
260                     }
261                         """
262                             .trimIndent()
263                     ),
264                     java(
265                         """
266                     package test.pkg;
267 
268                     import androidx.annotation.NonNull;
269 
270                     public class BadInterface {
271                         public interface Builder {
272                             @NonNull
273                             BadInterface build();
274                         }
275                     }
276                         """
277                             .trimIndent()
278                     ),
279                     java(
280                         """
281                     package test.pkg;
282 
283                     import androidx.annotation.NonNull;
284 
285                     public class BadClass {
286                         public static abstract class Builder {
287                             @NonNull
288                             public abstract BadClass build();
289                         }
290                     }
291                         """
292                             .trimIndent()
293                     ),
294                     androidxNonNullSource,
295                     androidxNullableSource
296                 )
297         )
298     }
299 }
300