blob: 106b7a6358cca8be3331efc5d26510471dbbcb27 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.test.validation;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.jacoco.core.JaCoCo;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.internal.Java9Support;
import org.jacoco.core.internal.instr.InstrSupport;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.SystemPropertiesRuntime;
import org.jacoco.core.test.TargetLoader;
import org.jacoco.core.test.validation.targets.Target01;
import org.jacoco.core.test.validation.targets.Target02;
import org.jacoco.core.test.validation.targets.Target03;
import org.jacoco.core.test.validation.targets.Target04;
import org.jacoco.core.test.validation.targets.Target05;
import org.jacoco.core.test.validation.targets.Target06;
import org.jacoco.core.test.validation.targets.Target07;
import org.jacoco.core.test.validation.targets.Target08;
import org.jacoco.core.test.validation.targets.Target09;
import org.jacoco.core.test.validation.targets.Target10;
import org.jacoco.core.test.validation.targets.Target11;
import org.jacoco.core.test.validation.targets.Target12;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.TraceClassVisitor;
/**
* Tests whether stackmap frames are correctly adjusted.
*/
public class FramesTest {
/**
* Stack sizes calculated for instrumented classes might be sometimes bigger
* than actually needed. This is an acceptable tradeoff in favor of keeping
* track of the actual stack sizes. For test assertions we need to replace
* max stack sizes with constant value.
*/
private static class MaxStackEliminator extends ClassVisitor {
public MaxStackEliminator(ClassVisitor cv) {
super(InstrSupport.ASM_API_VERSION, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
final MethodVisitor mv = super.visitMethod(access, name, desc,
signature, exceptions);
return new MethodVisitor(InstrSupport.ASM_API_VERSION, mv) {
@Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(-1, maxLocals);
}
};
}
}
private void testFrames(Class<?> target) throws IOException {
testFrames(TargetLoader.getClassDataAsBytes(target));
}
private void testFrames(byte[] source) throws IOException {
IRuntime runtime = new SystemPropertiesRuntime();
Instrumenter instrumenter = new Instrumenter(runtime);
source = calculateFrames(source);
byte[] actual = instrumenter.instrument(source, "TestTarget");
byte[] expected = calculateFrames(actual);
assertEquals(dump(expected), dump(actual));
}
private byte[] calculateFrames(byte[] source) {
ClassReader rc = new ClassReader(
Java9Support.downgradeIfRequired(source));
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
// Adjust Version to 1.6 to enable frames:
rc.accept(new ClassVisitor(InstrSupport.ASM_API_VERSION, cw) {
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
super.visit(Opcodes.V1_6, access, name, signature, superName,
interfaces);
}
}, 0);
return cw.toByteArray();
}
private String dump(byte[] bytes) {
final StringWriter buffer = new StringWriter();
final PrintWriter writer = new PrintWriter(buffer);
new ClassReader(bytes).accept(new MaxStackEliminator(
new TraceClassVisitor(writer)), ClassReader.EXPAND_FRAMES);
return buffer.toString();
}
@Test
public void testTarget01() throws IOException {
testFrames(Target01.class);
}
@Test
public void testTarget02() throws IOException {
testFrames(Target02.class);
}
@Test
public void testTarget03() throws IOException {
testFrames(Target03.class);
}
@Test
public void testTarget04() throws IOException {
testFrames(Target04.class);
}
@Test
public void testTarget05() throws IOException {
testFrames(Target05.class);
}
@Test
public void testTarget06() throws IOException {
testFrames(Target06.class);
}
@Test
public void testTarget07() throws IOException {
testFrames(Target07.class);
}
@Test
public void testTarget08() throws IOException {
testFrames(Target08.class);
}
@Test
public void testTarget09() throws IOException {
testFrames(Target09.class);
}
@Test
public void testTarget10() throws IOException {
testFrames(Target10.class);
}
@Test
public void testTarget11() throws IOException {
testFrames(Target11.class);
}
@Test
public void testTarget12() throws IOException {
testFrames(Target12.class);
}
}