View Javadoc

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  						 * new TestMethod("testMethodTwo") { public void run(junit.framework.TestCase testCase) throws
93  						 * Throwable { ((TestCase) testCase).testMethodTwo(); } }
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 							// CtConstructor c = new CtConstructor(parameters,
117 							// nestedClass);
118 							nestedClass.addConstructor(c);
119 
120 							nestedClass.addMethod(CtNewMethod.make(bodyRun.toString(), nestedClass));
121 
122 							// set major and minor version to the same as instrumented class
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 }