From 37890df3749892cb34e41398d6ebe238e28ca2bb Mon Sep 17 00:00:00 2001 From: Ashley Scopes <73482956+ascopes@users.noreply.github.com> Date: Sat, 21 Jan 2023 13:46:23 +0000 Subject: [PATCH] Add ability to limit the classes that actually get compiled --- .../jct/compilers/AbstractJctCompiler.java | 8 +- .../ascopes/jct/compilers/JctCompiler.java | 51 +++++ .../jct/compilers/impl/JctJsr199Interop.java | 18 +- .../compilers/AbstractJctCompilerTest.java | 31 ++- .../tests/unit/compilers/JctCompilerTest.java | 23 +++ .../compilers/impl/JctJsr199InteropTest.java | 189 ++++++++++++------ 6 files changed, 247 insertions(+), 73 deletions(-) diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/AbstractJctCompiler.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/AbstractJctCompiler.java index d6e0f100d..eabb45763 100644 --- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/AbstractJctCompiler.java +++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/AbstractJctCompiler.java @@ -25,6 +25,7 @@ import io.github.ascopes.jct.workspaces.Workspace; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Locale; import javax.annotation.Nullable; @@ -123,7 +124,12 @@ protected AbstractJctCompiler( @Override public JctCompilationImpl compile(Workspace workspace) { - return JctJsr199Interop.compile(workspace, myself(), jsr199Compiler, flagBuilder); + return JctJsr199Interop.compile(workspace, myself(), jsr199Compiler, flagBuilder, null); + } + + @Override + public JctCompilationImpl compile(Workspace workspace, Collection classNames) { + return JctJsr199Interop.compile(workspace, myself(), jsr199Compiler, flagBuilder, classNames); } @Override diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/JctCompiler.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/JctCompiler.java index 83738cb4c..7f4266efc 100644 --- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/JctCompiler.java +++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/JctCompiler.java @@ -23,6 +23,7 @@ import java.io.UncheckedIOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Collection; import java.util.List; import java.util.Locale; import javax.annotation.Nullable; @@ -126,15 +127,65 @@ public interface JctCompiler, R extends JctCompilati /** * Invoke the compilation and return the compilation result. * + *

The actual classes to compile will be dynamically discovered. If you wish to + * specify the specific classes to compile, see {@link #compile(Workspace, String, String...)} or + * {@link #compile(Workspace, Collection)}. + * * @param workspace the workspace to compile. * @return the compilation result. * @throws JctCompilerException if the compiler threw an unhandled exception. This should not * occur for compilation failures generally. * @throws IllegalStateException if no compilation units were found. * @throws UncheckedIOException if an IO error occurs. + * @see #compile(Workspace, String, String...) + * @see #compile(Workspace, Collection) */ R compile(Workspace workspace); + /** + * Invoke the compilation and return the compilation result. + * + *

Only classes matching the given class names will be compiled. + * + *

If you wish to let JCT determine which classes to compile dynamically, see + * {@link #compile(Workspace)} instead. + * + * @param workspace the workspace to compile. + * @param firstClassName the first class name to compile. + * @param additionalClassNames any additional class names to compile. + * @return the compilation result. + * @throws JctCompilerException if the compiler threw an unhandled exception. This should not + * occur for compilation failures generally. + * @throws IllegalStateException if no compilation units were found. + * @throws UncheckedIOException if an IO error occurs. + * @see #compile(Workspace) + * @see #compile(Workspace, Collection) + */ + default R compile(Workspace workspace, String firstClassName, String... additionalClassNames) { + return compile(workspace, IterableUtils.combineOneOrMore(firstClassName, additionalClassNames)); + } + + /** + * Invoke the compilation and return the compilation result. + * + *

Only classes matching the given class names will be compiled. + * + *

If you wish to let JCT determine which classes to compile dynamically, see + * {@link #compile(Workspace)} instead. + * + * @param workspace the workspace to compile. + * @param classNames the class names to compile. + * @return the compilation result. + * @throws JctCompilerException if the compiler threw an unhandled exception. This should not + * occur for compilation failures generally. + * @throws IllegalArgumentException if the collection is empty. + * @throws IllegalStateException if no compilation units were found. + * @throws UncheckedIOException if an IO error occurs. + * @see #compile(Workspace) + * @see #compile(Workspace, String, String...) + */ + R compile(Workspace workspace, Collection classNames); + /** * Apply a given configurer to this compiler that can throw a checked exception. * diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctJsr199Interop.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctJsr199Interop.java index 8f3d30a25..0ec02aea8 100644 --- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctJsr199Interop.java +++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctJsr199Interop.java @@ -36,10 +36,12 @@ import java.lang.module.ModuleFinder; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.ThreadSafe; import javax.tools.JavaCompiler; @@ -119,13 +121,17 @@ private JctJsr199Interop() { * @param compiler the compiler to use. * @param jsr199Compiler the JSR-199 compiler to use. * @param flagBuilder the flag builder to use. + * @param classNames the class names to compile, or {@code null} to automatically detect + * all classes. * @return the compilation factory. */ + @SuppressWarnings("NullableProblems") // https://youtrack.jetbrains.com/issue/IDEA-311124 public static JctCompilationImpl compile( Workspace workspace, JctCompiler compiler, JavaCompiler jsr199Compiler, - JctFlagBuilder flagBuilder + JctFlagBuilder flagBuilder, + @Nullable Collection classNames ) { // This method sucks, I hate it. If there is a nicer way of doing this without a load of // additional overhead, additional code, or additional complexity either in this class or the @@ -149,7 +155,8 @@ public static JctCompilationImpl compile( flags, fileManager, diagnosticListener, - compilationUnits + compilationUnits, + classNames ); var outputLines = writer.toString().lines().collect(Collectors.toList()); @@ -506,7 +513,8 @@ public static boolean performCompilerPass( List flags, JctFileManager fileManager, TracingDiagnosticListener diagnosticListener, - List compilationUnits + List compilationUnits, + @Nullable Collection classNames ) { var name = compiler.toString(); @@ -515,9 +523,7 @@ public static boolean performCompilerPass( fileManager, diagnosticListener, flags, - // TODO(ascopes): in the future, consider adding something here to allow customising - // the classes that get compiled, if desired. - null, + classNames, compilationUnits ); diff --git a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/AbstractJctCompilerTest.java b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/AbstractJctCompilerTest.java index 7c4ce914d..fb4d73c49 100644 --- a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/AbstractJctCompilerTest.java +++ b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/AbstractJctCompilerTest.java @@ -47,6 +47,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Set; import java.util.stream.Stream; import javax.annotation.processing.Processor; import javax.tools.JavaCompiler; @@ -320,13 +321,13 @@ void constructorInitialisesAnnotationProcessorDiscoveryToDefaultValue() { } } - @DisplayName(".compile(...) builds the expected compilation object") + @DisplayName(".compile(Workspace) builds the expected compilation object") @Test - void compileReturnsTheExpectedObject() { + void compileWorkspaceBuildsTheExpectedCompilationObject() { try (var factoryCls = mockStatic(JctJsr199Interop.class)) { // Given var expectedCompilation = mock(JctCompilationImpl.class); - factoryCls.when(() -> JctJsr199Interop.compile(any(), any(), any(), any())) + factoryCls.when(() -> JctJsr199Interop.compile(any(), any(), any(), any(), any())) .thenReturn(expectedCompilation); var expectedWorkspace = mock(Workspace.class); @@ -335,7 +336,29 @@ void compileReturnsTheExpectedObject() { // Then factoryCls.verify(() -> JctJsr199Interop - .compile(expectedWorkspace, compiler, jsr199Compiler, flagBuilder)); + .compile(expectedWorkspace, compiler, jsr199Compiler, flagBuilder, null)); + + assertThat(actualCompilation).isSameAs(expectedCompilation); + } + } + + @DisplayName(".compile(Workspace, Collection) builds the expected compilation object") + @Test + void compileWorkspaceCollectionBuildsTheExpectedCompilationObject() { + try (var factoryCls = mockStatic(JctJsr199Interop.class)) { + // Given + var expectedCompilation = mock(JctCompilationImpl.class); + factoryCls.when(() -> JctJsr199Interop.compile(any(), any(), any(), any(), any())) + .thenReturn(expectedCompilation); + var expectedWorkspace = mock(Workspace.class); + var classes = Set.of("foo.bar", "baz.bork", "qux.quxx"); + + // When + var actualCompilation = compiler.compile(expectedWorkspace, classes); + + // Then + factoryCls.verify(() -> JctJsr199Interop + .compile(expectedWorkspace, compiler, jsr199Compiler, flagBuilder, classes)); assertThat(actualCompilation).isSameAs(expectedCompilation); } diff --git a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/JctCompilerTest.java b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/JctCompilerTest.java index a1a5d7d69..b79c603de 100644 --- a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/JctCompilerTest.java +++ b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/JctCompilerTest.java @@ -26,7 +26,10 @@ import static org.mockito.Mockito.mock; import io.github.ascopes.jct.compilers.JctCompiler; +import io.github.ascopes.jct.workspaces.Workspace; import java.util.Arrays; +import java.util.List; +import java.util.Set; import java.util.stream.Stream; import javax.annotation.processing.Processor; import javax.lang.model.SourceVersion; @@ -260,6 +263,26 @@ void targetVersionSourceVersionCallsReleaseVersionString( assertThat(result).isSameAs(compiler); } + @DisplayName(".compile(Workspace, String, String...) calls .compile(Workspace, Collection)") + @Test + void compileStringVarargsCallsCompileCollection() { + // Given + var workspace = mock(Workspace.class); + + given(compiler.compile(any(), any(), any(), any())) + .willCallRealMethod(); + + var firstClass = "org.example.Foo"; + var secondClass = "org.example.Bar"; + var thirdClass = "com.organisation.FooBar"; + + // When + var result = compiler.compile(workspace, firstClass, secondClass, thirdClass); + + // Then + then(compiler).should().compile(workspace, List.of(firstClass, secondClass, thirdClass)); + } + static Stream sourceVersions() { return Stream .of(SourceVersion.values()) diff --git a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/impl/JctJsr199InteropTest.java b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/impl/JctJsr199InteropTest.java index d4cab1876..cc0deecd2 100644 --- a/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/impl/JctJsr199InteropTest.java +++ b/java-compiler-testing/src/test/java/io/github/ascopes/jct/tests/unit/compilers/impl/JctJsr199InteropTest.java @@ -92,11 +92,13 @@ import java.lang.module.FindException; import java.lang.module.ModuleFinder; import java.nio.file.Path; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.annotation.Nullable; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileManager.Location; @@ -113,6 +115,7 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.EnumSource; import org.junit.jupiter.params.provider.EnumSource.Mode; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Answers; import org.mockito.ArgumentCaptor; @@ -161,45 +164,54 @@ class CompileTest { @BeforeEach void setUp() { - staticMock.when(() -> compile(any(), any(), any(), any())) + staticMock.when(() -> compile(any(), any(), any(), any(), any())) .thenCallRealMethod(); } - JctCompilationImpl doCompile() { - return compile(workspace, compiler, jsr199Compiler, flagBuilder); + JctCompilationImpl doCompile(@Nullable Collection classNames) { + return compile(workspace, compiler, jsr199Compiler, flagBuilder, classNames); } @DisplayName("the writer is built using the compiler") + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") @SuppressWarnings("resource") - @Test - void writerIsBuiltUsingCompiler() { + void writerIsBuiltUsingCompiler(@Nullable Collection classes) { // When - doCompile(); + doCompile(classes); // Then staticMock.verify(() -> buildWriter(compiler)); } @DisplayName("errors while building writers get re-raised") + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") @SuppressWarnings("resource") - @Test - void errorsBuildingWritersAreReraised() { + void errorsBuildingWritersAreReraised(@Nullable Collection classes) { // Given var ex = someUncheckedException(); staticMock.when(() -> buildWriter(any())) .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); } @DisplayName("the writer is NOT closed after usage") + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") @SuppressWarnings("resource") - @Test - void writerIsNotClosedAfterUsage() throws IOException { + void writerIsNotClosedAfterUsage(@Nullable Collection classes) throws IOException { // DO NOT CLOSE THE WRITER, IT IS ATTACHED TO SYSTEM.OUT. // Closing SYSTEM.OUT causes IntelliJ to abort the entire test runner. // See https://youtrack.jetbrains.com/issue/IDEA-120628 @@ -210,136 +222,166 @@ void writerIsNotClosedAfterUsage() throws IOException { staticMock.when(() -> buildWriter(any())).thenReturn(writer); // When - doCompile(); + doCompile(classes); // Then verify(writer, never()).close(); } @DisplayName("the file manager is built using the compiler and workspace") - @Test - void fileManagerIsBuiltUsingCompilerAndWorkspace() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void fileManagerIsBuiltUsingCompilerAndWorkspace(@Nullable Collection classes) { // When - doCompile(); + doCompile(classes); // Then staticMock.verify(() -> buildFileManager(compiler, workspace)); } @DisplayName("errors while building file managers get re-raised") - @Test - void errorsBuildingFileManagersAreReraised() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void errorsBuildingFileManagersAreReraised(@Nullable Collection classes) { // Given var ex = someUncheckedException(); staticMock.when(() -> buildFileManager(any(), any())) .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); } @DisplayName("the file manager is closed after usage") - @Test - void fileManagerIsClosedAfterUsage() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void fileManagerIsClosedAfterUsage(@Nullable Collection classes) { // Given var fileManager = mock(JctFileManagerImpl.class); staticMock.when(() -> buildFileManager(any(), any())) .thenReturn(fileManager); // When - doCompile(); + doCompile(classes); // Then verify(fileManager).close(); } @DisplayName("the flags are built using the compiler and flag builder") - @Test - void flagsAreBuiltUsingCompilerAndFlagBuilder() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void flagsAreBuiltUsingCompilerAndFlagBuilder(@Nullable Collection classes) { // When - doCompile(); + doCompile(classes); // Then staticMock.verify(() -> buildFlags(compiler, flagBuilder)); } @DisplayName("errors while building flags get re-raised") - @Test - void errorsBuildingFlagsAreReraised() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void errorsBuildingFlagsAreReraised(@Nullable Collection classes) { // Given var ex = someUncheckedException(); staticMock.when(() -> buildFlags(any(), any())) .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); } @DisplayName("the diagnostic listener is built using the compiler") - @Test - void diagnosticListenerIsBuiltUsingCompiler() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void diagnosticListenerIsBuiltUsingCompiler(@Nullable Collection classes) { // When - doCompile(); + doCompile(classes); // Then staticMock.verify(() -> buildDiagnosticListener(compiler)); } @DisplayName("errors while building diagnostic listeners get re-raised") - @Test - void errorsBuildingDiagnosticListenersAreReraised() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void errorsBuildingDiagnosticListenersAreReraised(@Nullable Collection classes) { // Given var ex = someUncheckedException(); staticMock.when(() -> buildDiagnosticListener(any())) .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); } @DisplayName("compilation units are discovered using the file manager") - @Test - void compilationUnitsAreDiscoveredUsingTheFileManager() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void compilationUnitsAreDiscoveredUsingTheFileManager(@Nullable Collection classes) { // Given var fileManager = mock(JctFileManagerImpl.class); staticMock.when(() -> buildFileManager(any(), any())) .thenReturn(fileManager); // When - doCompile(); + doCompile(classes); // Then staticMock.verify(() -> findCompilationUnits(fileManager)); } @DisplayName("errors finding compilation units are reraised") - @Test - void errorsFindingCompilationUnitsAreReraised() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void errorsFindingCompilationUnitsAreReraised(@Nullable Collection classes) { // Given var ex = someIoException(); staticMock.when(() -> findCompilationUnits(any())) .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); } @DisplayName("performCompilerPass is called with the expected arguments") + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") @SuppressWarnings("resource") - @Test - void performCompilerPassCalledWithExpectedArguments() { + void performCompilerPassCalledWithExpectedArguments(@Nullable Collection classes) { // Given var flags = someFlags(); staticMock.when(() -> buildFlags(any(), any())) @@ -364,7 +406,7 @@ void performCompilerPassCalledWithExpectedArguments() { .thenReturn(compilationUnits); // When - doCompile(); + doCompile(classes); // Then staticMock.verify(() -> performCompilerPass( @@ -374,20 +416,25 @@ void performCompilerPassCalledWithExpectedArguments() { flags, fileManager, diagnosticListener, - compilationUnits + compilationUnits, + classes )); } @DisplayName("errors performing the compilation pass units are reraised") - @Test - void errorsPerformingTheCompilationPassAreReraised() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void errorsPerformingTheCompilationPassAreReraised(@Nullable Collection classes) { // Given var ex = someUncheckedException(); - staticMock.when(() -> performCompilerPass(any(), any(), any(), any(), any(), any(), any())) + staticMock + .when(() -> performCompilerPass(any(), any(), any(), any(), any(), any(), any(), any())) .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); @@ -432,11 +479,12 @@ void compilationResultsAreReturned(boolean result) { staticMock.when(() -> findCompilationUnits(any())) .thenReturn(compilationUnits); - staticMock.when(() -> performCompilerPass(any(), any(), any(), any(), any(), any(), any())) + staticMock + .when(() -> performCompilerPass(any(), any(), any(), any(), any(), any(), any(), any())) .thenReturn(result); // When - var compilation = doCompile(); + var compilation = doCompile(null); // Then assertThat(compilation) @@ -473,8 +521,11 @@ void compilationResultsAreReturned(boolean result) { @SuppressWarnings("resource") @DisplayName("errors extracting the writer lines are reraised") - @Test - void errorsExtractingWriterLinesAreReraised() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void errorsExtractingWriterLinesAreReraised(@Nullable Collection classes) { // Given var writer = mock(TeeWriter.class); staticMock.when(() -> buildWriter(any())) @@ -485,7 +536,7 @@ void errorsExtractingWriterLinesAreReraised() { .thenThrow(ex); // Then - assertThatThrownBy(this::doCompile) + assertThatThrownBy(() -> doCompile(classes)) .isInstanceOf(JctCompilerException.class) .hasMessage("Failed to compile due to an error: %s", ex) .hasCause(ex); @@ -1651,7 +1702,8 @@ class PerformCompilerPassTest { @BeforeEach void setUp() { - staticMock.when(() -> performCompilerPass(any(), any(), any(), any(), any(), any(), any())) + staticMock + .when(() -> performCompilerPass(any(), any(), any(), any(), any(), any(), any(), any())) .thenCallRealMethod(); when(jctJsr199Compiler.getTask(any(), any(), any(), any(), any(), any())) .thenReturn(task); @@ -1659,7 +1711,7 @@ void setUp() { compilationUnits = someCompilationUnits(); } - boolean doPerformCompilerPass() { + boolean doPerformCompilerPass(@Nullable Collection classes) { return performCompilerPass( compiler, jctJsr199Compiler, @@ -1667,13 +1719,19 @@ boolean doPerformCompilerPass() { flags, fileManager, tracingDiagnosticListener, - compilationUnits + compilationUnits, + classes ); } @DisplayName("the compilation task is initialised in the correct order before being called") - @Test - void theCompilationTaskIsInitialisedInTheCorrectOrderBeforeBeingCalled() { + @MethodSource( + "io.github.ascopes.jct.tests.unit.compilers.impl.JctJsr199InteropTest#explicitClassesArgs" + ) + @ParameterizedTest(name = "for classes = {0}") + void theCompilationTaskIsInitialisedInTheCorrectOrderBeforeBeingCalled( + @Nullable Collection classes + ) { // Given var locale = someLocale(); when(compiler.getLocale()).thenReturn(locale); @@ -1681,7 +1739,7 @@ void theCompilationTaskIsInitialisedInTheCorrectOrderBeforeBeingCalled() { var orderedMock = inOrder(jctJsr199Compiler, JctJsr199Interop.class, task); // When - doPerformCompilerPass(); + doPerformCompilerPass(classes); // Then orderedMock.verify(jctJsr199Compiler).getTask( @@ -1689,7 +1747,7 @@ void theCompilationTaskIsInitialisedInTheCorrectOrderBeforeBeingCalled() { fileManager, tracingDiagnosticListener, flags, - null, + classes, compilationUnits ); orderedMock.verify(task).setLocale(locale); @@ -1706,7 +1764,7 @@ void compilationsReturnTheResult(boolean expectedResult) { when(task.call()).thenReturn(expectedResult); // When - var actualResult = doPerformCompilerPass(); + var actualResult = doPerformCompilerPass(null); // Then assertThat(actualResult).isEqualTo(expectedResult); @@ -1720,7 +1778,7 @@ void buggyCompilersReturningNullFromTaskCallRaiseException() { when(task.call()).thenReturn(null); // Then - assertThatThrownBy(this::doPerformCompilerPass) + assertThatThrownBy(() -> doPerformCompilerPass(null)) .isInstanceOf(JctCompilerException.class) .hasNoCause() .hasMessage( @@ -1739,7 +1797,7 @@ void exceptionsThrownByTheCompilerAreWrappedAndReraised() { when(task.call()).thenThrow(cause); // Then - assertThatThrownBy(this::doPerformCompilerPass) + assertThatThrownBy(() -> doPerformCompilerPass(null)) .isInstanceOf(JctCompilerException.class) .hasCause(cause) .hasMessage( @@ -1860,4 +1918,11 @@ void disableApDiscovery() { verifyNoMoreInteractions(task); } } + + static Stream> explicitClassesArgs() { + return Stream.of( + null, + Set.of("org.example.Foo", "org.example.Bar") + ); + } }