1 /* TestStmtCoverage.java */
2 package org.quilt.cover.stmt;
3
4 import java.io.*;
5 import java.lang.Class;
6 import java.lang.reflect.*;
7 import java.net.*;
8
9 // DEBUG
10 import java.lang.reflect.Field;
11 import java.lang.reflect.Method;
12 // END
13
14 import junit.framework.*;
15 import org.apache.bcel.generic.*;
16 import org.quilt.cl.*;
17 import org.quilt.cover.stmt.*;
18
19 /***
20 * This is derived from org.quilt.cl.TestTransformer; it instruments
21 * the test-data classes and the classes synthesized by ClassFactory.
22 * All of the instrumented classes are run and checked to see that
23 * they produce normal output, despite the instrumentation ;-)
24 *
25 * @author <a href="jddixon@users.sourceforge.net">Jim Dixon</a>
26 */
27 public class TestStmtCoverage extends TestCase {
28
29 private ControlFlowGraph cfg;
30
31 /*** Classpath. */
32 private URL [] cp = null; // this is built up below
33
34 private String[] delegating = {
35 // NOTHING beyond standard defaults
36 };
37 // we want everything to be instrumented
38 private String[] include = {
39 "test.data.",
40 "AnonymousClass", "AnonymousClass2Catches",
41 "BasicLoad", "ComplicatedConstructor",
42 "ExceptionLoad", "ExceptionThrow",
43 "Finally", "Finally2Classes",
44 "InnerClass", "Looper",
45 "NestedTryBlocks", "OddSwitches",
46 "PrivateClass", "StaticInit",
47 "SuperClass", "SwitchLoad",
48 "Wimple"
49 };
50 private String[] exclude = {
51 // NOTHING
52 };
53
54 private GraphXformer spy;
55 private GraphXformer talker, talker2;
56
57 private StmtRegistry stmtReg;
58
59 private QuiltClassLoader qLoader = null;
60
61 public TestStmtCoverage (String name) {
62 super(name);
63 }
64
65 public void setUp () {
66 File sam1 = new File ("target/test-data-classes/");
67 String fullPath1 = sam1.getAbsolutePath() + "/";
68 File sam2 = new File ("target/classes");
69 String fullPath2 = sam2.getAbsolutePath() + "/";
70 File sam3 = new File ("target/test-classes");
71 String fullPath3 = sam3.getAbsolutePath() + "/";
72 try {
73 // Terminating slash is required. Relative paths don't
74 // work.
75 URL [] samples = {
76 new URL ( "file://" + fullPath1),
77 new URL ( "file://" + fullPath2),
78 new URL ( "file://" + fullPath3)
79 };
80 cp = samples;
81 } catch (MalformedURLException e) {
82 e.printStackTrace();
83 fail ("problem creating class path");
84 }
85 ClassLoader parent = ClassLoader.getSystemClassLoader();
86 qLoader = new QuiltClassLoader(
87 cp,
88 parent, // parent
89 delegating, // delegated classes
90 include, // being instrumented
91 exclude); // do NOT instrument
92
93 // Graph Xformers /////////////////////////////////
94 spy = new GraphSpy();
95 qLoader.addGraphXformer(spy);
96
97 // dumps graph BEFORE transformation
98 talker = new GraphTalker();
99 qLoader.addGraphXformer(talker);
100
101 // adds xformers for statement coverage to qLoader
102 // EXPERIMENT
103 stmtReg = (StmtRegistry) qLoader.addQuiltRegistry(
104 "org.quilt.cover.stmt.StmtRegistry");
105 // old way
106 //stmtReg = new StmtRegistry(qLoader);
107 //qLoader.addQuiltRegistry(stmtReg);
108
109 // dumps graph AFTER transformation
110 talker2 = new GraphTalker();
111 qLoader.addGraphXformer(talker2);
112 }
113
114 // SUPPORT METHODS //////////////////////////////////////////////
115 private RunTest loadAsRunTest (String name) {
116 Class clazz = null;
117 try {
118 clazz = qLoader.loadClass(name);
119 // // DEBUG -- trying to get fields causes an error
120 // Field[] fields = clazz.getFields();
121 // StringBuffer fieldData = new StringBuffer();
122 // for (int k = 0; k < fields.length; k++)
123 // fieldData.append(" ").append(fields[k].toString())
124 // .append("\n");
125
126 // Method[] methods = clazz.getMethods();
127 // StringBuffer methodData = new StringBuffer();
128 // for (int k = 0; k < methods.length; k++)
129 // methodData.append(" ").append(methods[k].toString())
130 // .append("\n");
131 //
132 // System.out.println("TestStmtRegistry: loading class " + name
133 // + "\nFIELDS (" + fields.length + ") :\n"
134 // + fieldData.toString()
135 // + "\nMETHODS (" + methods.length + ") :\n"
136 // + methodData.toString() );
137 // // END
138 } catch (ClassNotFoundException e) {
139 e.printStackTrace();
140 fail ("exception loading " + name + " using loadClass");
141 }
142 RunTest rt = null;
143 try {
144 rt = (RunTest) clazz.newInstance();
145 } catch ( InstantiationException e ) {
146 fail ("InstantiationException instantiating loaded class " + name);
147 } catch ( IllegalAccessException e ) {
148 fail ("IllegalAccessException instantiating loaded class " + name);
149 } catch (ClassCastException e) {
150 fail ("ClassCastException instantiating loaded class " + name);
151 }
152 return rt;
153 }
154 /***
155 * Check that the class has been properly instrumented by
156 * org.quilt.cover.stmt. At the moment this means only that the
157 * hitcount array, public static int[] q$$q is one of the class's
158 * fields. We also check that it has NOT been initialized,
159 * although we will eventually make sure that it has been.
160 */
161 private void checkInstrumentation(Object rt) {
162 String name = rt.getClass().getName();
163 System.out.println("checkInstrumentation for class " + name);
164 try {
165 Field qField = rt.getClass().getField("q$$q");
166 if (qField == null) {
167 System.out.println(name + " has no hit count array");
168 fail(name + " has NO hit count array");
169 } else try {
170 int [] hitCounts = (int[]) qField.get(null);
171 assertNotNull("q$$q has not been initialized", hitCounts);
172 } catch (IllegalAccessException e) {
173 e.printStackTrace();
174 }
175 // check version
176 qField = rt.getClass().getField("q$$qVer");
177 if (qField == null) {
178 System.out.println(name + " has no version field");
179 fail(name + " has NO version field");
180 } else try {
181 int version = qField.getInt(qField);
182 assertEquals("q$$q has wrong version number", 0, version);
183 } catch (IllegalAccessException e) {
184 e.printStackTrace();
185 }
186 // check StmtRegistry
187
188 } catch (NoSuchFieldException e) {
189 fail (name + " has no q$$q field");
190 }
191 }
192
193 // ACTUAL TESTS /////////////////////////////////////////////////
194 public void testGetReg() {
195 StmtRegistry regInLoader = (StmtRegistry)qLoader.getRegistry(
196 "org.quilt.cover.stmt.StmtRegistry");
197 assertNotNull("qLoader StmtRegistry is null", regInLoader);
198 assertSame ("qLoader has different StmtRegistry",
199 stmtReg, regInLoader);
200 }
201 public void testLoader() {
202 Class a1 = null;
203 try {
204 a1 = qLoader.loadClass("AnonymousClass");
205 } catch (ClassNotFoundException e) {
206 e.printStackTrace();
207 fail ("Error loading AnonymousClass using loadClass");
208 }
209 assertNotNull("qLoader returned null", a1);
210 } // END
211
212 // /***
213 // * Test classes from src/test-data. All of these (should) have a
214 // * RunTest interface. They are loaded and then run to see that
215 // * they produce expected values.
216 // *
217 // * By and large the test inputs are primes greater than 2; in earlier
218 // * tests some failed, returned 0, and were judged successful because
219 // * 0 was the expected result.
220 // *
221 // * At the moment these are split into three groups, so that if they
222 // * fail we will see more results.
223 // */
224 public void testInvokeTestData() {
225 RunTest
226 rt = loadAsRunTest("AnonymousClass");
227 checkInstrumentation(rt);
228 // AnonymousClass.runTest(x) returns x
229 assertEquals ("AnonymousClass isn't working", 47, rt.runTest(47));
230
231 rt = loadAsRunTest("BasicLoad");
232 checkInstrumentation(rt);
233 // BasicLoad.runTest(x) returns x*x
234 assertEquals ("BasicLoad isn't working", 49, rt.runTest(7));
235
236 rt = loadAsRunTest("ComplicatedConstructor");
237 checkInstrumentation(rt);
238 assertEquals("ComplicatedConstructor isn't working",
239 61, rt.runTest(3));
240 rt = loadAsRunTest("ExceptionLoad");
241 checkInstrumentation(rt);
242 // ExceptionLoad.runTest(x) also returns x*x
243 assertEquals ("ExceptionLoad isn't working", 121, rt.runTest(11));
244
245 rt = loadAsRunTest("InnerClass");
246 checkInstrumentation(rt);
247 // InnerClass.runTest(x) also returns x*x
248 assertEquals ("InnerClass isn't working", 9, rt.runTest(3));
249
250 rt = loadAsRunTest("Looper");
251 assertEquals("Looper isn't working", 127008000, rt.runTest(5));
252
253 // rt = loadAsRunTest("OddSwitches");
254 // // we like to play
255 // assertEquals( 91, rt.runTest(1001));
256 // assertEquals( 31, rt.runTest(3));
257 // assertEquals( 9, rt.runTest(9));
258 // assertEquals(101, rt.runTest(1005));
259 // assertEquals(-41, rt.runTest(-1));
260 // assertEquals( -3, rt.runTest(-51));
261 // assertEquals( 7, rt.runTest(-2));
262
263 rt = loadAsRunTest("PrivateClass");
264 checkInstrumentation(rt);
265 // returns 4
266 assertEquals ("PrivateClass isn't working", 4, rt.runTest(7));
267
268 rt = loadAsRunTest("SuperClass");
269 checkInstrumentation(rt);
270 // returns 3*x
271 assertEquals ("SuperClass isn't working", 21, rt.runTest(7));
272
273 // This would normally not be here, it would be at a higher
274 // level in the testing process. But we are testing the
275 // registry itself. XXX Collect the string and extract
276 // run results from it.
277 String runResults = stmtReg.getReport();
278 System.out.println("\nQuilt coverage report:\n" + runResults);
279 } // END TESTDATA
280
281 // SYNTHESIZED CLASSES //////////////////////////////////////////
282 // public void testSynth () {
283 // assertEquals ("synthesizing isn't disabled in loader",
284 // false, qLoader.getSynthEnabled() );
285 // qLoader.setSynthEnabled(true);
286 // assertEquals ("enabling synthesizing failed",
287 // true, qLoader.getSynthEnabled() );
288
289 // RunTest
290 // rt = loadAsRunTest("test.data.TestDefault");
291 // checkInstrumentation(rt);
292 // // testDefault.runTest(x) returns 2 whatever the input is
293 // assertEquals ("testDefault isn't working", 2, rt.runTest(47));
294 // assertEquals ("testDefault isn't working", 2, rt.runTest(-7));
295 // String
296 // runResults = stmtReg.getReport(); /// <-----------
297 // System.out.println("\nQuilt coverage report:\n" + runResults);
298
299 // rt = loadAsRunTest("test.data.TestIfThen");
300 // checkInstrumentation(rt);
301 // // testIfThen.runTest(x) returns 3 if x > 0, 5 otherwise
302 // assertEquals ("testIfThen isn't working", 3, rt.runTest(47));
303 // assertEquals ("testIfThen isn't working", 5, rt.runTest(-7));
304
305 // runResults = stmtReg.getReport(); /// <-----------
306 // System.out.println("\nQuilt coverage report:\n" + runResults);
307
308 // rt = loadAsRunTest("test.data.TestNPEWithCatch");
309 // checkInstrumentation(rt);
310 // // testNPEWithCatch.runTest(x) always returns 3
311 // assertEquals ("testNPEWithCatch isn't working", 3, rt.runTest(47));
312 // assertEquals ("testNPEWithCatch isn't working", 3, rt.runTest(-7));
313
314 // rt = loadAsRunTest("test.data.TestNPENoCatch");
315 // checkInstrumentation(rt);
316 // // testNPENoCatch.runTest(x) always throws a NullPointerException
317 // int x;
318 // try {
319 // x = rt.runTest(47);
320 // fail ("testNPENoCatch didn't throw exception");
321 // } catch (NullPointerException e) {
322 // ; // ignore it
323 // }
324 // try {
325 // x = rt.runTest(-7);
326 // fail ("testNPENoCatch didn't throw exception");
327 // } catch (NullPointerException e) {
328 // ; // ignore it
329 // }
330
331 // rt = loadAsRunTest("test.data.TestSelect");
332 // checkInstrumentation(rt);
333 // // testSelect.runTest(x) returns
334 // // 1 if x == 1; 3 if x == 2; 5 if x == 3; 2 otherwise
335 // assertEquals ("testSelect isn't working", 2, rt.runTest(47));
336 // assertEquals ("testSelect isn't working", 2, rt.runTest(-7));
337 // assertEquals ("testSelect isn't working", 1, rt.runTest(1));
338 // assertEquals ("testSelect isn't working", 3, rt.runTest(2));
339 // assertEquals ("testSelect isn't working", 5, rt.runTest(3));
340
341 // rt = loadAsRunTest("test.data.TestWhile");
342 // checkInstrumentation(rt);
343 // // testWhile.runTest(x) returns
344 // // 0 if x >= 0, x otherwise
345 // assertEquals ("testWhile isn't working", 0, rt.runTest(47));
346 // assertEquals ("testWhile isn't working",-7, rt.runTest(-7));
347 // } // END999
348
349 // /////////////////////////////////////////////////////////////////
350 // // BUGS BUGS BUGS BUGS //////////////////////////////////////////
351 // /////////////////////////////////////////////////////////////////
352 //
353 // /////////////////////////////////////////////////////////////////
354 // // LESSER BUGS //////////////////////////////////////////////////
355 // // "edge not in this graph" -- FIXED (a bit crudely)
356 // public void testNestedTryBlocks() {
357 // RunTest
358 // rt = loadAsRunTest("NestedTryBlocks");
359 // checkInstrumentation(rt);
360 // assertEquals ("NestedTryBlocks isn't working", 22, rt.runTest(7));
361 // } // END NESTED
362
363 /////////////////////////////////////////////////////////////////
364 // SERIOUS BUGS /////////////////////////////////////////////////
365
366 // // STATICINIT ///////////////////////////////////////////////////
367 // // XXX BUG java.lang.NullPointerException
368 // // at org.apache.bcel.generic.LineNumberGen
369 // // .getLineNumber(LineNumberGen.java:109)
370 // // at org.apache.bcel.generic.MethodGen
371 // // .getLineNumberTable(MethodGen.java:420)
372 // // at org.apache.bcel.generic.MethodGen.getMethod(MethodGen.java:599)
373 // public void testStaticInit() {
374 // RunTest
375 // rt = loadAsRunTest("StaticInit");
376 // checkInstrumentation(rt);
377 // assertEquals("StaticInit isn't working", 10, rt.runTest(7));
378 // } // END STATIC
379
380 // // TESTFINALLY //////////////////////////////////////////////////
381 // // XXX BUG Invalid start_pc/length in local var table BUG XXX
382 // public void testFinally() {
383 // RunTest
384 // rt = loadAsRunTest("Finally");
385 // checkInstrumentation(rt);
386
387 // // Finally.runTest(x) returns -1
388 // assertEquals ("Finally isn't working", -1, rt.runTest(11));
389 // assertEquals ("Finally isn't working", -1, rt.runTest(1));
390 // } // END FINALLY
391
392 // // TESTFINALLY2CATCHES //////////////////////////////////////////
393 // // XXX BUG Mismatched stack types BUG XXX
394 // public void testFinally2Catches() {
395 // RunTest
396 // rt = loadAsRunTest("Finally2Catches");
397 // checkInstrumentation(rt);
398
399 // // what Finally.runTest(x) returns is a bit complicated ...
400 // assertEquals ("Finally2Catches isn't working", 3600, rt.runTest(11));
401 // } // END
402
403 // // SWITCHLOAD
404 // // XXX BUG Falling off the end of the code BUG XXX
405 // public void testFinally2Catches() {
406 // RunTest
407 // rt = loadAsRunTest("SwitchLoad");
408 // checkInstrumentation(rt);
409 // // returns 42
410 // assertEquals ("SwitchLoad isn't working", 42, rt.runTest(7));
411 // } // END
412
413 // // WIMPLE ///////////////////////////////////////////////////////
414 // // XXX BUG java.lang.NullPointerException
415 // // at org.apache.bcel.generic.LineNumberGen
416 // // .getLineNumber(LineNumberGen.java:109)
417 // // at org.apache.bcel.generic.MethodGen
418 // // .getLineNumberTable(MethodGen.java:420)
419 // // at org.apache.bcel.generic.MethodGen.getMethod(MethodGen.java:599)
420 // public void testWimple() {
421 // RunTest
422 // rt = loadAsRunTest("Wimple");
423 // checkInstrumentation(rt);
424 // // returns ??
425 // assertEquals ("Wimple isn't working", 92, rt.runTest(7));
426 // } // END WIMPLE
427
428 }
This page was automatically generated by Maven