KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cobertura > coveragedata > ClassData


1 /*
2  * Cobertura - http://cobertura.sourceforge.net/
3  *
4  * Copyright (C) 2003 jcoverage ltd.
5  * Copyright (C) 2005 Mark Doliner
6  *
7  * Cobertura is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published
9  * by the Free Software Foundation; either version 2 of the License,
10  * or (at your option) any later version.
11  *
12  * Cobertura is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Cobertura; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20  * USA
21  */

22
23 package net.sourceforge.cobertura.coveragedata;
24
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
32 import java.util.SortedSet JavaDoc;
33 import java.util.TreeSet JavaDoc;
34
35 /**
36  * <p>
37  * ProjectData information is typically serialized to a file. An
38  * instance of this class records coverage information for a single
39  * class that has been instrumented.
40  * </p>
41  *
42  * <p>
43  * This class implements HasBeenInstrumented so that when cobertura
44  * instruments itself, it will omit this class. It does this to
45  * avoid an infinite recursion problem because instrumented classes
46  * make use of this class.
47  * </p>
48  */

49 public class ClassData extends CoverageDataContainer
50         implements Comparable JavaDoc, HasBeenInstrumented
51 {
52
53     private static final long serialVersionUID = 5;
54
55     /**
56      * Each key is a line number in this class, stored as an Integer object.
57      * Each value is information about the line, stored as a LineData object.
58      */

59     private Map JavaDoc branches = new HashMap JavaDoc();
60
61     private boolean containsInstrumentationInfo = false;
62
63     private Set JavaDoc methodNamesAndDescriptors = new HashSet JavaDoc();
64
65     private String JavaDoc name = null;
66
67     private String JavaDoc sourceFileName = null;
68
69     /**
70      * @param name In the format "net.sourceforge.cobertura.coveragedata.ClassData"
71      */

72     public ClassData(String JavaDoc name)
73     {
74         if (name == null)
75             throw new IllegalArgumentException JavaDoc(
76                     "Class name must be specified.");
77         this.name = name;
78     }
79
80     public LineData addLine(int lineNumber, String JavaDoc methodName,
81             String JavaDoc methodDescriptor)
82     {
83         LineData lineData = getLineData(lineNumber);
84         if (lineData == null)
85         {
86             lineData = new LineData(lineNumber);
87             // Each key is a line number in this class, stored as an Integer object.
88
// Each value is information about the line, stored as a LineData object.
89
children.put(new Integer JavaDoc(lineNumber), lineData);
90         }
91         lineData.setMethodNameAndDescriptor(methodName, methodDescriptor);
92         
93         // methodName and methodDescriptor can be null when cobertura.ser with
94
// no line information was loaded (or was not loaded at all).
95
if( methodName!=null && methodDescriptor!=null)
96             methodNamesAndDescriptors.add(methodName + methodDescriptor);
97         return lineData;
98     }
99
100     /**
101      * This is required because we implement Comparable.
102      */

103     public int compareTo(Object JavaDoc o)
104     {
105         if (!o.getClass().equals(ClassData.class))
106             return Integer.MAX_VALUE;
107         return this.name.compareTo(((ClassData)o).name);
108     }
109
110     public boolean containsInstrumentationInfo()
111     {
112         return this.containsInstrumentationInfo;
113     }
114
115     /**
116      * Returns true if the given object is an instance of the
117      * ClassData class, and it contains the same data as this
118      * class.
119      */

120     public boolean equals(Object JavaDoc obj)
121     {
122         if (this == obj)
123             return true;
124         if ((obj == null) || !(obj.getClass().equals(this.getClass())))
125             return false;
126
127         ClassData classData = (ClassData)obj;
128         return super.equals(obj)
129                 && this.branches.equals(classData.branches)
130                 && this.methodNamesAndDescriptors
131                         .equals(classData.methodNamesAndDescriptors)
132                 && this.name.equals(classData.name)
133                 && this.sourceFileName.equals(classData.sourceFileName);
134     }
135
136     public String JavaDoc getBaseName()
137     {
138         int lastDot = this.name.lastIndexOf('.');
139         if (lastDot == -1)
140         {
141             return this.name;
142         }
143         return this.name.substring(lastDot + 1);
144     }
145
146     /**
147      * @return The branch coverage rate for a particular method.
148      */

149     public double getBranchCoverageRate(String JavaDoc methodNameAndDescriptor)
150     {
151         int total = 0;
152         int hits = 0;
153
154         Iterator JavaDoc iter = branches.values().iterator();
155         while (iter.hasNext())
156         {
157             LineData next = (LineData)iter.next();
158             if (methodNameAndDescriptor.equals(next.getMethodName()
159                     + next.getMethodDescriptor()))
160             {
161                 total++;
162                 if (next.getHits() > 0)
163                 {
164                     hits++;
165                 }
166             }
167         }
168         if (total == 0)
169             return 1d;
170         return (double)hits / total;
171     }
172
173     public Collection JavaDoc getBranches()
174     {
175         return Collections.unmodifiableCollection(branches.keySet());
176     }
177
178     /**
179      * @param lineNumber The source code line number.
180      * @return The number of hits a particular line of code has.
181      */

182     public long getHitCount(int lineNumber)
183     {
184         Integer JavaDoc lineObject = new Integer JavaDoc(lineNumber);
185         if (!children.containsKey(lineObject))
186         {
187             return 0;
188         }
189
190         return ((LineData)children.get(lineObject)).getHits();
191     }
192
193     /**
194      * @return The line coverage rate for particular method
195      */

196     public double getLineCoverageRate(String JavaDoc methodNameAndDescriptor)
197     {
198         int total = 0;
199         int hits = 0;
200
201         Iterator JavaDoc iter = children.values().iterator();
202         while (iter.hasNext())
203         {
204             LineData next = (LineData)iter.next();
205             if (methodNameAndDescriptor.equals(next.getMethodName()
206                     + next.getMethodDescriptor()))
207             {
208                 total++;
209                 if (next.getHits() > 0)
210                 {
211                     hits++;
212                 }
213             }
214         }
215         if (total == 0)
216             return 1d;
217         return (double)hits / total;
218     }
219
220     private LineData getLineData(int lineNumber)
221     {
222         return (LineData)children.get(new Integer JavaDoc(lineNumber));
223     }
224
225     public SortedSet JavaDoc getLines()
226     {
227         return new TreeSet JavaDoc(this.children.values());
228     }
229
230     public Collection JavaDoc getLines(String JavaDoc methodNameAndDescriptor)
231     {
232         Collection JavaDoc lines = new HashSet JavaDoc();
233         Iterator JavaDoc iter = children.values().iterator();
234         while (iter.hasNext())
235         {
236             LineData next = (LineData)iter.next();
237             if (methodNameAndDescriptor.equals(next.getMethodName()
238                     + next.getMethodDescriptor()))
239             {
240                 lines.add(next);
241             }
242         }
243         return lines;
244     }
245
246     /**
247      * @return The method name and descriptor of each method found in the
248      * class represented by this instrumentation.
249      */

250     public Set JavaDoc getMethodNamesAndDescriptors()
251     {
252         return methodNamesAndDescriptors;
253     }
254
255     public String JavaDoc getName()
256     {
257         return name;
258     }
259
260     /**
261      * @return The number of branches in this class.
262      */

263     public int getNumberOfValidBranches()
264     {
265         return branches.size();
266     }
267
268     public String JavaDoc getPackageName()
269     {
270         int lastDot = this.name.lastIndexOf('.');
271         if (lastDot == -1)
272         {
273             return "";
274         }
275         return this.name.substring(0, lastDot);
276     }
277
278     /**
279      * Return the name of the file containing this class. If this
280      * class' sourceFileName has not been set (for whatever reason)
281      * then this method will attempt to infer the name of the source
282      * file using the class name.
283      *
284      * @return The name of the source file, for example
285      * net/sourceforge/cobertura/coveragedata/ClassData.java
286      */

287     public String JavaDoc getSourceFileName()
288     {
289         String JavaDoc baseName;
290         if (sourceFileName != null)
291             baseName = sourceFileName;
292         else
293         {
294             baseName = getBaseName();
295             int firstDollarSign = baseName.indexOf('$');
296             if (firstDollarSign == -1 || firstDollarSign == 0)
297                 baseName += ".java";
298             else
299                 baseName = baseName.substring(0, firstDollarSign)
300                         + ".java";
301         }
302
303         String JavaDoc packageName = getPackageName();
304         if (packageName.equals(""))
305             return baseName;
306         return packageName.replace('.', '/') + '/' + baseName;
307     }
308
309     public int hashCode()
310     {
311         return this.name.hashCode();
312     }
313
314     /**
315      * @return True if the line contains a branch statement.
316      */

317     public boolean isBranch(int lineNumber)
318     {
319         return branches.containsKey(new Integer JavaDoc(lineNumber));
320     }
321
322     /**
323      * Determine if a given line number is a valid line of code.
324      *
325      * @return True if the line contains executable code. False
326      * if the line is empty, or a comment, etc.
327      */

328     public boolean isValidSourceLineNumber(int lineNumber)
329     {
330         return children.containsKey(new Integer JavaDoc(lineNumber));
331     }
332
333     public void markLineAsBranch(int lineNumber)
334     {
335         LineData lineData = getLineData(lineNumber);
336         if (lineData != null)
337         {
338             lineData.setBranch(true);
339             this.branches.put(new Integer JavaDoc(lineNumber), lineData);
340         }
341     }
342
343     /**
344      * Merge some existing instrumentation with this instrumentation.
345      *
346      * @param coverageData Some existing coverage data.
347      */

348     public void merge(CoverageData coverageData)
349     {
350         ClassData classData = (ClassData)coverageData;
351
352         // If objects contain data for different classes then don't merge
353
if (!this.getName().equals(classData.getName()))
354             return;
355
356         super.merge(coverageData);
357
358         // We can't just call this.branches.putAll(classData.branches);
359
// Why not? If we did a putAll, then the LineData objects from
360
// the coverageData class would overwrite the LineData objects
361
// that are already in "this.branches" And we don't need to
362
// update the LineData objects that are already in this.branches
363
// because they are shared between this.branches and this.children,
364
// so the object hit counts will be moved when we called
365
// super.merge() above.
366
for (Iterator JavaDoc iter = classData.branches.keySet().iterator(); iter.hasNext();)
367         {
368             Object JavaDoc key = iter.next();
369             if (!this.branches.containsKey(key))
370             {
371                 this.branches.put(key, classData.branches.get(key));
372             }
373         }
374
375         this.containsInstrumentationInfo |= classData.containsInstrumentationInfo;
376         this.methodNamesAndDescriptors.addAll(classData
377                 .getMethodNamesAndDescriptors());
378         if (classData.sourceFileName != null)
379             this.sourceFileName = classData.sourceFileName;
380     }
381
382     public void removeLine(int lineNumber)
383     {
384         Integer JavaDoc lineObject = new Integer JavaDoc(lineNumber);
385         children.remove(lineObject);
386         branches.remove(lineObject);
387     }
388
389     public void setContainsInstrumentationInfo()
390     {
391         this.containsInstrumentationInfo = true;
392     }
393
394     public void setSourceFileName(String JavaDoc sourceFileName)
395     {
396         this.sourceFileName = sourceFileName;
397     }
398
399     /**
400      * Increment the number of hits for a particular line of code.
401      *
402      * @param lineNumber the line of code to increment the number of hits.
403      */

404     public void touch(int lineNumber)
405     {
406         LineData lineData = getLineData(lineNumber);
407         if (lineData == null)
408             lineData = addLine(lineNumber, null, null);
409         lineData.touch();
410     }
411
412 }
413
Popular Tags