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 testCompactSourceFile() throws Exception {
116 final String[] expected = {
117 "19:1: " + getCheckMessage(MSG_KEY, "Bar"),
118 };
119 verifyWithInlineConfigParser(
120 getNonCompilablePath("InputFinalClassCompactSourceFile.java"),
121 expected);
122 }
123
124 @Test
125 public void testCompactSourceFileAnonymousNestedResolution() throws Exception {
126 final String[] expected = {
127 "12:5: " + getCheckMessage(MSG_KEY, "Inner"),
128 };
129 verifyWithInlineConfigParser(
130 getNonCompilablePath(
131 "InputFinalClassCompactSourceFileAnonymousNestedResolution.java"),
132 expected);
133 }
134
135 @Test
136 public void testFinalClassConstructorInRecord() throws Exception {
137
138 final String[] expected = {
139 "27:9: " + getCheckMessage(MSG_KEY, "F"),
140 };
141
142 verifyWithInlineConfigParser(
143 getPath("InputFinalClassConstructorInRecord.java"),
144 expected);
145 }
146
147 @Test
148 public void testImproperToken() {
149 final FinalClassCheck finalClassCheck = new FinalClassCheck();
150 final DetailAstImpl badAst = new DetailAstImpl();
151 final int unsupportedTokenByCheck = TokenTypes.COMPILATION_UNIT;
152 badAst.setType(unsupportedTokenByCheck);
153 final IllegalStateException exc =
154 TestUtil.getExpectedThrowable(
155 IllegalStateException.class, () -> {
156 finalClassCheck.visitToken(badAst);
157 });
158 assertWithMessage("Invalid exception message")
159 .that(exc.getMessage())
160 .isEqualTo(badAst.toString());
161 }
162
163 @Test
164 public void testGetAcceptableTokens() {
165 final FinalClassCheck obj = new FinalClassCheck();
166 final int[] expected = {
167 TokenTypes.ANNOTATION_DEF,
168 TokenTypes.CLASS_DEF,
169 TokenTypes.ENUM_DEF,
170 TokenTypes.INTERFACE_DEF,
171 TokenTypes.RECORD_DEF,
172 TokenTypes.CTOR_DEF,
173 TokenTypes.PACKAGE_DEF,
174 TokenTypes.LITERAL_NEW,
175 };
176 assertWithMessage("Default acceptable tokens are invalid")
177 .that(obj.getAcceptableTokens())
178 .isEqualTo(expected);
179 }
180
181 @Test
182 public void testFinalClassInnerAndNestedClasses() throws Exception {
183 final String[] expected = {
184 "16:5: " + getCheckMessage(MSG_KEY, "SubClass"),
185 "19:5: " + getCheckMessage(MSG_KEY, "SameName"),
186 "45:9: " + getCheckMessage(MSG_KEY, "SameName"),
187 "69:13: " + getCheckMessage(MSG_KEY, "B"),
188 "84:9: " + getCheckMessage(MSG_KEY, "c"),
189 };
190 verifyWithInlineConfigParser(getPath("InputFinalClassInnerAndNestedClass.java"), expected);
191 }
192
193 @Test
194 public void testFinalClassStaticNestedClasses() throws Exception {
195
196 final String[] expected = {
197 "14:17: " + getCheckMessage(MSG_KEY, "C"),
198 "32:9: " + getCheckMessage(MSG_KEY, "B"),
199 "43:9: " + getCheckMessage(MSG_KEY, "C"),
200 "60:13: " + getCheckMessage(MSG_KEY, "Q"),
201 "76:9: " + getCheckMessage(MSG_KEY, "F"),
202 "83:9: " + getCheckMessage(MSG_KEY, "c"),
203 };
204
205 verifyWithInlineConfigParser(
206 getPath("InputFinalClassNestedStaticClassInsideInnerClass.java"),
207 expected);
208 }
209
210 @Test
211 public void testFinalClassEnum() throws Exception {
212 final String[] expected = {
213 "35:5: " + getCheckMessage(MSG_KEY, "DerivedClass"),
214 };
215 verifyWithInlineConfigParser(getPath("InputFinalClassEnum.java"), expected);
216 }
217
218 @Test
219 public void testFinalClassAnnotation() throws Exception {
220 final String[] expected = {
221 "15:5: " + getCheckMessage(MSG_KEY, "DerivedClass"),
222 };
223 verifyWithInlineConfigParser(getPath("InputFinalClassAnnotation.java"), expected);
224 }
225
226 @Test
227 public void testFinalClassInterface() throws Exception {
228 final String[] expected = {
229 "15:5: " + getCheckMessage(MSG_KEY, "DerivedClass"),
230 };
231 verifyWithInlineConfigParser(getPath("InputFinalClassInterface.java"), expected);
232 }
233
234 @Test
235 public void testFinalClassAnonymousInnerClass() throws Exception {
236 final String[] expected = {
237 "11:9: " + getCheckMessage(MSG_KEY, "b"),
238 "27:9: " + getCheckMessage(MSG_KEY, "m"),
239 "40:9: " + getCheckMessage(MSG_KEY, "q"),
240 "52:13: " + getCheckMessage(MSG_KEY, "b"),
241 "67:9: " + getCheckMessage(MSG_KEY, "g"),
242 "71:9: " + getCheckMessage(MSG_KEY, "y"),
243 "84:9: " + getCheckMessage(MSG_KEY, "n"),
244 "91:9: " + getCheckMessage(MSG_KEY, "n"),
245 };
246 verifyWithInlineConfigParser(getPath("InputFinalClassAnonymousInnerClass.java"), expected);
247 }
248
249 @Test
250 public void testFinalClassNestedInInterface() throws Exception {
251 final String[] expected = {
252 "24:5: " + getCheckMessage(MSG_KEY, "b"),
253 "28:13: " + getCheckMessage(MSG_KEY, "m"),
254 "50:5: " + getCheckMessage(MSG_KEY, "c"),
255 };
256 verifyWithInlineConfigParser(
257 getPath("InputFinalClassNestedInInterfaceWithAnonInnerClass.java"), expected);
258 }
259
260 @Test
261 public void testFinalClassNestedInEnum() throws Exception {
262 final String[] expected = {
263 "13:9: " + getCheckMessage(MSG_KEY, "j"),
264 "27:9: " + getCheckMessage(MSG_KEY, "n"),
265 };
266 verifyWithInlineConfigParser(getPath("InputFinalClassNestedInEnumWithAnonInnerClass.java"),
267 expected);
268 }
269
270 @Test
271 public void testFinalClassNestedInRecord() throws Exception {
272 final String[] expected = {
273 "13:9: " + getCheckMessage(MSG_KEY, "c"),
274 "31:13: " + getCheckMessage(MSG_KEY, "j"),
275 "49:5: " + getCheckMessage(MSG_KEY, "Nothing"),
276 };
277 verifyWithInlineConfigParser(getPath("InputFinalClassNestedInRecord.java"),
278 expected);
279 }
280
281
282
283
284
285
286
287
288 @Test
289 public void testClearState() throws Exception {
290 final FinalClassCheck check = new FinalClassCheck();
291 final DetailAST root = JavaParser.parseFile(new File(getPath("InputFinalClass.java")),
292 JavaParser.Options.WITHOUT_COMMENTS);
293 final Optional<DetailAST> packageDef = TestUtil.findTokenInAstByPredicate(root,
294 ast -> ast.getType() == TokenTypes.PACKAGE_DEF);
295
296 assertWithMessage("Ast should contain PACKAGE_DEF")
297 .that(packageDef.isPresent())
298 .isTrue();
299 assertWithMessage("State is not cleared on beginTree")
300 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
301 packageDef.orElseThrow(), "packageName",
302 packageName -> ((CharSequence) packageName).isEmpty()))
303 .isTrue();
304 }
305
306 @Test
307 public void testPrivateClassWithDefaultCtor() throws Exception {
308 final String[] expected = {
309 "14:5: " + getCheckMessage(MSG_KEY, "Some2"),
310 "19:1: " + getCheckMessage(MSG_KEY, "Some"),
311 "24:5: " + getCheckMessage(MSG_KEY, "Some3"),
312 "26:5: " + getCheckMessage(MSG_KEY, "Some4"),
313 "31:5: " + getCheckMessage(MSG_KEY, "PaperSetter"),
314 "36:5: " + getCheckMessage(MSG_KEY, "Paper"),
315 "44:5: " + getCheckMessage(MSG_KEY, "Node"),
316 "51:5: " + getCheckMessage(MSG_KEY, "Some1"),
317 "55:1: " + getCheckMessage(MSG_KEY, "Some2"),
318 "106:5: " + getCheckMessage(MSG_KEY, "NewCheck"),
319 "110:5: " + getCheckMessage(MSG_KEY, "NewCheck2"),
320 "115:5: " + getCheckMessage(MSG_KEY, "OldCheck"),
321 };
322 verifyWithInlineConfigParser(getPath("InputFinalClassPrivateCtor.java"),
323 expected);
324 }
325
326 @Test
327 public void testPrivateClassWithDefaultCtor2() throws Exception {
328 final String[] expected = {
329 "22:5: " + getCheckMessage(MSG_KEY, "PrivateClass"),
330 "34:5: " + getCheckMessage(MSG_KEY, "Check"),
331 "44:5: " + getCheckMessage(MSG_KEY, "K"),
332 "54:5: " + getCheckMessage(MSG_KEY, "Modifiers"),
333 };
334 verifyWithInlineConfigParser(getPath("InputFinalClassPrivateCtor2.java"),
335 expected);
336 }
337
338 @Test
339 public void testPrivateClassWithDefaultCtor3() throws Exception {
340 final String[] expected = {
341 "26:5: " + getCheckMessage(MSG_KEY, "MyClass"),
342 "30:5: " + getCheckMessage(MSG_KEY, "Check2"),
343 "31:9: " + getCheckMessage(MSG_KEY, "Check3"),
344 "35:5: " + getCheckMessage(MSG_KEY, "Check4"),
345 "40:5: " + getCheckMessage(MSG_KEY, "Check"),
346 };
347 verifyWithInlineConfigParser(getPath("InputFinalClassPrivateCtor3.java"),
348 expected);
349 }
350
351 }