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