View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2026 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.coding;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.coding.IllegalInstantiationCheck.MSG_KEY;
24  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
25  
26  import java.io.File;
27  import java.util.Collection;
28  import java.util.List;
29  import java.util.Optional;
30  
31  import org.junit.jupiter.api.Test;
32  
33  import com.google.common.collect.ImmutableMap;
34  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
35  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
36  import com.puppycrawl.tools.checkstyle.DetailAstImpl;
37  import com.puppycrawl.tools.checkstyle.JavaParser;
38  import com.puppycrawl.tools.checkstyle.api.DetailAST;
39  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
40  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
41  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
42  
43  public class IllegalInstantiationCheckTest
44      extends AbstractModuleTestSupport {
45  
46      @Override
47      public String getPackageLocation() {
48          return "com/puppycrawl/tools/checkstyle/checks/coding/illegalinstantiation";
49      }
50  
51      @Test
52      public void testDefault1() throws Exception {
53          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
54          verifyWithInlineConfigParser(
55                  getPath("InputIllegalInstantiationSemantic1.java"), expected);
56      }
57  
58      @Test
59      public void testDefault2() throws Exception {
60          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
61          verifyWithInlineConfigParser(
62                  getPath("InputIllegalInstantiationSemantic2.java"), expected);
63      }
64  
65      @Test
66      public void testClasses() throws Exception {
67          final String[] expected = {
68              "24:21: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
69              "29:21: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
70              "36:16: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
71              "43:21: " + getCheckMessage(MSG_KEY,
72                  "com.puppycrawl.tools.checkstyle.checks.coding."
73                  + "illegalinstantiation.InputModifier"),
74              "46:18: " + getCheckMessage(MSG_KEY, "java.io.File"),
75              "49:21: " + getCheckMessage(MSG_KEY, "java.awt.Color"),
76          };
77          verifyWithInlineConfigParser(
78                  getPath("InputIllegalInstantiationSemantic21.java"), expected);
79      }
80  
81      @Test
82      public void testClasses2() throws Exception {
83  
84          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
85  
86          verifyWithInlineConfigParser(
87                  getPath("InputIllegalInstantiationSemantic22.java"), expected);
88      }
89  
90      @Test
91      public void testSameClassNameAsJavaLang() throws Exception {
92          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
93          verifyWithInlineConfigParser(
94                  getPath("InputIllegalInstantiationSameClassNameJavaLang.java"),
95                  expected);
96      }
97  
98      @Test
99      public void testSameRecordNameAsJavaLang() throws Exception {
100         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
101         verifyWithInlineConfigParser(
102                 getPath("InputIllegalInstantiationSameRecordNameJavaLang.java"),
103                 expected);
104     }
105 
106     @Test
107     public void testJava8() throws Exception {
108         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
109         verifyWithInlineConfigParser(
110                 getPath("InputIllegalInstantiation.java"),
111                 expected);
112     }
113 
114     @Test
115     public void testNoPackage() throws Exception {
116         final String[] expected = {
117             "10:20: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
118         };
119         verifyWithInlineConfigParser(
120                 getPath("InputIllegalInstantiationNoPackage.java"), expected);
121     }
122 
123     @Test
124     public void testJavaLangPackage() throws Exception {
125         final String[] expected = {
126             "13:19: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
127             "21:20: " + getCheckMessage(MSG_KEY, "java.lang.String"),
128         };
129         verifyWithInlineConfigParser(
130                 getNonCompilablePath("InputIllegalInstantiationLang.java"),
131                 expected);
132     }
133 
134     @Test
135     public void testWrongPackage() throws Exception {
136         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
137         verifyWithInlineConfigParser(
138                 getNonCompilablePath("InputIllegalInstantiationLang2.java"),
139                 expected);
140     }
141 
142     @Test
143     public void testJavaLangPackage3() throws Exception {
144         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
145         verifyWithInlineConfigParser(
146                 getPath("InputIllegalInstantiationLang3.java"),
147                 expected);
148     }
149 
150     @Test
151     public void testNameSimilarToStandardClass() throws Exception {
152         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
153         verifyWithInlineConfigParser(
154             getPath("InputIllegalInstantiationNameSimilarToStandardClasses.java"),
155             expected);
156     }
157 
158     @Test
159     public void testTokensNotNull() {
160         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
161         assertWithMessage("Acceptable tokens should not be null")
162             .that(check.getAcceptableTokens())
163             .isNotNull();
164         assertWithMessage("Default tokens should not be null")
165             .that(check.getDefaultTokens())
166             .isNotNull();
167         assertWithMessage("Required tokens should not be null")
168             .that(check.getRequiredTokens())
169             .isNotNull();
170     }
171 
172     @Test
173     public void testImproperToken() {
174         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
175 
176         final DetailAstImpl lambdaAst = new DetailAstImpl();
177         lambdaAst.setType(TokenTypes.LAMBDA);
178         lambdaAst.setText("LAMBDA");
179 
180         final IllegalArgumentException exc =
181                 getExpectedThrowable(IllegalArgumentException.class,
182                         () -> check.visitToken(lambdaAst));
183         assertWithMessage("Message must include token name")
184             .that(exc.getMessage())
185             .contains("LAMBDA");
186     }
187 
188     /**
189      * We cannot reproduce situation when visitToken is called and leaveToken is not.
190      * So, we have to use reflection to be sure that even in such situation
191      * state of the field will be cleared.
192      *
193      * @throws Exception when code tested throws exception
194      */
195     @SuppressWarnings("unchecked")
196     @Test
197     public void testClearStateClassNames1() throws Exception {
198         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
199         final DetailAST root = JavaParser.parseFile(
200                 new File(getPath("InputIllegalInstantiationSemantic1.java")),
201                 JavaParser.Options.WITHOUT_COMMENTS);
202         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
203             ast -> ast.getType() == TokenTypes.CLASS_DEF);
204 
205         assertWithMessage("Ast should contain CLASS_DEF")
206                 .that(classDef.isPresent())
207                 .isTrue();
208         assertWithMessage("State is not cleared on beginTree")
209             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.orElseThrow(),
210                     "classNames", classNames -> ((Collection<String>) classNames).isEmpty()))
211             .isTrue();
212     }
213 
214     /**
215      * We cannot reproduce situation when visitToken is called and leaveToken is not.
216      * So, we have to use reflection to be sure that even in such situation
217      * state of the field will be cleared.
218      *
219      * @throws Exception when code tested throws exception
220      */
221     @Test
222     public void testClearStateImports1() throws Exception {
223         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
224         final DetailAST root = JavaParser.parseFile(new File(
225                 getPath("InputIllegalInstantiationSemantic1.java")),
226                 JavaParser.Options.WITHOUT_COMMENTS);
227         final Optional<DetailAST> importDef = TestUtil.findTokenInAstByPredicate(root,
228             ast -> ast.getType() == TokenTypes.IMPORT);
229 
230         assertWithMessage("Ast should contain IMPORT_DEF")
231                 .that(importDef.isPresent())
232                 .isTrue();
233         assertWithMessage("State is not cleared on beginTree")
234             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, importDef.orElseThrow(),
235                     "imports", imports -> ((Collection<?>) imports).isEmpty()))
236             .isTrue();
237     }
238 
239     /**
240      * We cannot reproduce situation when visitToken is called and leaveToken is not.
241      * So, we have to use reflection to be sure that even in such situation
242      * state of the field will be cleared.
243      *
244      * @throws Exception when code tested throws exception
245      */
246     @SuppressWarnings("unchecked")
247     @Test
248     public void testClearStateClassNames2() throws Exception {
249         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
250         final DetailAST root = JavaParser.parseFile(
251                 new File(getPath("InputIllegalInstantiationSemantic2.java")),
252                 JavaParser.Options.WITHOUT_COMMENTS);
253         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
254             ast -> ast.getType() == TokenTypes.CLASS_DEF);
255 
256         assertWithMessage("Ast should contain CLASS_DEF")
257                 .that(classDef.isPresent())
258                 .isTrue();
259         assertWithMessage("State is not cleared on beginTree")
260             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.orElseThrow(),
261                     "classNames", classNames -> ((Collection<String>) classNames).isEmpty()))
262             .isTrue();
263     }
264 
265     /**
266      * We cannot reproduce situation when visitToken is called and leaveToken is not.
267      * So, we have to use reflection to be sure that even in such situation
268      * state of the field will be cleared.
269      *
270      * @throws Exception when code tested throws exception
271      */
272     @Test
273     public void testClearStateImports2() throws Exception {
274         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
275         final DetailAST root = JavaParser.parseFile(new File(
276                 getPath("InputIllegalInstantiationSemantic2.java")),
277                 JavaParser.Options.WITHOUT_COMMENTS);
278         final Optional<DetailAST> importDef = TestUtil.findTokenInAstByPredicate(root,
279             ast -> ast.getType() == TokenTypes.IMPORT);
280 
281         assertWithMessage("Ast should contain IMPORT_DEF")
282                 .that(importDef.isPresent())
283                 .isTrue();
284         assertWithMessage("State is not cleared on beginTree")
285             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, importDef.orElseThrow(),
286                     "imports", imports -> ((Collection<?>) imports).isEmpty()))
287             .isTrue();
288     }
289 
290     /**
291      * We cannot reproduce situation when visitToken is called and leaveToken is not.
292      * So, we have to use reflection to be sure that even in such situation
293      * state of the field will be cleared.
294      *
295      * @throws Exception when code tested throws exception
296      */
297     @SuppressWarnings("unchecked")
298     @Test
299     public void testClearStateInstantiations() throws Exception {
300         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
301         final DetailAST root = JavaParser.parseFile(new File(
302                 getNonCompilablePath("InputIllegalInstantiationLang.java")),
303                 JavaParser.Options.WITHOUT_COMMENTS);
304         final Optional<DetailAST> literalNew = TestUtil.findTokenInAstByPredicate(root,
305             ast -> ast.getType() == TokenTypes.LITERAL_NEW);
306 
307         assertWithMessage("Ast should contain LITERAL_NEW")
308                 .that(literalNew.isPresent())
309                 .isTrue();
310         assertWithMessage("State is not cleared on beginTree")
311                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
312                         literalNew.orElseThrow(), "instantiations",
313                         instantiations -> ((Collection<DetailAST>) instantiations).isEmpty()))
314                 .isTrue();
315     }
316 
317     @Test
318     public void testStateIsClearedOnBeginTreePackageName() throws Exception {
319         final DefaultConfiguration checkConfig =
320                 createModuleConfig(IllegalInstantiationCheck.class);
321         checkConfig.addProperty("classes",
322                 "java.lang.Boolean,com.puppycrawl.tools.checkstyle.checks.coding."
323                         + "illegalinstantiation.InputIllegalInstantiationBeginTree2."
324                         + "InputModifier");
325         final String file1 = getPath(
326                 "InputIllegalInstantiationBeginTree1.java");
327         final String file2 = getPath(
328                 "InputIllegalInstantiationBeginTree2.java");
329         final List<String> expectedFirstInput = List.of(CommonUtil.EMPTY_STRING_ARRAY);
330         final List<String> expectedSecondInput = List.of(CommonUtil.EMPTY_STRING_ARRAY);
331         final File[] inputs = {new File(file1), new File(file2)};
332 
333         verify(createChecker(checkConfig), inputs, ImmutableMap.of(
334             file1, expectedFirstInput,
335             file2, expectedSecondInput));
336     }
337 
338 }