package org.approvaltests;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.approvaltests.core.ApprovalFailureReporter;
import org.approvaltests.reporters.DefaultFrontLoadedReporter;
import org.approvaltests.reporters.DiffReporter;
import org.approvaltests.reporters.EnvironmentAwareReporter;
import org.approvaltests.reporters.FirstWorkingReporter;
import org.approvaltests.reporters.MultiReporter;
import org.approvaltests.reporters.UseReporter;
import org.packagesettings.PackageLevelSettings;
import org.packagesettings.Settings;
import com.spun.util.ClassUtils;
import com.spun.util.ObjectUtils;
import com.spun.util.ThreadUtils;
public class ReporterFactory
{
public static final String FRONTLOADED_REPORTER = "FrontloadedReporter";
public static final String USE_REPORTER = "UseReporter";
public static ApprovalFailureReporter get()
{
StackTraceElement[] trace = ThreadUtils.getStackTrace();
ApprovalFailureReporter returned = getFromAnnotation(trace);
if (returned == null)
{
returned = getFromPackageSettings(trace);
}
if (returned == null)
{
returned = DiffReporter.INSTANCE;
}
return FirstWorkingReporter.combine(getFrontLoadedReporter(), returned);
}
private static ApprovalFailureReporter getFromPackageSettings(StackTraceElement[] trace)
{
Map<String, Settings> settings = PackageLevelSettings.getForStackTrace(trace);
Settings value = settings.get(USE_REPORTER);
if (value != null && value.getValue() instanceof ApprovalFailureReporter)
{
return (ApprovalFailureReporter) value.getValue();
}
else
{
return null;
}
}
/**
* Loaded from PackageSettings.FrontloadedReporter
*/
public static EnvironmentAwareReporter getFrontLoadedReporter()
{
Map<String, Settings> settings = PackageLevelSettings.get();
Settings value = settings.get(FRONTLOADED_REPORTER);
if (value != null && value.getValue() instanceof EnvironmentAwareReporter)
{
return (EnvironmentAwareReporter) value.getValue();
}
else
{
return DefaultFrontLoadedReporter.INSTANCE;
}
}
public static ApprovalFailureReporter getFromAnnotation(StackTraceElement[] trace)
{
UseReporter reporter = getAnnotationsFromStackTrace(UseReporter.class, trace).getFirst();
return reporter == null ? null : getReporter(reporter);
}
private static ApprovalFailureReporter getReporter(UseReporter reporter)
{
Class<? extends ApprovalFailureReporter>[] classes = reporter.value();
List<ApprovalFailureReporter> reporters = new ArrayList<ApprovalFailureReporter>();
for (Class<? extends ApprovalFailureReporter> clazz : classes)
{
ApprovalFailureReporter instance = ClassUtils.create(clazz);
reporters.add(instance);
}
return reporters.size() == 1 ? reporters.get(0) : new MultiReporter(reporters);
}
public static <T extends Annotation> StackListings<T> getAnnotationsFromStackTrace(Class<T> annotationClass,
StackTraceElement[] trace)
{
StackListings<T> listings = new StackListings<>();
for (StackTraceElement stack : trace)
{
Method method = null;
Class<?> clazz = null;
try
{
String methodName = stack.getMethodName();
clazz = ObjectUtils.loadClass(stack.getClassName());
method = clazz.getMethod(methodName, (Class<?>[]) null);
}
catch (Throwable e)
{
//ignore
}
T annotation = null;
if (method != null)
{
annotation = method.getAnnotation(annotationClass);
}
if (annotation != null)
{
listings.addToMethodList(annotation);
}
if (clazz != null)
{
annotation = clazz.getAnnotation(annotationClass);
}
if (annotation != null)
{
listings.addToClassList(annotation);
}
}
return listings;
}
}