1/*******************************************************************************
2 * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.core.test.validation;
13
14import static org.junit.Assert.assertEquals;
15import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
16import static org.objectweb.asm.Opcodes.ACC_SUPER;
17import static org.objectweb.asm.Opcodes.ALOAD;
18import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
19import static org.objectweb.asm.Opcodes.RETURN;
20import static org.objectweb.asm.Opcodes.V1_1;
21import static org.objectweb.asm.Opcodes.V1_2;
22import static org.objectweb.asm.Opcodes.V1_3;
23import static org.objectweb.asm.Opcodes.V1_4;
24import static org.objectweb.asm.Opcodes.V1_5;
25import static org.objectweb.asm.Opcodes.V1_6;
26import static org.objectweb.asm.Opcodes.V1_7;
27import static org.objectweb.asm.Opcodes.V1_8;
28
29import java.io.IOException;
30
31import org.jacoco.core.JaCoCo;
32import org.jacoco.core.instr.Instrumenter;
33import org.jacoco.core.runtime.IRuntime;
34import org.jacoco.core.runtime.SystemPropertiesRuntime;
35import org.junit.Test;
36import org.objectweb.asm.ClassReader;
37import org.objectweb.asm.ClassVisitor;
38import org.objectweb.asm.ClassWriter;
39import org.objectweb.asm.MethodVisitor;
40
41/**
42 * Test class inserted stackmap frames for different class file versions.
43 */
44public class ClassFileVersionsTest {
45
46	@Test
47	public void test_1_1() throws IOException {
48		testVersion(V1_1, false);
49	}
50
51	@Test
52	public void test_1_2() throws IOException {
53		testVersion(V1_2, false);
54	}
55
56	@Test
57	public void test_1_3() throws IOException {
58		testVersion(V1_3, false);
59	}
60
61	@Test
62	public void test_1_4() throws IOException {
63		testVersion(V1_4, false);
64	}
65
66	@Test
67	public void test_1_5() throws IOException {
68		testVersion(V1_5, false);
69	}
70
71	@Test
72	public void test_1_6() throws IOException {
73		testVersion(V1_6, true);
74	}
75
76	@Test
77	public void test_1_7() throws IOException {
78		testVersion(V1_7, true);
79	}
80
81	@Test
82	public void test_1_8() throws IOException {
83		testVersion(V1_8, true);
84	}
85
86	private void testVersion(int version, boolean frames) throws IOException {
87		final byte[] original = createClass(version);
88
89		IRuntime runtime = new SystemPropertiesRuntime();
90		Instrumenter instrumenter = new Instrumenter(runtime);
91		byte[] instrumented = instrumenter.instrument(original, "TestTarget");
92
93		assertFrames(instrumented, frames);
94	}
95
96	private void assertFrames(byte[] source, boolean expected) {
97		final boolean[] hasFrames = new boolean[] { false };
98		new ClassReader(source).accept(
99				new ClassVisitor(JaCoCo.ASM_API_VERSION) {
100
101					@Override
102					public MethodVisitor visitMethod(int access, String name,
103							String desc, String signature, String[] exceptions) {
104						return new MethodVisitor(JaCoCo.ASM_API_VERSION) {
105
106							@Override
107							public void visitFrame(int type, int nLocal,
108									Object[] local, int nStack, Object[] stack) {
109								hasFrames[0] = true;
110							}
111
112						};
113					}
114
115				}, 0);
116		assertEquals(Boolean.valueOf(expected), Boolean.valueOf(hasFrames[0]));
117	}
118
119	private byte[] createClass(int version) {
120
121		ClassWriter cw = new ClassWriter(0);
122		MethodVisitor mv;
123
124		cw.visit(version, ACC_PUBLIC + ACC_SUPER, "org/jacoco/test/Sample",
125				null, "java/lang/Object", null);
126
127		mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
128		mv.visitCode();
129		mv.visitVarInsn(ALOAD, 0);
130		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V",
131				false);
132		mv.visitInsn(RETURN);
133		mv.visitMaxs(1, 1);
134		mv.visitEnd();
135
136		cw.visitEnd();
137
138		return cw.toByteArray();
139	}
140
141}
142