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.metrics;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.metrics.ClassFanOutComplexityCheck.MSG_KEY;
24
25 import java.io.File;
26 import java.util.Collection;
27 import java.util.Map;
28 import java.util.Optional;
29
30 import org.junit.jupiter.api.Test;
31
32 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
33 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
34 import com.puppycrawl.tools.checkstyle.JavaParser;
35 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
36 import com.puppycrawl.tools.checkstyle.api.DetailAST;
37 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
38 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
39 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
40
41 public class ClassFanOutComplexityCheckTest extends AbstractModuleTestSupport {
42
43 @Override
44 protected String getPackageLocation() {
45 return "com/puppycrawl/tools/checkstyle/checks/metrics/classfanoutcomplexity";
46 }
47
48 @Test
49 public void test() throws Exception {
50
51 final String[] expected = {
52 "27:1: " + getCheckMessage(MSG_KEY, 3, 0),
53 "59:1: " + getCheckMessage(MSG_KEY, 1, 0),
54 };
55
56 verifyWithInlineConfigParser(
57 getPath("InputClassFanOutComplexity.java"), expected);
58 }
59
60 @Test
61 public void testExcludedPackagesDirectPackages() throws Exception {
62 final String[] expected = {
63 "29:1: " + getCheckMessage(MSG_KEY, 2, 0),
64 };
65
66 verifyWithInlineConfigParser(
67 getPath("InputClassFanOutComplexityExcludedPackagesDirectPackages.java"), expected);
68 }
69
70 @Test
71 public void testExcludedPackagesCommonPackages() throws Exception {
72 final String[] expected = {
73 "28:1: " + getCheckMessage(MSG_KEY, 2, 0),
74 "32:5: " + getCheckMessage(MSG_KEY, 2, 0),
75 "38:1: " + getCheckMessage(MSG_KEY, 1, 0),
76 };
77 verifyWithInlineConfigParser(
78 getPath("InputClassFanOutComplexityExcludedPackagesCommonPackage.java"), expected);
79 }
80
81 @Test
82 public void testExcludedPackagesCommonPackagesWithEndingDot() throws Exception {
83 final DefaultConfiguration checkConfig =
84 createModuleConfig(ClassFanOutComplexityCheck.class);
85
86 checkConfig.addProperty("max", "0");
87 checkConfig.addProperty("excludedPackages",
88 "com.puppycrawl.tools.checkstyle.checks.metrics.inputs.a.");
89
90 try {
91 createChecker(checkConfig);
92 assertWithMessage("exception expected").fail();
93 }
94 catch (CheckstyleException ex) {
95 assertWithMessage("Invalid exception message")
96 .that(ex.getMessage())
97 .isEqualTo("cannot initialize module com.puppycrawl.tools.checkstyle.TreeWalker - "
98 + "cannot initialize module com.puppycrawl.tools.checkstyle.checks."
99 + "metrics.ClassFanOutComplexityCheck - "
100 + "Cannot set property 'excludedPackages' to "
101 + "'com.puppycrawl.tools.checkstyle.checks.metrics.inputs.a.'");
102 assertWithMessage("Invalid exception message,")
103 .that(ex.getCause().getCause().getCause().getCause().getMessage())
104 .isEqualTo("the following values are not valid identifiers: ["
105 + "com.puppycrawl.tools.checkstyle.checks.metrics.inputs.a.]");
106 }
107 }
108
109 @Test
110 public void testExcludedPackagesAllIgnored() throws Exception {
111 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
112 verifyWithInlineConfigParser(
113 getPath("InputClassFanOutComplexityExcludedPackagesAllIgnored.java"), expected);
114 }
115
116 @Test
117 public void test15() throws Exception {
118
119 final String[] expected = {
120 "29:1: " + getCheckMessage(MSG_KEY, 1, 0),
121 };
122
123 verifyWithInlineConfigParser(
124 getPath("InputClassFanOutComplexity15Extensions.java"), expected);
125 }
126
127 @Test
128 public void testDefaultConfiguration() throws Exception {
129 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
130 verifyWithInlineConfigParser(
131 getPath("InputClassFanOutComplexity2.java"), expected);
132 }
133
134 @Test
135 public void testGetAcceptableTokens() {
136 final ClassFanOutComplexityCheck classFanOutComplexityCheckObj =
137 new ClassFanOutComplexityCheck();
138 final int[] actual = classFanOutComplexityCheckObj.getAcceptableTokens();
139 final int[] expected = {
140 TokenTypes.PACKAGE_DEF,
141 TokenTypes.IMPORT,
142 TokenTypes.CLASS_DEF,
143 TokenTypes.EXTENDS_CLAUSE,
144 TokenTypes.IMPLEMENTS_CLAUSE,
145 TokenTypes.ANNOTATION,
146 TokenTypes.INTERFACE_DEF,
147 TokenTypes.ENUM_DEF,
148 TokenTypes.TYPE,
149 TokenTypes.LITERAL_NEW,
150 TokenTypes.LITERAL_THROWS,
151 TokenTypes.ANNOTATION_DEF,
152 TokenTypes.RECORD_DEF,
153 };
154 assertWithMessage("Acceptable tokens should not be null")
155 .that(actual)
156 .isNotNull();
157 assertWithMessage("Invalid acceptable tokens")
158 .that(actual)
159 .isEqualTo(expected);
160 }
161
162 @Test
163 public void testRegularExpression() throws Exception {
164
165 final String[] expected = {
166 "44:1: " + getCheckMessage(MSG_KEY, 2, 0),
167 "76:1: " + getCheckMessage(MSG_KEY, 1, 0),
168 };
169
170 verifyWithInlineConfigParser(
171 getPath("InputClassFanOutComplexity3.java"), expected);
172 }
173
174 @Test
175 public void testEmptyRegularExpression() throws Exception {
176
177 final String[] expected = {
178 "44:1: " + getCheckMessage(MSG_KEY, 3, 0),
179 "76:1: " + getCheckMessage(MSG_KEY, 1, 0),
180 };
181
182 verifyWithInlineConfigParser(
183 getPath("InputClassFanOutComplexity4.java"), expected);
184 }
185
186 @Test
187 public void testWithMultiDimensionalArray() throws Exception {
188
189 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
190 verifyWithInlineConfigParser(
191 getPath("InputClassFanOutComplexityMultiDimensionalArray.java"), expected);
192 }
193
194 @Test
195 public void testPackageName() throws Exception {
196
197 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
198 verifyWithInlineConfigParser(
199 getPath("InputClassFanOutComplexityPackageName.java"), expected);
200 }
201
202 @Test
203 public void testExtends() throws Exception {
204 final String[] expected = {
205 "23:1: " + getCheckMessage(MSG_KEY, 1, 0),
206 };
207 verifyWithInlineConfigParser(
208 getPath("InputClassFanOutComplexityExtends.java"), expected);
209 }
210
211 @Test
212 public void testImplements() throws Exception {
213 final String[] expected = {
214 "23:1: " + getCheckMessage(MSG_KEY, 1, 0),
215 };
216 verifyWithInlineConfigParser(
217 getPath("InputClassFanOutComplexityImplements.java"), expected);
218 }
219
220 @Test
221 public void testAnnotation() throws Exception {
222 final String[] expected = {
223 "29:1: " + getCheckMessage(MSG_KEY, 2, 0),
224 "45:5: " + getCheckMessage(MSG_KEY, 2, 0),
225 "54:5: " + getCheckMessage(MSG_KEY, 3, 0),
226 "64:5: " + getCheckMessage(MSG_KEY, 2, 0),
227 "79:1: " + getCheckMessage(MSG_KEY, 1, 0),
228 "99:1: " + getCheckMessage(MSG_KEY, 1, 0),
229 "102:1: " + getCheckMessage(MSG_KEY, 1, 0),
230 };
231 verifyWithInlineConfigParser(
232 getPath("InputClassFanOutComplexityAnnotations.java"), expected);
233 }
234
235 @Test
236 public void testImplementsAndNestedCount() throws Exception {
237 final String[] expected = {
238 "26:1: " + getCheckMessage(MSG_KEY, 3, 0),
239 };
240 verifyWithInlineConfigParser(
241 getPath("InputClassFanOutComplexityImplementsAndNestedCount.java"), expected);
242 }
243
244 @Test
245 public void testClassFanOutComplexityRecords() throws Exception {
246 final String[] expected = {
247 "32:1: " + getCheckMessage(MSG_KEY, 4, 2),
248 "53:1: " + getCheckMessage(MSG_KEY, 4, 2),
249 };
250 verifyWithInlineConfigParser(
251 getNonCompilablePath("InputClassFanOutComplexityRecords.java"), expected);
252 }
253
254 @Test
255 public void testClassFanOutComplexityIgnoreVar() throws Exception {
256 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
257 verifyWithInlineConfigParser(
258 getPath("InputClassFanOutComplexityVar.java"), expected);
259 }
260
261 @Test
262 public void testClassFanOutComplexityRemoveIncorrectAnnotationToken() throws Exception {
263 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
264 verifyWithInlineConfigParser(
265 getPath("InputClassFanOutComplexityRemoveIncorrectAnnotationToken.java"), expected);
266 }
267
268 @Test
269 public void testClassFanOutComplexityRemoveIncorrectTypeParameter() throws Exception {
270 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
271 verifyWithInlineConfigParser(
272 getPath("InputClassFanOutComplexityRemoveIncorrectTypeParameter.java"), expected);
273 }
274
275 @Test
276 public void testClassFanOutComplexityMultiCatchBitwiseOr() throws Exception {
277 final String[] expected = {
278 "27:1: " + getCheckMessage(MSG_KEY, 5, 4),
279 };
280
281 verifyWithInlineConfigParser(
282 getPath("InputClassFanOutComplexityMultiCatchBitwiseOr.java"), expected);
283 }
284
285 @Test
286 public void testThrows() throws Exception {
287 final String[] expected = {
288 "25:1: " + getCheckMessage(MSG_KEY, 2, 0),
289 };
290
291 verifyWithInlineConfigParser(
292 getPath("InputClassFanOutComplexityThrows.java"), expected);
293 }
294
295 @Test
296 public void testSealedClasses() throws Exception {
297 final String[] expected = {
298 "25:1: " + getCheckMessage(MSG_KEY, 2, 0),
299 "32:1: " + getCheckMessage(MSG_KEY, 1, 0),
300 };
301
302 verifyWithInlineConfigParser(
303 getNonCompilablePath("InputClassFanOutComplexitySealedClasses.java"),
304 expected);
305 }
306
307
308
309
310
311
312
313
314 @Test
315 @SuppressWarnings("unchecked")
316 public void testClearStateImportedClassPackages() throws Exception {
317 final ClassFanOutComplexityCheck check = new ClassFanOutComplexityCheck();
318 final DetailAST root = JavaParser.parseFile(
319 new File(getPath("InputClassFanOutComplexity.java")),
320 JavaParser.Options.WITHOUT_COMMENTS);
321 final Optional<DetailAST> importAst = TestUtil.findTokenInAstByPredicate(root,
322 ast -> ast.getType() == TokenTypes.IMPORT);
323
324 assertWithMessage("Ast should contain IMPORT")
325 .that(importAst.isPresent())
326 .isTrue();
327 assertWithMessage("State is not cleared on beginTree")
328 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
329 importAst.orElseThrow(), "importedClassPackages",
330 importedClssPackage -> ((Map<String, String>) importedClssPackage).isEmpty()))
331 .isTrue();
332 }
333
334
335
336
337
338
339
340
341 @Test
342 public void testClearStateClassContexts() throws Exception {
343 final ClassFanOutComplexityCheck check = new ClassFanOutComplexityCheck();
344 final DetailAST root = JavaParser.parseFile(
345 new File(getPath("InputClassFanOutComplexity.java")),
346 JavaParser.Options.WITHOUT_COMMENTS);
347 final Optional<DetailAST> classDef = TestUtil.findTokenInAstByPredicate(root,
348 ast -> ast.getType() == TokenTypes.CLASS_DEF);
349
350 assertWithMessage("Ast should contain CLASS_DEF")
351 .that(classDef.isPresent())
352 .isTrue();
353 assertWithMessage("State is not cleared on beginTree")
354 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check, classDef.orElseThrow(),
355 "classesContexts",
356 classContexts -> ((Collection<?>) classContexts).size() == 1))
357 .isTrue();
358 }
359
360
361
362
363
364
365
366
367 @Test
368 public void testClearStatePackageName() throws Exception {
369 final ClassFanOutComplexityCheck check = new ClassFanOutComplexityCheck();
370 final DetailAST root = JavaParser.parseFile(
371 new File(getPath("InputClassFanOutComplexity.java")),
372 JavaParser.Options.WITHOUT_COMMENTS);
373 final Optional<DetailAST> packageDef = TestUtil.findTokenInAstByPredicate(root,
374 ast -> ast.getType() == TokenTypes.PACKAGE_DEF);
375
376 assertWithMessage("Ast should contain PACKAGE_DEF")
377 .that(packageDef.isPresent())
378 .isTrue();
379 assertWithMessage("State is not cleared on beginTree")
380 .that(TestUtil.isStatefulFieldClearedDuringBeginTree(check,
381 packageDef.orElseThrow(), "packageName",
382 packageName -> ((String) packageName).isEmpty()))
383 .isTrue();
384 }
385
386
387
388
389
390
391
392 @Test
393 public void testLambdaNew() throws Exception {
394 final String[] expected = {
395 "28:1: " + getCheckMessage(MSG_KEY, 2, 0),
396 };
397 verifyWithInlineConfigParser(
398 getPath("InputClassFanOutComplexityLambdaNew.java"), expected);
399 }
400
401 }