Skip to content

Commit e6bb105

Browse files
committed
Add architecture tests for test classes and methods
1 parent 5141248 commit e6bb105

24 files changed

+243
-59
lines changed

delphi-checks/src/test/java/au/com/integradev/delphi/checks/BeginEndRequiredCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ void testExceptElseWithBeginEndShouldNotAddIssue() {
139139
}
140140

141141
@Test
142-
void testShouldSkipAsmProcedure() {
142+
void testAsmProcedureShouldNotAddIssue() {
143143
CheckVerifier.newVerifier()
144144
.withCheck(new BeginEndRequiredCheck())
145145
.onFile(
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Sonar Delphi Plugin
3+
* Copyright (C) 2024 Integrated Application Development
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
* Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public
16+
* License along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
18+
*/
19+
package au.com.integradev.delphi.checks;
20+
21+
import static com.tngtech.archunit.base.DescribedPredicate.not;
22+
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
23+
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods;
24+
25+
import com.tngtech.archunit.base.DescribedPredicate;
26+
import com.tngtech.archunit.core.domain.JavaClass;
27+
import com.tngtech.archunit.core.domain.JavaClasses;
28+
import com.tngtech.archunit.core.domain.JavaMember;
29+
import com.tngtech.archunit.core.domain.JavaMethod;
30+
import com.tngtech.archunit.core.domain.JavaModifier;
31+
import com.tngtech.archunit.core.domain.properties.HasName;
32+
import com.tngtech.archunit.core.importer.ClassFileImporter;
33+
import com.tngtech.archunit.lang.ArchCondition;
34+
import com.tngtech.archunit.lang.ConditionEvents;
35+
import com.tngtech.archunit.lang.SimpleConditionEvent;
36+
import java.util.List;
37+
import org.junit.jupiter.api.Test;
38+
import org.sonar.plugins.communitydelphi.api.check.DelphiCheck;
39+
40+
class CheckTestNameTest {
41+
42+
private static final JavaClasses CHECKS_PACKAGE =
43+
new ClassFileImporter().importPackages("au.com.integradev.delphi.checks");
44+
45+
private static final DescribedPredicate<JavaMethod> VERIFY_ISSUES =
46+
callCheckVerifierMethod("verifyIssues")
47+
.or(callCheckVerifierMethod("verifyIssueOnFile"))
48+
.or(callCheckVerifierMethod("verifyIssueOnProject"));
49+
private static final DescribedPredicate<JavaMethod> VERIFY_NO_ISSUES =
50+
callMethod("au.com.integradev.delphi.checks.verifier.CheckVerifier.verifyNoIssues");
51+
private static final DescribedPredicate<JavaMethod> CALL_ASSERT_THROW_BY =
52+
callMethod("org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy");
53+
private static final DescribedPredicate<JavaMethod> CALL_ASSERT_NO_EXCEPTION =
54+
callMethod("org.assertj.core.api.AssertionsForClassTypes.assertThatNoException");
55+
private static final String IMPLEMENTATION_DETAIL_PREFIX = "testImplementationDetail";
56+
private static final DescribedPredicate<HasName> TESTING_IMPLEMENTATION_DETAILS =
57+
HasName.Predicates.nameStartingWith(IMPLEMENTATION_DETAIL_PREFIX);
58+
59+
private static final List<Class<?>> METATEST_CLASSES =
60+
List.of(CheckListTest.class, CheckMetadataTest.class, CheckTestNameTest.class);
61+
private static final DescribedPredicate<JavaMember> DECLARED_IN_METATESTS =
62+
new DescribedPredicate<>("declared in meta test classes") {
63+
@Override
64+
public boolean test(JavaMember member) {
65+
return METATEST_CLASSES.contains(member.getOwner().reflect());
66+
}
67+
};
68+
69+
private static final ArchCondition<JavaClass> HAVE_ASSOCIATED_CHECK =
70+
new ArchCondition<>("have an associated check") {
71+
@Override
72+
public void check(JavaClass item, ConditionEvents events) {
73+
String subjectName = item.getName().replaceAll("Test$", "");
74+
boolean hasSubject =
75+
CheckList.getChecks().stream().map(Class::getName).anyMatch(subjectName::equals);
76+
77+
if (!hasSubject) {
78+
String message =
79+
String.format(
80+
"%s does not have an associated subject %s", item.getFullName(), subjectName);
81+
events.add(SimpleConditionEvent.violated(item, message));
82+
}
83+
}
84+
};
85+
private static final ArchCondition<JavaClass> HAVE_ASSOCIATED_TEST =
86+
new ArchCondition<>("have an associated test") {
87+
@Override
88+
public void check(JavaClass item, ConditionEvents events) {
89+
String testName = item.getName() + "Test";
90+
boolean hasTest =
91+
item.getConstructorCallsToSelf().stream()
92+
.anyMatch(
93+
constructorCall ->
94+
constructorCall.getOriginOwner().getName().equals(testName));
95+
96+
if (!hasTest) {
97+
String message =
98+
String.format(
99+
"%s does not have an associated test %s", item.getFullName(), testName);
100+
events.add(SimpleConditionEvent.violated(item, message));
101+
}
102+
}
103+
};
104+
105+
static DescribedPredicate<JavaMethod> callMethod(String methodName) {
106+
return new DescribedPredicate<>("call " + methodName) {
107+
@Override
108+
public boolean test(JavaMethod method) {
109+
String methodPrefix = String.format("%s(", methodName);
110+
return method.getCallsFromSelf().stream()
111+
.anyMatch(call -> call.getTarget().getFullName().startsWith(methodPrefix));
112+
}
113+
};
114+
}
115+
116+
static DescribedPredicate<JavaMethod> callCheckVerifierMethod(String methodName) {
117+
return callMethod(
118+
String.format("au.com.integradev.delphi.checks.verifier.CheckVerifier.%s", methodName));
119+
}
120+
121+
@Test
122+
void testCheckTestsVerifyingIssuesAreNamedCorrectly() {
123+
methods()
124+
.that(VERIFY_ISSUES)
125+
.and(not(TESTING_IMPLEMENTATION_DETAILS))
126+
.should()
127+
.haveNameMatching(".*ShouldAdd(Issues?|QuickFix(es)?)$")
128+
.allowEmptyShould(true)
129+
.check(CHECKS_PACKAGE);
130+
}
131+
132+
@Test
133+
void testCheckTestsVerifyingNoIssuesAreNamedCorrectly() {
134+
methods()
135+
.that(VERIFY_NO_ISSUES)
136+
.and(not(TESTING_IMPLEMENTATION_DETAILS))
137+
.and(not(CALL_ASSERT_THROW_BY))
138+
.should()
139+
.haveNameMatching(".*ShouldNotAddIssues?$")
140+
.allowEmptyShould(true)
141+
.check(CHECKS_PACKAGE);
142+
}
143+
144+
@Test
145+
void testCheckTestsShouldThrowAreNamedCorrectly() {
146+
methods()
147+
.that(CALL_ASSERT_THROW_BY)
148+
.and(not(TESTING_IMPLEMENTATION_DETAILS))
149+
.should()
150+
.haveNameMatching(".*ShouldThrow$")
151+
.allowEmptyShould(true)
152+
.check(CHECKS_PACKAGE);
153+
}
154+
155+
@Test
156+
void testCheckTestsShouldNotThrowAreNamedCorrectly() {
157+
methods()
158+
.that(CALL_ASSERT_NO_EXCEPTION)
159+
.and(not(TESTING_IMPLEMENTATION_DETAILS))
160+
.should()
161+
.haveNameMatching(".*ShouldNotThrow$")
162+
.allowEmptyShould(true)
163+
.check(CHECKS_PACKAGE);
164+
}
165+
166+
@Test
167+
void testCheckTestsShouldBeNamedCorrectly() {
168+
methods()
169+
.that()
170+
.areAnnotatedWith(Test.class)
171+
.and(not(DECLARED_IN_METATESTS))
172+
.should()
173+
.haveNameMatching(".*Should((Not)?(Throw|Add(Issues?|QuickFix(es)?)))")
174+
.orShould()
175+
.haveNameMatching(IMPLEMENTATION_DETAIL_PREFIX + ".*")
176+
.allowEmptyShould(true)
177+
.check(CHECKS_PACKAGE);
178+
}
179+
180+
@Test
181+
void testCheckTestsHaveAnAssociatedCheck() {
182+
classes()
183+
.that()
184+
.haveSimpleNameEndingWith("Test")
185+
.and()
186+
.doNotBelongToAnyOf(CheckListTest.class, CheckMetadataTest.class, CheckTestNameTest.class)
187+
.should(HAVE_ASSOCIATED_CHECK)
188+
.allowEmptyShould(true)
189+
.check(CHECKS_PACKAGE);
190+
}
191+
192+
@Test
193+
void testChecksHaveAnAssociatedTest() {
194+
classes()
195+
.that()
196+
.areAssignableTo(DelphiCheck.class)
197+
.and()
198+
.doNotHaveModifier(JavaModifier.ABSTRACT)
199+
.should(HAVE_ASSOCIATED_TEST)
200+
.allowEmptyShould(true)
201+
.check(CHECKS_PACKAGE);
202+
}
203+
}

delphi-checks/src/test/java/au/com/integradev/delphi/checks/ClassPerFileCheckTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void testTwoClassesShouldAddIssue() {
8080
}
8181

8282
@Test
83-
void testMultipleViolationsShouldAddOneIssue() {
83+
void testMultipleViolationsShouldAddIssue() {
8484
CheckVerifier.newVerifier()
8585
.withCheck(new ClassPerFileCheck())
8686
.onFile(
@@ -99,7 +99,7 @@ void testMultipleViolationsShouldAddOneIssue() {
9999
}
100100

101101
@Test
102-
void testFalsePositiveMetaClass() {
102+
void testClassReferenceShouldNotAddIssue() {
103103
CheckVerifier.newVerifier()
104104
.withCheck(new ClassPerFileCheck())
105105
.onFile(
@@ -113,7 +113,7 @@ void testFalsePositiveMetaClass() {
113113
}
114114

115115
@Test
116-
void testFalsePositiveClassMethods() {
116+
void testClassMethodsShouldNotAddIssue() {
117117
CheckVerifier.newVerifier()
118118
.withCheck(new ClassPerFileCheck())
119119
.onFile(

delphi-checks/src/test/java/au/com/integradev/delphi/checks/CognitiveComplexityRoutineCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void testTooComplexRoutineShouldAddIssue() {
5757
}
5858

5959
@Test
60-
void testTooComplexSubProcedureShouldOnlyAddIssueForSubProcedure() {
60+
void testTooComplexSubProcedureShouldAddIssue() {
6161
DelphiTestUnitBuilder builder =
6262
new DelphiTestUnitBuilder()
6363
.appendImpl("function Foo: Integer;")

delphi-checks/src/test/java/au/com/integradev/delphi/checks/CommentedOutCodeCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ void testStackOverflowShouldNotAddIssue() {
330330
}
331331

332332
@Test
333-
void testRegexTimeoutCharSequenceSubsequence() {
333+
void testImplementationDetailRegexTimeoutCharSequenceSubsequence() {
334334
CharSequence charSequence = new RegexTimeoutCharSequence("Hello, World!", 0);
335335
assertThat(charSequence.subSequence(0, 5)).asString().isEqualTo("Hello");
336336
}

delphi-checks/src/test/java/au/com/integradev/delphi/checks/ConstructorNameCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void testConstructorWithoutPrefixShouldAddIssue() {
6464
}
6565

6666
@Test
67-
void testBadPascalCaseAddIssue() {
67+
void testBadPascalCaseShouldAddIssue() {
6868
CheckVerifier.newVerifier()
6969
.withCheck(new ConstructorNameCheck())
7070
.onFile(

delphi-checks/src/test/java/au/com/integradev/delphi/checks/CyclomaticComplexityRoutineCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void testTooComplexRoutineShouldAddIssue() {
7575
}
7676

7777
@Test
78-
void testTooComplexNestedRoutineeShouldOnlyAddIssueForNestedRoutine() {
78+
void testTooComplexNestedRoutineShouldAddIssue() {
7979
DelphiTestUnitBuilder builder =
8080
new DelphiTestUnitBuilder()
8181
.appendImpl("function Foo: Integer;") // 1

delphi-checks/src/test/java/au/com/integradev/delphi/checks/EmptyFileCheckTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ void testTypeDeclarationShouldNotAddIssue() {
107107
}
108108

109109
@Test
110-
void testIgnorePackage() {
110+
void testPackageShouldNotAddIssue() {
111111
CheckVerifier.newVerifier()
112112
.withCheck(new EmptyFileCheck())
113113
.onFile(DelphiTestFile.fromResource(PACKAGE_FILE))

delphi-checks/src/test/java/au/com/integradev/delphi/checks/EmptyRoutineCheckTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ void testEmptyExceptionalRoutinesWithCommentsShouldNotAddIssue() {
160160
}
161161

162162
@Test
163-
void testFalsePositiveForwardTypeDeclaration() {
163+
void testForwardTypeDeclarationShouldNotAddIssue() {
164164
CheckVerifier.newVerifier()
165165
.withCheck(new EmptyRoutineCheck())
166166
.onFile(
@@ -179,7 +179,7 @@ void testFalsePositiveForwardTypeDeclaration() {
179179
}
180180

181181
@Test
182-
void testFalsePositiveOverloadedMethod() {
182+
void testOverloadedMethodShouldNotAddIssue() {
183183
CheckVerifier.newVerifier()
184184
.withCheck(new EmptyRoutineCheck())
185185
.onFile(

delphi-checks/src/test/java/au/com/integradev/delphi/checks/FieldNameCheckTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void testFieldNameWithoutPrefixShouldAddIssue() {
5757
}
5858

5959
@Test
60-
void testPublicAndPublishedFieldsShouldNotAddIssue() {
60+
void testPublicAndPublishedFieldsShouldAddIssue() {
6161
CheckVerifier.newVerifier()
6262
.withCheck(new FieldNameCheck())
6363
.onFile(
@@ -76,7 +76,7 @@ void testPublicAndPublishedFieldsShouldNotAddIssue() {
7676
}
7777

7878
@Test
79-
void testPublicAndPublishedFieldsInMultipleClassesShouldNotAddIssue() {
79+
void testPublicAndPublishedFieldsInMultipleClassesShouldAddIssue() {
8080
CheckVerifier.newVerifier()
8181
.withCheck(new FieldNameCheck())
8282
.onFile(

0 commit comments

Comments
 (0)