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