package com.sora.util.akatsuki; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; import javax.tools.JavaFileObject; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.sora.util.akatsuki.CompilerUtils.Result; public abstract class BaseTestEnvironment implements TestEnvironment { public static final Pattern NEW_LINE_PATTERN = Pattern.compile("\\r?\\n"); protected final List<TestSource> sources; private final Result result; public BaseTestEnvironment(IntegrationTestBase base, List<TestSource> sources) { this.sources = Collections.unmodifiableList(sources); try { // find all top level classes JavaFileObject[] javaFileObjects = sources.stream().filter(TestSource::toplevel) .map(TestSource::generateFileObject).toArray(JavaFileObject[]::new); result = CompilerUtils.compile(Thread.currentThread().getContextClassLoader(), base.processors(), ImmutableList.of("-Aakatsuki.loggingLevel=VERBOSE"), javaFileObjects); if (result.compilationException != null) throw result.compilationException; } catch (Exception e) { throw new RuntimeException("Compilation was unsuccessful." + printReport(), e); } System.out.println(printReport()); initialize(); } public BaseTestEnvironment(IntegrationTestBase base, TestSource source, TestSource... required) { this(base, Lists.asList(source, required)); } private void initialize() { try { setupTestEnvironment(); } catch (Exception e) { throw new RuntimeException( "Compilation was successful but an error occurred while setting up the test " + "environment." + printReport(), e); } } protected abstract void setupTestEnvironment() throws Exception; public Class<?> findClass(String className) throws ClassNotFoundException { return result.classLoader.loadClass(className); } public ClassLoader classLoader() { return result.classLoader; } public ImmutableList<JavaFileObject> generatedSources() { return result.sources; } public Class<?>[] sourceClasses() throws Exception { return sources.stream().map(s -> { try { return findClass(s.fqcn()); } catch (ClassNotFoundException e) { // damn lambda throw new RuntimeException(e); } }).toArray(Class[]::new); } @Override public String printReport() { try { StringBuilder builder = new StringBuilder("\n=======Test status report======="); builder.append("\n\u2022Compiler Input:\n"); for (TestSource source : sources) { builder.append("\n\tFully qualified name: ").append(source.fqcn()).append("\n"); final String sourceCode = source.generateSource(); final String[] lines = NEW_LINE_PATTERN.split(sourceCode); String format = String.format("%%0%dd", String.valueOf(lines.length).length()); for (int i = 0; i < lines.length; i++) { builder.append("\t\t").append(String.format(format, i + 1)).append('.') .append(lines[i]); if (i != lines.length - 1) builder.append("\n"); } } builder.append("\n\u2022Annotation processor output:"); if (result == null || result.sources.isEmpty()) { builder.append("\n\tNo sources generated."); } else { builder.append(result.printGeneratedSources("\t")); } return builder.toString(); } catch (Exception e) { return "[Unable to print report for sources:" + sources + " due to exception: " + Throwables.getStackTraceAsString(e) + "]"; } } }