/*******************************************************************************
* Copyright (c) 2012 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.xpect.runner;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.emf.common.util.URI;
import org.xpect.runner.XpectTestFiles.XpectTestFileCollector;
import org.xpect.util.IBundleInfo;
import org.xpect.util.IBundleInfo.Context;
import org.xpect.util.IBundleInfo.Registry;
import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
/**
* @author Moritz Eysholdt - Initial contribution and API
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@XpectURIProvider(XpectTestFileCollector.class)
public @interface XpectTestFiles {
static class Builder implements XpectTestFiles {
private String baseDir = "";
private List<String> files = Lists.newArrayList();
private FileRoot relativeTo = FileRoot.CLASS;
public Builder addFile(String file) {
this.files.add(file);
return this;
}
public Class<? extends Annotation> annotationType() {
return XpectTestFiles.class;
}
public String baseDir() {
return baseDir;
}
public IXpectURIProvider create(Class<?> owner) {
return new XpectTestFileCollector(owner, this);
}
public String[] fileExtensions() {
return new String[] { "xt" };
}
public String[] files() {
return files.toArray(new String[files.size()]);
}
public FileRoot relativeTo() {
return relativeTo;
}
public Builder relativeTo(FileRoot relativeTo) {
this.relativeTo = relativeTo;
return this;
}
public Builder withBaseDir(String baseDir) {
this.baseDir = baseDir;
return this;
}
}
public static enum FileRoot {
CLASS, CURRENT, PROJECT, SOURCE
}
public static class XpectTestFileCollector implements IXpectURIProvider {
protected final XpectTestFiles ctx;
protected final Class<?> owner;
protected IBundleInfo project;
protected XpectTestFileCollector(Class<?> owner, XpectTestFiles ctx) {
this.owner = owner;
this.ctx = ctx;
}
protected URI createURI(File file) {
return URI.createFileURI(file.getAbsolutePath());
}
public URI deresolveToProject(URI uri) {
return uri.deresolve(getBundle().getRootURI());
}
public Collection<URI> getAllURIs() {
IBundleInfo bundle = getBundle();
Context context = getContext();
List<URI> result = Lists.newArrayList();
String localPath = getLocalPath();
if (ctx.files().length == 0) {
result.addAll(bundle.find(context, localPath, Predicates.<String> alwaysTrue(), ctx.fileExtensions()));
} else {
for (String file : ctx.files()) {
if (!Strings.isNullOrEmpty(localPath))
file = localPath + "/" + file;
result.add(bundle.find(context, file));
}
}
return result;
}
protected IBundleInfo getBundle() {
Registry registry = IBundleInfo.Registry.INSTANCE;
if (ctx.relativeTo() == FileRoot.CURRENT)
return registry.getBundle(URI.createFileURI(new File(".").getAbsoluteFile().getParent()));
return getProject();
}
protected IBundleInfo.Context getContext() {
switch (ctx.relativeTo()) {
case SOURCE:
case CLASS:
return Context.SOURCE;
case PROJECT:
case CURRENT:
return Context.ROOT;
}
return Context.ROOT;
}
protected String getLocalPath() {
List<String> segments = Lists.newArrayList();
if (ctx.relativeTo() == FileRoot.CLASS)
Collections.addAll(segments, owner.getPackage().getName().split("\\."));
if (!Strings.isNullOrEmpty(ctx.baseDir()))
Collections.addAll(segments, ctx.baseDir().split("/"));
return Joiner.on('/').join(segments);
}
protected IBundleInfo getProject() {
if (project == null)
project = IBundleInfo.Registry.INSTANCE.getBundle(owner);
return project;
}
protected URI resolvePlatformResourceURI(URI uri) {
List<String> segments = uri.segmentsList();
if (segments.size() < 2)
throw new RuntimeException("URI " + uri + " has an invalid format");
String symbolicName = segments.get(1);
IBundleInfo bundle = IBundleInfo.Registry.INSTANCE.getBundle(symbolicName);
if (bundle == null)
throw new RuntimeException("Bundle " + symbolicName + " not found.");
URI uriInBundle = URI.createURI(Joiner.on('/').join(segments.subList(2, segments.size())));
return uriInBundle.resolve(bundle.getRootURI());
}
protected URI resolveProjectRelativeURI(URI uri) {
List<String> segments = uri.segmentsList();
URI uriInProject = URI.createURI(Joiner.on('/').join(segments));
return uriInProject.resolve(getProject().getRootURI());
}
public URI resolveURI(URI base, String newURI) {
URI uri = URI.createURI(newURI);
if (uri.isPlatformResource())
return resolvePlatformResourceURI(uri);
if (uri.hasAbsolutePath())
return resolveProjectRelativeURI(uri);
return uri.resolve(base);
}
@Override
public String toString() {
List<String> items = Lists.newArrayList();
items.add("relativeTo=" + ctx.relativeTo().name());
if (ctx.files().length > 0)
items.add("files=" + Joiner.on(",").join(ctx.files()));
if (!Strings.isNullOrEmpty(ctx.baseDir()))
items.add("baseDir=" + ctx.baseDir());
items.add("fileExtensions=" + Joiner.on(",").join(ctx.fileExtensions()));
return "@" + XpectTestFiles.class.getSimpleName() + "(" + Joiner.on(", ").join(items) + ")";
}
}
String baseDir() default "";
String[]fileExtensions() default { "xt", "xpect" };
String[]files() default {};
FileRoot relativeTo() default FileRoot.CLASS;
}