Repository: geode Updated Branches: refs/heads/release/1.2.1 ce3ed8ace -> aa36d3c3c
GEODE-3313: Test utility supports building jar files with multiple classes (cherry picked from commit 06b839c) Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/df954000 Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/df954000 Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/df954000 Branch: refs/heads/release/1.2.1 Commit: df95400032a08040a7b71f0d8d3752fedc9b04c8 Parents: ce3ed8a Author: Jared Stewart <[email protected]> Authored: Tue Aug 8 10:11:07 2017 -0700 Committer: Jared Stewart <[email protected]> Committed: Mon Aug 21 11:43:27 2017 -0700 ---------------------------------------------------------------------- geode-junit/build.gradle | 6 +- .../geode/test/compiler/ClassNameExtractor.java | 33 +++++ .../geode/test/compiler/CompiledSourceCode.java | 35 ++++++ .../apache/geode/test/compiler/JarBuilder.java | 120 ++++++++++++++++++ .../geode/test/compiler/JavaCompiler.java | 123 ++++++++++++++++++ .../test/compiler/UncompiledSourceCode.java | 71 +++++++++++ .../test/compiler/ClassNameExtractorTest.java | 54 ++++++++ .../geode/test/compiler/JarBuilderTest.java | 126 +++++++++++++++++++ .../geode/test/compiler/JavaCompilerTest.java | 78 ++++++++++++ .../test/compiler/UncompiledSourceCodeTest.java | 43 +++++++ .../geode/test/compiler/AbstractClass.java | 18 +++ .../geode/test/compiler/ConcreteClass.java | 19 +++ 12 files changed, 725 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/build.gradle ---------------------------------------------------------------------- diff --git a/geode-junit/build.gradle b/geode-junit/build.gradle index e47095f..7c533ad 100755 --- a/geode-junit/build.gradle +++ b/geode-junit/build.gradle @@ -19,7 +19,11 @@ dependencies { compile 'com.jayway.jsonpath:json-path:' + project.'json-path.version' testCompile 'commons-lang:commons-lang:' + project.'commons-lang.version' testCompile 'com.google.guava:guava:' + project.'guava.version' - testCompile 'org.assertj:assertj-core:' + project.'assertj-core.version' + compile 'org.assertj:assertj-core:' + project.'assertj-core.version' + compile 'commons-io:commons-io:' + project.'commons-io.version' + compile 'commons-lang:commons-lang:' + project.'commons-lang.version' + compile 'com.google.guava:guava:' + project.'guava.version' + compile('junit:junit:' + project.'junit.version') { exclude module: 'hamcrest-core' http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java new file mode 100644 index 0000000..c48224c --- /dev/null +++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ClassNameExtractor { + private static final Pattern EXTRACT_CLASS_NAME_REGEX = + Pattern.compile("(?:public|private|protected)* *(?:abstract)* *(?:class|interface) +(\\w+)"); + + public String extractFromSourceCode(String sourceCode) { + Matcher m = EXTRACT_CLASS_NAME_REGEX.matcher(sourceCode); + if (m.find()) { + return m.group(1); + } else { + throw new IllegalArgumentException( + String.format("Unable to parse class or interface name from: \n'%s'", sourceCode)); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java new file mode 100644 index 0000000..c1bfa3d --- /dev/null +++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +public class CompiledSourceCode { + + /** + * Fully qualified classname in a format suitable for Class.forName + */ + public String className; + + public byte[] compiledBytecode; + + public CompiledSourceCode(String className, byte[] aBytes) { + this.className = className.replace('/', '.'); + this.compiledBytecode = aBytes; + } + + @Override + public String toString() { + return className; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java new file mode 100644 index 0000000..bd9222e --- /dev/null +++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; + + +/** + * This class accepts java source code in the format of .java source files or strings containing the + * contents of .java source files, and compiles the given source code into a jar file specified by + * the user. + * + * <p> + * Example of usage: + * + * <pre> + * @Rule + * public TemporaryFolder temporaryFolder= new TemporaryFolder(); + * + * @Test + * public void buildJarUsingStrings() { + * File tempDir = temporaryFolder.getRoot() + * JarBuilder jarBuilder = new JarBuilder(tempDir); + * File outputJar = new File("output.jar"); + * + * String classInFooBarPackage = "package foo.bar; public class ClassA {int n = 10;}"; + * String classInDefaultPackage = "public class ClassB {}"; + * jarBuilder.buildJar(outputJar, classInFooBarPackage, classInDefaultPackage); + * } + * + * @Test + * public void buildJarUsingFiles() { + * File tempDir = temporaryFolder.getRoot() + * JarBuilder jarBuilder = new JarBuilder(tempDir); + * File outputJar = new File("output.jar"); + * + * File sourceFileOne = new File("ClassA.java"); + * File sourceFileTwo = new File("ClassB.java"); + * jarBuilder.buildJar(outputJar, sourceFileOne, sourceFileTwo); + * } + * + * @Test + * public void buildJarUsingClassNames() { + * File tempDir = temporaryFolder.getRoot() + * JarBuilder jarBuilder = new JarBuilder(tempDir); + * File outputJar = new File("output.jar"); + * + * String classInFooBarPackage = "foo.bar.ClassInFooBarPackage"; + * String classInDefaultPackage = "ClassInDefaultPackage"; + * jarBuilder.buildJar(outputJar, classInFooBarPackage, classInDefaultPackage); + * } + * </pre> + **/ +public class JarBuilder { + private final JavaCompiler javaCompiler = new JavaCompiler(); + + public void buildJarFromClassNames(File outputJarFile, String... classNames) throws IOException { + UncompiledSourceCode[] uncompiledSourceCodes = Arrays.stream(classNames) + .map(UncompiledSourceCode::fromClassName).toArray(UncompiledSourceCode[]::new); + + List<CompiledSourceCode> compiledSourceCodes = javaCompiler.compile(uncompiledSourceCodes); + + buildJar(outputJarFile, compiledSourceCodes); + } + + public void buildJar(File outputJarFile, String... sourceFileContents) throws IOException { + List<CompiledSourceCode> compiledSourceCodes = javaCompiler.compile(sourceFileContents); + + buildJar(outputJarFile, compiledSourceCodes); + } + + public void buildJar(File outputJarFile, File... sourceFiles) throws IOException { + List<CompiledSourceCode> compiledSourceCodes = javaCompiler.compile(sourceFiles); + + buildJar(outputJarFile, compiledSourceCodes); + } + + private void buildJar(File outputJarFile, List<CompiledSourceCode> compiledSourceCodes) + throws IOException { + assertThat(outputJarFile).doesNotExist(); + + try (FileOutputStream outputStream = new FileOutputStream(outputJarFile)) { + JarOutputStream jarOutputStream = new JarOutputStream(outputStream); + for (CompiledSourceCode compiledSource : compiledSourceCodes) { + + String formattedName = compiledSource.className.replace(".", "/"); + if (!formattedName.endsWith(".class")) { + formattedName = formattedName.concat(".class"); + } + + JarEntry entry = new JarEntry(formattedName); + entry.setTime(System.currentTimeMillis()); + jarOutputStream.putNextEntry(entry); + jarOutputStream.write(compiledSource.compiledBytecode); + jarOutputStream.closeEntry(); + } + jarOutputStream.close(); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java new file mode 100644 index 0000000..8449605 --- /dev/null +++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import static java.util.stream.Collectors.toList; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import javax.tools.ToolProvider; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; +import org.apache.commons.io.FileUtils; + + +public class JavaCompiler { + private File tempDir; + + public JavaCompiler() { + this.tempDir = Files.createTempDir(); + tempDir.deleteOnExit(); + } + + public List<CompiledSourceCode> compile(File... sourceFiles) throws IOException { + String[] sourceFileContents = + Arrays.stream(sourceFiles).map(this::readFileToString).toArray(String[]::new); + + return compile(sourceFileContents); + } + + public List<CompiledSourceCode> compile(String... sourceFileContents) throws IOException { + UncompiledSourceCode[] uncompiledSourceCodes = Arrays.stream(sourceFileContents) + .map(UncompiledSourceCode::fromSourceCode).toArray(UncompiledSourceCode[]::new); + + return compile(uncompiledSourceCodes); + } + + public List<CompiledSourceCode> compile(UncompiledSourceCode... uncompiledSources) + throws IOException { + File temporarySourcesDirectory = createSubdirectory(tempDir, "sources"); + File temporaryClassesDirectory = createSubdirectory(tempDir, "classes"); + + List<String> options = Stream.of("-d", temporaryClassesDirectory.getAbsolutePath(), + "-classpath", System.getProperty("java.class.path")).collect(toList()); + + try { + for (UncompiledSourceCode sourceCode : uncompiledSources) { + File sourceFile = new File(temporarySourcesDirectory, sourceCode.simpleClassName + ".java"); + FileUtils.writeStringToFile(sourceFile, sourceCode.sourceCode, Charsets.UTF_8); + options.add(sourceFile.getAbsolutePath()); + } + + int exitCode = ToolProvider.getSystemJavaCompiler().run(System.in, System.out, System.err, + options.toArray(new String[] {})); + + if (exitCode != 0) { + throw new RuntimeException( + "Unable to compile the given source code. See System.err for details."); + } + + List<CompiledSourceCode> compiledSourceCodes = new ArrayList<>(); + addCompiledClasses(compiledSourceCodes, "", temporaryClassesDirectory); + return compiledSourceCodes; + } finally { + FileUtils.deleteDirectory(temporaryClassesDirectory); + } + } + + private static void addCompiledClasses(List<CompiledSourceCode> ret, String pkgName, File dir) + throws IOException { + for (File file : dir.listFiles()) { + String filename = file.getName(); + + if (file.isDirectory()) { + String qname = pkgName + filename + "."; + addCompiledClasses(ret, qname, file); + } else if (filename.endsWith(".class")) { + String qname = pkgName + filename.substring(0, filename.length() - 6); + ret.add(new CompiledSourceCode(qname, FileUtils.readFileToByteArray(file))); + } else { + System.err.println("Unexpected file : " + file.getAbsolutePath()); + } + } + } + + private File createSubdirectory(File parent, String directoryName) { + File subdirectory = parent.toPath().resolve(directoryName).toFile(); + if (!subdirectory.exists()) { + subdirectory.mkdirs(); + } + + if (!subdirectory.exists() || !subdirectory.isDirectory()) { + throw new IllegalArgumentException("Invalid directory" + subdirectory.getAbsolutePath()); + } + + return subdirectory; + } + + private String readFileToString(File file) { + try { + return FileUtils.readFileToString(file, Charsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java new file mode 100644 index 0000000..4161f5e --- /dev/null +++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.SystemUtils; + +public class UncompiledSourceCode { + public String simpleClassName; + public String sourceCode; + + private UncompiledSourceCode(String simpleClassName, String sourceCode) { + this.simpleClassName = simpleClassName; + this.sourceCode = sourceCode; + } + + public static UncompiledSourceCode fromSourceCode(String sourceCode) { + String simpleClassName = new ClassNameExtractor().extractFromSourceCode(sourceCode); + return new UncompiledSourceCode(simpleClassName, sourceCode); + } + + public static UncompiledSourceCode fromClassName(String fullyQualifiedClassName) { + ClassNameWithPackage classNameWithPackage = ClassNameWithPackage.of(fullyQualifiedClassName); + boolean isPackageSpecified = StringUtils.isNotBlank(classNameWithPackage.packageName); + + StringBuilder sourceCode = new StringBuilder(); + if (isPackageSpecified) { + sourceCode.append(String.format("package %s;", classNameWithPackage.packageName)); + sourceCode.append(SystemUtils.LINE_SEPARATOR); + } + + sourceCode.append(String.format("public class %s {}", classNameWithPackage.simpleClassName)); + + return new UncompiledSourceCode(classNameWithPackage.simpleClassName, sourceCode.toString()); + } + + private static class ClassNameWithPackage { + String packageName; + String simpleClassName; + + static ClassNameWithPackage of(String fqClassName) { + int indexOfLastDot = fqClassName.lastIndexOf("."); + + if (indexOfLastDot == -1) { + return new ClassNameWithPackage("", fqClassName); + } else { + String specifiedPackage = fqClassName.substring(0, indexOfLastDot); + String simpleClassName = fqClassName.substring(indexOfLastDot + 1); + + return new ClassNameWithPackage(specifiedPackage, simpleClassName); + } + } + + private ClassNameWithPackage(String packageName, String simpleClassName) { + this.packageName = packageName; + this.simpleClassName = simpleClassName; + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java new file mode 100644 index 0000000..db060f8 --- /dev/null +++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; +import org.assertj.core.api.SoftAssertions; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.UnitTest; + +@Category(UnitTest.class) +public class ClassNameExtractorTest { + private static final String SPACE = " "; + private static final String CLASS_NAME_TO_FIND = "MyClassNameToFind"; + + @Test + public void extractsClassNames() throws Exception { + SoftAssertions softAssertions = new SoftAssertions(); + ClassNameExtractor classNameExtractor = new ClassNameExtractor(); + + Set<List<String>> permutationsToTest = Sets.cartesianProduct( + ImmutableSet.of("public ", "private ", "protected ", ""), ImmutableSet.of("abstract ", ""), + ImmutableSet.of("static ", ""), ImmutableSet.of("class ", "interface "), + ImmutableSet.of("extends Foo ", ""), ImmutableSet.of("implements Bar ", "")); + + for (List<String> permutation : permutationsToTest) { + String firstLineOfSource = + permutation.get(0) + permutation.get(1) + permutation.get(2) + permutation.get(3) + + CLASS_NAME_TO_FIND + SPACE + permutation.get(4) + permutation.get(5) + " {"; + + String className = classNameExtractor.extractFromSourceCode(firstLineOfSource); + softAssertions.assertThat(className).isEqualTo(CLASS_NAME_TO_FIND); + } + + softAssertions.assertAll(); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java new file mode 100644 index 0000000..a718fde --- /dev/null +++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import static java.util.stream.Collectors.toSet; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.test.junit.categories.IntegrationTest; + +@Category(IntegrationTest.class) +public class JarBuilderTest { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private JarBuilder jarBuilder; + private File outputJar; + + @Before + public void setup() { + jarBuilder = new JarBuilder(); + outputJar = new File(temporaryFolder.getRoot(), "output.jar"); + } + + @Test + public void jarWithSingleClass() throws Exception { + File classContents = loadTestResource("AbstractClass.java"); + jarBuilder.buildJar(outputJar, classContents); + + Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar); + assertThat(jarEntryNames) + .containsExactlyInAnyOrder("org/apache/geode/test/compiler/AbstractClass.class"); + } + + @Test + public void jarWithTwoDependentClasses() throws Exception { + File sourceFileOne = loadTestResource("AbstractClass.java"); + File sourceFileTwo = loadTestResource("ConcreteClass.java"); + + jarBuilder.buildJar(outputJar, sourceFileOne, sourceFileTwo); + + Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar); + + assertThat(jarEntryNames).containsExactlyInAnyOrder( + "org/apache/geode/test/compiler/AbstractClass.class", + "org/apache/geode/test/compiler/ConcreteClass.class"); + } + + @Test + public void jarWithClassInDefaultPackage() throws Exception { + String classInFooBarPackage = "package foo.bar; public class ClassInFooBarPackage {}"; + String classInDefaultPackage = "public class ClassInDefaultPackage {}"; + jarBuilder.buildJar(outputJar, classInFooBarPackage, classInDefaultPackage); + + Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar); + assertThat(jarEntryNames).containsExactlyInAnyOrder("ClassInDefaultPackage.class", + "foo/bar/ClassInFooBarPackage.class"); + } + + + @Test + public void jarFromOnlyClassNames() throws Exception { + String defaultPackageClassName = "DefaultClass"; + String otherPackageClassName = "foo.bar.OtherClass"; + jarBuilder.buildJarFromClassNames(outputJar, defaultPackageClassName, otherPackageClassName); + + Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar); + assertThat(jarEntryNames).containsExactlyInAnyOrder("DefaultClass.class", + "foo/bar/OtherClass.class"); + } + + @Test + public void canLoadClassesFromJar() throws Exception { + String defaultPackageClassName = "DefaultClass"; + String otherPackageClassName = "foo.bar.OtherClass"; + jarBuilder.buildJarFromClassNames(outputJar, defaultPackageClassName, otherPackageClassName); + + URLClassLoader jarClassLoader = new URLClassLoader(new URL[] {outputJar.toURL()}); + + jarClassLoader.loadClass("DefaultClass"); + jarClassLoader.loadClass("foo.bar.OtherClass"); + } + + private Set<String> jarEntryNamesFromFile(File jarFile) throws Exception { + assertThat(jarFile).exists(); + + Enumeration<JarEntry> jarEntries = new JarFile(jarFile).entries(); + return Collections.list(jarEntries).stream().map(JarEntry::getName).collect(toSet()); + } + + private File loadTestResource(String fileName) throws URISyntaxException { + URL resourceFileURL = this.getClass().getResource(fileName); + assertThat(resourceFileURL).isNotNull(); + + URI resourceUri = resourceFileURL.toURI(); + return new File(resourceUri); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java new file mode 100644 index 0000000..b306511 --- /dev/null +++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; + +import org.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.test.junit.categories.IntegrationTest; + +@Category(IntegrationTest.class) +public class JavaCompilerTest { + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void compileSingleClass() throws Exception { + File implementsFunctionSourceFile = getFileFromTestResources("AbstractClass.java"); + String classContents = FileUtils.readFileToString(implementsFunctionSourceFile, "UTF-8"); + + List<CompiledSourceCode> compiledSourceCodes = new JavaCompiler().compile(classContents); + + assertThat(compiledSourceCodes).hasSize(1); + } + + @Test + public void compileTwoDependentClasses() throws Exception { + File sourceFileOne = getFileFromTestResources("AbstractClass.java"); + File sourceFileTwo = getFileFromTestResources("ConcreteClass.java"); + + List<CompiledSourceCode> compiledSourceCodes = + new JavaCompiler().compile(sourceFileOne, sourceFileTwo); + + assertThat(compiledSourceCodes).hasSize(2); + } + + @Test + public void invalidSourceThrowsException() throws Exception { + JavaCompiler javaCompiler = new JavaCompiler(); + String sourceCode = "public class foo {this is not valid java source code}"; + assertThatThrownBy(() -> javaCompiler.compile(sourceCode)).isInstanceOf(Exception.class); + } + + private File getFileFromTestResources(String fileName) throws URISyntaxException { + URL resourceFileURL = this.getClass().getResource(fileName); + assertThat(resourceFileURL).isNotNull(); + + URI resourceUri = resourceFileURL.toURI(); + File file = new File(resourceUri); + + assertThat(file).exists(); + return file; + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java new file mode 100644 index 0000000..9db2808 --- /dev/null +++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.commons.lang.SystemUtils; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.UnitTest; + +@Category(UnitTest.class) +public class UncompiledSourceCodeTest { + @Test + public void fromClassNameWithNoPackage() throws Exception { + UncompiledSourceCode uncompiledSourceCode = UncompiledSourceCode.fromClassName("NoPackage"); + assertThat(uncompiledSourceCode.simpleClassName).isEqualTo("NoPackage"); + assertThat(uncompiledSourceCode.sourceCode).isEqualTo("public class NoPackage {}"); + } + + @Test + public void fromClassNameWithPackage() throws Exception { + UncompiledSourceCode uncompiledSourceCode = + UncompiledSourceCode.fromClassName("foo.bar.ClassName"); + assertThat(uncompiledSourceCode.simpleClassName).isEqualTo("ClassName"); + assertThat(uncompiledSourceCode.sourceCode) + .isEqualTo("package foo.bar;" + SystemUtils.LINE_SEPARATOR + "public class ClassName {}"); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java b/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java new file mode 100644 index 0000000..24ed0c6 --- /dev/null +++ b/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + +public abstract class AbstractClass { +} http://git-wip-us.apache.org/repos/asf/geode/blob/df954000/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java ---------------------------------------------------------------------- diff --git a/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java b/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java new file mode 100644 index 0000000..bf98672 --- /dev/null +++ b/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java @@ -0,0 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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.apache.geode.test.compiler; + + +public class ConcreteClass extends AbstractClass { +}
