001 /*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2003 jcoverage ltd.
005 * Copyright (C) 2005 Mark Doliner
006 * Copyright (C) 2005 Mark Sinke
007 * Copyright (C) 2006 Jiri Mares
008 *
009 * Cobertura is free software; you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as published
011 * by the Free Software Foundation; either version 2 of the License,
012 * or (at your option) any later version.
013 *
014 * Cobertura is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017 * General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * along with Cobertura; if not, write to the Free Software
021 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
022 * USA
023 */
024
025 package net.sourceforge.cobertura.coveragedata;
026
027 import java.io.Serializable;
028 import java.util.ArrayList;
029 import java.util.List;
030
031 import net.sourceforge.cobertura.util.StringUtil;
032
033 /**
034 * <p>
035 * This class implements HasBeenInstrumented so that when cobertura
036 * instruments itself, it will omit this class. It does this to
037 * avoid an infinite recursion problem because instrumented classes
038 * make use of this class.
039 * </p>
040 */
041 public class LineData
042 implements Comparable, CoverageData, HasBeenInstrumented, Serializable
043 {
044 private static final long serialVersionUID = 4;
045
046 private long hits;
047 private List jumps;
048 private List switches;
049 private final int lineNumber;
050 private String methodDescriptor;
051 private String methodName;
052
053 LineData(int lineNumber)
054 {
055 this(lineNumber, null, null);
056 }
057
058 LineData(int lineNumber, String methodName, String methodDescriptor)
059 {
060 this.hits = 0;
061 this.jumps = null;
062 this.lineNumber = lineNumber;
063 this.methodName = methodName;
064 this.methodDescriptor = methodDescriptor;
065 }
066
067 /**
068 * This is required because we implement Comparable.
069 */
070 public int compareTo(Object o)
071 {
072 if (!o.getClass().equals(LineData.class))
073 return Integer.MAX_VALUE;
074 return this.lineNumber - ((LineData)o).lineNumber;
075 }
076
077 public boolean equals(Object obj)
078 {
079 if (this == obj)
080 return true;
081 if ((obj == null) || !(obj.getClass().equals(this.getClass())))
082 return false;
083
084 LineData lineData = (LineData)obj;
085 return (this.hits == lineData.hits)
086 && ((this.jumps == lineData.jumps) || ((this.jumps != null) && (this.jumps.equals(lineData.jumps))))
087 && ((this.switches == lineData.switches) || ((this.switches != null) && (this.switches.equals(lineData.switches))))
088 && (this.lineNumber == lineData.lineNumber)
089 && (this.methodDescriptor.equals(lineData.methodDescriptor))
090 && (this.methodName.equals(lineData.methodName));
091 }
092
093 public double getBranchCoverageRate()
094 {
095 if (getNumberOfValidBranches() == 0)
096 return 1d;
097 return ((double) getNumberOfCoveredBranches()) / getNumberOfValidBranches();
098 }
099
100 public String getConditionCoverage()
101 {
102 StringBuffer ret = new StringBuffer();
103 if (getNumberOfValidBranches() == 0)
104 {
105 ret.append(StringUtil.getPercentValue(1.0));
106 }
107 else
108 {
109 ret.append(StringUtil.getPercentValue(getBranchCoverageRate()));
110 ret.append(" (").append(getNumberOfCoveredBranches()).append("/").append(getNumberOfValidBranches()).append(")");
111 }
112 return ret.toString();
113 }
114
115 public long getHits()
116 {
117 return hits;
118 }
119
120 public boolean isCovered()
121 {
122 return (getHits() > 0) && ((getNumberOfValidBranches() == 0) || ((1.0 - getBranchCoverageRate()) < 0.0001));
123 }
124
125 public double getLineCoverageRate()
126 {
127 return (getHits() > 0) ? 1 : 0;
128 }
129
130 public int getLineNumber()
131 {
132 return lineNumber;
133 }
134
135 public String getMethodDescriptor()
136 {
137 return methodDescriptor;
138 }
139
140 public String getMethodName()
141 {
142 return methodName;
143 }
144
145 /**
146 * @see net.sourceforge.cobertura.coveragedata.CoverageData#getNumberOfCoveredBranches()
147 */
148 /*public int getNumberOfCoveredBranches()
149 {
150 if (this.branches == null)
151 return 0;
152 int covered = 0;
153 for (Iterator i = this.branches.iterator(); i.hasNext(); covered += ((BranchData) i.next()).getNumberOfCoveredBranches());
154 return covered;
155 }*/
156
157 public int getNumberOfCoveredLines()
158 {
159 return (getHits() > 0) ? 1 : 0;
160 }
161
162 public int getNumberOfValidBranches()
163 {
164 int ret = 0;
165 if (jumps != null)
166 for (int i = jumps.size() - 1; i >= 0; i--)
167 ret += ((JumpData) jumps.get(i)).getNumberOfValidBranches();
168 if (switches != null)
169 for (int i = switches.size() - 1; i >= 0; i--)
170 ret += ((SwitchData) switches.get(i)).getNumberOfValidBranches();
171 return ret;
172 }
173
174 public int getNumberOfCoveredBranches()
175 {
176 int ret = 0;
177 if (jumps != null)
178 for (int i = jumps.size() - 1; i >= 0; i--)
179 ret += ((JumpData) jumps.get(i)).getNumberOfCoveredBranches();
180 if (switches != null)
181 for (int i = switches.size() - 1; i >= 0; i--)
182 ret += ((SwitchData) switches.get(i)).getNumberOfCoveredBranches();
183 return ret;
184 }
185
186 public int getNumberOfValidLines()
187 {
188 return 1;
189 }
190
191 public int hashCode()
192 {
193 return this.lineNumber;
194 }
195
196 public boolean hasBranch()
197 {
198 return (jumps != null) || (switches != null);
199 }
200
201 public void merge(CoverageData coverageData)
202 {
203 LineData lineData = (LineData)coverageData;
204 this.hits += lineData.hits;
205 if (lineData.jumps != null)
206 if (this.jumps == null)
207 this.jumps = lineData.jumps;
208 else
209 {
210 for (int i = Math.min(this.jumps.size(), lineData.jumps.size()) - 1; i >= 0; i--)
211 ((JumpData) this.jumps.get(i)).merge((JumpData) lineData.jumps.get(i));
212 for (int i = Math.min(this.jumps.size(), lineData.jumps.size()); i < lineData.jumps.size(); i++)
213 this.jumps.add(lineData.jumps.get(i));
214 }
215 if (lineData.switches != null)
216 if (this.switches == null)
217 this.switches = lineData.switches;
218 else
219 {
220 for (int i = Math.min(this.switches.size(), lineData.switches.size()) - 1; i >= 0; i--)
221 ((SwitchData) this.switches.get(i)).merge((SwitchData) lineData.switches.get(i));
222 for (int i = Math.min(this.switches.size(), lineData.switches.size()); i < lineData.switches.size(); i++)
223 this.switches.add(lineData.switches.get(i));
224 }
225 if (lineData.methodName != null)
226 this.methodName = lineData.methodName;
227 if (lineData.methodDescriptor != null)
228 this.methodDescriptor = lineData.methodDescriptor;
229 }
230
231 void addJump(int jumpNumber)
232 {
233 getJumpData(jumpNumber);
234 }
235
236 void addSwitch(int switchNumber, int[] keys)
237 {
238 getSwitchData(switchNumber, new SwitchData(switchNumber, keys));
239 }
240
241 void addSwitch(int switchNumber, int min, int max)
242 {
243 getSwitchData(switchNumber, new SwitchData(switchNumber, min, max));
244 }
245
246 void setMethodNameAndDescriptor(String name, String descriptor)
247 {
248 this.methodName = name;
249 this.methodDescriptor = descriptor;
250 }
251
252 void touch()
253 {
254 this.hits++;
255 }
256
257 void touchJump(int jumpNumber, boolean branch)
258 {
259 getJumpData(jumpNumber).touchBranch(branch);
260 }
261
262 void touchSwitch(int switchNumber, int branch)
263 {
264 getSwitchData(switchNumber, null).touchBranch(branch);
265 }
266
267 public int getConditionSize() {
268 return ((jumps == null) ? 0 : jumps.size()) + ((switches == null) ? 0 :switches.size());
269 }
270
271 public Object getConditionData(int index)
272 {
273 Object branchData = null;
274 int jumpsSize = (jumps == null) ? 0 : jumps.size();
275 int switchesSize = (switches == null) ? 0 :switches.size();
276 if (index < jumpsSize)
277 {
278 branchData = jumps.get(index);
279 }
280 else if (index < jumpsSize + switchesSize)
281 {
282 branchData = switches.get(index - jumpsSize);
283 }
284 return branchData;
285 }
286
287 public String getConditionCoverage(int index) {
288 Object branchData = getConditionData(index);
289 if (branchData == null)
290 {
291 return StringUtil.getPercentValue(1.0);
292 }
293 else if (branchData instanceof JumpData)
294 {
295 JumpData jumpData = (JumpData) branchData;
296 return StringUtil.getPercentValue(jumpData.getBranchCoverageRate());
297 }
298 else
299 {
300 SwitchData switchData = (SwitchData) branchData;
301 return StringUtil.getPercentValue(switchData.getBranchCoverageRate());
302
303 }
304 }
305
306 JumpData getJumpData(int jumpNumber)
307 {
308 if (jumps == null)
309 {
310 jumps = new ArrayList();
311 }
312 if (jumps.size() <= jumpNumber)
313 {
314 for (int i = jumps.size(); i <= jumpNumber; jumps.add(new JumpData(i++)));
315 }
316 return (JumpData) jumps.get(jumpNumber);
317 }
318
319 SwitchData getSwitchData(int switchNumber, SwitchData data)
320 {
321 if (switches == null)
322 {
323 switches = new ArrayList();
324 }
325 if (switches.size() < switchNumber)
326 {
327 for (int i = switches.size(); i < switchNumber; switches.add(new SwitchData(i++)));
328 }
329 if (switches.size() == switchNumber)
330 if (data != null)
331 switches.add(data);
332 else
333 switches.add(new SwitchData(switchNumber));
334 return (SwitchData) switches.get(switchNumber);
335 }
336
337 }