![JAR search and dependency download from the Maven repository](/logo.png)
net.sourceforge.cobertura.coveragedata.LineData Maven / Gradle / Ivy
/*
* Cobertura - http://cobertura.sourceforge.net/
*
* Copyright (C) 2003 jcoverage ltd.
* Copyright (C) 2005 Mark Doliner
* Copyright (C) 2005 Mark Sinke
* Copyright (C) 2006 Jiri Mares
*
* Cobertura is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* Cobertura is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cobertura; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
package net.sourceforge.cobertura.coveragedata;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import net.sourceforge.cobertura.util.StringUtil;
/**
*
* This class implements HasBeenInstrumented so that when cobertura
* instruments itself, it will omit this class. It does this to
* avoid an infinite recursion problem because instrumented classes
* make use of this class.
*
*/
public class LineData
implements Comparable, CoverageData, HasBeenInstrumented, Serializable
{
private static final long serialVersionUID = 4;
private transient Lock lock;
private long hits;
private List jumps;
private List switches;
private final int lineNumber;
private String methodDescriptor;
private String methodName;
LineData(int lineNumber)
{
this(lineNumber, null, null);
}
LineData(int lineNumber, String methodName, String methodDescriptor)
{
this.hits = 0;
this.jumps = null;
this.lineNumber = lineNumber;
this.methodName = methodName;
this.methodDescriptor = methodDescriptor;
initLock();
}
private void initLock()
{
lock = new ReentrantLock();
}
/**
* This is required because we implement Comparable.
*/
public int compareTo(Object o)
{
if (!o.getClass().equals(LineData.class))
return Integer.MAX_VALUE;
return this.lineNumber - ((LineData)o).lineNumber;
}
public boolean equals(Object obj)
{
if (this == obj)
return true;
if ((obj == null) || !(obj.getClass().equals(this.getClass())))
return false;
LineData lineData = (LineData)obj;
getBothLocks(lineData);
try
{
return (this.hits == lineData.hits)
&& ((this.jumps == lineData.jumps) || ((this.jumps != null) && (this.jumps.equals(lineData.jumps))))
&& ((this.switches == lineData.switches) || ((this.switches != null) && (this.switches.equals(lineData.switches))))
&& (this.lineNumber == lineData.lineNumber)
&& (this.methodDescriptor.equals(lineData.methodDescriptor))
&& (this.methodName.equals(lineData.methodName));
}
finally
{
lock.unlock();
lineData.lock.unlock();
}
}
public double getBranchCoverageRate()
{
if (getNumberOfValidBranches() == 0)
return 1d;
lock.lock();
try
{
return ((double) getNumberOfCoveredBranches()) / getNumberOfValidBranches();
}
finally
{
lock.unlock();
}
}
public String getConditionCoverage()
{
StringBuffer ret = new StringBuffer();
if (getNumberOfValidBranches() == 0)
{
ret.append(StringUtil.getPercentValue(1.0));
}
else
{
lock.lock();
try
{
ret.append(StringUtil.getPercentValue(getBranchCoverageRate()));
ret.append(" (").append(getNumberOfCoveredBranches()).append("/").append(getNumberOfValidBranches()).append(")");
}
finally
{
lock.unlock();
}
}
return ret.toString();
}
public long getHits()
{
lock.lock();
try
{
return hits;
}
finally
{
lock.unlock();
}
}
public boolean isCovered()
{
lock.lock();
try
{
return (getHits() > 0) && ((getNumberOfValidBranches() == 0) || ((1.0 - getBranchCoverageRate()) < 0.0001));
}
finally
{
lock.unlock();
}
}
public double getLineCoverageRate()
{
return (getHits() > 0) ? 1 : 0;
}
public int getLineNumber()
{
return lineNumber;
}
public String getMethodDescriptor()
{
lock.lock();
try
{
return methodDescriptor;
}
finally
{
lock.unlock();
}
}
public String getMethodName()
{
lock.lock();
try
{
return methodName;
}
finally
{
lock.unlock();
}
}
/**
* @see net.sourceforge.cobertura.coveragedata.CoverageData#getNumberOfCoveredBranches()
*/
/*public int getNumberOfCoveredBranches()
{
if (this.branches == null)
return 0;
int covered = 0;
for (Iterator i = this.branches.iterator(); i.hasNext(); covered += ((BranchData) i.next()).getNumberOfCoveredBranches());
return covered;
}*/
public int getNumberOfCoveredLines()
{
return (getHits() > 0) ? 1 : 0;
}
public int getNumberOfValidBranches()
{
int ret = 0;
lock.lock();
try
{
if (jumps != null)
for (int i = jumps.size() - 1; i >= 0; i--)
ret += ((JumpData) jumps.get(i)).getNumberOfValidBranches();
if (switches != null)
for (int i = switches.size() - 1; i >= 0; i--)
ret += ((SwitchData) switches.get(i)).getNumberOfValidBranches();
return ret;
}
finally
{
lock.unlock();
}
}
public int getNumberOfCoveredBranches()
{
int ret = 0;
lock.lock();
try
{
if (jumps != null)
for (int i = jumps.size() - 1; i >= 0; i--)
ret += ((JumpData) jumps.get(i)).getNumberOfCoveredBranches();
if (switches != null)
for (int i = switches.size() - 1; i >= 0; i--)
ret += ((SwitchData) switches.get(i)).getNumberOfCoveredBranches();
return ret;
}
finally
{
lock.unlock();
}
}
public int getNumberOfValidLines()
{
return 1;
}
public int hashCode()
{
return this.lineNumber;
}
public boolean hasBranch()
{
lock.lock();
try
{
return (jumps != null) || (switches != null);
}
finally
{
lock.unlock();
}
}
public void merge(CoverageData coverageData)
{
LineData lineData = (LineData)coverageData;
getBothLocks(lineData);
try
{
this.hits += lineData.hits;
if (lineData.jumps != null)
if (this.jumps == null)
this.jumps = lineData.jumps;
else
{
for (int i = Math.min(this.jumps.size(), lineData.jumps.size()) - 1; i >= 0; i--)
((JumpData) this.jumps.get(i)).merge((JumpData) lineData.jumps.get(i));
for (int i = Math.min(this.jumps.size(), lineData.jumps.size()); i < lineData.jumps.size(); i++)
this.jumps.add(lineData.jumps.get(i));
}
if (lineData.switches != null)
if (this.switches == null)
this.switches = lineData.switches;
else
{
for (int i = Math.min(this.switches.size(), lineData.switches.size()) - 1; i >= 0; i--)
((SwitchData) this.switches.get(i)).merge((SwitchData) lineData.switches.get(i));
for (int i = Math.min(this.switches.size(), lineData.switches.size()); i < lineData.switches.size(); i++)
this.switches.add(lineData.switches.get(i));
}
if (lineData.methodName != null)
this.methodName = lineData.methodName;
if (lineData.methodDescriptor != null)
this.methodDescriptor = lineData.methodDescriptor;
}
finally
{
lock.unlock();
lineData.lock.unlock();
}
}
void addJump(int jumpNumber)
{
getJumpData(jumpNumber);
}
void addSwitch(int switchNumber, int[] keys)
{
getSwitchData(switchNumber, new SwitchData(switchNumber, keys));
}
void addSwitch(int switchNumber, int min, int max)
{
getSwitchData(switchNumber, new SwitchData(switchNumber, min, max));
}
void setMethodNameAndDescriptor(String name, String descriptor)
{
lock.lock();
try
{
this.methodName = name;
this.methodDescriptor = descriptor;
}
finally
{
lock.unlock();
}
}
void touch()
{
lock.lock();
try
{
this.hits++;
}
finally
{
lock.unlock();
}
}
void touchJump(int jumpNumber, boolean branch)
{
getJumpData(jumpNumber).touchBranch(branch);
}
void touchSwitch(int switchNumber, int branch)
{
getSwitchData(switchNumber, null).touchBranch(branch);
}
public int getConditionSize() {
lock.lock();
try
{
return ((jumps == null) ? 0 : jumps.size()) + ((switches == null) ? 0 :switches.size());
}
finally
{
lock.unlock();
}
}
public Object getConditionData(int index)
{
Object branchData = null;
lock.lock();
try
{
int jumpsSize = (jumps == null) ? 0 : jumps.size();
int switchesSize = (switches == null) ? 0 :switches.size();
if (index < jumpsSize)
{
branchData = jumps.get(index);
}
else if (index < jumpsSize + switchesSize)
{
branchData = switches.get(index - jumpsSize);
}
return branchData;
}
finally
{
lock.unlock();
}
}
public String getConditionCoverage(int index) {
Object branchData = getConditionData(index);
if (branchData == null)
{
return StringUtil.getPercentValue(1.0);
}
else if (branchData instanceof JumpData)
{
JumpData jumpData = (JumpData) branchData;
return StringUtil.getPercentValue(jumpData.getBranchCoverageRate());
}
else
{
SwitchData switchData = (SwitchData) branchData;
return StringUtil.getPercentValue(switchData.getBranchCoverageRate());
}
}
JumpData getJumpData(int jumpNumber)
{
lock.lock();
try
{
if (jumps == null)
{
jumps = new ArrayList();
}
if (jumps.size() <= jumpNumber)
{
for (int i = jumps.size(); i <= jumpNumber; jumps.add(new JumpData(i++)));
}
return (JumpData) jumps.get(jumpNumber);
}
finally
{
lock.unlock();
}
}
SwitchData getSwitchData(int switchNumber, SwitchData data)
{
lock.lock();
try
{
if (switches == null)
{
switches = new ArrayList();
}
if (switches.size() < switchNumber)
{
for (int i = switches.size(); i < switchNumber; switches.add(new SwitchData(i++)));
}
if (switches.size() == switchNumber)
if (data != null)
switches.add(data);
else
switches.add(new SwitchData(switchNumber));
return (SwitchData) switches.get(switchNumber);
}
finally
{
lock.unlock();
}
}
private void getBothLocks(LineData other) {
/*
* To prevent deadlock, we need to get both locks or none at all.
*
* When this method returns, the thread will have both locks.
* Make sure you unlock them!
*/
boolean myLock = false;
boolean otherLock = false;
while ((!myLock) || (!otherLock))
{
try
{
myLock = lock.tryLock();
otherLock = other.lock.tryLock();
}
finally
{
if ((!myLock) || (!otherLock))
{
//could not obtain both locks - so unlock the one we got.
if (myLock)
{
lock.unlock();
}
if (otherLock)
{
other.lock.unlock();
}
//do a yield so the other threads will get to work.
Thread.yield();
}
}
}
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
in.defaultReadObject();
initLock();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy