package org.smoothbuild.acceptance.builtin.java; import static org.hamcrest.Matchers.containsString; import static org.smoothbuild.util.Streams.inputStreamToByteArray; import static org.testory.Testory.then; import static org.testory.Testory.thenEqual; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import org.junit.Test; import org.smoothbuild.acceptance.AcceptanceTestCase; public class JavacTest extends AcceptanceTestCase { @Test public void error_is_logged_when_compilation_error_occurs() throws Exception { givenFile("MyClass.java", "public private class MyClass {}"); givenScript("result: [file('//MyClass.java')] | javac;"); whenSmoothBuild("result"); thenFinishedWithError(); then(output(), containsString("modifier private not allowed here")); } @Test public void zero_files_can_be_compiled() throws Exception { givenScript("result: [] | javac;"); whenSmoothBuild("result"); thenFinishedWithSuccess(); then(output(), containsString("Param 'sources' is empty list.")); } @Test public void one_file_can_be_compiled() throws Exception { givenFile("MyClass.java", "public class MyClass {\n" + "public static String myMethod() {return \"test-string\";}}"); givenScript("result: [file('//MyClass.java')] | javac;"); whenSmoothBuild("result"); thenFinishedWithSuccess(); thenEqual("test-string", invoke(new File(artifact("result"), "MyClass.class"), "myMethod")); } @Test public void one_file_with_library_dependency_can_be_compiled() throws Exception { StringBuilder classSource = new StringBuilder(); classSource.append("import library.LibraryClass;"); classSource.append("public class MyClass {"); classSource.append(" public static String myMethod() {"); classSource.append(" return Integer.toString(LibraryClass.add(2, 3));"); classSource.append(" }"); classSource.append("}"); StringBuilder librarySource = new StringBuilder(); librarySource.append("package library;"); librarySource.append("public class LibraryClass {"); librarySource.append(" public static int add(int a, int b) {"); librarySource.append(" return a + b;"); librarySource.append(" }"); librarySource.append("}"); givenFile("src/MyClass.java", classSource.toString()); givenFile("srclib/library/LibraryClass.java", librarySource.toString()); givenScript("libraryJar: files('//srclib') | javac | jar;" + "result: files('//src') | javac(libs=[libraryJar])" + " | concatenateFileArrays(with=javac(files('//srclib')));"); whenSmoothBuild("result"); thenFinishedWithSuccess(); File libraryClassFile = new File(artifact("result"), "library/LibraryClass.class"); File classFile = new File(artifact("result"), "MyClass.class"); MyClassLoader classLoader = new MyClassLoader(); loadClass(classLoader, byteCode(libraryClassFile)); thenEqual("5", invoke(classLoader, classFile, "myMethod")); } @Test public void duplicate_java_files_cause_error() throws Exception { givenFile("MyClass.java", "public class MyClass {}"); givenScript("result: [file('//MyClass.java'), file('//MyClass.java')] | javac;"); whenSmoothBuild("result"); thenFinishedWithError(); then(output(), containsString("duplicate class: MyClass")); } @Test public void illegal_source_parameter_causes_error() throws Exception { givenFile("MyClass.java", "public class MyClass {}"); givenScript("result: [file('//MyClass.java')] | javac(source='0.9');"); whenSmoothBuild("result"); thenFinishedWithError(); then(output(), containsString("Parameter source has illegal value = '0.9'.")); } @Test public void illegal_target_parameter_causes_error() throws Exception { givenFile("MyClass.java", "public class MyClass {}"); givenScript("result: [file('//MyClass.java')] | javac(target='0.9');"); whenSmoothBuild("result"); thenFinishedWithError(); then(output(), containsString("Parameter target has illegal value = '0.9'.")); } @Test public void compiling_enum_with_source_parameter_set_to_too_old_java_version_causes_error() throws Exception { givenFile("MyClass.java", "public enum MyClass { VALUE }"); givenScript("result: [file('//MyClass.java')] | javac(source='1.4', target='1.4');"); whenSmoothBuild("result"); thenFinishedWithError(); then(output(), containsString("enums are not supported in -source 1.4")); } private Object invoke(File appClassFile, String method) throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { return invoke(new MyClassLoader(), appClassFile, method); } private Object invoke(MyClassLoader classLoader, File appClassFile, String method) throws IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Class<?> klass = loadClass(classLoader, byteCode(appClassFile)); return klass.getMethod(method).invoke(null); } private byte[] byteCode(File classFilePath) throws IOException { return inputStreamToByteArray(new FileInputStream(classFilePath)); } private Class<?> loadClass(MyClassLoader classLoader, byte[] bytes) { return classLoader.defineClass(null, bytes); } private static class MyClassLoader extends ClassLoader { public Class<?> defineClass(String name, byte[] bytes) { return super.defineClass(name, bytes, 0, bytes.length); } } }