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.internal;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods;
24 import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
25
26 import java.util.List;
27
28 import org.junit.jupiter.api.Test;
29
30 import com.tngtech.archunit.core.domain.JavaClasses;
31 import com.tngtech.archunit.core.domain.JavaModifier;
32 import com.tngtech.archunit.core.importer.ClassFileImporter;
33 import com.tngtech.archunit.core.importer.ImportOption;
34 import com.tngtech.archunit.lang.ArchRule;
35 import com.tngtech.archunit.lang.EvaluationResult;
36
37 public class ArchUnitTest {
38
39
40
41
42
43
44 private static final List<String> API_PACKAGE_SUPPRESSION_DETAILS = List.of(
45 "Constructor <com.puppycrawl.tools.checkstyle.api.FileText.<init>(java.io.File, java.lang"
46 + ".String)> gets field <com.puppycrawl.tools.checkstyle.utils.CommonUtil"
47 + ".EMPTY_STRING_ARRAY>",
48 "Constructor <com.puppycrawl.tools.checkstyle.api.Violation.<init>(int, int, int, int,"
49 + " java.lang.String, java.lang.String, [Ljava.lang.Object;,"
50 + " com.puppycrawl.tools.checkstyle.api.SeverityLevel, java.lang.String,"
51 + " java.lang.Class, java.lang.String)> calls method"
52 + " <com.puppycrawl.tools.checkstyle.utils.UnmodifiableCollectionUtil.copyOfArray"
53 + "([Ljava.lang.Object;, int)>",
54 "Constructor <com.puppycrawl.tools.checkstyle.api.FileText.<init>(java.io.File, java.util"
55 + ".List)> gets field <com.puppycrawl.tools.checkstyle.utils.CommonUtil"
56 + ".EMPTY_STRING_ARRAY>",
57 "Method <com.puppycrawl.tools.checkstyle.api.AbstractCheck.log(com.puppycrawl.tools"
58 + ".checkstyle.api.DetailAST, java.lang.String, [Ljava.lang.Object;)> calls method "
59 + "<com.puppycrawl.tools.checkstyle.utils.CommonUtil.lengthExpandedTabs(java.lang"
60 + ".String, int, int)>",
61 "Method <com.puppycrawl.tools.checkstyle.api.AbstractCheck.log(int, int, java.lang"
62 + ".String, [Ljava.lang.Object;)> calls method <com.puppycrawl.tools.checkstyle.utils"
63 + ".CommonUtil.lengthExpandedTabs(java.lang.String, int, int)>",
64 "Method <com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck.log(int, int, java.lang"
65 + ".String, [Ljava.lang.Object;)> calls method <com.puppycrawl.tools.checkstyle.utils"
66 + ".CommonUtil.lengthExpandedTabs(java.lang.String, int, int)>",
67 "Method <com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck.process(java.io.File, "
68 + "com.puppycrawl.tools.checkstyle.api.FileText)> calls method <com.puppycrawl.tools"
69 + ".checkstyle.utils.CommonUtil.matchesFileExtension(java.io.File, [Ljava.lang"
70 + ".String;)>",
71 "Method <com.puppycrawl.tools.checkstyle.api.FileContents.lineIsBlank(int)> calls method "
72 + "<com.puppycrawl.tools.checkstyle.utils.CommonUtil.isBlank(java.lang.String)>"
73 );
74
75
76
77
78
79
80
81 @Test
82 public void nonProtectedCheckMethodsTest() {
83
84 final String[] methodsWithOverrideAnnotation = {
85 "processFiltered",
86 "getMethodName",
87 "mustCheckName",
88 "postProcessHeaderLines",
89 "getLogMessageId",
90 };
91 final String ignoreMethodList = String.join("|", methodsWithOverrideAnnotation);
92 final JavaClasses importedClasses = new ClassFileImporter()
93 .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
94 .importPackages("com.puppycrawl.tools.checkstyle.checks");
95
96 final ArchRule checkMethodsShouldNotBeProtectedRule =
97 methods().that()
98 .haveNameNotMatching(".*(" + ignoreMethodList + ")").and()
99 .areDeclaredInClassesThat()
100 .haveSimpleNameEndingWith("Check").and()
101 .areDeclaredInClassesThat()
102 .doNotHaveModifier(JavaModifier.ABSTRACT)
103 .should().notBeProtected();
104
105 checkMethodsShouldNotBeProtectedRule.check(importedClasses);
106 }
107
108
109
110
111
112
113 @Test
114 public void testClassesInApiDoNotDependOnClassesInUtil() {
115 final JavaClasses apiPackage = new ClassFileImporter()
116 .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
117 .importPackages("com.puppycrawl.tools.checkstyle.api");
118
119 final String[] utilPackages = {
120 "com.puppycrawl.tools.checkstyle.utils",
121 "com.puppycrawl.tools.checkstyle.checks.javadoc.utils",
122 };
123
124 final ArchRule classShouldNotDependOnUtilPackages = noClasses()
125 .should()
126 .dependOnClassesThat()
127 .resideInAnyPackage(utilPackages);
128
129 final EvaluationResult result = classShouldNotDependOnUtilPackages.evaluate(apiPackage);
130
131 final List<String> allDescriptions = result.getFailureReport().getDetails();
132 final List<String> outdatedSuppressions = API_PACKAGE_SUPPRESSION_DETAILS.stream()
133 .filter(suppression -> {
134 return allDescriptions.stream()
135 .noneMatch(description -> description.startsWith(suppression));
136 })
137 .toList();
138
139 assertWithMessage("Outdated suppressions (can be removed)")
140 .that(outdatedSuppressions)
141 .isEmpty();
142
143 final EvaluationResult filtered = result.filterDescriptionsMatching(description -> {
144 return API_PACKAGE_SUPPRESSION_DETAILS.stream()
145 .noneMatch(description::startsWith);
146 });
147
148 assertWithMessage("api package: %s", classShouldNotDependOnUtilPackages.getDescription())
149 .that(filtered.getFailureReport().getDetails())
150 .isEmpty();
151 }
152
153 }