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.AbstractFileSetCheck.setFileExtensions"
72 + "([Ljava.lang.String;)> calls method <com.puppycrawl.tools.checkstyle.utils"
73 + ".CommonUtil.startsWithChar(java.lang.String, char)>",
74 "Method <com.puppycrawl.tools.checkstyle.AbstractAutomaticBean$PatternConverter"
75 + ".convert(java.lang.Class, java.lang.Object)> calls method <com.puppycrawl.tools"
76 + ".checkstyle.utils.CommonUtil.createPattern(java.lang.String)>",
77 "Method <com.puppycrawl.tools.checkstyle.AbstractAutomaticBean$RelaxedStringArray"
78 + "Converter.convert(java.lang.Class, java.lang.Object)> gets field <com.puppycrawl"
79 + ".tools.checkstyle.utils.CommonUtil.EMPTY_STRING_ARRAY>",
80 "Method <com.puppycrawl.tools.checkstyle.AbstractAutomaticBean$UriConverter.convert("
81 + "java.lang.Class, java.lang.Object)> calls method <com.puppycrawl.tools.checkstyle"
82 + ".utils.CommonUtil.getUriByFilename(java.lang.String)>",
83 "Method <com.puppycrawl.tools.checkstyle.AbstractAutomaticBean$UriConverter.convert("
84 + "java.lang.Class, java.lang.Object)> calls method <com.puppycrawl.tools.checkstyle"
85 + ".utils.CommonUtil.isBlank(java.lang.String)>",
86 "Method <com.puppycrawl.tools.checkstyle.api.FileContents.lineIsBlank(int)> calls method "
87 + "<com.puppycrawl.tools.checkstyle.utils.CommonUtil.isBlank(java.lang.String)>"
88 );
89
90
91
92
93
94
95
96 @Test
97 public void nonProtectedCheckMethodsTest() {
98
99 final String[] methodsWithOverrideAnnotation = {
100 "processFiltered",
101 "getMethodName",
102 "mustCheckName",
103 "postProcessHeaderLines",
104 "getLogMessageId",
105 };
106 final String ignoreMethodList = String.join("|", methodsWithOverrideAnnotation);
107 final JavaClasses importedClasses = new ClassFileImporter()
108 .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
109 .importPackages("com.puppycrawl.tools.checkstyle.checks");
110
111 final ArchRule checkMethodsShouldNotBeProtectedRule =
112 methods().that()
113 .haveNameNotMatching(".*(" + ignoreMethodList + ")").and()
114 .areDeclaredInClassesThat()
115 .haveSimpleNameEndingWith("Check").and()
116 .areDeclaredInClassesThat()
117 .doNotHaveModifier(JavaModifier.ABSTRACT)
118 .should().notBeProtected();
119
120 checkMethodsShouldNotBeProtectedRule.check(importedClasses);
121 }
122
123
124
125
126
127
128 @Test
129 public void testClassesInApiDoNotDependOnClassesInUtil() {
130 final JavaClasses apiPackage = new ClassFileImporter()
131 .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
132 .importPackages("com.puppycrawl.tools.checkstyle.api");
133
134 final String[] utilPackages = {
135 "com.puppycrawl.tools.checkstyle.utils",
136 "com.puppycrawl.tools.checkstyle.checks.javadoc.utils",
137 };
138
139 final ArchRule classShouldNotDependOnUtilPackages = noClasses()
140 .should()
141 .dependOnClassesThat()
142 .resideInAnyPackage(utilPackages);
143
144 final EvaluationResult result = classShouldNotDependOnUtilPackages.evaluate(apiPackage);
145 final EvaluationResult filtered = result.filterDescriptionsMatching(description -> {
146 return API_PACKAGE_SUPPRESSION_DETAILS.stream()
147 .noneMatch(description::startsWith);
148 });
149
150 assertWithMessage("api package: " + classShouldNotDependOnUtilPackages.getDescription())
151 .that(filtered.getFailureReport().getDetails())
152 .isEmpty();
153 }
154
155 }