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

Use Google's compile-testing library. #49

Merged
merged 4 commits into from
Sep 26, 2023
Merged
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
1 change: 1 addition & 0 deletions extensions/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies {
testImplementation libs.assertj
testImplementation libs.bundles.junit.jupiter
testImplementation libs.commons.io
testImplementation libs.compile.testing
testImplementation libs.dummymaker
testImplementation libs.guava
testImplementation libs.mapstruct.core
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package org.mapstruct.extensions.spring.converter;

import static com.google.common.collect.Iterables.concat;
import static java.nio.file.Files.createTempDirectory;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static javax.lang.model.element.Modifier.*;
import static javax.tools.StandardLocation.CLASS_OUTPUT;

import com.google.testing.compile.Compilation;
import com.google.testing.compile.Compiler;
import com.squareup.javapoet.*;
import java.io.IOException;
import java.util.Set;
import javax.annotation.processing.Processor;
import javax.tools.*;
Expand Down Expand Up @@ -49,27 +47,14 @@ protected static JavaFileObject toJavaFileObject(JavaFile.Builder fileBuilder) {
COMPONENT_JAVA_FILE_OBJECT,
LAZY_JAVA_FILE_OBJECT);

protected static boolean compile(
final Processor processor, final JavaFileObject... additionalCompilationUnits)
throws IOException {
protected static Compilation compile(
final Processor processor, final JavaFileObject... additionalCompilationUnits) {
return compile(processor, concat(COMMON_COMPILATION_UNITS, asList(additionalCompilationUnits)));
}

protected static boolean compile(
final Processor processor, final Iterable<JavaFileObject> compilationUnits)
throws IOException {
final var compiler = ToolProvider.getSystemJavaCompiler();

final var diagnostics = new DiagnosticCollector<JavaFileObject>();
final var fileManager = compiler.getStandardFileManager(diagnostics, null, null);
fileManager.setLocation(CLASS_OUTPUT, singletonList(createTempDirectory("classes").toFile()));

final var task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
task.setProcessors(singletonList(processor));

final var success = task.call();
diagnostics.getDiagnostics().forEach(System.err::println);
return success;
protected static Compilation compile(
final Processor processor, final Iterable<JavaFileObject> compilationUnits) {
return Compiler.javac().withProcessors(processor).compile(compilationUnits);
}

private static TypeSpec buildSimpleModelClassTypeSpec(final String className) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package org.mapstruct.extensions.spring.converter;

import static com.google.common.collect.Iterables.concat;
import static com.google.testing.compile.CompilationSubject.assertThat;
import static com.google.testing.compile.Compiler.javac;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import static javax.lang.model.element.Modifier.*;
import static org.assertj.core.api.BDDAssertions.then;
import static org.assertj.core.api.InstanceOfAssertFactories.list;
import static org.mockito.ArgumentMatchers.any;

import com.google.testing.compile.Compilation;
import com.squareup.javapoet.*;
import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.ref.WeakReference;
import java.time.Clock;
import java.util.List;
import java.util.Locale;
import javax.tools.*;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -51,7 +56,7 @@ class ConverterMapperProcessorTest extends AbstractProcessorTest {

@Captor private ArgumentCaptor<ConversionServiceAdapterDescriptor> descriptorArgumentCaptor;

private boolean compile(final JavaFileObject... additionalCompilationUnits) throws IOException {
private Compilation compile(final JavaFileObject... additionalCompilationUnits) {
return compile(processor, additionalCompilationUnits);
}

Expand All @@ -72,46 +77,75 @@ private static TypeSpec buildConfigClassWithExternalConversion(final String clas
}

@Test
void shouldCompileSimpleConverterMapper() throws IOException {
void shouldCompileSimpleConverterMapper() {
// Given
final JavaFile mapperFile =
JavaFile.builder(
PACKAGE_NAME, converterMapperWithoutGenericSourceOrTargetTypeBuilder().build())
.build();

// When
final boolean compileResult = compile(mapperFile.toJavaFileObject());

// Then
then(compileResult).isTrue();
// When - Then
assertThat(
javac()
.withProcessors(processor)
.compile(concat(List.of(mapperFile.toJavaFileObject()), COMMON_COMPILATION_UNITS)))
.succeeded();
BDDMockito.then(adapterGenerator)
.should()
.writeGeneratedCodeToOutput(descriptorArgumentCaptor.capture(), any(Writer.class));
then(descriptorArgumentCaptor.getValue())
.isNotNull()
.extracting(ConversionServiceAdapterDescriptor::getFromToMappings)
.asInstanceOf(list(FromToMapping.class))
.containsExactly(new FromToMapping().source(CAR_CLASS_NAME).target(CAR_DTO_CLASS_NAME));
}

@Test
void shouldCompileConverterMapperWithGenericSourceType() throws IOException {
void shouldCompileConverterMapperWithGenericSourceType() {
// Given
final JavaFile mapperFile =
JavaFile.builder(PACKAGE_NAME, converterMapperWithGenericSourceTypeBuilder().build())
.build();

// When
final boolean compileResult = compile(mapperFile.toJavaFileObject());

// Then
then(compileResult).isTrue();
// When - Then
assertThat(
javac()
.withProcessors(processor)
.compile(concat(List.of(mapperFile.toJavaFileObject()), COMMON_COMPILATION_UNITS)))
.succeeded();
BDDMockito.then(adapterGenerator)
.should()
.writeGeneratedCodeToOutput(descriptorArgumentCaptor.capture(), any(Writer.class));
then(descriptorArgumentCaptor.getValue())
.isNotNull()
.extracting(ConversionServiceAdapterDescriptor::getFromToMappings)
.asInstanceOf(list(FromToMapping.class))
.containsExactly(
new FromToMapping().source(genericSourceTypeName()).target(CAR_DTO_CLASS_NAME));
}

@Test
void shouldCompileConverterMapperWithGenericTargetType() throws IOException {
void shouldCompileConverterMapperWithGenericTargetType() {
// Given
final JavaFile mapperFile =
JavaFile.builder(PACKAGE_NAME, converterMapperWithGenericTargetTypeBuilder().build())
.build();

// When
final boolean compileResult = compile(mapperFile.toJavaFileObject());

// Then
then(compileResult).isTrue();
// When - Then
assertThat(
javac()
.withProcessors(processor)
.compile(concat(List.of(mapperFile.toJavaFileObject()), COMMON_COMPILATION_UNITS)))
.succeeded();
BDDMockito.then(adapterGenerator)
.should()
.writeGeneratedCodeToOutput(descriptorArgumentCaptor.capture(), any(Writer.class));
then(descriptorArgumentCaptor.getValue())
.isNotNull()
.extracting(ConversionServiceAdapterDescriptor::getFromToMappings)
.asInstanceOf(list(FromToMapping.class))
.containsExactly(
new FromToMapping().source(CAR_CLASS_NAME).target(genericTargetTypeName()));
}

private static TypeSpec.Builder converterMapperWithoutGenericSourceOrTargetTypeBuilder() {
Expand All @@ -127,15 +161,23 @@ private static TypeSpec.Builder converterMapperBuilder(
}

private static TypeSpec.Builder converterMapperWithGenericSourceTypeBuilder() {
return converterMapperBuilder(
ParameterizedTypeName.get(ClassName.get(WeakReference.class), CAR_CLASS_NAME),
CAR_DTO_CLASS_NAME);
return converterMapperBuilder(genericSourceTypeName(), CAR_DTO_CLASS_NAME);
}

private static ParameterizedTypeName genericSourceTypeName() {
return genericTypeName(CAR_CLASS_NAME);
}

private static ParameterizedTypeName genericTypeName(final ClassName wrappedClassName) {
return ParameterizedTypeName.get(ClassName.get(WeakReference.class), wrappedClassName);
}

private static TypeSpec.Builder converterMapperWithGenericTargetTypeBuilder() {
return converterMapperBuilder(
CAR_CLASS_NAME,
ParameterizedTypeName.get(ClassName.get(WeakReference.class), CAR_DTO_CLASS_NAME));
return converterMapperBuilder(CAR_CLASS_NAME, genericTargetTypeName());
}

private static ParameterizedTypeName genericTargetTypeName() {
return genericTypeName(CAR_DTO_CLASS_NAME);
}

private static TypeSpec.Builder plainCarMapperBuilder(
Expand All @@ -155,18 +197,20 @@ private static MethodSpec convertMethod(
}

@Test
void shouldIgnoreNonConverterMappers() throws IOException {
void shouldIgnoreNonConverterMappers() {
// Given
final JavaFile plainMapperFile =
JavaFile.builder(
PACKAGE_NAME, plainCarMapperBuilder(CAR_CLASS_NAME, CAR_DTO_CLASS_NAME).build())
.build();

// When
final boolean compileResult = compile(plainMapperFile.toJavaFileObject());

// Then
then(compileResult).isTrue();
// When - Then
assertThat(
javac()
.withProcessors(processor)
.compile(
concat(List.of(plainMapperFile.toJavaFileObject()), COMMON_COMPILATION_UNITS)))
.succeeded();
BDDMockito.then(adapterGenerator)
.should()
.writeGeneratedCodeToOutput(descriptorArgumentCaptor.capture(), any(Writer.class));
Expand All @@ -176,7 +220,7 @@ PACKAGE_NAME, plainCarMapperBuilder(CAR_CLASS_NAME, CAR_DTO_CLASS_NAME).build())
}

@Test
void shouldProcessOnlyConvertMethodForMapperWithMultipleMethods() throws IOException {
void shouldProcessOnlyConvertMethodForMapperWithMultipleMethods() {
// Given
final JavaFile mapperFile =
JavaFile.builder(
Expand All @@ -186,11 +230,12 @@ void shouldProcessOnlyConvertMethodForMapperWithMultipleMethods() throws IOExcep
.build())
.build();

// When
final boolean compileResult = compile(mapperFile.toJavaFileObject());

// Then
then(compileResult).isTrue();
// When - Then
assertThat(
javac()
.withProcessors(processor)
.compile(concat(List.of(mapperFile.toJavaFileObject()), COMMON_COMPILATION_UNITS)))
.succeeded();
BDDMockito.then(adapterGenerator)
.should()
.writeGeneratedCodeToOutput(descriptorArgumentCaptor.capture(), any(Writer.class));
Expand All @@ -202,7 +247,7 @@ void shouldProcessOnlyConvertMethodForMapperWithMultipleMethods() throws IOExcep
}

@Test
void shouldAddConversionServiceCallsForExternalConversions() throws IOException {
void shouldAddConversionServiceCallsForExternalConversions() {
// Given
final JavaFile mappingConfigFile =
JavaFile.builder(
Expand All @@ -213,12 +258,17 @@ PACKAGE_NAME, buildConfigClassWithExternalConversion("StringToLocaleConfig"))
PACKAGE_NAME, converterMapperWithoutGenericSourceOrTargetTypeBuilder().build())
.build();

// When
final boolean compileResult =
compile(mappingConfigFile.toJavaFileObject(), mapperFile.toJavaFileObject());
// When - Then
assertThat(
javac()
.withProcessors(processor)
.compile(
concat(
List.of(
mapperFile.toJavaFileObject(), mappingConfigFile.toJavaFileObject()),
COMMON_COMPILATION_UNITS)))
.succeeded();

// Then
then(compileResult).isTrue();
BDDMockito.then(adapterGenerator)
.should()
.writeGeneratedCodeToOutput(descriptorArgumentCaptor.capture(), any(Writer.class));
Expand All @@ -234,7 +284,7 @@ PACKAGE_NAME, converterMapperWithoutGenericSourceOrTargetTypeBuilder().build())
}

@Test
void shouldCompileMapperWithDelegatingConverterAnnotation() throws IOException {
void shouldCompileMapperWithDelegatingConverterAnnotation() {
final var delegatingConverterAnnotationTypeSpec =
TypeSpec.annotationBuilder(ClassName.get(DelegatingConverter.class))
.addAnnotation(
Expand Down Expand Up @@ -279,12 +329,11 @@ void shouldCompileMapperWithDelegatingConverterAnnotation() throws IOException {
final var autowiredFile =
JavaFile.builder("org.springframework.beans.factory.annotation", autowiredTypeSpec).build();

final var compileResult =
compile(
delegatingConverterFile.toJavaFileObject(),
mapperFile.toJavaFileObject(),
autowiredFile.toJavaFileObject());

then(compileResult).isTrue();
assertThat(
compile(
delegatingConverterFile.toJavaFileObject(),
mapperFile.toJavaFileObject(),
autowiredFile.toJavaFileObject()))
.succeeded();
}
}
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ asciidoctorPlugin = "3.3.2"
assertj = "3.24.2"
commons-io = "2.13.0"
commons-lang3 = "3.13.0"
compile-testing = "0.21.0"
dependencyCheck = "8.4.0"
dummymaker = "4.0.0"
guava = "32.1.2-jre"
Expand All @@ -21,6 +22,7 @@ versionsPlugin = "0.48.0"
assertj = { group = "org.assertj", name = "assertj-core", version.ref = "assertj"}
commons-io = { group = "commons-io", name = "commons-io", version.ref = "commons-io" }
commons-lang3 = { group = "org.apache.commons", name = "commons-lang3", version.ref = "commons-lang3" }
compile-testing = { group = "com.google.testing.compile", name = "compile-testing", version.ref = "compile-testing" }
dummymaker = { group = "com.github.goodforgod", name = "dummymaker", version.ref = "dummymaker"}
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
jakarta-annotation = { group = "jakarta.annotation", name = "jakarta.annotation-api", version.ref = "jakarta-annotation-api" }
Expand Down