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 testJava8() throws Exception {
100         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
101         verifyWithInlineConfigParser(
102                 getPath("InputIllegalInstantiation.java"),
103                 expected);
104     }
105 
106     @Test
107     public void testNoPackage() throws Exception {
108         final String[] expected = {
109             "10:20: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
110         };
111         verifyWithInlineConfigParser(
112                 getPath("InputIllegalInstantiationNoPackage.java"), expected);
113     }
114 
115     @Test
116     public void testJavaLangPackage() throws Exception {
117         final String[] expected = {
118             "13:19: " + getCheckMessage(MSG_KEY, "java.lang.Boolean"),
119             "21:20: " + getCheckMessage(MSG_KEY, "java.lang.String"),
120         };
121         verifyWithInlineConfigParser(
122                 getNonCompilablePath("InputIllegalInstantiationLang.java"),
123                 expected);
124     }
125 
126     @Test
127     public void testWrongPackage() throws Exception {
128         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
129         verifyWithInlineConfigParser(
130                 getNonCompilablePath("InputIllegalInstantiationLang2.java"),
131                 expected);
132     }
133 
134     @Test
135     public void testJavaLangPackage3() throws Exception {
136         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
137         verifyWithInlineConfigParser(
138                 getPath("InputIllegalInstantiationLang3.java"),
139                 expected);
140     }
141 
142     @Test
143     public void testNameSimilarToStandardClass() throws Exception {
144         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
145         verifyWithInlineConfigParser(
146             getPath("InputIllegalInstantiationNameSimilarToStandardClasses.java"),
147             expected);
148     }
149 
150     @Test
151     public void testTokensNotNull() {
152         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
153         assertWithMessage("Acceptable tokens should not be null")
154             .that(check.getAcceptableTokens())
155             .isNotNull();
156         assertWithMessage("Default tokens should not be null")
157             .that(check.getDefaultTokens())
158             .isNotNull();
159         assertWithMessage("Required tokens should not be null")
160             .that(check.getRequiredTokens())
161             .isNotNull();
162     }
163 
164     @Test
165     public void testImproperToken() {
166         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
167 
168         final DetailAstImpl lambdaAst = new DetailAstImpl();
169         lambdaAst.setType(TokenTypes.LAMBDA);
170         lambdaAst.setText("LAMBDA");
171 
172         final IllegalArgumentException exc =
173                 getExpectedThrowable(IllegalArgumentException.class,
174                         () -> check.visitToken(lambdaAst));
175         assertWithMessage("Message must include token name")
176             .that(exc.getMessage())
177             .contains("LAMBDA");
178     }
179 
180     /**
181      * We cannot reproduce situation when visitToken is called and leaveToken is not.
182      * So, we have to use reflection to be sure that even in such situation
183      * state of the field will be cleared.
184      *
185      * @throws Exception when code tested throws exception
186      */
187     @SuppressWarnings("unchecked")
188     @Test
189     public void testClearStateClassNames1() throws Exception {
190         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
191         final DetailAST root = JavaParser.parseFile(
192                 new File(getPath("InputIllegalInstantiationSemantic1.java")),
193                 JavaParser.Options.WITHOUT_COMMENTS);
194         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
195             ast -> ast.getType() == TokenTypes.CLASS_DEF);
196 
197         assertWithMessage("Ast should contain CLASS_DEF")
198                 .that(classDef.isPresent())
199                 .isTrue();
200         assertWithMessage("State is not cleared on beginTree")
201             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.orElseThrow(),
202                     "classNames", classNames -> ((Collection<String>) classNames).isEmpty()))
203             .isTrue();
204     }
205 
206     /**
207      * We cannot reproduce situation when visitToken is called and leaveToken is not.
208      * So, we have to use reflection to be sure that even in such situation
209      * state of the field will be cleared.
210      *
211      * @throws Exception when code tested throws exception
212      */
213     @Test
214     public void testClearStateImports1() throws Exception {
215         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
216         final DetailAST root = JavaParser.parseFile(new File(
217                 getPath("InputIllegalInstantiationSemantic1.java")),
218                 JavaParser.Options.WITHOUT_COMMENTS);
219         final Optional<DetailAST> importDef = TestUtil.findTokenInAstByPredicate(root,
220             ast -> ast.getType() == TokenTypes.IMPORT);
221 
222         assertWithMessage("Ast should contain IMPORT_DEF")
223                 .that(importDef.isPresent())
224                 .isTrue();
225         assertWithMessage("State is not cleared on beginTree")
226             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, importDef.orElseThrow(),
227                     "imports", imports -> ((Collection<?>) imports).isEmpty()))
228             .isTrue();
229     }
230 
231     /**
232      * We cannot reproduce situation when visitToken is called and leaveToken is not.
233      * So, we have to use reflection to be sure that even in such situation
234      * state of the field will be cleared.
235      *
236      * @throws Exception when code tested throws exception
237      */
238     @SuppressWarnings("unchecked")
239     @Test
240     public void testClearStateClassNames2() throws Exception {
241         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
242         final DetailAST root = JavaParser.parseFile(
243                 new File(getPath("InputIllegalInstantiationSemantic2.java")),
244                 JavaParser.Options.WITHOUT_COMMENTS);
245         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
246             ast -> ast.getType() == TokenTypes.CLASS_DEF);
247 
248         assertWithMessage("Ast should contain CLASS_DEF")
249                 .that(classDef.isPresent())
250                 .isTrue();
251         assertWithMessage("State is not cleared on beginTree")
252             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.orElseThrow(),
253                     "classNames", classNames -> ((Collection<String>) classNames).isEmpty()))
254             .isTrue();
255     }
256 
257     /**
258      * We cannot reproduce situation when visitToken is called and leaveToken is not.
259      * So, we have to use reflection to be sure that even in such situation
260      * state of the field will be cleared.
261      *
262      * @throws Exception when code tested throws exception
263      */
264     @Test
265     public void testClearStateImports2() throws Exception {
266         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
267         final DetailAST root = JavaParser.parseFile(new File(
268                 getPath("InputIllegalInstantiationSemantic2.java")),
269                 JavaParser.Options.WITHOUT_COMMENTS);
270         final Optional<DetailAST> importDef = TestUtil.findTokenInAstByPredicate(root,
271             ast -> ast.getType() == TokenTypes.IMPORT);
272 
273         assertWithMessage("Ast should contain IMPORT_DEF")
274                 .that(importDef.isPresent())
275                 .isTrue();
276         assertWithMessage("State is not cleared on beginTree")
277             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, importDef.orElseThrow(),
278                     "imports", imports -> ((Collection<?>) imports).isEmpty()))
279             .isTrue();
280     }
281 
282     /**
283      * We cannot reproduce situation when visitToken is called and leaveToken is not.
284      * So, we have to use reflection to be sure that even in such situation
285      * state of the field will be cleared.
286      *
287      * @throws Exception when code tested throws exception
288      */
289     @SuppressWarnings("unchecked")
290     @Test
291     public void testClearStateInstantiations() throws Exception {
292         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
293         final DetailAST root = JavaParser.parseFile(new File(
294                 getNonCompilablePath("InputIllegalInstantiationLang.java")),
295                 JavaParser.Options.WITHOUT_COMMENTS);
296         final Optional<DetailAST> literalNew = TestUtil.findTokenInAstByPredicate(root,
297             ast -> ast.getType() == TokenTypes.LITERAL_NEW);
298 
299         assertWithMessage("Ast should contain LITERAL_NEW")
300                 .that(literalNew.isPresent())
301                 .isTrue();
302         assertWithMessage("State is not cleared on beginTree")
303                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
304                         literalNew.orElseThrow(), "instantiations",
305                         instantiations -> ((Collection<DetailAST>) instantiations).isEmpty()))
306                 .isTrue();
307     }
308 
309     @Test
310     public void testStateIsClearedOnBeginTreePackageName() throws Exception {
311         final DefaultConfiguration checkConfig =
312                 createModuleConfig(IllegalInstantiationCheck.class);
313         checkConfig.addProperty("classes",
314                 "java.lang.Boolean,com.puppycrawl.tools.checkstyle.checks.coding."
315                         + "illegalinstantiation.InputIllegalInstantiationBeginTree2."
316                         + "InputModifier");
317         final String file1 = getPath(
318                 "InputIllegalInstantiationBeginTree1.java");
319         final String file2 = getPath(
320                 "InputIllegalInstantiationBeginTree2.java");
321         final List<String> expectedFirstInput = List.of(CommonUtil.EMPTY_STRING_ARRAY);
322         final List<String> expectedSecondInput = List.of(CommonUtil.EMPTY_STRING_ARRAY);
323         final File[] inputs = {new File(file1), new File(file2)};
324 
325         verify(createChecker(checkConfig), inputs, ImmutableMap.of(
326             file1, expectedFirstInput,
327             file2, expectedSecondInput));
328     }
329 }