package janala.instrument;
import janala.utils.MyLogger;
import java.io.*;
import java.util.Map;
import java.util.HashMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Coverage implements Serializable {
private static final long serialVersionUID = 1L;
private final HashMap<String, Integer> classNameToCid;
private final TreeMap<Integer, String> cidmidToName;
private int nBranches;
private int nCovered;
private final TreeMap<Integer, Integer> covered;
private final TreeMap<Integer, Integer> tmpCovered; // transient
private boolean isNewClass;
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (o == this) {
return true;
}
if (o instanceof Coverage) {
Coverage other = (Coverage)o;
return classNameToCid.equals(other.classNameToCid) &&
cidmidToName.equals(other.cidmidToName) &&
covered.equals(other.covered) &&
(nBranches == other.nBranches) &&
(nCovered == other.nCovered);
} else {
return false;
}
}
@Override
public String toString() {
return "nBranches=" + nBranches + ", nCovered=" + nCovered + ", classNameToCid=" +
classNameToCid.toString() + ", cidmidToName=" + cidmidToName.toString() +
", covered=" + covered.toString() + ", tmpCovered=" + tmpCovered.toString();
}
private String lastMethod;
private String lastClassName;
public static Coverage instance = null;
private static final Logger logger = MyLogger.getLogger(Coverage.class.getName());
public Coverage() {
classNameToCid = new HashMap<String, Integer>();
nBranches = 0;
nCovered = 0;
covered = new TreeMap<Integer, Integer>();
tmpCovered = new TreeMap<Integer, Integer>();
cidmidToName = new TreeMap<Integer, String>();
}
public static Coverage get() {
if (instance == null) {
instance = new Coverage();
}
return instance;
}
/** Parse a coverage object from an input stream */
public static Coverage parse(InputStream is) {
ObjectInputStream inputStream = null;
try {
inputStream = new ObjectInputStream(is);
Object tmp = inputStream.readObject();
inputStream.close();
if (tmp instanceof Coverage) {
return (Coverage) tmp;
} else {
return new Coverage();
}
} catch (Exception e) {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException unused) {
}
}
return new Coverage();
}
}
public static void read(String fileName) {
try {
instance = parse(new FileInputStream(fileName));
} catch (Exception e) {
instance = new Coverage();
}
}
public void write(OutputStream os) throws IOException {
ObjectOutputStream outputStream = new ObjectOutputStream(os);
this.tmpCovered.clear();
outputStream.writeObject(this);
outputStream.close();
}
public void write(String outputFile) {
try {
if (outputFile != null) {
write(new FileOutputStream(outputFile));
}
} catch (Exception e) {
logger.log(Level.SEVERE, "", e);
throw new RuntimeException("Error happened while writing coverage");
}
}
public int getCid(String cname) {
int ret = -1; // invalid
lastClassName = cname;
if (classNameToCid.containsKey(cname)) {
isNewClass = false;
return classNameToCid.get(cname);
} else {
classNameToCid.put(cname, ret = classNameToCid.size());
if (cname.equals("catg/CATG")) {
isNewClass = false;
} else {
isNewClass = true;
}
return ret;
}
}
public void setCidmidToName(int mid) {
int cid = classNameToCid.get(lastClassName);
int cidmid = GlobalStateForInstrumentation.getCidMid(cid, mid);
cidmidToName.put(cidmid, lastClassName + "." + lastMethod);
}
public void addBranchCount(int iid) {
if (isNewClass) {
nBranches += 2;
covered.put(iid, 0);
}
}
public void visitBranch(int iid, boolean side) {
if (!tmpCovered.containsKey(iid)) {
tmpCovered.put(iid, 0);
}
tmpCovered.put(iid, tmpCovered.get(iid) | (side ? 1 : 2));
}
public void commitBranches(boolean print) {
for (int key : tmpCovered.keySet()) {
int value = tmpCovered.get(key);
if (covered.containsKey(key)) {
int oldValue = covered.get(key);
covered.put(key, oldValue | value);
if ((value & 2) > (oldValue & 2)) {
nCovered++;
}
if ((value & 1) > (oldValue & 1)) {
nCovered++;
}
}
}
if (print) {
printCoverage(System.out);
}
}
public void printCoverage(PrintStream out) {
Map<Integer, Integer> methodToTotalBranches = new TreeMap<Integer, Integer>();
Map<Integer, Integer> methodToCoveredBranches = new TreeMap<Integer, Integer>();
Map<Integer, Boolean> mcovered = new TreeMap<Integer, Boolean>();
for (int key : covered.keySet()) {
int cidmid = GlobalStateForInstrumentation.extractCidMid(key);
if (!methodToTotalBranches.containsKey(cidmid)) {
methodToTotalBranches.put(cidmid, 0);
methodToCoveredBranches.put(cidmid, 0);
mcovered.put(cidmid, false);
}
methodToTotalBranches.put(cidmid, methodToTotalBranches.get(cidmid) + 2);
int value = covered.get(key);
if (value > 0) {
if ((value & 2) > 0) {
methodToCoveredBranches.put(cidmid, methodToCoveredBranches.get(cidmid) + 1);
}
if ((value & 1) > 0) {
methodToCoveredBranches.put(cidmid, methodToCoveredBranches.get(cidmid) + 1);
}
mcovered.put(cidmid, true);
}
}
int mtotals = 0;
for (int key : methodToTotalBranches.keySet()) {
if (mcovered.get(key)) {
mtotals += methodToTotalBranches.get(key);
}
}
out.println(
"Branch coverage with respect to covered classes = "
+ (100.0 * nCovered / nBranches)
+ "%");
out.println(
"Branch coverage with respect to covered methods = " + (100.0 * nCovered / mtotals) + "%");
out.println("Total branches in covered methods = " + mtotals);
}
public void setLastMethod(String lastMethod) {
this.lastMethod = lastMethod;
}
public String getLastMethod() {
return lastMethod;
}
}