Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#641 Added tooling tests #880

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class ArchUnitTestDescriptor extends AbstractArchUnitTestDescriptor implements C
private ClassCache classCache;

private ArchUnitTestDescriptor(ElementResolver resolver, Class<?> testClass, ClassCache classCache) {
super(resolver.getUniqueId(), testClass.getSimpleName(), ClassSource.from(testClass), testClass);
super(resolver.getUniqueId(), testClass.getName(), ClassSource.from(testClass), testClass);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed this because Jupiter would group field-flavored and method-flavored test results under different parent nodes (one under FQ class name and the other under simple class name)

this.testClass = testClass;
this.classCache = classCache;
}
Expand Down Expand Up @@ -243,7 +243,7 @@ Class<?> getDefinitionLocation() {
}

String getDisplayName() {
return archTests.getDefinitionLocation().getSimpleName();
return archTests.getDefinitionLocation().getName();
}

void handleFields(Consumer<? super Field> doWithField) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ void a_single_test_class() {
TestDescriptor child = getOnlyElement(descriptor.getChildren());
assertThat(child).isInstanceOf(ArchUnitTestDescriptor.class);
assertThat(child.getUniqueId()).isEqualTo(engineId.append(CLASS_SEGMENT_TYPE, SimpleRuleField.class.getName()));
assertThat(child.getDisplayName()).isEqualTo(SimpleRuleField.class.getSimpleName());
assertThat(child.getDisplayName()).isEqualTo(SimpleRuleField.class.getName());
assertThat(child.getType()).isEqualTo(CONTAINER);
assertThat(child.getParent().get()).isEqualTo(descriptor);
}
Expand All @@ -177,7 +177,7 @@ void multiple_test_classes() {
TestDescriptor descriptor = testEngine.discover(discoveryRequest, createEngineId());

Set<String> displayNames = descriptor.getChildren().stream().map(TestDescriptor::getDisplayName).collect(toSet());
assertThat(displayNames).containsOnly(SimpleRuleField.class.getSimpleName(), SimpleRuleMethod.class.getSimpleName());
assertThat(displayNames).containsOnly(SimpleRuleField.class.getName(), SimpleRuleMethod.class.getName());
}

@Test
Expand Down
137 changes: 137 additions & 0 deletions archunit-tooling-test/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import org.apache.tools.ant.filters.ReplaceTokens

plugins {
id 'archunit.java-production-conventions'
}

ext.moduleName = 'com.tngtech.archunit.tooling'
ext.minimumJavaVersion = JavaVersion.VERSION_1_9

sourceSets {
testFixtures {
Copy link
Contributor Author

@crizzis crizzis Jun 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't just apply java-test-fixtures because then the source set gets added to the classpath in the form of a Jar. This messes up the test engines, which depend on file paths inside the resources directories

java {
compileClasspath += main.compileClasspath
runtimeClasspath += main.runtimeClasspath
}
}
main {
java {
compileClasspath += project.sourceSets.testFixtures.output
runtimeClasspath += project.sourceSets.testFixtures.output
}
}
test {
java {
compileClasspath += project.sourceSets.testFixtures.output
runtimeClasspath += project.sourceSets.testFixtures.output
}
}
}

jar.enabled = false

task copyFixtureSources(type: Copy) {
into new File(project.sourceSets.testFixtures.output.resourcesDir, '@sources')
from(project.sourceSets.testFixtures.java) {
include '**/*.java'
}
}

processTestFixturesResources {
filesMatching(['**/pom.xml', '**/build.gradle']) {
filter ReplaceTokens, tokens: [
"junitDependency.version": project.property("archunit.version")
]
}
}

dependencies {
implementation project(path: ':archunit-junit5-engine-api')
implementation project(path: ':archunit-junit5-engine')
implementation project(path: ':archunit-junit4')
implementation dependency.junit5JupiterEngine
implementation dependency.junit5VintageEngine
implementation dependency.junitPlatform
implementation dependency.junitPlatformLauncher
implementation dependency.guava
implementation dependency.systemLambda
implementation dependency.mavenInvoker
implementation dependency.surefireReportParser
implementation dependency.commonsIo
implementation dependency.gradleToolingApi
implementation dependency.surefireSharedUtils

compileOnly dependency.findBugsAnnotations

testFixturesImplementation project(path: ':archunit')
testFixturesImplementation project(path: ':archunit-junit5-engine-api')
testFixturesImplementation project(path: ':archunit-junit5-api')
testFixturesImplementation project(path: ':archunit-junit5-engine')
testFixturesImplementation project(path: ':archunit-junit4')
testFixturesImplementation dependency.junitPlatform
testFixturesImplementation dependency.junit5JupiterEngine
testFixturesImplementation dependency.junit5JupiterApi

testImplementation dependency.assertj
testImplementation dependency.junitJupiterParams
testImplementation dependency.junitPioneer
}

String getMavenRepoPath(Project project) {
def pubs = project.publishing.publications.findAll() as Set<MavenPublication>
def pub = pubs[0]
if (!pub){
return null
}
String groupPath = pub.groupId.replace('.', '/')
return "$groupPath/$pub.artifactId"
}

def resolveAgainstMavenLocal(String path) {
new File(new File(repositories.mavenLocal().url), path)
}

def deleteSafely(File file) {
if (file.exists()) {
println "Deleting ${file.toURI().toString()}"
delete file
} else {
println "Could not find ${file.toURI().toString()}"
}
}

task removeFromMavenLocal {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This task cleans the local Maven repo to make sure we are running the Surefire and Gradle tests with an up-to-date version of ArchUnit jars

group = 'other'
description = 'Remove artifact and all versions/classifiers/flavors from local maven repository.'
doLast {
[project(':archunit-junit5-engine-api'),
project(':archunit-junit5-engine'),
project(':archunit-junit5-api'),
project(':archunit-junit5'),
project(':archunit-junit4'),
project(':archunit')].each { project ->
File file = resolveAgainstMavenLocal(getMavenRepoPath(project))
deleteSafely file
}
}
}

task publishJUnitDepsToMavenLocal {
group = 'other'
description = 'Publishes ArchUnit JUnit artifacts to local Maven repo'
dependsOn project(':archunit-junit5-engine-api').tasks.publishMavenJavaPublicationToMavenLocal
dependsOn project(':archunit-junit5-engine').tasks.publishMavenJavaPublicationToMavenLocal
dependsOn project(':archunit-junit5-api').tasks.publishMavenJavaPublicationToMavenLocal
dependsOn project(':archunit-junit5').tasks.publishMavenJavaPublicationToMavenLocal
dependsOn project(':archunit-junit4').tasks.publishMavenJavaPublicationToMavenLocal
dependsOn project(':archunit').tasks.publishMavenJavaPublicationToMavenLocal
}

clean {
dependsOn removeFromMavenLocal
}

test {
dependsOn copyFixtureSources, publishJUnitDepsToMavenLocal
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.tngtech.archunit.tooling;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

public class ExecutedTestFile {
private final String fixture;
private final Map<String, TestResult> results = new ConcurrentHashMap<>();

public ExecutedTestFile(String fixture) {
this.fixture = fixture;
}

public String getFixture() {
return fixture;
}

public Map<String, TestResult> getResults() {
return Collections.unmodifiableMap(results);
}

public int size() {
return results.size();
}

public Optional<TestResult> getResult(String testCase) {
return Optional.ofNullable(results.get(testCase))
.or(() -> findMatchingParameterizedTestName(testCase).map(results::get));
}

private Optional<String> findMatchingParameterizedTestName(String testCase) {
Pattern parameterizedPattern = Pattern.compile(testCase + "\\(.*\\)");
return results.keySet().stream()
.filter(key -> parameterizedPattern.matcher(key).matches())
.findAny();
}

public void addResult(String testCase, TestResult result) {
results.put(testCase, result);
}

public boolean hasInitializationError() {
return getResult("initializationError").isPresent();
}

public enum TestResult {
SUCCESS,
FAILURE,
ERROR,
SKIPPED
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tngtech.archunit.tooling;

public interface TestEngine {

TestReport execute(TestFile testFiles) throws Exception;

default boolean reportsErrors() {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.tngtech.archunit.tooling;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class TestFile {
private final Class<?> fixture;
private final Set<String> testCases;

public TestFile(Class<?> fixture, Set<String> testCases) {
this.fixture = fixture;
this.testCases = testCases;
}

public TestFile(Class<?> fixture, String testCase, String... more) {
this(fixture, toSet(testCase, more));
}

private static Set<String> toSet(String testCase, String[] more) {
Set<String> result = new HashSet<>();
result.add(testCase);
result.addAll(Arrays.asList(more));
return result;
}

public TestFile(Class<?> fixture) {
this(fixture, null);
}

public Class<?> getFixture() {
return fixture;
}

public Set<String> getTestCases() {
return testCases;
}

public boolean hasTestCasesFilter() {
return Objects.nonNull(testCases);
}

public boolean isSuite() {
return fixture.getSimpleName().contains("Suite");
}

public TestingFramework getTestingFramework() {
if (fixture.getSimpleName().contains("JUnit4")) {
return TestingFramework.JUNIT4;
}
if (fixture.getSimpleName().contains("JUnit5")) {
return TestingFramework.JUNIT5;
}
throw new IllegalStateException("Could not determine testing framework");
}

public enum TestingFramework {
JUNIT4,
JUNIT5
}

@Override
public String toString() {
if (hasTestCasesFilter()) {
return testCases + " in " + fixture.getSimpleName();
}
return "All tests in " + fixture.getSimpleName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.tngtech.archunit.tooling;

public interface TestPattern {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.tngtech.archunit.tooling;

import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

public class TestReport {

private final Set<ExecutedTestFile> files = new HashSet<>();

public Set<ExecutedTestFile> getFiles() {
return Collections.unmodifiableSet(files);
}

public void addFile(ExecutedTestFile file) {
files.add(file);
}

public Optional<ExecutedTestFile> getFile(String fixture) {
return files.stream()
.filter(file -> file.getFixture().equals(fixture))
.findFirst();
}

public synchronized ExecutedTestFile ensureFileForFixture(String fixture) {
return getFile(fixture)
.orElseGet(() -> newTestFile(fixture));
}

private ExecutedTestFile newTestFile(String fixture) {
ExecutedTestFile result = new ExecutedTestFile(fixture);
files.add(result);
return result;
}
}
Loading