diff --git a/acceptance-tests/acceptance-tests-avaje-inject/pom.xml b/acceptance-tests/acceptance-tests-avaje-inject/pom.xml new file mode 100644 index 000000000..cfe188fc8 --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + + + io.github.ascopes.jct + acceptance-tests + 0.0.1-SNAPSHOT + ../pom.xml + + + acceptance-tests-avaje-inject + + + 8.10 + + + + + ${project.groupId} + java-compiler-testing + test + + + + io.avaje + avaje-inject + ${avaje-inject.version} + test + + + + io.avaje + avaje-inject-generator + ${avaje-inject.version} + test + + + + org.apache.groovy + groovy + test + + + + org.junit.jupiter + junit-jupiter + test + + + + org.slf4j + slf4j-simple + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + + + + + diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/groovy/io/github/ascopes/jct/acceptancetests/avajeinject/AvajeInjectTest.groovy b/acceptance-tests/acceptance-tests-avaje-inject/src/test/groovy/io/github/ascopes/jct/acceptancetests/avajeinject/AvajeInjectTest.groovy new file mode 100644 index 000000000..f58988d2b --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/groovy/io/github/ascopes/jct/acceptancetests/avajeinject/AvajeInjectTest.groovy @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.ascopes.jct.acceptancetests.avajeinject + + +import io.github.ascopes.jct.compilers.JctCompiler +import io.github.ascopes.jct.filemanagers.LoggingMode +import io.github.ascopes.jct.junit.JavacCompilerTest +import io.github.ascopes.jct.workspaces.Workspaces +import org.junit.jupiter.api.DisplayName + +import static io.github.ascopes.jct.assertions.JctAssertions.assertThatCompilation + +@DisplayName("Avaje Inject acceptance tests") +class AvajeInjectTest { + @DisplayName("Dependency injection code gets generated as expected") + @JavacCompilerTest(modules = true) + void dependencyInjectionCodeGetsGeneratedAsExpected(JctCompiler compiler) { + // Given + try (def workspace = Workspaces.newWorkspace()) { + workspace + .createSourcePathPackage() + .rootDirectory() + .copyContentsFrom("src", "test", "resources", "code") + + // When + def compilation = compiler + .diagnosticLoggingMode(LoggingMode.STACKTRACES) + .compile(workspace) + + // Then + assertThatCompilation(compilation) + .isSuccessfulWithoutWarnings() + .classOutput() + .packages() + .allFilesExist( + 'org/example/CoffeeMaker.class', + 'org/example/Grinder.class', + 'org/example/Pump.class', + 'org/example/CoffeeMaker$DI.class', + 'org/example/Grinder$DI.class', + 'org/example/Pump$DI.class', + ) + } + } +} diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/module-info.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/module-info.java new file mode 100644 index 000000000..c4118d411 --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/module-info.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +module org.example { + exports org.example; + + requires io.avaje.inject; + + provides io.avaje.inject.spi.Module with org.example.ExampleModule; +} diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/CoffeeMaker.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/CoffeeMaker.java new file mode 100644 index 000000000..c375b4280 --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/CoffeeMaker.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +/** + * Makes coffee. + */ +@Singleton +public class CoffeeMaker { + + private final Grinder grinder; + private final Pump pump; + + @Inject + public CoffeeMaker(Grinder grinder, Pump pump) { + this.grinder = grinder; + this.pump = pump; + } + + public void makeCoffee() { + // ... + } +} diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Grinder.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Grinder.java new file mode 100644 index 000000000..0ea9c93f6 --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Grinder.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import jakarta.inject.Singleton; + +/** + * Grinds coffee. + */ +@Singleton +public class Grinder { + // ... +} diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Pump.java b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Pump.java new file mode 100644 index 000000000..2210b1ac6 --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/code/org/example/Pump.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import jakarta.inject.Singleton; + +/** + * Pumps coffee. + */ +@Singleton +public class Pump { + // ... +} diff --git a/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/junit-platform.properties b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/junit-platform.properties new file mode 100644 index 000000000..bcdc4a0f4 --- /dev/null +++ b/acceptance-tests/acceptance-tests-avaje-inject/src/test/resources/junit-platform.properties @@ -0,0 +1,3 @@ +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.classes.default=SAME_THREAD +junit.jupiter.execution.parallel.mode.default=CONCURRENT diff --git a/acceptance-tests/acceptance-tests-error-prone/pom.xml b/acceptance-tests/acceptance-tests-error-prone/pom.xml new file mode 100644 index 000000000..5cd83d4ac --- /dev/null +++ b/acceptance-tests/acceptance-tests-error-prone/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + + io.github.ascopes.jct + acceptance-tests + 0.0.1-SNAPSHOT + ../pom.xml + + + acceptance-tests-error-prone + + + + --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED + --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED + --add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED + --add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED + + + 2.16 + + + + + ${project.groupId} + java-compiler-testing + test + + + + com.google.errorprone + error_prone_core + ${error-prone.version} + + + + org.apache.groovy + groovy + test + + + + org.junit.jupiter + junit-jupiter + test + + + + org.slf4j + slf4j-simple + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + + + + + diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/groovy/io/github/ascopes/jct/acceptancetests/errorprone/ErrorProneTest.groovy b/acceptance-tests/acceptance-tests-error-prone/src/test/groovy/io/github/ascopes/jct/acceptancetests/errorprone/ErrorProneTest.groovy new file mode 100644 index 000000000..a2047132d --- /dev/null +++ b/acceptance-tests/acceptance-tests-error-prone/src/test/groovy/io/github/ascopes/jct/acceptancetests/errorprone/ErrorProneTest.groovy @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.github.ascopes.jct.acceptancetests.errorprone + +import io.github.ascopes.jct.compilers.JctCompiler +import io.github.ascopes.jct.junit.JavacCompilerTest +import io.github.ascopes.jct.workspaces.Workspaces +import org.junit.jupiter.api.DisplayName + +import static io.github.ascopes.jct.assertions.JctAssertions.assertThatCompilation + +@DisplayName("Error-prone acceptance tests") +class ErrorProneTest { + + @DisplayName("Happy paths work as expected") + @JavacCompilerTest + void happyPathsWorkAsExpected(JctCompiler compiler) { + try (def workspace = Workspaces.newWorkspace()) { + // Given + workspace + .createSourcePathPackage() + .createDirectory("org", "example") + .copyContentsFrom("src", "test", "resources", "code", "nullness", "happy") + + // When + def compilation = compiler + .addCompilerOptions( + "-Xplugin:ErrorProne", + "-XDcompilePolicy=simple", + ) + .compile(workspace) + + // Then + assertThatCompilation(compilation) + .isSuccessfulWithoutWarnings() + } + } + + @DisplayName("Sad paths fail as expected") + @JavacCompilerTest + void sadPathsFailAsExpected(JctCompiler compiler) { + try (def workspace = Workspaces.newWorkspace()) { + // Given + workspace + .createSourcePathPackage() + .createDirectory("org", "example") + .copyContentsFrom("src", "test", "resources", "code", "nullness", "sad") + + // When + def compilation = compiler + .addCompilerOptions( + "-Xplugin:ErrorProne", + "-XDcompilePolicy=simple", + ) + .compile(workspace) + + // Then + assertThatCompilation(compilation) + .isFailure() + .diagnostics() + .errors() + .singleElement() + .message() + .startsWith( + "[MustBeClosedChecker] This method returns a resource which must be managed " + + "carefully, not just left for garbage collection." + ) + } + } +} diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/happy/HappyCase.java b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/happy/HappyCase.java new file mode 100644 index 000000000..7578763f5 --- /dev/null +++ b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/happy/HappyCase.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import com.google.errorprone.annotations.MustBeClosed; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * This should pass error-prone because it always closes an auto-closeable resource. + */ +public class HappyCase { + + /** + * Do something. + * + * @param args arguments. + * @throws IOException any exception. + */ + public static void main(String[] args) throws IOException { + try (InputStream inputStream = inputStream()) { + inputStream.read(); + } + } + + @MustBeClosed + private static InputStream inputStream() throws IOException { + Path tempFile = Files.createTempFile("foo", "bar"); + return Files.newInputStream(tempFile); + } +} diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/sad/SadCase.java b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/sad/SadCase.java new file mode 100644 index 000000000..9505542a2 --- /dev/null +++ b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/code/nullness/sad/SadCase.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import com.google.errorprone.annotations.MustBeClosed; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * This should fail error-prone because it never closes an auto-closeable resource. + */ +public class SadCase { + + /** + * Do something. + * + * @param args arguments. + * @throws IOException any exception. + */ + public static void main(String[] args) throws IOException { + InputStream inputStream = inputStream(); + inputStream.read(); + } + + @MustBeClosed + private static InputStream inputStream() throws IOException { + Path tempFile = Files.createTempFile("foo", "bar"); + return Files.newInputStream(tempFile); + } +} diff --git a/acceptance-tests/acceptance-tests-error-prone/src/test/resources/junit-platform.properties b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/junit-platform.properties new file mode 100644 index 000000000..bcdc4a0f4 --- /dev/null +++ b/acceptance-tests/acceptance-tests-error-prone/src/test/resources/junit-platform.properties @@ -0,0 +1,3 @@ +junit.jupiter.execution.parallel.enabled=true +junit.jupiter.execution.parallel.mode.classes.default=SAME_THREAD +junit.jupiter.execution.parallel.mode.default=CONCURRENT diff --git a/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/happy/HappyCase.java b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/happy/HappyCase.java new file mode 100644 index 000000000..b3660e1f0 --- /dev/null +++ b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/happy/HappyCase.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * This should pass checkerframework. + */ +public class HappyCase { + + public static void main(String[] args) { + @Nullable String foo = null; + System.out.println(foo); + } +} diff --git a/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/sad/SadCase.java b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/sad/SadCase.java new file mode 100644 index 000000000..3084eeb8d --- /dev/null +++ b/acceptance-tests/acceptance-tests-manifold-systems/src/test/resources/code/nullness/sad/SadCase.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 - 2022 Ashley Scopes + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.example; + +import org.checkerframework.checker.nullness.qual.NonNull; + +/** + * This should fail checkerframework because it assigns a null value to a non-null holder. + */ +public class SadCase { + + public static void main(String[] args) { + @NonNull String foo = null; + System.out.println(foo); + } +} diff --git a/acceptance-tests/pom.xml b/acceptance-tests/pom.xml index 0fb824796..b9a8aa2c1 100644 --- a/acceptance-tests/pom.xml +++ b/acceptance-tests/pom.xml @@ -15,8 +15,10 @@ pom + acceptance-tests-avaje-inject acceptance-tests-checkerframework acceptance-tests-dagger + acceptance-tests-error-prone acceptance-tests-google-auto-factory acceptance-tests-google-auto-service acceptance-tests-google-auto-value diff --git a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java index 811e30c91..1ca8d8daf 100644 --- a/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java +++ b/java-compiler-testing/src/main/java/io/github/ascopes/jct/compilers/impl/JctCompilationFactory.java @@ -149,7 +149,7 @@ public JctCompilationImpl build() { ); var outputLines = writer.toString().lines().collect(Collectors.toList()); - + if (result == CompilationResult.SKIPPED) { LOGGER.warn("There was nothing to compile..."); }