package com.redhat.ceylon.test.eclipse.plugin.util;
import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getProjectDeclaredSourceModules;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TEST;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TESTS;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TESTS_ERROR;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TESTS_FAILED;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TESTS_SKIPPED;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TESTS_RUNNING;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TESTS_SUCCESS;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TEST_ERROR;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TEST_FAILED;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TEST_SKIPPED;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TEST_RUNNING;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.TEST_SUCCESS;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestImageRegistry.getImage;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestPlugin.CEYLON_TEST_MODULE_NAME;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestPlugin.LAUNCH_CONFIG_TYPE;
import static com.redhat.ceylon.test.eclipse.plugin.CeylonTestPlugin.LAUNCH_CONFIG_TYPE_JS;
import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import com.redhat.ceylon.common.Backend;
import com.redhat.ceylon.eclipse.core.builder.CeylonNature;
import com.redhat.ceylon.model.typechecker.model.Annotation;
import com.redhat.ceylon.model.typechecker.model.Class;
import com.redhat.ceylon.model.typechecker.model.ClassOrInterface;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Function;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.ModuleImport;
import com.redhat.ceylon.model.typechecker.model.Package;
import com.redhat.ceylon.model.typechecker.model.Type;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.Value;
import com.redhat.ceylon.test.eclipse.plugin.CeylonTestPlugin;
import com.redhat.ceylon.test.eclipse.plugin.model.TestElement;
public class CeylonTestUtil {
private static final String CEYLON_FILE_EXTENSION = "ceylon";
private static final NumberFormat ELAPSED_TIME_FORMAT;
static {
ELAPSED_TIME_FORMAT = NumberFormat.getNumberInstance();
ELAPSED_TIME_FORMAT.setGroupingUsed(true);
ELAPSED_TIME_FORMAT.setMinimumFractionDigits(3);
ELAPSED_TIME_FORMAT.setMaximumFractionDigits(3);
ELAPSED_TIME_FORMAT.setMinimumIntegerDigits(1);
}
public static Display getDisplay() {
Display display= Display.getCurrent();
if (display == null) {
display= Display.getDefault();
}
return display;
}
public static IWorkspaceRoot getWorkspaceRoot() {
return ResourcesPlugin.getWorkspace().getRoot();
}
public static IWorkbenchWindow getActiveWorkbenchWindow() {
return CeylonTestPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow();
}
public static IWorkbenchPage getActivePage() {
IWorkbenchWindow activeWorkbenchWindow = getActiveWorkbenchWindow();
if (activeWorkbenchWindow != null) {
return activeWorkbenchWindow.getActivePage();
}
return null;
}
public static Shell getShell() {
IWorkbenchWindow activeWorkbenchWindow = getActiveWorkbenchWindow();
if (activeWorkbenchWindow != null) {
return activeWorkbenchWindow.getShell();
}
return null;
}
public static List<IProject> getProjects() {
List<IProject> ceylonProjects = new ArrayList<IProject>();
IProject[] projects = getWorkspaceRoot().getProjects();
if (projects != null) {
for (IProject project : projects) {
if (isCeylonProject(project)) {
ceylonProjects.add(project);
}
}
}
return ceylonProjects;
}
public static IProject getProject(String projectName) {
List<IProject> projects = getProjects();
for (IProject project : projects) {
if (project.getName().equals(projectName)) {
return project;
}
}
return null;
}
public static IProject getProject(ILaunch launch) throws CoreException {
ILaunchConfiguration launchConfiguration = launch.getLaunchConfiguration();
String projectName = launchConfiguration.getAttribute(ATTR_PROJECT_NAME, (String) null);
return getProject(projectName);
}
public static Module getModule(IProject project, String moduleName) {
for (Module module : getProjectDeclaredSourceModules(project)) {
if (module.getNameAsString().equals(moduleName)) {
return module;
}
}
return null;
}
public static Package getPackage(IProject project, String pkgName) {
for (Module module : getProjectDeclaredSourceModules(project)) {
Package pkg = module.getDirectPackage(pkgName);
if (pkg != null) {
return pkg;
}
}
return null;
}
public static Object getPackageOrDeclaration(IProject project, String qualifiedName) {
Object result = null;
String pkgName = null;
int pkgSepIndex = qualifiedName.indexOf("::");
if (pkgSepIndex == -1) {
pkgName = qualifiedName;
} else {
pkgName = qualifiedName.substring(0, pkgSepIndex);
}
Package pkg = getPackage(project, pkgName);
if (pkg != null && pkgSepIndex != -1) {
Declaration d;
int memberSepIndex = qualifiedName.indexOf(".", pkgSepIndex);
if (memberSepIndex != -1) {
String baseName = qualifiedName.substring(pkgSepIndex + 2, memberSepIndex);
String methodName = qualifiedName.substring(memberSepIndex + 1);
d = pkg.getMember(baseName, null, false);
d = extractAnonymousClassIfRequired(d);
if (d != null) {
Declaration m = d.getMember(methodName, null, false);
if( m instanceof Function && d instanceof Class ) {
result = new MethodWithContainer((Class)d, (Function)m);
}
}
} else {
String baseName = qualifiedName.substring(pkgSepIndex + 2);
d = pkg.getMember(baseName, null, false);
result = extractAnonymousClassIfRequired(d);
}
} else {
result = pkg;
}
return result;
}
public static List<MethodWithContainer> getAllMethods(ClassOrInterface c) {
List<MethodWithContainer> members = new ArrayList<MethodWithContainer>();
getAllMethods(c, c, members);
return members;
}
private static void getAllMethods(ClassOrInterface c, TypeDeclaration t, List<MethodWithContainer> members) {
for (Declaration d : t.getMembers()) {
if (d instanceof Function) {
Function m = (Function) d;
boolean contains = false;
for (MethodWithContainer member : members) {
String name = member.getMethod().getName();
if (name!=null && name.equals(m.getName())) {
contains = true;
break;
}
}
if (!contains) {
members.add(new MethodWithContainer(c, m));
}
}
}
Type et = t.getExtendedType();
if (et != null) {
getAllMethods(c, et.getDeclaration(), members);
}
for (Type st : t.getSatisfiedTypes()) {
getAllMethods(c, st.getDeclaration(), members);
}
}
public static Declaration extractAnonymousClassIfRequired(Declaration d) {
if (d instanceof Value) {
Value value = (Value) d;
TypeDeclaration typeDeclaration = value.getTypeDeclaration();
if (typeDeclaration instanceof Class && typeDeclaration.isAnonymous()) {
return typeDeclaration;
}
}
return d;
}
public static boolean isCeylonProject(IProject project) {
return project.isOpen() && CeylonNature.isEnabled(project);
}
public static boolean isCeylonFile(IFile file) {
return isCeylonProject(file.getProject()) && CEYLON_FILE_EXTENSION.equals(file.getFileExtension());
}
public static boolean isTestable(Object element) {
if (element instanceof IProject || element instanceof Module || element instanceof Package) {
return true;
}
else if( element instanceof Class ) {
return isTestableClass((Class) element);
}
else if( element instanceof Function ) {
return isTestableMethod((Function) element, null);
}
else if( element instanceof MethodWithContainer ) {
MethodWithContainer m = (MethodWithContainer) element;
return isTestableMethod(m.getMethod(), m.getContainer());
}
return false;
}
private static boolean isTestableClass(Class clazz) {
if (clazz.isToplevel() && !clazz.isAbstract()) {
List<MethodWithContainer> methods = getAllMethods(clazz);
for (MethodWithContainer method : methods) {
if (containsTestAnnotation(method.getMethod())) {
return true;
}
}
}
return false;
}
private static boolean isTestableMethod(Function method, TypeDeclaration container) {
boolean isTestableMethod = false;
if (method.isToplevel() || (container instanceof Class && isTestableClass((Class) container))) {
if (!method.isFormal() && containsTestAnnotation(method)) {
isTestableMethod = true;
}
}
return isTestableMethod;
}
private static boolean containsTestAnnotation(Function method) {
List<Annotation> annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation.getName().equals("test")) {
return true;
}
}
return false;
}
public static Image getTestStateImage(TestElement testElement) {
Image image = null;
if(testElement != null) {
if( testElement.getChildren() == null || testElement.getChildren().size() == 0 ) {
switch(testElement.getState()) {
case RUNNING: image = getImage(TEST_RUNNING); break;
case SUCCESS: image = getImage(TEST_SUCCESS); break;
case FAILURE: image = getImage(TEST_FAILED); break;
case ERROR: image = getImage(TEST_ERROR); break;
case SKIPPED_OR_ABORTED: image = getImage(TEST_SKIPPED); break;
default: image = getImage(TEST); break;
}
} else {
switch(testElement.getState()) {
case RUNNING: image = getImage(TESTS_RUNNING); break;
case SUCCESS: image = getImage(TESTS_SUCCESS); break;
case FAILURE: image = getImage(TESTS_FAILED); break;
case ERROR: image = getImage(TESTS_ERROR); break;
case SKIPPED_OR_ABORTED: image = getImage(TESTS_SKIPPED); break;
default: image = getImage(TESTS); break;
}
}
}
return image;
}
public static String getElapsedTimeInSeconds(long milis) {
double seconds = milis / 1000.0;
return ELAPSED_TIME_FORMAT.format(seconds);
}
public static boolean containsCeylonTestImport(Module module) {
if( module != null ) {
for (ModuleImport moduleImport : module.getImports()) {
if (moduleImport.getModule().getNameAsString().equals(CEYLON_TEST_MODULE_NAME)) {
return true;
}
}
}
return false;
}
public static boolean checkNativeBackend(Module module, String launchConfigType) {
if (module.isNative()) {
if (Objects.equals(launchConfigType, LAUNCH_CONFIG_TYPE) && !module.getNativeBackends().supports(Backend.Java.asSet())) {
return false;
}
if (Objects.equals(launchConfigType, LAUNCH_CONFIG_TYPE_JS) && !module.getNativeBackends().supports(Backend.JavaScript.asSet())) {
return false;
}
}
return true;
}
}