package net.sourceforge.cobertura.coveragedata;
import net.sourceforge.cobertura.CoverageIgnore;
import net.sourceforge.cobertura.instrument.pass3.AbstractCodeProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@CoverageIgnore
public class TouchCollector {
private static final Logger logger = LoggerFactory.getLogger(TouchCollector.class);
private static Map<Class<?>, Integer> registeredClasses = new ConcurrentHashMap<Class<?>, Integer>();
static {
ProjectData.getGlobalProjectData();
}
public static synchronized void registerClass(Class<?> classa) {
registeredClasses.put(classa, 0);
}
public static synchronized void registerClass(String classa)
throws ClassNotFoundException {
try {
boolean found = false;
Class<?> clazz;
try {
clazz = Class.forName(classa.replace("/", "."), false,
Thread.currentThread().getContextClassLoader());
for (Method meth : clazz.getMethods()) {
if (meth.toString().contains("net.sourceforge.cobertura")) {
registerClass(clazz);
found = true;
}
}
} catch (NoClassDefFoundError ncdfe) {
}
if (!found) {
clazz = Class.forName(classa.replace("/", "."));
registerClass(clazz);
}
} catch (ClassNotFoundException e) {
logger.error("Exception when registering class: "
+ classa, e);
throw e;
}
}
public static synchronized void applyTouchesOnProjectData(
ProjectData projectData) {
logger.debug("=================== START OF REPORT ======================== ");
for (Class<?> c : registeredClasses.keySet()) {
logger.debug("Report: " + c.getName());
ClassData cd = projectData.getOrCreateClassData(c.getName());
applyTouchesToSingleClassOnProjectData(cd, c);
}
logger.debug("=================== END OF REPORT ======================== ");
}
private static void applyTouchesToSingleClassOnProjectData(
final ClassData classData, final Class<?> c) {
logger.trace("----------- " + maybeCanonicalName(c)
+ " ---------------- ");
try {
Method m0 = c
.getDeclaredMethod(AbstractCodeProvider.COBERTURA_GET_AND_RESET_COUNTERS_METHOD_NAME);
m0.setAccessible(true);
final int[] res = (int[]) m0.invoke(null, new Object[]{});
LightClassmapListener lightClassmap = new ApplyToClassDataLightClassmapListener(
classData, res);
Method m = c.getDeclaredMethod(
AbstractCodeProvider.COBERTURA_CLASSMAP_METHOD_NAME,
LightClassmapListener.class);
m.setAccessible(true);
m.invoke(null, lightClassmap);
} catch (Exception e) {
logger.error("Cannot apply touches", e);
}
}
private static String maybeCanonicalName(final Class<?> c) {
try {
return c.getCanonicalName();
} catch (Throwable t) {
return c.getName();
}
}
@CoverageIgnore
private static class ApplyToClassDataLightClassmapListener
implements
LightClassmapListener {
private final ClassData classData;
private final int[] res;
private int currentLine = 0;
private int jumpsInLine = 0;
private int switchesInLine = 0;
private void updateLine(int new_line) {
if (new_line != currentLine) {
currentLine = new_line;
jumpsInLine = 0;
switchesInLine = 0;
}
}
public ApplyToClassDataLightClassmapListener(ClassData cd, int[] res) {
classData = cd;
this.res = res;
}
public void setSource(String source) {
logger.debug("source: " + source);
classData.setSourceFileName(source);
}
public void setClazz(Class<?> clazz) {
}
public void setClazz(String clazz) {
}
public void putLineTouchPoint(int classLine, int counterId,
String methodName, String methodDescription) {
updateLine(classLine);
LineData ld = classData.addLine(classLine, methodName,
methodDescription);
ld.touch(res[counterId]);
}
public void putSwitchTouchPoint(int classLine, int maxBranches,
int... counterIds) {
updateLine(classLine);
LineData ld = getOrCreateLine(classLine);
int switchId = switchesInLine++;
classData.addLineSwitch(classLine, switchId, 0,
counterIds.length - 2, maxBranches);
for (int i = 0; i < counterIds.length; i++) {
ld.touchSwitch(switchId, i - 1, res[counterIds[i]]);
}
}
public void putJumpTouchPoint(int classLine, int trueCounterId,
int falseCounterId) {
updateLine(classLine);
LineData ld = getOrCreateLine(classLine);
int branchId = jumpsInLine++;
classData.addLineJump(classLine, branchId);
ld.touchJump(branchId, true, res[trueCounterId]);
ld.touchJump(branchId, false, res[falseCounterId]);
}
private LineData getOrCreateLine(int classLine) {
LineData ld = classData.getLineData(classLine);
if (ld == null) {
ld = classData.addLine(classLine, null, null);
}
return ld;
}
}
}