• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2018 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  *******************************************************************************/
12 package org.jacoco.core.internal.flow;
13 
14 import static org.junit.Assert.assertEquals;
15 
16 import java.util.Arrays;
17 
18 import org.jacoco.core.instr.MethodRecorder;
19 import org.junit.After;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.objectweb.asm.Label;
23 import org.objectweb.asm.MethodVisitor;
24 import org.objectweb.asm.Opcodes;
25 import org.objectweb.asm.commons.AnalyzerAdapter;
26 import org.objectweb.asm.util.Printer;
27 
28 /**
29  * Unit tests for {@link MethodProbesAdapter}.
30  */
31 public 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 
TraceAdapter(MethodRecorder recorder)49 		TraceAdapter(MethodRecorder recorder) {
50 			super(recorder.getVisitor());
51 			printer = recorder.getPrinter();
52 		}
53 
54 		@Override
visitProbe(int probeId)55 		public void visitProbe(int probeId) {
56 			rec("visitProbe", Integer.valueOf(probeId));
57 		}
58 
59 		@Override
visitInsnWithProbe(int opcode, int probeId)60 		public void visitInsnWithProbe(int opcode, int probeId) {
61 			rec("visitInsnWithProbe", Integer.valueOf(opcode),
62 					Integer.valueOf(probeId));
63 		}
64 
65 		@Override
visitJumpInsnWithProbe(int opcode, Label label, int probeId, IFrame frame)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
visitTableSwitchInsnWithProbes(int min, int max, Label dflt, Label[] labels, IFrame frame)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
visitLookupSwitchInsnWithProbes(Label dflt, int[] keys, Label[] labels, IFrame frame)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 
rec(String name, Object... args)88 		private void rec(String name, Object... args) {
89 			printer.text.add(name + Arrays.asList(args));
90 		}
91 
92 	}
93 
94 	@Before
setup()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
verify()116 	public void verify() {
117 		assertEquals(expected, actual);
118 	}
119 
120 	@Test
testVisitProbe1()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
testVisitProbe2()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
testVisitProbe3()142 	public void testVisitProbe3() {
143 		adapter.visitLabel(label);
144 
145 		expectedVisitor.visitLabel(label);
146 	}
147 
148 	@Test
testVisitInsn1()149 	public void testVisitInsn1() {
150 		adapter.visitInsn(Opcodes.RETURN);
151 
152 		expectedVisitor.visitInsnWithProbe(Opcodes.RETURN, 1000);
153 	}
154 
155 	@Test
testVisitInsn2()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
testVisitJumpInsn1()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
testVisitJumpInsn2()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
testVisitJumpInsn3()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
testVisitJumpInsn4()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
testVisitLookupSwitchInsn1()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
testVisitLookupSwitchInsn2()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
testVisitLookupSwitchInsn3()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
testVisitTableSwitchInsn1()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
testVisitTableSwitchInsn2()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
testVisitTableSwitchInsn3()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
testVisitTryCatchBlockNoProbe()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 		adapter.visitInsn(Opcodes.NOP);
324 		adapter.visitLabel(end);
325 
326 		expectedVisitor.visitTryCatchBlock(start, end, handler,
327 				"java/lang/Exception");
328 		expectedVisitor.visitLabel(start);
329 		expectedVisitor.visitInsn(Opcodes.NOP);
330 		expectedVisitor.visitLabel(end);
331 	}
332 
333 	@Test
testVisitTryCatchBlockWithProbeBeforeStart()334 	public void testVisitTryCatchBlockWithProbeBeforeStart() {
335 		Label start = new Label();
336 		LabelInfo.setSuccessor(start);
337 		LabelInfo.setTarget(start);
338 		Label end = new Label();
339 		Label handler1 = new Label();
340 		Label handler2 = new Label();
341 
342 		adapter.visitTryCatchBlock(start, end, handler1, "java/lang/Exception");
343 		adapter.visitTryCatchBlock(start, end, handler2, "java/lang/Throwable");
344 		adapter.visitLabel(start);
345 		adapter.visitInsn(Opcodes.NOP);
346 		adapter.visitLabel(end);
347 
348 		Label probe = new Label();
349 		expectedVisitor.visitTryCatchBlock(probe, end, handler1,
350 				"java/lang/Exception");
351 		expectedVisitor.visitTryCatchBlock(probe, end, handler2,
352 				"java/lang/Throwable");
353 		expectedVisitor.visitLabel(probe);
354 		expectedVisitor.visitProbe(1000);
355 		expectedVisitor.visitLabel(start);
356 		expectedVisitor.visitInsn(Opcodes.NOP);
357 		expectedVisitor.visitLabel(end);
358 	}
359 
360 	@Test
testVisitTryCatchBlockWithProbeBeforeEnd()361 	public void testVisitTryCatchBlockWithProbeBeforeEnd() {
362 		Label start = new Label();
363 		Label end = new Label();
364 		LabelInfo.setSuccessor(end);
365 		LabelInfo.setTarget(end);
366 		Label handler1 = new Label();
367 		Label handler2 = new Label();
368 
369 		adapter.visitTryCatchBlock(start, end, handler1, "java/lang/Exception");
370 		adapter.visitTryCatchBlock(start, end, handler2, "java/lang/Throwable");
371 		adapter.visitLabel(start);
372 		adapter.visitInsn(Opcodes.NOP);
373 		adapter.visitLabel(end);
374 
375 		Label probe = new Label();
376 		expectedVisitor.visitTryCatchBlock(start, probe, handler1,
377 				"java/lang/Exception");
378 		expectedVisitor.visitTryCatchBlock(start, probe, handler2,
379 				"java/lang/Throwable");
380 		expectedVisitor.visitLabel(start);
381 		expectedVisitor.visitInsn(Opcodes.NOP);
382 		expectedVisitor.visitLabel(probe);
383 		expectedVisitor.visitProbe(1000);
384 		expectedVisitor.visitLabel(end);
385 	}
386 
387 	/**
388 	 * https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-2.html#jvms-2.11.10
389 	 */
390 	@Test
testStructuredLocking()391 	public void testStructuredLocking() {
392 		Label start = new Label();
393 		LabelInfo.setSuccessor(start);
394 		LabelInfo.setTarget(start);
395 		Label end = new Label();
396 		LabelInfo.setSuccessor(end);
397 		LabelInfo.setTarget(end);
398 		Label handlerStart = new Label();
399 		Label handlerEnd = new Label();
400 		Label after = new Label();
401 
402 		adapter.visitTryCatchBlock(start, end, handlerStart, null);
403 		adapter.visitTryCatchBlock(handlerStart, handlerEnd, handlerStart,
404 				null);
405 		adapter.visitVarInsn(Opcodes.ALOAD, 1);
406 		adapter.visitInsn(Opcodes.MONITORENTER);
407 		adapter.visitLabel(start);
408 		adapter.visitInsn(Opcodes.NOP);
409 		adapter.visitVarInsn(Opcodes.ALOAD, 1);
410 		adapter.visitInsn(Opcodes.MONITOREXIT);
411 		adapter.visitLabel(end);
412 		adapter.visitJumpInsn(Opcodes.GOTO, after);
413 		adapter.visitLabel(handlerStart);
414 		adapter.visitVarInsn(Opcodes.ALOAD, 1);
415 		adapter.visitInsn(Opcodes.MONITOREXIT);
416 		adapter.visitLabel(handlerEnd);
417 		adapter.visitInsn(Opcodes.ATHROW);
418 		adapter.visitLabel(after);
419 
420 		Label probe1 = new Label();
421 		Label probe2 = new Label();
422 		expectedVisitor.visitTryCatchBlock(probe1, probe2, handlerStart, null);
423 		expectedVisitor.visitTryCatchBlock(handlerStart, handlerEnd,
424 				handlerStart, null);
425 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 1);
426 		expectedVisitor.visitInsn(Opcodes.MONITORENTER);
427 		// next probe must be INSIDE range of instructions covered by handler,
428 		// otherwise monitorexit won't be executed
429 		// in case if probe causes exception
430 		expectedVisitor.visitLabel(probe1);
431 		expectedVisitor.visitProbe(1000);
432 		expectedVisitor.visitLabel(start);
433 		expectedVisitor.visitInsn(Opcodes.NOP);
434 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 1);
435 		expectedVisitor.visitInsn(Opcodes.MONITOREXIT);
436 		// next probe must be OUTSIDE range of instructions covered by handler,
437 		// otherwise monitorexit will be executed second time
438 		// in case if probe causes exception
439 		expectedVisitor.visitLabel(probe2);
440 		expectedVisitor.visitProbe(1001);
441 		expectedVisitor.visitLabel(end);
442 		expectedVisitor.visitJumpInsn(Opcodes.GOTO, after);
443 		expectedVisitor.visitLabel(handlerStart);
444 		expectedVisitor.visitVarInsn(Opcodes.ALOAD, 1);
445 		expectedVisitor.visitInsn(Opcodes.MONITOREXIT);
446 		expectedVisitor.visitLabel(handlerEnd);
447 		expectedVisitor.visitInsnWithProbe(Opcodes.ATHROW, 1002);
448 		expectedVisitor.visitLabel(after);
449 	}
450 
451 	// === IProbeIdGenerator ===
452 
nextId()453 	public int nextId() {
454 		return id++;
455 	}
456 
457 }
458