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