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.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 
154         try {
155             check.visitToken(lambdaAst);
156             assertWithMessage("IllegalArgumentException is expected").fail();
157         }
158         catch (IllegalArgumentException ex) {
159             // it is OK
160         }
161     }
162 
163     /**
164      * We cannot reproduce situation when visitToken is called and leaveToken is not.
165      * So, we have to use reflection to be sure that even in such situation
166      * state of the field will be cleared.
167      *
168      * @throws Exception when code tested throws exception
169      */
170     @Test
171     @SuppressWarnings("unchecked")
172     public void testClearStateClassNames() throws Exception {
173         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
174         final DetailAST root = JavaParser.parseFile(
175                 new File(getPath("InputIllegalInstantiationSemantic.java")),
176                 JavaParser.Options.WITHOUT_COMMENTS);
177         final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
178             ast -> ast.getType() == TokenTypes.CLASS_DEF);
179 
180         assertWithMessage("Ast should contain CLASS_DEF")
181                 .that(classDef.isPresent())
182                 .isTrue();
183         assertWithMessage("State is not cleared on beginTree")
184             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.orElseThrow(),
185                     "classNames", classNames -> ((Collection<String>) classNames).isEmpty()))
186             .isTrue();
187     }
188 
189     /**
190      * We cannot reproduce situation when visitToken is called and leaveToken is not.
191      * So, we have to use reflection to be sure that even in such situation
192      * state of the field will be cleared.
193      *
194      * @throws Exception when code tested throws exception
195      */
196     @Test
197     public void testClearStateImports() throws Exception {
198         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
199         final DetailAST root = JavaParser.parseFile(new File(
200                 getPath("InputIllegalInstantiationSemantic.java")),
201                 JavaParser.Options.WITHOUT_COMMENTS);
202         final Optional<DetailAST> importDef = TestUtil.findTokenInAstByPredicate(root,
203             ast -> ast.getType() == TokenTypes.IMPORT);
204 
205         assertWithMessage("Ast should contain IMPORT_DEF")
206                 .that(importDef.isPresent())
207                 .isTrue();
208         assertWithMessage("State is not cleared on beginTree")
209             .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, importDef.orElseThrow(),
210                     "imports", imports -> ((Collection<?>) imports).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     @SuppressWarnings("unchecked")
223     public void testClearStateInstantiations() throws Exception {
224         final IllegalInstantiationCheck check = new IllegalInstantiationCheck();
225         final DetailAST root = JavaParser.parseFile(new File(
226                 getNonCompilablePath("InputIllegalInstantiationLang.java")),
227                 JavaParser.Options.WITHOUT_COMMENTS);
228         final Optional<DetailAST> literalNew = TestUtil.findTokenInAstByPredicate(root,
229             ast -> ast.getType() == TokenTypes.LITERAL_NEW);
230 
231         assertWithMessage("Ast should contain LITERAL_NEW")
232                 .that(literalNew.isPresent())
233                 .isTrue();
234         assertWithMessage("State is not cleared on beginTree")
235                 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
236                         literalNew.orElseThrow(), "instantiations",
237                         instantiations -> ((Collection<DetailAST>) instantiations).isEmpty()))
238                 .isTrue();
239     }
240 
241     @Test
242     public void testStateIsClearedOnBeginTreePackageName() throws Exception {
243         final DefaultConfiguration checkConfig =
244                 createModuleConfig(IllegalInstantiationCheck.class);
245         checkConfig.addProperty("classes",
246                 "java.lang.Boolean,com.puppycrawl.tools.checkstyle.checks.coding."
247                         + "illegalinstantiation.InputIllegalInstantiationBeginTree2."
248                         + "InputModifier");
249         final String file1 = getPath(
250                 "InputIllegalInstantiationBeginTree1.java");
251         final String file2 = getPath(
252                 "InputIllegalInstantiationBeginTree2.java");
253         final List<String> expectedFirstInput = List.of(CommonUtil.EMPTY_STRING_ARRAY);
254         final List<String> expectedSecondInput = List.of(CommonUtil.EMPTY_STRING_ARRAY);
255         final File[] inputs = {new File(file1), new File(file2)};
256 
257         verify(createChecker(checkConfig), inputs, ImmutableMap.of(
258             file1, expectedFirstInput,
259             file2, expectedSecondInput));
260     }
261 }