View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.design;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck.MSG_KEY;
24  
25  import java.io.File;
26  
27  import org.antlr.v4.runtime.CommonToken;
28  import org.junit.jupiter.api.Test;
29  
30  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
31  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
32  import com.puppycrawl.tools.checkstyle.JavaParser;
33  import com.puppycrawl.tools.checkstyle.api.DetailAST;
34  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
35  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
36  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
37  
38  public class VisibilityModifierCheckTest
39      extends AbstractModuleTestSupport {
40  
41      @Override
42      protected String getPackageLocation() {
43          return "com/puppycrawl/tools/checkstyle/checks/design/visibilitymodifier";
44      }
45  
46      @Test
47      public void testGetRequiredTokens() {
48          final VisibilityModifierCheck checkObj = new VisibilityModifierCheck();
49          final int[] expected = {
50              TokenTypes.VARIABLE_DEF,
51              TokenTypes.IMPORT,
52          };
53          assertWithMessage("Default required tokens are invalid")
54              .that(checkObj.getRequiredTokens())
55              .isEqualTo(expected);
56      }
57  
58      @Test
59      public void testInner()
60              throws Exception {
61          final String[] expected = {
62              "47:24: " + getCheckMessage(MSG_KEY, "rData"),
63              "50:27: " + getCheckMessage(MSG_KEY, "protectedVariable"),
64              "53:17: " + getCheckMessage(MSG_KEY, "packageVariable"),
65              "58:29: " + getCheckMessage(MSG_KEY, "sWeird"),
66              "60:19: " + getCheckMessage(MSG_KEY, "sWeird2"),
67              "94:20: " + getCheckMessage(MSG_KEY, "someValue"),
68              "97:11: " + getCheckMessage(MSG_KEY, "fSerialVersionUID"),
69          };
70          verifyWithInlineConfigParser(
71                  getPath("InputVisibilityModifierInner.java"), expected);
72      }
73  
74      @Test
75      public void testIgnoreAccess()
76              throws Exception {
77          final String[] expected = {
78              "34:20: " + getCheckMessage(MSG_KEY, "fData"),
79              "94:20: " + getCheckMessage(MSG_KEY, "someValue"),
80          };
81          verifyWithInlineConfigParser(
82                  getPath("InputVisibilityModifierInner1.java"), expected);
83      }
84  
85      @Test
86      public void testSimple() throws Exception {
87          final String[] expected = {
88              "49:19: " + getCheckMessage(MSG_KEY, "mNumCreated2"),
89              "59:23: " + getCheckMessage(MSG_KEY, "sTest1"),
90              "61:26: " + getCheckMessage(MSG_KEY, "sTest3"),
91              "63:16: " + getCheckMessage(MSG_KEY, "sTest2"),
92              "66:9: " + getCheckMessage(MSG_KEY, "mTest1"),
93              "68:16: " + getCheckMessage(MSG_KEY, "mTest2"),
94          };
95          verifyWithInlineConfigParser(
96                  getPath("InputVisibilityModifierSimple.java"), expected);
97      }
98  
99      @Test
100     public void testStrictJavadoc() throws Exception {
101         final String[] expected = {
102             "49:9: " + getCheckMessage(MSG_KEY, "mLen"),
103             "50:19: " + getCheckMessage(MSG_KEY, "mDeer"),
104             "51:16: " + getCheckMessage(MSG_KEY, "aFreddo"),
105         };
106         verifyWithInlineConfigParser(
107                 getPath("InputVisibilityModifierPublicOnly.java"), expected);
108     }
109 
110     @Test
111     public void testAllowPublicFinalFieldsInImmutableClass() throws Exception {
112         final String[] expected = {
113             "33:39: " + getCheckMessage(MSG_KEY, "includes"),
114             "34:39: " + getCheckMessage(MSG_KEY, "excludes"),
115             "37:23: " + getCheckMessage(MSG_KEY, "list"),
116             "55:20: " + getCheckMessage(MSG_KEY, "value"),
117             "57:24: " + getCheckMessage(MSG_KEY, "bValue"),
118             "58:31: " + getCheckMessage(MSG_KEY, "longValue"),
119             "62:19: " + getCheckMessage(MSG_KEY, "C_D_E"),
120         };
121         verifyWithInlineConfigParser(
122                 getPath("InputVisibilityModifierImmutable.java"), expected);
123     }
124 
125     @Test
126     public void testAllowPublicFinalFieldsInImmutableClassWithNonCanonicalClasses()
127             throws Exception {
128         final String[] expected = {
129             "28:39: " + getCheckMessage(MSG_KEY, "includes"),
130             "29:39: " + getCheckMessage(MSG_KEY, "excludes"),
131             "31:29: " + getCheckMessage(MSG_KEY, "money"),
132             "32:23: " + getCheckMessage(MSG_KEY, "list"),
133             "48:35: " + getCheckMessage(MSG_KEY, "uri"),
134             "49:35: " + getCheckMessage(MSG_KEY, "file"),
135             "50:20: " + getCheckMessage(MSG_KEY, "value"),
136             "51:35: " + getCheckMessage(MSG_KEY, "url"),
137             "52:24: " + getCheckMessage(MSG_KEY, "bValue"),
138             "53:21: " + getCheckMessage(MSG_KEY, "longValue"),
139             "57:19: " + getCheckMessage(MSG_KEY, "C_D_E"),
140         };
141         verifyWithInlineConfigParser(
142                 getPath("InputVisibilityModifierImmutable2.java"), expected);
143     }
144 
145     @Test
146     public void testDisAllowPublicFinalAndImmutableFieldsInImmutableClass() throws Exception {
147         final String[] expected = {
148             "32:22: " + getCheckMessage(MSG_KEY, "someIntValue"),
149             "33:39: " + getCheckMessage(MSG_KEY, "includes"),
150             "34:39: " + getCheckMessage(MSG_KEY, "excludes"),
151             "35:25: " + getCheckMessage(MSG_KEY, "notes"),
152             "36:29: " + getCheckMessage(MSG_KEY, "money"),
153             "37:23: " + getCheckMessage(MSG_KEY, "list"),
154             "51:28: " + getCheckMessage(MSG_KEY, "f"),
155             "52:30: " + getCheckMessage(MSG_KEY, "bool"),
156             "53:35: " + getCheckMessage(MSG_KEY, "uri"),
157             "54:35: " + getCheckMessage(MSG_KEY, "file"),
158             "55:20: " + getCheckMessage(MSG_KEY, "value"),
159             "56:35: " + getCheckMessage(MSG_KEY, "url"),
160             "57:24: " + getCheckMessage(MSG_KEY, "bValue"),
161             "58:21: " + getCheckMessage(MSG_KEY, "longValue"),
162             "62:19: " + getCheckMessage(MSG_KEY, "C_D_E"),
163         };
164         verifyWithInlineConfigParser(
165                 getPath("InputVisibilityModifierImmutable3.java"), expected);
166     }
167 
168     @Test
169     public void testAllowPublicFinalFieldsInNonFinalClass() throws Exception {
170         final String[] expected = {
171             "55:20: " + getCheckMessage(MSG_KEY, "value"),
172             "57:24: " + getCheckMessage(MSG_KEY, "bValue"),
173             "58:21: " + getCheckMessage(MSG_KEY, "longValue"),
174         };
175         verifyWithInlineConfigParser(
176                 getPath("InputVisibilityModifierImmutable4.java"), expected);
177     }
178 
179     @Test
180     public void testUserSpecifiedImmutableClassesList() throws Exception {
181         final String[] expected = {
182             "30:29: " + getCheckMessage(MSG_KEY, "money"),
183             "47:35: " + getCheckMessage(MSG_KEY, "uri"),
184             "48:35: " + getCheckMessage(MSG_KEY, "file"),
185             "49:20: " + getCheckMessage(MSG_KEY, "value"),
186             "50:35: " + getCheckMessage(MSG_KEY, "url"),
187             "51:24: " + getCheckMessage(MSG_KEY, "bValue"),
188             "52:21: " + getCheckMessage(MSG_KEY, "longValue"),
189             "56:19: " + getCheckMessage(MSG_KEY, "C_D_E"),
190         };
191         verifyWithInlineConfigParser(
192                 getPath("InputVisibilityModifierImmutable5.java"), expected);
193     }
194 
195     @Test
196     public void testImmutableSpecifiedSameTypeName() throws Exception {
197         final String[] expected = {
198             "23:46: " + getCheckMessage(MSG_KEY, "calendar"),
199             "26:36: " + getCheckMessage(MSG_KEY, "address"),
200             "27:36: " + getCheckMessage(MSG_KEY, "adr"),
201         };
202         verifyWithInlineConfigParser(
203                 getPath("InputVisibilityModifierImmutableSameTypeName.java"),
204                 expected);
205     }
206 
207     @Test
208     public void testImmutableValueSameTypeName() throws Exception {
209         final String[] expected = {
210             "28:46: " + getCheckMessage(MSG_KEY, "calendar"),
211             "29:59: " + getCheckMessage(MSG_KEY, "calendar2"),
212             "30:59: " + getCheckMessage(MSG_KEY, "calendar3"),
213         };
214         verifyWithInlineConfigParser(
215                 getPath("InputVisibilityModifierImmutableSameTypeName2.java"),
216                 expected);
217     }
218 
219     @Test
220     public void testImmutableStarImportFalseNegative() throws Exception {
221         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
222         verifyWithInlineConfigParser(
223                 getPath("InputVisibilityModifierImmutableStarImport.java"), expected);
224     }
225 
226     @Test
227     public void testImmutableStarImportNoWarn() throws Exception {
228         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
229         verifyWithInlineConfigParser(
230                 getPath("InputVisibilityModifierImmutableStarImport2.java"),
231                 expected);
232     }
233 
234     @Test
235     public void testDefaultAnnotationPatterns() throws Exception {
236         final String[] expected = {
237             "61:19: " + getCheckMessage(MSG_KEY, "customAnnotatedPublic"),
238             "64:12: " + getCheckMessage(MSG_KEY, "customAnnotatedPackage"),
239             "67:22: " + getCheckMessage(MSG_KEY, "customAnnotatedProtected"),
240             "69:19: " + getCheckMessage(MSG_KEY, "unannotatedPublic"),
241             "70:12: " + getCheckMessage(MSG_KEY, "unannotatedPackage"),
242             "71:22: " + getCheckMessage(MSG_KEY, "unannotatedProtected"),
243         };
244         verifyWithInlineConfigParser(
245                 getPath("InputVisibilityModifierAnnotated.java"), expected);
246     }
247 
248     @Test
249     public void testCustomAnnotationPatterns() throws Exception {
250         final String[] expected = {
251             "37:28: " + getCheckMessage(MSG_KEY, "publicJUnitRule"),
252             "40:28: " + getCheckMessage(MSG_KEY, "fqPublicJUnitRule"),
253             "43:19: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPublic"),
254             "46:12: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPackage"),
255             "49:22: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedProtected"),
256             "52:19: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPublic"),
257             "55:12: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPackage"),
258             "58:22: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedProtected"),
259             "69:19: " + getCheckMessage(MSG_KEY, "unannotatedPublic"),
260             "70:12: " + getCheckMessage(MSG_KEY, "unannotatedPackage"),
261             "71:22: " + getCheckMessage(MSG_KEY, "unannotatedProtected"),
262             "80:35: " + getCheckMessage(MSG_KEY, "publicJUnitClassRule"),
263             "83:35: " + getCheckMessage(MSG_KEY, "fqPublicJUnitClassRule"),
264         };
265         verifyWithInlineConfigParser(
266                 getPath("InputVisibilityModifierAnnotated2.java"), expected);
267     }
268 
269     @Test
270     public void testIgnoreAnnotationNoPattern() throws Exception {
271         final String[] expected = {
272             "36:28: " + getCheckMessage(MSG_KEY, "publicJUnitRule"),
273             "39:28: " + getCheckMessage(MSG_KEY, "fqPublicJUnitRule"),
274             "42:19: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPublic"),
275             "45:12: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedPackage"),
276             "48:22: " + getCheckMessage(MSG_KEY, "googleCommonsAnnotatedProtected"),
277             "51:19: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPublic"),
278             "54:12: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedPackage"),
279             "57:22: " + getCheckMessage(MSG_KEY, "fqGoogleCommonsAnnotatedProtected"),
280             "60:19: " + getCheckMessage(MSG_KEY, "customAnnotatedPublic"),
281             "63:12: " + getCheckMessage(MSG_KEY, "customAnnotatedPackage"),
282             "66:22: " + getCheckMessage(MSG_KEY, "customAnnotatedProtected"),
283             "68:19: " + getCheckMessage(MSG_KEY, "unannotatedPublic"),
284             "69:12: " + getCheckMessage(MSG_KEY, "unannotatedPackage"),
285             "70:22: " + getCheckMessage(MSG_KEY, "unannotatedProtected"),
286             "79:35: " + getCheckMessage(MSG_KEY, "publicJUnitClassRule"),
287             "82:35: " + getCheckMessage(MSG_KEY, "fqPublicJUnitClassRule"),
288         };
289         verifyWithInlineConfigParser(
290                 getPath("InputVisibilityModifierAnnotated3.java"), expected);
291     }
292 
293     @Test
294     public void testIgnoreAnnotationSameName() throws Exception {
295         final String[] expected = {
296             "33:28: " + getCheckMessage(MSG_KEY, "publicJUnitRule"),
297             "36:28: " + getCheckMessage(MSG_KEY, "publicJUnitClassRule"),
298         };
299         verifyWithInlineConfigParser(
300                 getPath("InputVisibilityModifierAnnotatedSameTypeName.java"),
301                 expected);
302     }
303 
304     @Test
305     public void testGetAcceptableTokens() {
306         final VisibilityModifierCheck obj = new VisibilityModifierCheck();
307         final int[] expected = {
308             TokenTypes.VARIABLE_DEF,
309             TokenTypes.IMPORT,
310         };
311         assertWithMessage("Default acceptable tokens are invalid")
312             .that(obj.getAcceptableTokens())
313             .isEqualTo(expected);
314     }
315 
316     @Test
317     public void testPublicImmutableFieldsNotAllowed() throws Exception {
318         final String[] expected = {
319             "31:22: " + getCheckMessage(MSG_KEY, "someIntValue"),
320             "32:39: " + getCheckMessage(MSG_KEY, "includes"),
321             "33:35: " + getCheckMessage(MSG_KEY, "notes"),
322             "34:29: " + getCheckMessage(MSG_KEY, "value"),
323             "35:23: " + getCheckMessage(MSG_KEY, "list"),
324         };
325         verifyWithInlineConfigParser(
326                 getPath("InputVisibilityModifiersPublicImmutable.java"), expected);
327     }
328 
329     @Test
330     public void testPublicFinalFieldsNotAllowed() throws Exception {
331         final String[] expected = {
332             "31:22: " + getCheckMessage(MSG_KEY, "someIntValue"),
333             "32:39: " + getCheckMessage(MSG_KEY, "includes"),
334             "33:25: " + getCheckMessage(MSG_KEY, "notes"),
335             "34:29: " + getCheckMessage(MSG_KEY, "value"),
336             "35:23: " + getCheckMessage(MSG_KEY, "list"),
337         };
338         verifyWithInlineConfigParser(
339                 getPath("InputVisibilityModifiersPublicImmutable2.java"), expected);
340     }
341 
342     @Test
343     public void testPublicFinalFieldsAllowed() throws Exception {
344         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
345         verifyWithInlineConfigParser(
346                 getPath("InputVisibilityModifiersPublicImmutable3.java"), expected);
347     }
348 
349     @Test
350     public void testPublicFinalFieldInEnum() throws Exception {
351         final String[] expected = {
352             "35:23: " + getCheckMessage(MSG_KEY, "hole"),
353         };
354         verifyWithInlineConfigParser(
355                 getPath("InputVisibilityModifiersEnumIsSealed.java"), expected);
356     }
357 
358     @Test
359     public void testWrongTokenType() {
360         final VisibilityModifierCheck obj = new VisibilityModifierCheck();
361         final DetailAstImpl ast = new DetailAstImpl();
362         ast.initialize(new CommonToken(TokenTypes.CLASS_DEF, "class"));
363         try {
364             obj.visitToken(ast);
365             assertWithMessage("exception expected").fail();
366         }
367         catch (IllegalArgumentException ex) {
368             assertWithMessage("Invalid exception message")
369                 .that(ex.getMessage())
370                 .isEqualTo("Unexpected token type: class");
371         }
372     }
373 
374     @Test
375     public void testNullModifiers() throws Exception {
376         final String[] expected = {
377             "32:50: " + getCheckMessage(MSG_KEY, "i"),
378         };
379         verifyWithInlineConfigParser(
380                 getPath("InputVisibilityModifiersNullModifiers.java"), expected);
381     }
382 
383     @Test
384     public void testVisibilityModifiersOfGenericFields() throws Exception {
385         final String[] expected = {
386             "31:56: " + getCheckMessage(MSG_KEY, "perfSeries"),
387             "32:66: " + getCheckMessage(MSG_KEY, "peopleMap"),
388             "33:66: " + getCheckMessage(MSG_KEY, "someMap"),
389             "34:76: " + getCheckMessage(MSG_KEY, "newMap"),
390             "36:45: " + getCheckMessage(MSG_KEY, "optionalOfObject"),
391             "37:35: " + getCheckMessage(MSG_KEY, "obj"),
392             "39:19: " + getCheckMessage(MSG_KEY, "rqUID"),
393             "40:29: " + getCheckMessage(MSG_KEY, "rqTime"),
394             "41:45: " + getCheckMessage(MSG_KEY, "rates"),
395             "42:50: " + getCheckMessage(MSG_KEY, "loans"),
396             "43:60: " + getCheckMessage(MSG_KEY, "cards"),
397             "44:60: " + getCheckMessage(MSG_KEY, "values"),
398             "45:70: " + getCheckMessage(MSG_KEY, "permissions"),
399             "47:38: " + getCheckMessage(MSG_KEY, "mapOfStrings"),
400             "48:48: " + getCheckMessage(MSG_KEY, "names"),
401             "49:48: " + getCheckMessage(MSG_KEY, "links"),
402             "50:38: " + getCheckMessage(MSG_KEY, "presentations"),
403             "51:48: " + getCheckMessage(MSG_KEY, "collection"),
404             "54:73: " + getCheckMessage(MSG_KEY, "exceptions"),
405         };
406         verifyWithInlineConfigParser(
407                 getPath("InputVisibilityModifierGenerics.java"), expected);
408     }
409 
410     /**
411      * We can not cover this mutation because it forces all imports to be non static,
412      * but static imports are ignored, so we will not see any effect on validation.
413      * We could remove this method at all, and it will work correctly as we can not use
414      * class with name "", but in this case internal collection will have short names
415      * as "" that will not make problems, but will be weird in debug.
416      *
417      * @throws Exception when exception occurred during execution.
418      */
419     @Test
420     public void testIsStarImportNullAst() throws Exception {
421         final DetailAST importAst = JavaParser.parseFile(
422             new File(getPath("InputVisibilityModifierIsStarImport.java")),
423             JavaParser.Options.WITHOUT_COMMENTS).getFirstChild().getNextSibling();
424         final VisibilityModifierCheck check = new VisibilityModifierCheck();
425         final boolean actual = TestUtil.invokeMethod(check, "isStarImport", importAst);
426 
427         assertWithMessage("Should return true when star import is passed")
428                 .that(actual)
429                 .isTrue();
430     }
431 
432     @Test
433     public void testPackageClassName() throws Exception {
434         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
435         verifyWithInlineConfigParser(
436                 getNonCompilablePath("InputVisibilityModifierPackageClassName.java"),
437                 expected);
438     }
439 
440 }