net.serenitybdd.screenplay.InstrumentedTask Maven / Gradle / Ivy
package net.serenitybdd.screenplay;
import net.serenitybdd.core.steps.Instrumented;
import net.thucydides.model.environment.SystemEnvironmentVariables;
import net.thucydides.model.util.EnvironmentVariables;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static java.util.Arrays.stream;
import static net.thucydides.model.ThucydidesSystemProperty.MANUAL_TASK_INSTRUMENTATION;
public class InstrumentedTask {
public static T of(T task) {
EnvironmentVariables environmentVariables = SystemEnvironmentVariables.currentEnvironmentVariables();
if (MANUAL_TASK_INSTRUMENTATION.booleanFrom(environmentVariables, false)) {
return task;
} else if(isInstrumented(task) || !shouldInstrument(task)) {
return task;
}
return (T) instrumentedCopyOf(task, task.getClass());
}
static boolean shouldInstrument(T task) {
Optional performAs = stream(task.getClass().getMethods())
.filter(method -> method.getName().equals("performAs"))
.findFirst();
return performAs.isPresent() && defaultConstructorPresentFor(task.getClass());
}
private static boolean defaultConstructorPresentFor(Class extends Performable> taskClass) {
return findAllConstructorsIn(taskClass).stream()
.anyMatch( constructor -> constructor.getParameterCount() == 0 );
}
private static List> findAllConstructorsIn(Class extends Performable> taskClass) {
List> allConstructors = new ArrayList<>();
allConstructors.addAll(Arrays.asList(taskClass.getConstructors()));
allConstructors.addAll(Arrays.asList(taskClass.getDeclaredConstructors()));
return allConstructors;
}
private static Performable instrumentedCopyOf(Performable task, Class taskClass) {
Performable instrumentedTask = null;
try {
instrumentedTask = (Performable) Instrumented.instanceOf(taskClass).newInstance();
} catch(IllegalArgumentException missingDefaultConstructor) {
throw new TaskInstantiationException("Could not instantiate "
+ taskClass
+ ". If you are not instrumenting a Task class explicitly you need to give the class a default constructor."
+ "A task class cannot be instrumented if it is final (so if you are writing in Kotlin, make sure the task class is 'open'.");
}
CopyNonNullProperties.from(task).to(instrumentedTask);
return instrumentedTask;
}
static boolean isInstrumented(Performable task) {
try {
return task.getClass().getSimpleName().contains("ByteBuddy");
} catch(NullPointerException ignore) {
throw new TaskInstantiationException("Your Task class must have a public constructor.");
}
}
}