1/*******************************************************************************
2 * Copyright (c) 2009, 2017 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.internal.flow;
13
14import static org.junit.Assert.assertEquals;
15
16import java.util.Arrays;
17
18import org.jacoco.core.instr.MethodRecorder;
19import org.junit.After;
20import org.junit.Before;
21import org.junit.Test;
22import org.objectweb.asm.Label;
23import org.objectweb.asm.MethodVisitor;
24import org.objectweb.asm.Opcodes;
25import org.objectweb.asm.commons.AnalyzerAdapter;
26import org.objectweb.asm.util.Printer;
27
28/**
29 * Unit tests for {@link MethodProbesAdapter}.
30 */
31public class MethodProbesAdapterTest implements IProbeIdGenerator {
32
33	private Label label;
34
35	private int id;
36
37	private MethodRecorder expected, actual;
38
39	private MethodProbesVisitor expectedVisitor;
40
41	private MethodVisitor adapter;
42
43	private IFrame frame;
44
45	private static class TraceAdapter extends MethodProbesVisitor {
46
47		private final Printer printer;
48
49		TraceAdapter(MethodRecorder recorder) {
50			super(recorder.getVisitor());
51			printer = recorder.getPrinter();
52		}
53
54		@Override
55		public void visitProbe(int probeId) {
56			rec("visitProbe", Integer.valueOf(probeId));
57		}
58
59		@Override
60		public void visitInsnWithProbe(int opcode, int probeId) {
61			rec("visitInsnWithProbe", Integer.valueOf(opcode),
62					Integer.valueOf(probeId));
63		}
64
65		@Override
66		public void visitJumpInsnWithProbe(int opcode, Label label,
67				int probeId, IFrame frame) {
68			rec("visitJumpInsnWithProbe", Integer.valueOf(opcode), label,
69					Integer.valueOf(probeId));
70			frame.accept(this);
71		}
72
73		@Override
74		public void visitTableSwitchInsnWithProbes(int min, int max,
75				Label dflt, Label[] labels, IFrame frame) {
76			rec("visitTableSwitchInsnWithProbes", Integer.valueOf(min),
77					Integer.valueOf(max), dflt, labels);
78			frame.accept(this);
79		}
80
81		@Override
82		public void visitLookupSwitchInsnWithProbes(Label dflt, int[] keys,
83				Label[] labels, IFrame frame) {
84			rec("visitLookupSwitchInsnWithProbes", dflt, keys, labels);
85			frame.accept(this);
86		}
87
88		private void rec(String name, Object... args) {
89			printer.text.add(name + Arrays.asList(args));
90		}
91
92	}
93
94	@Before
95	public void setup() {
96		label = new Label();
97		id = 1000;
98		expected = new MethodRecorder();
99		expectedVisitor = new TraceAdapter(expected);
100		actual = new MethodRecorder();
101		MethodProbesVisitor actualVisitor = new TraceAdapter(actual);
102		MethodProbesAdapter probesAdapter = new MethodProbesAdapter(
103				actualVisitor, this);
104		final AnalyzerAdapter analyzer = new AnalyzerAdapter("Foo", 0, "doit",
105				"()V", probesAdapter);
106		probesAdapter.setAnalyzer(analyzer);
107		adapter = analyzer;
108		frame = new IFrame() {
109
110			public void accept(MethodVisitor mv) {
111			}
112		};
113	}
114
115	@After
116	public void verify() {
117		assertEquals(expected, actual);
118	}
119
120	@Test
121	public void testVisitProbe1() {
122		LabelInfo.setTarget(label);
123		LabelInfo.setSuccessor(label);
124
125		adapter.visitLabel(label);
126
127		expectedVisitor.visitProbe(1000);
128		expectedVisitor.visitLabel(label);
129	}
130
131	@Test
132	public void testVisitProbe2() {
133		LabelInfo.setTarget(label);
134		LabelInfo.setTarget(label);
135
136		adapter.visitLabel(label);
137
138		expectedVisitor.visitLabel(label);
139	}
140
141	@Test
142	public void testVisitProbe3() {
143		adapter.visitLabel(label);
144
145		expectedVisitor.visitLabel(label);
146	}
147
148	@Test
149	public void testVisitInsn1() {
150		adapter.visitInsn(Opcodes.RETURN);
151
152		expectedVisitor.visitInsnWithProbe(Opcodes.RETURN, 1000);
153	}
154
155	@Test
156	public void testVisitInsn2() {
157		adapter.visitInsn(Opcodes.ICONST_0);
158		adapter.visitInsn(Opcodes.ICONST_0);
159		adapter.visitInsn(Opcodes.IADD);
160
161		expectedVisitor.visitInsn(Opcodes.ICONST_0);
162		expectedVisitor.visitInsn(Opcodes.ICONST_0);
163		expectedVisitor.visitInsn(Opcodes.IADD);
164	}
165
166	@Test
167	public void testVisitJumpInsn1() {
168		LabelInfo.setTarget(label);
169		LabelInfo.setTarget(label);
170
171		adapter.visitJumpInsn(Opcodes.GOTO, label);
172
173		expectedVisitor
174				.visitJumpInsnWithProbe(Opcodes.GOTO, label, 1000, frame);
175		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
176				0, null);
177	}
178
179	@Test
180	public void testVisitJumpInsn2() {
181		LabelInfo.setTarget(label);
182		LabelInfo.setTarget(label);
183
184		adapter.visitInsn(Opcodes.ICONST_0);
185		adapter.visitJumpInsn(Opcodes.IFLT, label);
186
187		expectedVisitor.visitInsn(Opcodes.ICONST_0);
188		expectedVisitor
189				.visitJumpInsnWithProbe(Opcodes.IFLT, label, 1000, frame);
190		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
191				0, null);
192	}
193
194	@Test
195	public void testVisitJumpInsn3() {
196		adapter.visitInsn(Opcodes.ICONST_0);
197		adapter.visitJumpInsn(Opcodes.IFLT, label);
198
199		expectedVisitor.visitInsn(Opcodes.ICONST_0);
200		expectedVisitor.visitJumpInsn(Opcodes.IFLT, label);
201	}
202
203	@Test
204	public void testVisitJumpInsn4() {
205		LabelInfo.setTarget(label);
206		LabelInfo.setTarget(label);
207
208		adapter.visitInsn(Opcodes.ICONST_0);
209		adapter.visitInsn(Opcodes.ICONST_0);
210		adapter.visitJumpInsn(Opcodes.IF_ICMPEQ, label);
211
212		expectedVisitor.visitInsn(Opcodes.ICONST_0);
213		expectedVisitor.visitInsn(Opcodes.ICONST_0);
214		expectedVisitor.visitJumpInsnWithProbe(Opcodes.IF_ICMPEQ, label, 1000,
215				frame);
216		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
217				0, null);
218	}
219
220	@Test
221	public void testVisitLookupSwitchInsn1() {
222		LabelInfo.setTarget(label);
223		LabelInfo.setTarget(label);
224
225		final int[] keys = new int[] { 0, 1 };
226		final Label[] labels = new Label[] { label, label };
227		adapter.visitInsn(Opcodes.ICONST_0);
228		adapter.visitLookupSwitchInsn(label, keys, labels);
229
230		expectedVisitor.visitInsn(Opcodes.ICONST_0);
231		expectedVisitor.visitLookupSwitchInsnWithProbes(label, keys, labels,
232				frame);
233		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
234				0, null);
235		assertEquals(1000, LabelInfo.getProbeId(label));
236	}
237
238	@Test
239	public void testVisitLookupSwitchInsn2() {
240		Label label2 = new Label();
241		LabelInfo.setTarget(label2);
242		LabelInfo.setTarget(label2);
243
244		final int[] keys = new int[] { 0, 1 };
245		final Label[] labels = new Label[] { label2, label };
246		adapter.visitInsn(Opcodes.ICONST_0);
247		adapter.visitLookupSwitchInsn(label, keys, labels);
248
249		expectedVisitor.visitInsn(Opcodes.ICONST_0);
250		expectedVisitor.visitLookupSwitchInsnWithProbes(label, keys, labels,
251				frame);
252		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
253				0, null);
254		assertEquals(LabelInfo.NO_PROBE, LabelInfo.getProbeId(label));
255		assertEquals(1000, LabelInfo.getProbeId(label2));
256	}
257
258	@Test
259	public void testVisitLookupSwitchInsn3() {
260		final int[] keys = new int[] { 0, 1 };
261		final Label[] labels = new Label[] { label, label };
262		adapter.visitInsn(Opcodes.ICONST_0);
263		adapter.visitLookupSwitchInsn(label, keys, labels);
264
265		expectedVisitor.visitInsn(Opcodes.ICONST_0);
266		expectedVisitor.visitLookupSwitchInsn(label, keys, labels);
267	}
268
269	@Test
270	public void testVisitTableSwitchInsn1() {
271		LabelInfo.setTarget(label);
272		LabelInfo.setTarget(label);
273
274		final Label[] labels = new Label[] { label, label };
275		adapter.visitInsn(Opcodes.ICONST_0);
276		adapter.visitTableSwitchInsn(0, 1, label, labels);
277
278		expectedVisitor.visitInsn(Opcodes.ICONST_0);
279		expectedVisitor.visitTableSwitchInsnWithProbes(0, 1, label, labels,
280				frame);
281		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
282				0, null);
283		assertEquals(1000, LabelInfo.getProbeId(label));
284	}
285
286	@Test
287	public void testVisitTableSwitchInsn2() {
288		Label label2 = new Label();
289		LabelInfo.setTarget(label2);
290		LabelInfo.setTarget(label2);
291
292		final Label[] labels = new Label[] { label2, label };
293		adapter.visitInsn(Opcodes.ICONST_0);
294		adapter.visitTableSwitchInsn(0, 1, label, labels);
295
296		expectedVisitor.visitInsn(Opcodes.ICONST_0);
297		expectedVisitor.visitTableSwitchInsnWithProbes(0, 1, label, labels,
298				frame);
299		expectedVisitor.visitFrame(Opcodes.F_FULL, 1, new Object[] { "Foo" },
300				0, null);
301		assertEquals(LabelInfo.NO_PROBE, LabelInfo.getProbeId(label));
302		assertEquals(1000, LabelInfo.getProbeId(label2));
303	}
304
305	@Test
306	public void testVisitTableSwitchInsn3() {
307		final Label[] labels = new Label[] { label, label };
308		adapter.visitInsn(Opcodes.ICONST_0);
309		adapter.visitTableSwitchInsn(0, 1, label, labels);
310
311		expectedVisitor.visitInsn(Opcodes.ICONST_0);
312		expectedVisitor.visitTableSwitchInsn(0, 1, label, labels);
313	}
314
315	@Test
316	public void testVisitTryCatchBlockNoProbe() {
317		Label start = new Label();
318		Label end = new Label();
319		Label handler = new Label();
320
321		adapter.visitTryCatchBlock(start, end, handler, "java/lang/Exception");
322		adapter.visitLabel(start);
323
324		expectedVisitor.visitTryCatchBlock(start, end, handler,
325				"java/lang/Exception");
326		expectedVisitor.visitLabel(start);
327	}
328
329	@Test
330	public void testVisitTryCatchBlockWithProbe() {
331		Label target = new Label();
332		LabelInfo.setSuccessor(target);
333		LabelInfo.setTarget(target);
334		Label end = new Label();
335		Label handler = new Label();
336		Label start = new Label();
337
338		adapter.visitTryCatchBlock(target, end, handler, "java/lang/Exception");
339		adapter.visitLabel(target);
340
341		expectedVisitor.visitTryCatchBlock(start, end, handler,
342				"java/lang/Exception");
343		expectedVisitor.visitLabel(start);
344		expectedVisitor.visitProbe(1000);
345		expectedVisitor.visitLabel(target);
346	}
347
348	@Test
349	public void testVisitMultipleTryCatchBlocksWithProbe() {
350		Label target = new Label();
351		LabelInfo.setSuccessor(target);
352		LabelInfo.setTarget(target);
353		Label end = new Label();
354		Label handler1 = new Label();
355		Label handler2 = new Label();
356		Label start = new Label();
357
358		adapter.visitTryCatchBlock(target, end, handler1, "java/lang/Exception");
359		adapter.visitTryCatchBlock(target, end, handler2, "java/io/IOException");
360		adapter.visitLabel(target);
361
362		expectedVisitor.visitTryCatchBlock(start, end, handler1,
363				"java/lang/Exception");
364		expectedVisitor.visitTryCatchBlock(start, end, handler2,
365				"java/io/IOException");
366		expectedVisitor.visitLabel(start);
367		expectedVisitor.visitProbe(1000);
368		expectedVisitor.visitLabel(target);
369	}
370
371	// === IProbeIdGenerator ===
372
373	public int nextId() {
374		return id++;
375	}
376
377}
378