/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.test;
import juzu.impl.common.Resource;
import juzu.impl.common.Name;
import juzu.impl.compiler.CompilationError;
import juzu.impl.compiler.CompilationException;
import juzu.impl.compiler.Compiler;
import juzu.impl.fs.Filter;
import juzu.impl.fs.spi.filter.FilterFileSystem;
import juzu.impl.fs.spi.url.Node;
import juzu.impl.fs.spi.url.URLFileSystem;
import juzu.impl.metamodel.MetaModelProcessor;
import juzu.impl.fs.spi.ReadFileSystem;
import juzu.impl.fs.spi.ReadWriteFileSystem;
import juzu.impl.common.Tools;
import juzu.processor.MainProcessor;
import javax.annotation.processing.Processor;
import javax.inject.Provider;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.WeakHashMap;
/**
* Make compile assertion.
*
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
*/
public class CompilerAssert<I, O> {
public static final Provider<MetaModelProcessor> META_MODEL_PROCESSOR_FACTORY = new Provider<MetaModelProcessor>() {
public MetaModelProcessor get() {
return new MainProcessor();
}
};
/** A cache to speed up unit tests. */
private static WeakHashMap<ClassLoader, ReadFileSystem<Node>> classPathCache = new WeakHashMap<ClassLoader, ReadFileSystem<Node>>();
/** . */
private ClassLoader classLoader;
/** . */
private CompileStrategy<I, O> strategy;
public CompilerAssert(
boolean incremental,
ReadWriteFileSystem<I> sourcePath,
ReadWriteFileSystem<O> sourceOutput,
ReadWriteFileSystem<O> classOutput) {
//
ReadFileSystem<Node> classPath = classPathCache.get(Thread.currentThread().getContextClassLoader());
if (classPath == null) {
try {
classPathCache.put(
Thread.currentThread().getContextClassLoader(),
classPath = new URLFileSystem().add(Thread.currentThread().getContextClassLoader(), ClassLoader.getSystemClassLoader().getParent()));
}
catch (Exception e) {
throw AbstractTestCase.failure(e);
}
}
// Filter .java file as compiler may use it through classpath
classPath = new FilterFileSystem<Node>(classPath, new Filter<Node>() {
public boolean acceptDir(Node dir, String name) throws IOException {
return true;
}
public boolean acceptFile(Node file, String name) throws IOException {
return !name.endsWith(".java");
}
});
//
this.strategy = incremental ? new CompileStrategy.Incremental<I, O>(
sourcePath,
sourceOutput,
classOutput) : new CompileStrategy.Batch<I, O>(
classPath,
sourcePath,
sourceOutput,
classOutput);
//
this.strategy.addClassPath(classPath);
this.strategy.processorFactory = META_MODEL_PROCESSOR_FACTORY;
this.strategy.javaCompiler = JavaCompilerProvider.DEFAULT;
}
public CompilerAssert(
ReadWriteFileSystem<I> sourcePath,
ReadWriteFileSystem<O> sourceOutput,
ReadWriteFileSystem<O> classOutput) {
this(false, sourcePath, sourceOutput, classOutput);
}
public CompilerAssert(ReadWriteFileSystem<I> sourcePath, ReadWriteFileSystem<O> output) {
this(false, sourcePath, output, output);
}
public CompilerAssert(boolean incremental, ReadWriteFileSystem<I> sourcePath, ReadWriteFileSystem<O> output) {
this(incremental, sourcePath, output, output);
}
public CompilerAssert<I, O> with(final Processor processor) {
strategy.processorFactory = new Provider<Processor>() {
public Processor get() {
return processor;
}
};
return this;
}
public CompilerAssert<I, O> with(Provider<? extends Processor> processorFactory) {
strategy.processorFactory = processorFactory;
return this;
}
public CompilerAssert<I, O> with(JavaCompilerProvider javaCompilerProvider) {
strategy.javaCompiler = javaCompilerProvider;
return this;
}
public CompilerAssert<I, O> addClassPath(ReadFileSystem<?> classPath) {
strategy.addClassPath(classPath);
return this;
}
public ReadFileSystem<I> getSourcePath() {
return strategy.sourcePath;
}
public ReadWriteFileSystem<O> getClassOutput() {
return strategy.classOutput;
}
public ReadWriteFileSystem<O> getSourceOutput() {
return strategy.sourceOutput;
}
public CompilerAssert<I, O> formalErrorReporting() {
return formalErrorReporting(true);
}
public CompilerAssert<I, O> formalErrorReporting(boolean formalErrorReporting) {
if (formalErrorReporting) {
strategy.config.withProcessorOption("juzu.error_reporting", "formal");
}
else {
strategy.config.withProcessorOption("juzu.error_reporting", null);
}
return this;
}
public ClassLoader getClassLoader() {
return classLoader;
}
public List<CompilationError> failCompile() {
try {
strategy.compile();
throw AbstractTestCase.failure("Was expecting compilation to fail");
}
catch (CompilationException e) {
return e.getErrors();
}
catch (Exception e) {
throw AbstractTestCase.failure(e);
}
}
public Compiler assertCompile() {
try {
strategy.compile();
ArrayList<URL> urls = new ArrayList<URL>();
urls.add(strategy.classOutput.getURL());
Iterator<ReadFileSystem<?>> i = strategy.classPath.iterator(); // Skip the first one that is the context classloader
i.next();
while (i.hasNext()) {
urls.add(i.next().getURL());
}
classLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), Thread.currentThread().getContextClassLoader());
return strategy.compiler;
}
catch (Exception e) {
throw AbstractTestCase.failure(e);
}
}
public Class<?> assertClass(String className) {
try {
return classLoader.loadClass(className);
}
catch (ClassNotFoundException e) {
throw AbstractTestCase.failure(e);
}
}
public FileResource<I> assertSource(String name, String ext) {
I path;
try {
String[] atoms = Tools.split(name, '.');
atoms[atoms.length - 1] += "." + ext;
path = strategy.sourcePath.getPath(atoms);
if (path == null) {
throw AbstractTestCase.failure("Was not expecting " + Arrays.asList(name) + " to be null file");
}
return new FileResource<I>(strategy.sourcePath, path);
}
catch (IOException e) {
throw AbstractTestCase.failure(e);
}
}
public JavaFile<I> assertJavaSource(String name) {
FileResource<I> resource = assertSource(name, "java");
return new JavaFile<I>(resource);
}
public JavaFile<I> assertAddJavaSource(String name) {
Name n = Name.parse(name);
FileResource<I> source = assertAddSource(name, "java", "package " + n.getParent() + ";\npublic class " + n.getIdentifier() + " {}\n");
return new JavaFile<I>(source);
}
public FileResource<I> assertAddSource(String name, String ext, String content) {
try {
ReadWriteFileSystem<I> fs = strategy.sourcePath;
String[] atoms = Tools.split(name, '.');
I path;
if (atoms.length > 1) {
path = fs.makePath(Tools.iterable(atoms, 0, atoms.length - 1));
fs.createDir(path);
} else {
path = fs.getRoot();
}
path = fs.makePath(path, atoms[atoms.length - 1] + "." + ext);
fs.updateResource(path, new Resource(content));
return new FileResource<I>(fs, path);
}
catch (IOException e) {
throw AbstractTestCase.failure(e);
}
}
public void assertRemoveSource(String name) {
try {
I path = strategy.sourcePath.getPath(name);
if (path == null) {
throw AbstractTestCase.failure("Cannot remove path " + Tools.join('/', name));
}
strategy.sourcePath.removePath(path);
}
catch (Exception e) {
throw AbstractTestCase.failure(e);
}
}
}