KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > quilt > cover > stmt > StmtRegistry


1 /* StmtRegistry.java */
2 package org.quilt.cover.stmt;
3
4 import java.lang.reflect.Field JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.Hashtable JavaDoc;
7 import java.util.Map JavaDoc;
8 import java.util.Set JavaDoc;
9 import org.quilt.cl.*;
10 import org.quilt.reg.*;
11
12 /**
13  * <p>Registry for statement coverage information. As Quilt-instrumented
14  * classes are loaded, they register their <code>q$$q</code> hit count
15  * arrays and are assigned an ID unique in the life of the registry.
16  * The registry maintains: </p>
17  * <ul>
18  * <li><b>hit counts</b>, keyed on class name</li>
19  * <li><b>method end counter indexes</b>, keyed on class and method name</li>
20  * <li><b>line number ranges</b>, keyed on class and counter index</li>
21  * </ul>
22  * <p>This and other information in the registry allows it the generate
23  * a number of reports summarizing coverage at</p>
24  * <ul>
25  * <li><b>package</b> level (soon)</li>
26  * <li><b>class</b> level (now)</li>
27  * <li><b>method</b> level (now)</li>
28  * <li><b>line</b> level (soonish)</li>
29  * </ul>
30  *
31  * <p>The registry is associated with the Quilt class loader when it
32  * is created. Information can been retrieved from the registry at
33  * any time. It will be accumulated as new instances of Quilt-instrumented
34  * classes are run.</p>
35  *
36  * @author <a HREF="mailto:jddixon@users.sourceforge.net">Jim Dixon</a>
37  */

38 public class StmtRegistry extends QuiltRegistry {
39
40     /** XXX */
41     private static StmtRegistry INSTANCE = null;
42    
43     /** Returns a reference to the latest instance to announce itself. */
44     public static StmtRegistry getInstance () {
45         return INSTANCE;
46     }
47
48     /** Maps class name to array of names of instrumented methods */
49     private Map JavaDoc methodNames = new Hashtable JavaDoc(); // key className, value String[]
50
/** Maps class name to array of index of last counters for each method */
51     private Map JavaDoc methodEnds = new Hashtable JavaDoc(); // key className, value int[]
52

53     /**
54      * Constructor specifying Quilt class loader the registry is
55      * associated with.
56      */

57     public StmtRegistry (QuiltClassLoader qcl) {
58         super(qcl);
59         INSTANCE = this; // XXX the horror
60
ClassAction classAct = new ClassAction(this);
61         
62         cxf = new ClassXformer[] { classAct };
63         mxf = new MethodXformer[] { new MethodAction(this) };
64         gxf = new GraphXformer[] { new GraphAction(this, classAct) };
65         setTransformers();
66     }
67
68     /**
69      * Clear counters associated with registry entries.
70      */

71     public void reset() {
72         // XXX DO NOTHING FOR NOW XXX
73
}
74
75     /**
76      * Dump the registry as plain text.
77      * @todo More elaborate reports.
78      */

79     public String JavaDoc getReport() {
80         StringBuffer JavaDoc sb = new StringBuffer JavaDoc()
81             .append("\n=========================\n")
82             .append( " QUILT COVERAGE REPORT \n");
83         if (isEmpty()) {
84             sb.append("* the registry is empty *\n");
85         } else {
86             Set JavaDoc keys = keySet();
87             Iterator JavaDoc i = keys.iterator();
88             while (i.hasNext()) {
89                 // class --> hit count arrays
90
String JavaDoc[] name = (String JavaDoc[]) i.next();
91                 int [] counts = (int[])get(name);
92                 int count = counts.length;
93                 String JavaDoc className = name[0];
94     
95                 sb.append(className + ": " + count + " counters, "
96                     + getClassCoverage(className) + "% coverage\n ");
97 // // DEBUG ONLY: DUMP COUNTER ARRAY
98
// for (int k = 0; k < count; k++) {
99
// sb.append(" " + counts[k]);
100
// }
101
// sb.append("\n");
102
// // END
103

104                 String JavaDoc [] methods = (String JavaDoc[])methodNames.get(className);
105                 if (methods == null) {
106                     sb.append(" NULL\n");
107                 } else {
108                     // there can be more than one <init> method :-(
109
for (int k = 0; k < methods.length; k++) {
110                         sb.append(" ").append(methods[k])
111                           .append(" ").append(getMethodCoverage(className,k))
112                           .append("% coverage\n");
113                     }
114                 }
115             }
116         }
117         sb.append("=========================\n");
118         return sb.toString();
119     }
120
121     /**
122      * Get the percentage of counters in the class that have counts
123      * greater than zero. The percentage is rounded down. If no
124      * class information is found, returns zero.
125      *
126      * @return an integer between 0 and 100, zero if class not found
127      */

128     int getClassCoverage (String JavaDoc className) {
129         int nonZero = 0;
130         int[] hitCounts = (int[]) get(new String JavaDoc[] {className});
131         if (hitCounts != null) {
132             for (int k = 0; k < hitCounts.length; k++) {
133                 if (hitCounts[k] > 0) {
134                     nonZero++;
135                 }
136             }
137             nonZero = (nonZero*100)/hitCounts.length;
138         }
139         return nonZero;
140     }
141
142     /**
143      * Get the percentage of counters in the Nth method that have counts
144      * greater than zero. The percentage is rounded down. If no
145      * class or method information is found, returns zero.
146      *
147      * XXX The 'methodEnds' array actually contains cumulative counts,
148      * so values must be reduced by one.
149      *
150      * @return an integer between 0 and 100, zero if class not found
151      */

152     int getMethodCoverage (String JavaDoc className, int n) {
153         int nonZero = 0;
154         // XXX should report if either of these two is null or if
155
// cardinalities differ
156
int[] hitCounts = (int[]) get(new String JavaDoc[] {className});
157         int[] ends = (int[]) methodEnds.get(className);
158         if ( n < 0 || n >= hitCounts.length ) {
159             throw new IllegalArgumentException JavaDoc("index out of range");
160         }
161         int counterCount = 0;
162         int lastCounter = ends[n] -1 ;
163         int firstCounter = n == 0 ? 0 : ends[n - 1];
164         if (hitCounts != null && ends != null) {
165             for (int k = firstCounter; k <= lastCounter; k++) {
166                 counterCount++;
167                 if (hitCounts[k] > 0) {
168                     nonZero++;
169                 }
170             }
171             if (counterCount > 0) {
172                 nonZero = (nonZero*100)/counterCount;
173             }
174         }
175         return nonZero;
176     }
177         
178     // GET/PUT METHODS //////////////////////////////////////////////
179
// CLASSID ////////////////////////////////////////////
180
private static int nextClassID = 0;
181
182     public int getClassID (String JavaDoc className) {
183         int classID = -1;
184         try {
185             Field JavaDoc qField = Class.forName(className).getField("q$$qID");
186             // a trifle uncertain about the argument
187
classID = qField.getInt(qField);
188         } catch (Exception JavaDoc e) {
189             // just ignore any errors
190
// DEBUG
191
System.out.println("StmtRegistry.getClassID("
192                                     + className + ") failed - " + e);
193             // END
194
}
195         return classID;
196     }
197     // HIT COUNTS /////////////////////////////////////////
198
/**
199      * Get a reference to the hit count array for a class.
200      */

201     public int [] getCounts (String JavaDoc className) {
202         int[] counts = null;
203         try {
204             counts = (int[])get ( new String JavaDoc[] {className} );
205         } catch (Exception JavaDoc e) {
206             // just ignore any errors
207
System.out.println("StmtRegistry.getCounts ("
208                 + className + ") failed - " + e);
209         }
210         return counts;
211     }
212     /**
213      * Register a class by passing a reference to its integer hit count
214      * array. Returns a class ID which is unique within this run. The
215      * ID will be stored in a static in the class, public static int q$$qID
216      *
217      * XXX So far absolutely no value to using String array as key; could
218      * just be String.
219      *
220      * @param className Name of the class being registered.
221      * @param counts Reference to the class's public static hit count array.
222      * @return A unique class ID on success, -1 on failure.
223      */

224     
225     public int registerCounts (String JavaDoc className, int [] counts) {
226         int classID = -1;
227         try {
228             put ( new String JavaDoc[] {className} , counts );
229             classID = nextClassID++;
230         } catch (Exception JavaDoc e) {
231             // just ignore any errors
232
System.out.println("StmtRegistry.registerCounts for "
233                 + className + ", q$$q) failed - " + e);
234         }
235         return classID;
236     }
237
238     public void registerMethods (String JavaDoc className, String JavaDoc [] methods,
239                                                    int [] endCounts) {
240         if (className == null || methods == null || endCounts == null) {
241             throw new IllegalArgumentException JavaDoc("null parameter");
242         }
243         methodNames.put ( className, methods );
244         methodEnds.put ( className, endCounts );
245     }
246     // VERSION ////////////////////////////////////////////
247
public int getQuiltVersion (String JavaDoc className) {
248         int quiltVersion = -1;
249         try {
250             Field JavaDoc qField = Class.forName(className).getField("q$$qVer");
251             // a trifle uncertain about the argument
252
quiltVersion = qField.getInt(qField);
253         } catch (Exception JavaDoc e) {
254             // just ignore any errors
255
// DEBUG
256
System.out.println("StmtRegistry.getClassID("
257                                     + className + ") failed - " + e);
258             // END
259
}
260         return quiltVersion;
261     }
262     // EPHEMERA ///////////////////////////////////////////
263
/** Maps class name to temporary data structure */
264     private Map JavaDoc ephemera = new Hashtable JavaDoc(); // key className
265

266     /** get reference to temporary data for class */
267     Ephemera getEphemera (String JavaDoc className) {
268         if (ephemera.containsKey(className)) {
269             return (Ephemera) ephemera.get(className);
270         } else {
271             return null;
272         }
273     }
274     /** add temporary data for class to registry */
275     boolean putEphemera (String JavaDoc className, Ephemera eph) {
276         if (ephemera.containsKey(className)) {
277             return false; // operation failed
278
}
279         // XXX Should allow for failure
280
ephemera.put(className, eph);
281         return true;
282     }
283     /**
284      * Remove the reference from the registry.
285      *
286      * @param className Name of the class we are storing information about
287      * @return The reference or null if none was found or null was the
288      * stored value.
289      */

290     Ephemera removeEphemera (String JavaDoc className) {
291         return (Ephemera) ephemera.remove(className);
292     }
293     // EXPERIMENT ///////////////////////////////////////////////////
294
/** STUB */
295     public int registerClass(String JavaDoc name, org.quilt.cover.stmt.QIC junk) {
296         System.out.println(
297                 "**************************"
298             + "\nQCL.registerClass " + name
299             + "\n**************************" );
300         return 52; // <=================================
301
}
302     
303 }
304
Popular Tags