1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.FinalClassCheck.MSG_KEY;
24
25 import java.io.File;
26 import java.util.Optional;
27
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
37 public class FinalClassCheckTest
38 extends AbstractModuleTestSupport {
39
40 @Override
41 public String getPackageLocation() {
42 return "com/puppycrawl/tools/checkstyle/checks/design/finalclass";
43 }
44
45 @Test
46 public void testGetRequiredTokens() {
47 final FinalClassCheck checkObj = new FinalClassCheck();
48 final int[] expected = {
49 TokenTypes.ANNOTATION_DEF,
50 TokenTypes.CLASS_DEF,
51 TokenTypes.ENUM_DEF,
52 TokenTypes.INTERFACE_DEF,
53 TokenTypes.RECORD_DEF,
54 TokenTypes.CTOR_DEF,
55 TokenTypes.PACKAGE_DEF,
56 TokenTypes.LITERAL_NEW,
57 };
58 assertWithMessage("Default required tokens are invalid")
59 .that(checkObj.getRequiredTokens())
60 .isEqualTo(expected);
61 }
62
63 @Test
64 public void testFinalClass() throws Exception {
65 final String[] expected = {
66 "11:1: " + getCheckMessage(MSG_KEY, "InputFinalClass"),
67 "19:4: " + getCheckMessage(MSG_KEY, "test4"),
68 };
69 verifyWithInlineConfigParser(
70 getPath("InputFinalClass.java"), expected);
71 }
72
73 @Test
74 public void testFinalClass2() throws Exception {
75 final String[] expected = {
76 "26:5: " + getCheckMessage(MSG_KEY, "InnerFinalClass"),
77 "33:5: " + getCheckMessage(MSG_KEY, "SomeClass"),
78 "39:5: " + getCheckMessage(MSG_KEY, "SomeClass"),
79 "60:1: " + getCheckMessage(MSG_KEY, "TestNewKeyword"),
80 "93:5: " + getCheckMessage(MSG_KEY, "NestedClass"),
81 };
82 verifyWithInlineConfigParser(
83 getPath("InputFinalClass2.java"), expected);
84 }
85
86 @Test
87 public void testClassWithPrivateCtorAndNestedExtendingSubclass() throws Exception {
88 final String[] expected = {
89 "13:9: " + getCheckMessage(MSG_KEY, "ExtendA"),
90 "18:9: " + getCheckMessage(MSG_KEY, "ExtendB"),
91 "22:5: " + getCheckMessage(MSG_KEY, "C"),
92 "24:9: " + getCheckMessage(MSG_KEY, "ExtendC"),
93 };
94 verifyWithInlineConfigParser(
95 getNonCompilablePath(
96 "InputFinalClassClassWithPrivateCtorWithNestedExtendingClass.java"),
97 expected);
98 }
99
100 @Test
101 public void testClassWithPrivateCtorAndNestedExtendingSubclassWithoutPackage()
102 throws Exception {
103 final String[] expected = {
104 "11:9: " + getCheckMessage(MSG_KEY, "ExtendA"),
105 "14:5: " + getCheckMessage(MSG_KEY, "C"),
106 "16:9: " + getCheckMessage(MSG_KEY, "ExtendC"),
107 };
108 verifyWithInlineConfigParser(
109 getNonCompilablePath(
110 "InputFinalClassClassWithPrivateCtorWithNestedExtendingClassWithoutPackage.java"),
111 expected);
112 }
113
114 @Test
115 public void testFinalClassConstructorInRecord() throws Exception {
116
117 final String[] expected = {
118 "27:9: " + getCheckMessage(MSG_KEY, "F"),
119 };
120
121 verifyWithInlineConfigParser(
122 getPath("InputFinalClassConstructorInRecord.java"),
123 expected);
124 }
125
126 @Test
127 public void testImproperToken() {
128 final FinalClassCheck finalClassCheck = new FinalClassCheck();
129 final DetailAstImpl badAst = new DetailAstImpl();
130 final int unsupportedTokenByCheck = TokenTypes.COMPILATION_UNIT;
131 badAst.setType(unsupportedTokenByCheck);
132 final IllegalStateException exc =
133 TestUtil.getExpectedThrowable(
134 IllegalStateException.class, () -> {
135 finalClassCheck.visitToken(badAst);
136 });
137 assertWithMessage("Invalid exception message")
138 .that(exc.getMessage())
139 .isEqualTo(badAst.toString());
140 }
141
142 @Test
143 public void testGetAcceptableTokens() {
144 final FinalClassCheck obj = new FinalClassCheck();
145 final int[] expected = {
146 TokenTypes.ANNOTATION_DEF,
147 TokenTypes.CLASS_DEF,
148 TokenTypes.ENUM_DEF,
149 TokenTypes.INTERFACE_DEF,
150 TokenTypes.RECORD_DEF,
151 TokenTypes.CTOR_DEF,
152 TokenTypes.PACKAGE_DEF,
153 TokenTypes.LITERAL_NEW,
154 };
155 assertWithMessage("Default acceptable tokens are invalid")
156 .that(obj.getAcceptableTokens())
157 .isEqualTo(expected);
158 }
159
160 @Test
161 public void testFinalClassInnerAndNestedClasses() throws Exception {
162 final String[] expected = {
163 "16:5: " + getCheckMessage(MSG_KEY, "SubClass"),
164 "19:5: " + getCheckMessage(MSG_KEY, "SameName"),
165 "45:9: " + getCheckMessage(MSG_KEY, "SameName"),
166 "69:13: " + getCheckMessage(MSG_KEY, "B"),
167 "84:9: " + getCheckMessage(MSG_KEY, "c"),
168 };
169 verifyWithInlineConfigParser(getPath("InputFinalClassInnerAndNestedClass.java"), expected);
170 }
171
172 @Test
173 public void testFinalClassStaticNestedClasses() throws Exception {
174
175 final String[] expected = {
176 "14:17: " + getCheckMessage(MSG_KEY, "C"),
177 "32:9: " + getCheckMessage(MSG_KEY, "B"),
178 "43:9: " + getCheckMessage(MSG_KEY, "C"),
179 "60:13: " + getCheckMessage(MSG_KEY, "Q"),
180 "76:9: " + getCheckMessage(MSG_KEY, "F"),
181 "83:9: " + getCheckMessage(MSG_KEY, "c"),
182 };
183
184 verifyWithInlineConfigParser(
185 getPath("InputFinalClassNestedStaticClassInsideInnerClass.java"),
186 expected);
187 }
188
189 @Test
190 public void testFinalClassEnum() throws Exception {
191 final String[] expected = {
192 "35:5: " + getCheckMessage(MSG_KEY, "DerivedClass"),
193 };
194 verifyWithInlineConfigParser(getPath("InputFinalClassEnum.java"), expected);
195 }
196
197 @Test
198 public void testFinalClassAnnotation() throws Exception {
199 final String[] expected = {
200 "15:5: " + getCheckMessage(MSG_KEY, "DerivedClass"),
201 };
202 verifyWithInlineConfigParser(getPath("InputFinalClassAnnotation.java"), expected);
203 }
204
205 @Test
206 public void testFinalClassInterface() throws Exception {
207 final String[] expected = {
208 "15:5: " + getCheckMessage(MSG_KEY, "DerivedClass"),
209 };
210 verifyWithInlineConfigParser(getPath("InputFinalClassInterface.java"), expected);
211 }
212
213 @Test
214 public void testFinalClassAnonymousInnerClass() throws Exception {
215 final String[] expected = {
216 "11:9: " + getCheckMessage(MSG_KEY, "b"),
217 "27:9: " + getCheckMessage(MSG_KEY, "m"),
218 "40:9: " + getCheckMessage(MSG_KEY, "q"),
219 "52:13: " + getCheckMessage(MSG_KEY, "b"),
220 "67:9: " + getCheckMessage(MSG_KEY, "g"),
221 "71:9: " + getCheckMessage(MSG_KEY, "y"),
222 "84:9: " + getCheckMessage(MSG_KEY, "n"),
223 "91:9: " + getCheckMessage(MSG_KEY, "n"),
224 };
225 verifyWithInlineConfigParser(getPath("InputFinalClassAnonymousInnerClass.java"), expected);
226 }
227
228 @Test
229 public void testFinalClassNestedInInterface() throws Exception {
230 final String[] expected = {
231 "24:5: " + getCheckMessage(MSG_KEY, "b"),
232 "28:13: " + getCheckMessage(MSG_KEY, "m"),
233 "50:5: " + getCheckMessage(MSG_KEY, "c"),
234 };
235 verifyWithInlineConfigParser(
236 getPath("InputFinalClassNestedInInterfaceWithAnonInnerClass.java"), expected);
237 }
238
239 @Test
240 public void testFinalClassNestedInEnum() throws Exception {
241 final String[] expected = {
242 "13:9: " + getCheckMessage(MSG_KEY, "j"),
243 "27:9: " + getCheckMessage(MSG_KEY, "n"),
244 };
245 verifyWithInlineConfigParser(getPath("InputFinalClassNestedInEnumWithAnonInnerClass.java"),
246 expected);
247 }
248
249 @Test
250 public void testFinalClassNestedInRecord() throws Exception {
251 final String[] expected = {
252 "13:9: " + getCheckMessage(MSG_KEY, "c"),
253 "31:13: " + getCheckMessage(MSG_KEY, "j"),
254 "49:5: " + getCheckMessage(MSG_KEY, "Nothing"),
255 };
256 verifyWithInlineConfigParser(getPath("InputFinalClassNestedInRecord.java"),
257 expected);
258 }
259
260
261
262
263
264
265
266
267 @Test
268 public void testClearState() throws Exception {
269 final FinalClassCheck check = new FinalClassCheck();
270 final DetailAST root = JavaParser.parseFile(new File(getPath("InputFinalClass.java")),
271 JavaParser.Options.WITHOUT_COMMENTS);
272 final Optional<DetailAST> packageDef = TestUtil.findTokenInAstByPredicate(root,
273 ast -> ast.getType() == TokenTypes.PACKAGE_DEF);
274
275 assertWithMessage("Ast should contain PACKAGE_DEF")
276 .that(packageDef.isPresent())
277 .isTrue();
278 assertWithMessage("State is not cleared on beginTree")
279 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
280 packageDef.orElseThrow(), "packageName",
281 packageName -> ((CharSequence) packageName).isEmpty()))
282 .isTrue();
283 }
284
285 @Test
286 public void testPrivateClassWithDefaultCtor() throws Exception {
287 final String[] expected = {
288 "14:5: " + getCheckMessage(MSG_KEY, "Some2"),
289 "19:1: " + getCheckMessage(MSG_KEY, "Some"),
290 "24:5: " + getCheckMessage(MSG_KEY, "Some3"),
291 "26:5: " + getCheckMessage(MSG_KEY, "Some4"),
292 "31:5: " + getCheckMessage(MSG_KEY, "PaperSetter"),
293 "36:5: " + getCheckMessage(MSG_KEY, "Paper"),
294 "44:5: " + getCheckMessage(MSG_KEY, "Node"),
295 "51:5: " + getCheckMessage(MSG_KEY, "Some1"),
296 "55:1: " + getCheckMessage(MSG_KEY, "Some2"),
297 "106:5: " + getCheckMessage(MSG_KEY, "NewCheck"),
298 "110:5: " + getCheckMessage(MSG_KEY, "NewCheck2"),
299 "115:5: " + getCheckMessage(MSG_KEY, "OldCheck"),
300 };
301 verifyWithInlineConfigParser(getPath("InputFinalClassPrivateCtor.java"),
302 expected);
303 }
304
305 @Test
306 public void testPrivateClassWithDefaultCtor2() throws Exception {
307 final String[] expected = {
308 "22:5: " + getCheckMessage(MSG_KEY, "PrivateClass"),
309 "34:5: " + getCheckMessage(MSG_KEY, "Check"),
310 "44:5: " + getCheckMessage(MSG_KEY, "K"),
311 "54:5: " + getCheckMessage(MSG_KEY, "Modifiers"),
312 };
313 verifyWithInlineConfigParser(getPath("InputFinalClassPrivateCtor2.java"),
314 expected);
315 }
316
317 @Test
318 public void testPrivateClassWithDefaultCtor3() throws Exception {
319 final String[] expected = {
320 "26:5: " + getCheckMessage(MSG_KEY, "MyClass"),
321 "30:5: " + getCheckMessage(MSG_KEY, "Check2"),
322 "31:9: " + getCheckMessage(MSG_KEY, "Check3"),
323 "35:5: " + getCheckMessage(MSG_KEY, "Check4"),
324 "40:5: " + getCheckMessage(MSG_KEY, "Check"),
325 };
326 verifyWithInlineConfigParser(getPath("InputFinalClassPrivateCtor3.java"),
327 expected);
328 }
329 }