Skip to content

Commit

Permalink
Use Google's compile-testing library. (#49)
Browse files Browse the repository at this point in the history
* Use Google's compile-testing library.

* Google Compile Testing Library working now.

* Google Compile Testing Library working now.
  • Loading branch information
Chessray authored Sep 26, 2023
1 parent b74f80e commit aa9d219
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 74 deletions.
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

0 comments on commit aa9d219

Please sign in to comment.