diff --git a/src/main/java/com/zyxist/chainsaw/exec/RunTaskConfigurator.java b/src/main/java/com/zyxist/chainsaw/exec/RunTaskConfigurator.java index 810f6f92..5407f2f6 100644 --- a/src/main/java/com/zyxist/chainsaw/exec/RunTaskConfigurator.java +++ b/src/main/java/com/zyxist/chainsaw/exec/RunTaskConfigurator.java @@ -19,10 +19,16 @@ import com.zyxist.chainsaw.TaskConfigurator; import com.zyxist.chainsaw.algorithms.ModulePatcher; import com.zyxist.chainsaw.jigsaw.JigsawCLI; +import com.zyxist.chainsaw.jigsaw.cli.PatchItem; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.tasks.JavaExec; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; + +import java.io.File; +import java.util.Optional; import static com.zyxist.chainsaw.ChainsawPlugin.PATCH_CONFIGURATION_NAME; @@ -39,10 +45,16 @@ public void updateConfiguration(Project project, JavaExec task) { } @Override - public Action doFirst(final Project project, final JavaExec run) { - return new Action() { + public Action doFirst(Project project, JavaExec task) { + return (nothing) -> {}; + } + + @Override + public Optional> doLast(final Project project, final JavaExec run) { + return Optional.of(new Action() { @Override public void execute(Task task) { + final SourceSet mainSourceSet = ((SourceSetContainer) project.getProperties().get("sourceSets")).getByName("main"); JigsawCLI cli = new JigsawCLI(run.getClasspath().getAsPath()); cli.module(moduleConfig.getName(), run.getMain()); @@ -54,6 +66,6 @@ public void execute(Task task) { run.setJvmArgs(cli.generateArgs()); run.setClasspath(project.files()); } - }; + }); } } diff --git a/src/test/groovy/com/zyxist/chainsaw/builder/JigsawProjectBuilder.java b/src/test/groovy/com/zyxist/chainsaw/builder/JigsawProjectBuilder.java index cd6e2f08..24337257 100644 --- a/src/test/groovy/com/zyxist/chainsaw/builder/JigsawProjectBuilder.java +++ b/src/test/groovy/com/zyxist/chainsaw/builder/JigsawProjectBuilder.java @@ -30,7 +30,9 @@ public class JigsawProjectBuilder { private static final String DEFAULT_MODULE_NAME = "com.example"; private static final String JAVA_SRC = "src/main/java"; + private static final String JAVA_RESOURCES = "src/main/resources"; private static final String TEST_SRC = "src/test/java"; + private static final String TEST_RESOURCES = "src/test/resources"; private String javaPlugin = ""; private String pkgName = DEFAULT_PKG_NAME; @@ -177,14 +179,25 @@ public JigsawProjectBuilder createModuleDescriptor() throws IOException { public JigsawProjectBuilder createJavaFile(JavaCodeFactory factory) throws IOException { String path = JAVA_SRC + "/" + factory.getFilename(this); - createDirectories(path); - File file = tmpDir.newFile(path); - ResourceGroovyMethods.leftShift(file, factory.generateCode(this)); - return this; + return createFile(path, factory); + } + + public JigsawProjectBuilder createJavaResourceFile(JavaCodeFactory factory) throws IOException { + String path = JAVA_RESOURCES + "/" + factory.getFilename(this); + return createFile(path, factory); } public JigsawProjectBuilder createJavaTestFile(JavaCodeFactory factory) throws IOException { String path = TEST_SRC + "/" + factory.getFilename(this); + return createFile(path, factory); + } + + public JigsawProjectBuilder createTestResourceFile(JavaCodeFactory factory) throws IOException { + String path = TEST_RESOURCES + "/" + factory.getFilename(this); + return createFile(path, factory); + } + + private JigsawProjectBuilder createFile(String path, JavaCodeFactory factory) throws IOException { createDirectories(path); File file = tmpDir.newFile(path); ResourceGroovyMethods.leftShift(file, factory.generateCode(this)); diff --git a/src/test/groovy/com/zyxist/chainsaw/builder/factory/JUnit5SampleResourceTestFactory.groovy b/src/test/groovy/com/zyxist/chainsaw/builder/factory/JUnit5SampleResourceTestFactory.groovy new file mode 100644 index 00000000..c699d89f --- /dev/null +++ b/src/test/groovy/com/zyxist/chainsaw/builder/factory/JUnit5SampleResourceTestFactory.groovy @@ -0,0 +1,71 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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 com.zyxist.chainsaw.builder.factory + +import com.zyxist.chainsaw.builder.JavaCodeFactory +import com.zyxist.chainsaw.builder.JigsawProjectBuilder + +class JUnit5SampleResourceTestFactory implements JavaCodeFactory { + private boolean useModuleLoader + + static def junit5TestAccessingResources() { + def factory = new JUnit5SampleResourceTestFactory() + factory.useModuleLoader = false + return factory + } + + static def junit5TestAccessingModularResources() { + def factory = new JUnit5SampleResourceTestFactory() + factory.useModuleLoader = true + return factory + } + + @Override + String getFilename(JigsawProjectBuilder builder) { + return builder.getPackageName().replace(".", "/") + "/SampleResourceTest.java" + } + + @Override + String generateCode(JigsawProjectBuilder builder) { + def loadingCode = useModuleLoader ? getModularLoadingCode() : getClasspathLoadingCode() + return """ +package ${builder.getPackageName()}; + +import java.util.Properties; +import java.io.IOException; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SampleResourceTest { + @Test + public void readsTestResources() throws IOException { + Properties props = new Properties(); + props.load($loadingCode); + + assertEquals("Hello world", props.get("property")); + } +} +""" + } + + private String getClasspathLoadingCode() { + return "getClass().getClassLoader().getResourceAsStream(\"text-resource.properties\")" + } + + private String getModularLoadingCode() { + return "getClass().getModule().getResourceAsStream(\"text-resource.properties\")" + } +} diff --git a/src/test/groovy/com/zyxist/chainsaw/builder/factory/RunnableResourceClassFactory.groovy b/src/test/groovy/com/zyxist/chainsaw/builder/factory/RunnableResourceClassFactory.groovy new file mode 100644 index 00000000..0a10a928 --- /dev/null +++ b/src/test/groovy/com/zyxist/chainsaw/builder/factory/RunnableResourceClassFactory.groovy @@ -0,0 +1,66 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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 com.zyxist.chainsaw.builder.factory + +import com.zyxist.chainsaw.builder.JavaCodeFactory +import com.zyxist.chainsaw.builder.JigsawProjectBuilder + +class RunnableResourceClassFactory implements JavaCodeFactory { + private boolean useModuleLoader + + static def runnableResourceClasspathClass() { + def factory = new RunnableResourceClassFactory() + factory.useModuleLoader = false + return factory + } + + static def runnableResourceModularClass() { + def factory = new RunnableResourceClassFactory() + factory.useModuleLoader = true + return factory + } + + @Override + String getFilename(JigsawProjectBuilder builder) { + return builder.getPackageName().replace(".", "/") + "/ResourceClass.java" + } + + @Override + String generateCode(JigsawProjectBuilder builder) { + def loadingCode = useModuleLoader ? getModularLoadingCode() : getClasspathLoadingCode() + return """ +package ${builder.getPackageName()}; +import java.util.Properties; +import java.io.IOException; + +public class ResourceClass { + public static void main(String... args) throws IOException { + Properties props = new Properties(); + props.load($loadingCode); + System.out.println(props.get("property")); + } +} +""" + } + + private String getClasspathLoadingCode() { + return "ResourceClass.class.getClassLoader().getResourceAsStream(\"text-resource.properties\")" + } + + private String getModularLoadingCode() { + return "ResourceClass.class.getModule().getResourceAsStream(\"text-resource.properties\")" + } +} diff --git a/src/test/groovy/com/zyxist/chainsaw/builder/factory/SampleTextResourceFactory.groovy b/src/test/groovy/com/zyxist/chainsaw/builder/factory/SampleTextResourceFactory.groovy new file mode 100644 index 00000000..33844272 --- /dev/null +++ b/src/test/groovy/com/zyxist/chainsaw/builder/factory/SampleTextResourceFactory.groovy @@ -0,0 +1,45 @@ +/* + * Copyright 2018 the original author or authors. + * + * 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 com.zyxist.chainsaw.builder.factory + +import com.zyxist.chainsaw.builder.JavaCodeFactory +import com.zyxist.chainsaw.builder.JigsawProjectBuilder + +class SampleTextResourceFactory implements JavaCodeFactory { + private boolean inPackage = false + + static SampleTextResourceFactory sampleTextResource() { + return new SampleTextResourceFactory() + } + + static SampleTextResourceFactory samplePackagedTextResource() { + def factory = new SampleTextResourceFactory() + factory.inPackage = true + return factory + } + + @Override + String getFilename(JigsawProjectBuilder builder) { + return (inPackage ? builder.getPackageName().replace(".", "/") + "/" : "") + "text-resource.properties" + } + + @Override + String generateCode(JigsawProjectBuilder builder) { + return """ +property=Hello world +""" + } +} diff --git a/src/test/groovy/com/zyxist/chainsaw/integration/ChainsawPluginSpec.groovy b/src/test/groovy/com/zyxist/chainsaw/integration/ChainsawPluginSpec.groovy index 58605c28..24217570 100644 --- a/src/test/groovy/com/zyxist/chainsaw/integration/ChainsawPluginSpec.groovy +++ b/src/test/groovy/com/zyxist/chainsaw/integration/ChainsawPluginSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,10 @@ import spock.lang.Specification import static com.zyxist.chainsaw.builder.factory.JUnit4SampleTestFactory.junit4Test import static com.zyxist.chainsaw.builder.factory.RunnableJavaClassFactory.runnableJavaClass +import static com.zyxist.chainsaw.builder.factory.RunnableResourceClassFactory.runnableResourceClasspathClass +import static com.zyxist.chainsaw.builder.factory.RunnableResourceClassFactory.runnableResourceModularClass +import static com.zyxist.chainsaw.builder.factory.SampleTextResourceFactory.samplePackagedTextResource +import static com.zyxist.chainsaw.builder.factory.SampleTextResourceFactory.sampleTextResource import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class ChainsawPluginSpec extends Specification { @@ -42,15 +46,19 @@ class ChainsawPluginSpec extends Specification { .exportedPackage("com.example") .gradleJavaPlugin("application") .testCompileDependency(Dependencies.JUNIT4_DEPENDENCY) + + } + + @IgnoreIf({NOT_JAVA_9}) + def "can assemble a module"() { + given: + project .mainClass("com.example.AClass") .createJavaFile(runnableJavaClass()) .createJavaTestFile(junit4Test()) .createModuleDescriptor() .createGradleBuild() - } - @IgnoreIf({NOT_JAVA_9}) - def "can assemble a module"() { when: def result = GradleRunner.create() .withProjectDir(project.root) @@ -67,6 +75,14 @@ class ChainsawPluginSpec extends Specification { @IgnoreIf({NOT_JAVA_9}) def "can check a module"() { + given: + project + .mainClass("com.example.AClass") + .createJavaFile(runnableJavaClass()) + .createJavaTestFile(junit4Test()) + .createModuleDescriptor() + .createGradleBuild() + when: def result = GradleRunner.create() .withProjectDir(project.root) @@ -81,6 +97,14 @@ class ChainsawPluginSpec extends Specification { @IgnoreIf({NOT_JAVA_9}) def "can run with a module"() { + given: + project + .mainClass("com.example.AClass") + .createJavaFile(runnableJavaClass()) + .createJavaTestFile(junit4Test()) + .createModuleDescriptor() + .createGradleBuild() + when: def result = GradleRunner.create() .withProjectDir(project.root) @@ -92,4 +116,46 @@ class ChainsawPluginSpec extends Specification { then: result.output.contains("Hello World!") } + + @IgnoreIf({NOT_JAVA_9}) + def "resources loaded with classloader are visible in runtime"() { + project + .mainClass("com.example.ResourceClass") + .createJavaFile(runnableResourceClasspathClass()) + .createJavaResourceFile(sampleTextResource()) + .createModuleDescriptor() + .createGradleBuild() + + when: + def result = GradleRunner.create() + .withProjectDir(project.root) + .withDebug(true) + .forwardOutput() + .withArguments("run") + .withPluginClasspath().build() + + then: + result.output.contains("Hello world") + } + + @IgnoreIf({NOT_JAVA_9}) + def "resources loaded with module loader are visible in runtime"() { + project + .mainClass("com.example.ResourceClass") + .createJavaFile(runnableResourceModularClass()) + .createJavaResourceFile(sampleTextResource()) + .createModuleDescriptor() + .createGradleBuild() + + when: + def result = GradleRunner.create() + .withProjectDir(project.root) + .withDebug(true) + .forwardOutput() + .withArguments("run", "--stacktrace") + .withPluginClasspath().build() + + then: + result.output.contains("Hello world") + } } \ No newline at end of file diff --git a/src/test/groovy/com/zyxist/chainsaw/integration/JUnit5TestSpec.groovy b/src/test/groovy/com/zyxist/chainsaw/integration/JUnit5TestSpec.groovy index 5c9027b2..65cfeaae 100644 --- a/src/test/groovy/com/zyxist/chainsaw/integration/JUnit5TestSpec.groovy +++ b/src/test/groovy/com/zyxist/chainsaw/integration/JUnit5TestSpec.groovy @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,11 @@ import org.junit.rules.TemporaryFolder import spock.lang.IgnoreIf import spock.lang.Specification +import static com.zyxist.chainsaw.builder.factory.JUnit5SampleResourceTestFactory.junit5TestAccessingModularResources +import static com.zyxist.chainsaw.builder.factory.JUnit5SampleResourceTestFactory.junit5TestAccessingResources import static com.zyxist.chainsaw.builder.factory.JUnit5SampleTestFactory.junit5TestWithMocks import static com.zyxist.chainsaw.builder.factory.RegularJavaClassFactory.regularJavaClass +import static com.zyxist.chainsaw.builder.factory.SampleTextResourceFactory.sampleTextResource import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class JUnit5TestSpec extends Specification { @@ -45,7 +48,6 @@ class JUnit5TestSpec extends Specification { .testRuntimeDependency(Dependencies.JUNIT5_ENGINE_DEPENDENCY) .extraTestModule(Dependencies.MOCKITO_MODULE) .createJavaFile(regularJavaClass("AClass")) - .createJavaTestFile(junit5TestWithMocks()) } @IgnoreIf({NOT_JAVA_9}) @@ -53,6 +55,7 @@ class JUnit5TestSpec extends Specification { given: project .gradleJavaPlugin("java") + .createJavaTestFile(junit5TestWithMocks()) .createGradleBuild() .createModuleDescriptor() @@ -73,6 +76,51 @@ class JUnit5TestSpec extends Specification { given: project .gradleJavaPlugin("application") + .createJavaTestFile(junit5TestWithMocks()) + .createGradleBuild() + .createModuleDescriptor() + + when: + def result = GradleRunner.create() + .withProjectDir(tmpDir.root) + .withDebug(true) + .forwardOutput() + .withArguments("check") + .withPluginClasspath().build() + + then: + result.task(":junitPlatformTest").outcome == SUCCESS + } + + @IgnoreIf({NOT_JAVA_9}) + def "JUnit5 tests shall see the test resources loaded via classpath"() { + given: + project + .gradleJavaPlugin("java") + .createTestResourceFile(sampleTextResource()) + .createJavaTestFile(junit5TestAccessingResources()) + .createGradleBuild() + .createModuleDescriptor() + + when: + def result = GradleRunner.create() + .withProjectDir(tmpDir.root) + .withDebug(true) + .forwardOutput() + .withArguments("check") + .withPluginClasspath().build() + + then: + result.task(":junitPlatformTest").outcome == SUCCESS + } + + @IgnoreIf({NOT_JAVA_9}) + def "JUnit5 tests shall see the test resources loaded via modular path"() { + given: + project + .gradleJavaPlugin("java") + .createTestResourceFile(sampleTextResource()) + .createJavaTestFile(junit5TestAccessingModularResources()) .createGradleBuild() .createModuleDescriptor()