001 /*
002 * Cobertura - http://cobertura.sourceforge.net/
003 *
004 * Copyright (C) 2003 jcoverage ltd.
005 * Copyright (C) 2005 Mark Doliner <thekingant@users.sourceforge.net>
006 *
007 * Cobertura is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published
009 * by the Free Software Foundation; either version 2 of the License,
010 * or (at your option) any later version.
011 *
012 * Cobertura is distributed in the hope that it will be useful, but
013 * WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Cobertura; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020 * USA
021 */
022
023 package net.sourceforge.cobertura.coverage;
024
025 import java.io.Serializable;
026 import java.util.Collections;
027 import java.util.HashMap;
028 import java.util.HashSet;
029 import java.util.Iterator;
030 import java.util.Map;
031 import java.util.Set;
032
033 /**
034 * <p>
035 * CoverageData information is typically serialized to a file. An
036 * instance of this class records coverage information for a single
037 * class that has been instrumented.
038 * </p>
039 *
040 * <p>
041 * This class implements HasBeenInstrumented so that when cobertura
042 * instruments itself, it will omit this class. It does this to
043 * avoid an infinite recursion problem because instrumented classes
044 * make use of this class.
045 * </p>
046 */
047 public class CoverageData implements HasBeenInstrumented, Serializable
048 {
049
050 private static final long serialVersionUID = 2;
051
052 /**
053 * Each key is a line number in this class, stored as an Integer object.
054 * Each value is information about the line, stored as a LineInformation object.
055 */
056 private Map conditionals = new HashMap();
057
058 /**
059 * Each key is a line number in this class, stored as an Integer object.
060 * Each value is information about the line, stored as a LineInformation object.
061 */
062 private Map lines = new HashMap();
063
064 private Set methodNamesAndDescriptors = new HashSet();
065
066 private String sourceFileName = null;
067
068 public void addLine(int lineNumber, String methodName,
069 String methodDescriptor)
070 {
071 LineInformation lineInformation = getLineInformation(lineNumber);
072 if (lineInformation == null)
073 {
074 lineInformation = new LineInformation(lineNumber);
075 lines.put(new Integer(lineNumber), lineInformation);
076 }
077 lineInformation.setMethodNameAndDescriptor(methodName,
078 methodDescriptor);
079 methodNamesAndDescriptors.add(methodName + methodDescriptor);
080 }
081
082 /**
083 * @return The branch coverage rate for the class.
084 */
085 public double getBranchCoverageRate()
086 {
087 if (conditionals.size() == 0)
088 {
089 // no conditional branches, therefore 100% branch coverage.
090 return 1d;
091 }
092 return (double)getNumberOfCoveredBranches() / conditionals.size();
093 }
094
095 /**
096 * @return The branch coverage rate for a particular method.
097 */
098 public double getBranchCoverageRate(String methodNameAndDescriptor)
099 {
100 int total = 0;
101 int hits = 0;
102
103 Iterator iter = conditionals.values().iterator();
104 while (iter.hasNext())
105 {
106 LineInformation next = (LineInformation)iter.next();
107 if (methodNameAndDescriptor.equals(next.getMethodName()
108 + next.getMethodDescriptor()))
109 {
110 total++;
111 if (next.getHits() > 0)
112 {
113 hits++;
114 }
115 }
116 }
117 return (double)hits / total;
118 }
119
120 public Set getConditionals()
121 {
122 return Collections.unmodifiableSet(conditionals.keySet());
123 }
124
125 /**
126 * @param lineNumber The source code line number.
127 * @return The number of hits a particular line of code has.
128 */
129 public long getHitCount(int lineNumber)
130 {
131 Integer lineNum = new Integer(lineNumber);
132 if (!lines.containsKey(lineNum))
133 {
134 return 0;
135 }
136
137 return ((LineInformation)lines.get(lineNum)).getHits();
138 }
139
140 /**
141 * @return The line coverage rate for the class
142 */
143 public double getLineCoverageRate()
144 {
145 if (lines.size() == 0)
146 {
147 return 1d;
148 }
149 return (double)getNumberOfCoveredLines() / lines.size();
150 }
151
152 /**
153 * @return The line coverage rate for particular method
154 */
155 public double getLineCoverageRate(String methodNameAndDescriptor)
156 {
157 int total = 0;
158 int hits = 0;
159
160 Iterator iter = lines.values().iterator();
161 while (iter.hasNext())
162 {
163 LineInformation next = (LineInformation)iter.next();
164 if (methodNameAndDescriptor.equals(next.getMethodName()
165 + next.getMethodDescriptor()))
166 {
167 total++;
168 if (next.getHits() > 0)
169 {
170 hits++;
171 }
172 }
173 }
174 return (double)hits / total;
175 }
176
177 private LineInformation getLineInformation(int lineNumber)
178 {
179 return (LineInformation)lines.get(new Integer(lineNumber));
180 }
181
182 /**
183 * @return The method name and descriptor of each method found in the
184 * class represented by this instrumentation.
185 */
186 public Set getMethodNamesAndDescriptors()
187 {
188 return methodNamesAndDescriptors;
189 }
190
191 /**
192 * @return The number of branches in this class covered by testing.
193 */
194 public int getNumberOfCoveredBranches()
195 {
196 int num = 0;
197
198 Iterator iter = conditionals.values().iterator();
199 while (iter.hasNext())
200 {
201 if (((LineInformation)iter.next()).getHits() > 0)
202 num++;
203 }
204
205 return num;
206 }
207
208 /**
209 * @return The number of lines in this class covered by testing.
210 */
211 public int getNumberOfCoveredLines()
212 {
213 int num = 0;
214
215 Iterator iter = lines.values().iterator();
216 while (iter.hasNext())
217 {
218 if (((LineInformation)iter.next()).getHits() > 0)
219 num++;
220 }
221
222 return num;
223 }
224
225 /**
226 * @return The number of branches in this class.
227 */
228 public int getNumberOfValidBranches()
229 {
230 return conditionals.size();
231 }
232
233 /**
234 * @return The number of lines in this class.
235 */
236 public int getNumberOfValidLines()
237 {
238 return lines.size();
239 }
240
241 public String getSourceFileName()
242 {
243 return sourceFileName;
244 }
245
246 /**
247 * @return The set of valid source line numbers
248 */
249 public Set getValidLineNumbers()
250 {
251 return Collections.unmodifiableSet(lines.keySet());
252 }
253
254 /**
255 * Determine if a given line number is a valid line of code.
256 *
257 * @return True if the line contains executable code. False
258 * if the line is empty, or a comment, etc.
259 */
260 public boolean isValidSourceLineNumber(int lineNumber)
261 {
262 return lines.containsKey(new Integer(lineNumber));
263 }
264
265 public void markLineAsConditional(int lineNumber)
266 {
267 LineInformation lineInformation = getLineInformation(lineNumber);
268 if (lineInformation != null)
269 {
270 lineInformation.setConditional(true);
271 this.conditionals.put(new Integer(lineNumber), lineInformation);
272 }
273 }
274
275 /**
276 * Merge some existing instrumentation with this instrumentation.
277 *
278 * @param coverageData Some existing coverage data.
279 */
280 public void merge(CoverageData coverageData)
281 {
282 lines.putAll(coverageData.lines);
283 conditionals.putAll(coverageData.conditionals);
284 methodNamesAndDescriptors.addAll(coverageData
285 .getMethodNamesAndDescriptors());
286 }
287
288 public void removeLine(int lineNumber)
289 {
290 lines.remove(new Integer(lineNumber));
291 }
292
293 public void setSourceFileName(String sourceFileName)
294 {
295 this.sourceFileName = sourceFileName;
296 }
297
298 /**
299 * Increment the number of hits for a particular line of code.
300 *
301 * @param lineNumber the line of code to increment the number of hits.
302 */
303 public void touch(int lineNumber)
304 {
305 LineInformation lineInformation = getLineInformation(lineNumber);
306 if (lineInformation != null)
307 lineInformation.touch();
308 }
309
310 }