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