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