/*
* RHQ Management Platform
* Copyright (C) 2005-2012 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.test.arquillian.impl;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.jboss.arquillian.test.spi.TestClass;
import org.jboss.arquillian.test.spi.event.suite.TestEvent;
import org.rhq.core.pc.PluginContainer;
/**
*
*
* @author Lukas Krejci
*/
public abstract class AbstractAnnotatedMethodExecutor<T extends Annotation> {
protected static class ApplicableTestMethodsAndOrder {
private String[] applicableTestMethodNames;
private int order;
public ApplicableTestMethodsAndOrder(String[] applicableTestMethodNames, int order) {
this.applicableTestMethodNames = applicableTestMethodNames;
this.order = order;
}
public String[] getApplicableTestMethodNames() {
return applicableTestMethodNames;
}
public int getOrder() {
return order;
}
}
private static class AnnotatedMethod {
private Method testMethod;
private ApplicableTestMethodsAndOrder methodsAndOrder;
public AnnotatedMethod(Method testMethod, ApplicableTestMethodsAndOrder methodsAndOrder) {
this.testMethod = testMethod;
this.methodsAndOrder = methodsAndOrder;
}
public Method getTestMethod() {
return testMethod;
}
public ApplicableTestMethodsAndOrder getApplicablTestMethodsAndOrder() {
return methodsAndOrder;
}
}
private Class<T> annotationClass;
protected AbstractAnnotatedMethodExecutor(Class<T> annotationClass) {
this.annotationClass = annotationClass;
}
protected abstract ApplicableTestMethodsAndOrder getApplicableTestMethodsAndOrder(T annotation);
private static final Comparator<AnnotatedMethod> ORDERING = new Comparator<AnnotatedMethod>() {
@Override
public int compare(AnnotatedMethod m1, AnnotatedMethod m2) {
int o1 = m1.getApplicablTestMethodsAndOrder().getOrder();
int o2 = m2.getApplicablTestMethodsAndOrder().getOrder();
if (o1 > 0) {
if (o2 > 0) {
return o1 - o2;
} else {
//explicitly ordered stuff always precedes the unordered
return -1;
}
} else {
//explicitly ordered stuff always precedes the unordered
return o2 > 0 ? 1 : 0;
}
}
};
protected abstract boolean isApplicableToTest(TestEvent testEvent);
protected void process(PluginContainer pluginContainer, TestEvent testEvent) {
if (isApplicableToTest(testEvent)) {
doProcess(testEvent);
}
}
private void doProcess(TestEvent event) {
Object testCase = event.getTestInstance();
TestClass testClass = event.getTestClass();
String testMethodName = event.getTestMethod().getName();
for (Method m : filterAndOrderMethods(testMethodName, testClass.getMethods(annotationClass))) {
try {
m.invoke(testCase, (Object[]) null);
} catch (Exception e) {
throw new IllegalStateException("Failed to execute @" + annotationClass.getSimpleName()
+ " method [" + m + "] - cause: " + e, e);
}
}
}
private List<Method> filterAndOrderMethods(String targetTestMethodName, Method[] methods) {
List<AnnotatedMethod> ordered = new ArrayList<AnnotatedMethod>(methods.length);
for (int i = 0; i < methods.length; ++i) {
T annotation = methods[i].getAnnotation(annotationClass);
ApplicableTestMethodsAndOrder o = getApplicableTestMethodsAndOrder(annotation);
AnnotatedMethod m = new AnnotatedMethod(methods[i], o);
ordered.add(m);
}
Iterator<AnnotatedMethod> it = ordered.iterator();
//filter
while (it.hasNext()) {
AnnotatedMethod m = it.next();
String[] applicableTestMethodNames = m.getApplicablTestMethodsAndOrder().getApplicableTestMethodNames();
if (applicableTestMethodNames.length > 0
&& !Arrays.asList(applicableTestMethodNames).contains(targetTestMethodName)) {
it.remove();
}
}
//order
Collections.sort(ordered, ORDERING);
//convert to List<Method>
List<Method> ret = new ArrayList<Method>(ordered.size());
for(AnnotatedMethod m : ordered) {
ret.add(m.getTestMethod());
}
return ret;
}
}