}
return result;
}
ClassData diffClasses(ClassData larger, ClassData smaller) {
ClassData result = new ClassData(larger.getName());
for (Object o : larger.getLines()) {
LineData lld = (LineData) o;
long afterHits = lld.getHits();
long prevHits = 0;
long prevConditions = 0;
if (smaller != null) {
LineData sld = smaller.getLineCoverage(lld.getLineNumber());
if (sld != null) {
prevHits = sld.getHits();
prevConditions = sld.getConditionSize();
}
}
int diffHits = (int) (afterHits - prevHits);
result.addLine(lld.getLineNumber(), lld.getMethodName(),
lld.getMethodDescriptor());
if (diffHits > 0) {
result.touch(lld.getLineNumber(), diffHits);
}
if (diffHits < 0) {
errors.add("Coverage decreased on line " + lld.getLineNumber()
+ " of " + larger.getName());
}
if (prevConditions > lld.getConditionSize()) {
errors.add("Jump or Switch disappeared on line "
+ lld.getLineNumber() + " of " + larger.getName());
}
for (int i = 0; i < lld.getConditionSize(); i++) {
Object cd = lld.getConditionData(i);
if (cd instanceof JumpData) {
JumpData ljd = (JumpData) cd;
result.addLineJump(lld.getLineNumber(), i);
long prevTrue = 0;
long prevFalse = 0;
if (smaller != null) {
LineData sld = smaller.getLineCoverage(lld
.getLineNumber());
if (sld != null) {
JumpData sjd = (JumpData) sld.getConditionData(i);
if (sjd != null) {
prevTrue = sjd.getTrueHits();
prevFalse = sjd.getFalseHits();
} else {
errors.add("Somehow, JumpData null at condition "
+ i + " on line " + lld.getLineNumber());
}
}
}
long diffTrueHits = ljd.getTrueHits() - prevTrue;
long diffFalseHits = ljd.getFalseHits() - prevFalse;
if (diffTrueHits > 0) {
result.touchJump(lld.getLineNumber(), i, true,
(int) diffTrueHits);
}
if (diffFalseHits > 0) {
result.touchJump(lld.getLineNumber(), i, false,
(int) diffFalseHits);
}
if (diffFalseHits < 0 || diffTrueHits < 0) {
errors.add("Jump coverage on " + result.getName() + ":"
+ lld.getLineNumber() + ":" + i + " decreased:"
+ "true from " + prevTrue + " by "
+ diffTrueHits + ", false from " + prevFalse
+ " by " + diffFalseHits);
}
} else if (cd instanceof SwitchData) {
SwitchData lsd = (SwitchData) cd;
result.addLineSwitch(lld.getLineNumber(), i, 0, 0, lsd.getMaxBranches());
long[] prevBranchHits = new long[lsd
.getNumberOfValidBranches() - 1];
long prevDefaultHits = 0;
if (smaller != null) {
LineData sld = smaller.getLineCoverage(lld
.getLineNumber());
if (sld != null) {
SwitchData ssd = (SwitchData) sld
.getConditionData(i);
if (ssd != null) {
for (int j = 0; j < prevBranchHits.length; j++) {
// returns -1 on an error condition.
// probably never happens in normal
// situation, but does in unit test.
prevBranchHits[j] = Math.max(0,
ssd.getHits(j));
}
prevDefaultHits = ssd.getDefaultHits();
}
}
}
for (int j = 0; j < prevBranchHits.length; j++) {
long diffBranchHits = lsd.getHits(j)
- prevBranchHits[j];
result.touchSwitch(lld.getLineNumber(), i, j,
(int) diffBranchHits);
if (diffBranchHits < 0) {
errors.add("Switch coverage " + i + "," + j
+ " on line " + lld.getLineNumber()
+ " decreased.");
}
}
long diffDefaultHits = lsd.getDefaultHits()
- prevDefaultHits;
if (diffDefaultHits > 0) {
result.touchSwitch(lld.getLineNumber(), i, -1,
(int) diffDefaultHits);
}
if (diffDefaultHits < 0) {
errors.add("Switch coverage " + i + ",default on line "
+ lld.getLineNumber() + " decreased.");
}
}
}
}
Set<Integer> largerLines = lineNumbers(larger);
Set<Integer> smallerLines = lineNumbers(smaller);
smallerLines.removeAll(largerLines);
if (smallerLines.size() > 0) {
errors.add("Line(s) disappeared from class " + larger.getName()
+ ": " + smallerLines);
}
// This arabesque accommodates .groovy files, and I suppose any others
// that follow the java package/directory convention.
int iName = larger.getSourceFileName().lastIndexOf("/");
String sfName = larger.getSourceFileName().substring(iName + 1,
larger.getSourceFileName().length());
result.setSourceFileName(sfName);
return result;
}