package samples.powermockito.junit4.jacoco;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.analysis.IMethodCoverage;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfoStore;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.LoggerRuntime;
import org.jacoco.core.runtime.RuntimeData;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import static org.assertj.core.api.Assertions.assertThat;
public class JacocoCoverageTest {
public static final String[] TARGET = new String[]{
TargetTest.class.getName(),
StaticMethods.class.getName(),
InstanceMethods.class.getName()
};
@Test
public void jacocoOfflineInstShouldCalculateCoverageAfterPowerMockTransformation() throws Exception {
final RuntimeData data = new RuntimeData();
runTargetTest(data);
final CoverageBuilder coverageBuilder = collectCoverage(getExecutionDataStore(data));
assertCodeCoverage(coverageBuilder);
}
private void runTargetTest(RuntimeData data) throws Exception {IRuntime runtime = new LoggerRuntime();
instrumentClasses(runtime);
runtime.startup(data);
JUnitCore.runClasses(TargetTest.class);
runtime.shutdown();
restoreOriginalClasses();
}
private void assertCodeCoverage(CoverageBuilder coverageBuilder) {
for (IClassCoverage classCoverage : coverageBuilder.getClasses()) {
for (IMethodCoverage methodCoverage : classCoverage.getMethods()) {
if (methodCoverage.getName().equals("calculateSomething")) {
assertThat(methodCoverage.getLineCounter().getCoveredRatio()).isEqualTo(1.0);
assertThat(methodCoverage.getLineCounter().getCoveredCount()).isEqualTo(4);
}
}
}
}
private CoverageBuilder collectCoverage(ExecutionDataStore executionData) throws IOException {
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionData, coverageBuilder);
for (String className : TARGET) {
analyzer.analyzeClass(getClass().getResourceAsStream(classNameToFileName(className)), className);
}
return coverageBuilder;
}
private ExecutionDataStore getExecutionDataStore(RuntimeData data) {
final ExecutionDataStore executionData = new ExecutionDataStore();
final SessionInfoStore sessionInfos = new SessionInfoStore();
data.collect(executionData, sessionInfos, false);
return executionData;
}
private void restoreOriginalClasses() throws URISyntaxException, IOException {
for (String className : TARGET) {
final String classResource = classNameToFileName(className);
URL classResourceURL = getClass().getResource(classResource);
File originalFile = new File(classResourceURL.toURI());
restoreOriginalFile(originalFile);
}
}
private void instrumentClasses(IRuntime runtime) throws URISyntaxException, IOException {
Instrumenter instr = new Instrumenter(runtime);
for (String className : TARGET) {
instrumentClass(instr, className);
}
}
private static void copyFileUsingStream(File source, File dest) throws IOException {
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream(source);
os = new FileOutputStream(dest, false);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) > 0) {
os.write(buffer, 0, length);
}
} finally {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
}
}
private void restoreOriginalFile(File originalFile) throws IOException {
File backup = new File(originalFile.getAbsolutePath() + ".bak");
if (originalFile.exists()) {
originalFile.delete();
}
copyFileUsingStream(backup, originalFile);
}
private void instrumentClass(Instrumenter instr,
String className) throws URISyntaxException, IOException {
URL classResourceURL = getClass().getResource(classNameToFileName(className));
File originalFile = new File(classResourceURL.toURI());
copyOriginalFile(originalFile);
final byte[] instrumented = instr.instrument(classResourceURL.openStream(), className);
writeInstrumentedFile(originalFile, instrumented);
}
private void copyOriginalFile(File originalFile) throws IOException, URISyntaxException {
File backup = new File(originalFile.getAbsolutePath() + ".bak");
if (backup.exists()) {
backup.delete();
}
copyFileUsingStream(originalFile, backup);
}
private void writeInstrumentedFile(File originalFile, byte[] instrumented) throws IOException {
FileOutputStream fooStream = null;
try {
fooStream = new FileOutputStream(originalFile, false);
fooStream.write(instrumented);
} finally {
if (fooStream != null) {
fooStream.close();
}
}
}
private String classNameToFileName(String name) {return '/' + name.replace('.', '/') + ".class";}
}