1 package com.pyx4me.cldcunit;
2
3 import java.util.Arrays;
4 import java.util.HashMap;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Vector;
8
9 import javassist.CannotCompileException;
10 import javassist.CtClass;
11 import javassist.CtConstructor;
12 import javassist.CtField;
13 import javassist.CtMethod;
14 import javassist.CtNewConstructor;
15 import javassist.CtNewMethod;
16 import javassist.NotFoundException;
17 import net.sf.jour.InterceptorException;
18 import net.sf.jour.filter.Pointcut;
19 import net.sf.jour.filter.PointcutListFilter;
20 import net.sf.jour.instrumentor.Instrumentor;
21 import net.sf.jour.instrumentor.InstrumentorResults;
22 import net.sf.jour.instrumentor.InstrumentorResultsImpl;
23 import net.sf.jour.log.Logger;
24
25 public class TestCaseReflectionDataInstrumentor implements Instrumentor {
26
27 protected static final Logger log = Logger.getLogger(TestCaseReflectionDataInstrumentor.class);
28
29 protected PointcutListFilter pointcuts;
30
31 private static final String instrumentedFiled = "__testMethodsArray";
32
33 public InstrumentorResults instrument(CtClass clazz) throws InterceptorException {
34
35 if (clazz.isInterface() || clazz.getName().startsWith("junit.framework.")) {
36 return InstrumentorResultsImpl.NOT_MODIFIED;
37 }
38
39 try {
40 clazz.getField(instrumentedFiled);
41 log.debug("already instrumented:" + clazz.getName());
42 return InstrumentorResultsImpl.NOT_MODIFIED;
43 } catch (NotFoundException ok) {
44 }
45
46 long countMethods = 0;
47
48 boolean modified = false;
49
50 List createdClasses = new Vector();
51 HashMap instrumented = new HashMap();
52
53 StringBuffer bodyCreateDeclaredTestMethods = new StringBuffer();
54
55 bodyCreateDeclaredTestMethods
56 .append("private static junit.framework.TestMethod[] createDeclaredTestMethods() {\n");
57 bodyCreateDeclaredTestMethods.append("return new junit.framework.TestMethod[] {\n");
58
59 boolean hasDeclaredTestMethod = false;
60
61 boolean hasDeclaredTestSuite = false;
62
63 for (Iterator i = pointcuts.iterator(); i.hasNext();) {
64 Pointcut pointcut = (Pointcut) i.next();
65
66 if (pointcut.acceptClass(clazz)) {
67
68 Iterator methods = Arrays.asList(clazz.getDeclaredMethods()).iterator();
69 while (methods.hasNext()) {
70 CtMethod method = (CtMethod) methods.next();
71 if (!instrumented.containsKey(method) && pointcut.acceptMethod(method) && pointcuts.match(method)) {
72
73 log.debug("found method:" + clazz.getName() + "." + method.getName() + "("
74 + method.getSignature() + ")");
75
76 modified = true;
77 instrumented.put(method, null);
78
79 if (method.getName().equals("suite")) {
80 hasDeclaredTestSuite = true;
81 continue;
82 }
83
84 if (hasDeclaredTestMethod) {
85 bodyCreateDeclaredTestMethods.append(",");
86 } else {
87 hasDeclaredTestMethod = true;
88 }
89
90 countMethods++;
91
92
93
94
95 String nestedClassName = "_TestMethod_" + method.getName();
96 CtClass nestedClass = clazz.makeNestedClass(nestedClassName, true);
97 bodyCreateDeclaredTestMethods.append("new ").append(clazz.getName()).append(".").append(
98 nestedClassName).append("()");
99 bodyCreateDeclaredTestMethods.append(".named(\"");
100 bodyCreateDeclaredTestMethods.append(method.getName());
101 bodyCreateDeclaredTestMethods.append("\")\n");
102
103 StringBuffer bodyRun = new StringBuffer();
104 bodyRun.append("public void run(junit.framework.TestCase testCase) throws Throwable {\n");
105 bodyRun.append("((");
106 bodyRun.append(clazz.getName());
107 bodyRun.append(")testCase).");
108 bodyRun.append(method.getName());
109 bodyRun.append("();\n");
110 bodyRun.append("}\n");
111
112 try {
113 nestedClass.setSuperclass(clazz.getClassPool().get("junit.framework.TestMethod"));
114 CtClass[] parameters = null;
115 CtConstructor c = CtNewConstructor.make(parameters, null, nestedClass);
116
117
118 nestedClass.addConstructor(c);
119
120 nestedClass.addMethod(CtNewMethod.make(bodyRun.toString(), nestedClass));
121
122
123 nestedClass.getClassFile().setMajorVersion(clazz.getClassFile().getMajorVersion());
124 nestedClass.getClassFile().setMinorVersion(clazz.getClassFile().getMinorVersion());
125
126 createdClasses.add(nestedClass);
127 } catch (NotFoundException e) {
128 throw new InterceptorException("Can't add nestedClass", e);
129 } catch (CannotCompileException e) {
130 log.info(bodyRun.toString());
131 throw new InterceptorException("Can't add nestedClass", e);
132 }
133
134 }
135 }
136 }
137 }
138
139 bodyCreateDeclaredTestMethods.append("};}\n");
140
141 if (modified) {
142 StringBuffer code = null;
143 try {
144 clazz.addField(CtField.make("private static final junit.framework.TestMethod[] " + instrumentedFiled
145 + ";", clazz));
146 code = bodyCreateDeclaredTestMethods;
147 log.debug("bodyCreateDeclaredTestMethods:" + bodyCreateDeclaredTestMethods.toString());
148 clazz.addMethod(CtNewMethod.make(bodyCreateDeclaredTestMethods.toString(), clazz));
149
150 StringBuffer bodyDeclaredTestMethods = new StringBuffer();
151 bodyDeclaredTestMethods.append("public junit.framework.TestMethod[] getDeclaredTestMethods() {\n");
152 bodyDeclaredTestMethods.append("if(").append(instrumentedFiled).append(" == null) { ").append(
153 instrumentedFiled).append(" = createDeclaredTestMethods();}\n");
154 bodyDeclaredTestMethods.append("return ").append(instrumentedFiled).append("; }");
155 code = bodyDeclaredTestMethods;
156
157 log.debug("bodyDeclaredTestMethods:" + bodyDeclaredTestMethods.toString());
158
159 clazz.addMethod(CtNewMethod.make(bodyDeclaredTestMethods.toString(), clazz));
160
161 StringBuffer bodySuite = new StringBuffer();
162 if (hasDeclaredTestSuite) {
163 bodySuite.append("public junit.framework.Test getSuite() { return suite(); }");
164 } else {
165 bodySuite.append("public junit.framework.Test getSuite() { return null; }");
166 }
167
168 code = bodySuite;
169 clazz.addMethod(CtNewMethod.make(bodySuite.toString(), clazz));
170 code = null;
171 clazz.addInterface(clazz.getClassPool().get("cldcunit.runner.TestCaseReflectionData"));
172
173 } catch (NotFoundException e) {
174 throw new InterceptorException("Can't add ReflectionData", e);
175 } catch (CannotCompileException e) {
176 if (code != null) {
177 log.info(code.toString());
178 }
179 throw new InterceptorException("Can't add ReflectionData", e);
180 }
181 log.debug("instrumented:" + clazz.getName());
182 }
183
184 log.debug("end instrumenting:" + clazz.getName());
185 if (modified) {
186 return new InstrumentorResultsImpl(0, countMethods, createdClasses);
187 } else {
188 return InstrumentorResultsImpl.NOT_MODIFIED;
189 }
190 }
191
192 public void setPointcuts(PointcutListFilter pointcuts) {
193 this.pointcuts = pointcuts;
194 }
195 }