001
014
015 package com.liferay.portal.kernel.test;
016
017 import com.liferay.portal.kernel.process.ClassPathUtil;
018 import com.liferay.portal.kernel.util.StringUtil;
019
020 import java.lang.reflect.Constructor;
021 import java.lang.reflect.Method;
022
023 import java.net.URL;
024 import java.net.URLClassLoader;
025
026 import java.util.ArrayList;
027 import java.util.Arrays;
028 import java.util.Iterator;
029 import java.util.List;
030
031 import org.junit.rules.TestRule;
032 import org.junit.runner.Description;
033 import org.junit.runners.model.Statement;
034
035
038 public class CodeCoverageAssertor implements TestRule {
039
040 public CodeCoverageAssertor() {
041 this(null, null, true);
042 }
043
044 public CodeCoverageAssertor(
045 String[] includes, String[] excludes, boolean includeInnerClasses) {
046
047 _includes = includes;
048 _excludes = excludes;
049 _includeInnerClasses = includeInnerClasses;
050 }
051
052 public void appendAssertClasses(List<Class<?>> assertClasses) {
053 }
054
055 @Override
056 public Statement apply(
057 final Statement statement, final Description description) {
058
059 return new Statement() {
060
061 @Override
062 public void evaluate() throws Throwable {
063 String className = description.getClassName();
064
065 if (className.endsWith("Test")) {
066 className = className.substring(0, className.length() - 4);
067 }
068
069 String[] includes = _includes;
070
071 if (includes == null) {
072 includes = _generateIncludes(className);
073 }
074
075 _DYNAMICALLY_INSTRUMENT_METHOD.invoke(
076 null, includes, _excludes);
077
078 try {
079 statement.evaluate();
080 }
081 finally {
082 List<Class<?>> assertClasses = new ArrayList<Class<?>>();
083
084 ClassLoader classLoader = getClassLoader();
085
086 Class<?> clazz = classLoader.loadClass(className);
087
088 assertClasses.add(clazz);
089
090 appendAssertClasses(assertClasses);
091
092 _purgeSyntheticClasses(assertClasses);
093
094 _ASSERT_COVERAGE_METHOD.invoke(
095 null, _includeInnerClasses,
096 assertClasses.toArray(
097 new Class<?>[assertClasses.size()]));
098 }
099 }
100
101 };
102 }
103
104 protected ClassLoader getClassLoader() {
105 Class<?> clazz = getClass();
106
107 return clazz.getClassLoader();
108 }
109
110 private static void _purgeSyntheticClasses(List<Class<?>> assertClasses) {
111 Iterator<Class<?>> iterator = assertClasses.iterator();
112
113 while (iterator.hasNext()) {
114 Class<?> assertClass = iterator.next();
115
116 if (assertClass.isSynthetic()) {
117 iterator.remove();
118 }
119 }
120 }
121
122 private String[] _generateIncludes(String mainClassName) throws Exception {
123 List<Class<?>> assertClasses = new ArrayList<Class<?>>();
124
125 String jvmClassPath = ClassPathUtil.getJVMClassPath(false);
126
127 URL[] urls = ClassPathUtil.getClassPathURLs(jvmClassPath);
128
129 ClassLoader classLoader = new URLClassLoader(urls, null);
130
131 Class<?> mainClass = classLoader.loadClass(mainClassName);
132
133 assertClasses.add(mainClass);
134
135 if (_includeInnerClasses) {
136 assertClasses.addAll(Arrays.asList(mainClass.getDeclaredClasses()));
137 }
138
139 if (getClass() != CodeCoverageAssertor.class) {
140 Class<?> reloadedClass = classLoader.loadClass(
141 getClass().getName());
142
143 Method appendAssertClassesMethod = reloadedClass.getMethod(
144 "appendAssertClasses", List.class);
145
146 appendAssertClassesMethod.setAccessible(true);
147
148 Constructor<?> constructor = reloadedClass.getDeclaredConstructor();
149
150 constructor.setAccessible(true);
151
152 Object reloadedObject = constructor.newInstance();
153
154 appendAssertClassesMethod.invoke(reloadedObject, assertClasses);
155 }
156
157 _purgeSyntheticClasses(assertClasses);
158
159 String[] includes = new String[assertClasses.size()];
160
161 for (int i = 0; i < assertClasses.size(); i++) {
162 Class<?> assertClass = assertClasses.get(i);
163
164 includes[i] = StringUtil.replace(
165 assertClass.getName(), new String[] {".", "$"},
166 new String[] {"/", "\\$"});
167 }
168
169 return includes;
170 }
171
172 private static final Method _ASSERT_COVERAGE_METHOD;
173
174 private static final Method _DYNAMICALLY_INSTRUMENT_METHOD;
175
176 static {
177 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
178
179 try {
180 Class<?> instrumentationAgentClass = systemClassLoader.loadClass(
181 "com.liferay.cobertura.instrument.InstrumentationAgent");
182
183 _ASSERT_COVERAGE_METHOD = instrumentationAgentClass.getMethod(
184 "assertCoverage", boolean.class, Class[].class);
185 _DYNAMICALLY_INSTRUMENT_METHOD =
186 instrumentationAgentClass.getMethod(
187 "dynamicallyInstrument", String[].class, String[].class);
188 }
189 catch (Exception e) {
190 throw new ExceptionInInitializerError(e);
191 }
192 }
193
194 private final String[] _excludes;
195 private final boolean _includeInnerClasses;
196 private final String[] _includes;
197
198 }