package rocks.inspectit.agent.java.instrumentation.asm; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import info.novatec.inspectit.org.objectweb.asm.ClassReader; import info.novatec.inspectit.org.objectweb.asm.ClassWriter; import info.novatec.inspectit.org.objectweb.asm.MethodVisitor; import info.novatec.inspectit.org.objectweb.asm.Opcodes; import java.util.Arrays; import java.util.Collections; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.asm.Type; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import rocks.inspectit.agent.java.IAgent; import rocks.inspectit.agent.java.hooking.IHookDispatcher; import rocks.inspectit.agent.java.instrumentation.InstrumenterFactory; import rocks.inspectit.shared.all.instrumentation.config.IMethodInstrumentationPoint; import rocks.inspectit.shared.all.instrumentation.config.impl.MethodInstrumentationConfig; import rocks.inspectit.shared.all.instrumentation.config.impl.SpecialInstrumentationPoint; import rocks.inspectit.shared.all.instrumentation.config.impl.SubstitutionDescriptor; /** * @author Ivan Senic * */ @SuppressWarnings("PMD") public class SpecialMethodInstrumenterTest extends AbstractInstrumentationTest { protected static final String TEST_CLASS_FQN = "rocks.inspectit.agent.java.instrumentation.asm.InstrumentationTestClass"; protected static final Answer<MethodVisitor> SPECIAL_INSTRUMENTER_ANSWER = new Answer<MethodVisitor>() { @Override public MethodVisitor answer(InvocationOnMock invocation) throws Throwable { Object[] arguments = invocation.getArguments(); SpecialInstrumentationPoint sip = (SpecialInstrumentationPoint) arguments[0]; return getSpecialMethodInstrumenter((MethodVisitor) arguments[1], (Integer) arguments[2], (String) arguments[3], (String) arguments[4], sip.getId(), sip.getSubstitutionDescriptor()); } }; public static IHookDispatcher dispatcher; public static IAgent a; @Mock IHookDispatcher hookDispatcher; @Mock IAgent agent; @Mock InstrumenterFactory instrumenterFactory; @Mock SpecialInstrumentationPoint sip; @Mock MethodInstrumentationConfig config; ClassInstrumenter classInstrumenter; LoaderAwareClassWriter classWriter; @BeforeMethod public void init() { dispatcher = hookDispatcher; a = agent; } // inner class naming based on the substitution type, not possible to call by the test method public class NoSubstitution extends SpecialMethodInstrumenterTest { @BeforeMethod public void setReturnValueDescriptor() { when(sip.getSubstitutionDescriptor()).thenReturn(new SubstitutionDescriptor(false, false)); } @Test public void noResult() throws Exception { String methodName = "stringNullParameter"; long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void resultOnBefore() throws Exception { String methodName = "stringNullParameter"; Object returnValue = "returnValue"; long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void resultOnAfter() throws Exception { String methodName = "stringNullParameter"; Object returnValue = "returnValue"; long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName)).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } } public class ReturnValueSubstitution extends SpecialMethodInstrumenterTest { @BeforeMethod public void setReturnValueDescriptor() { when(sip.getSubstitutionDescriptor()).thenReturn(new SubstitutionDescriptor(true, false)); } // static @Test public void hookStaticVoid() throws Exception { String methodName = "voidNullParameterStatic"; long methodId = 7L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. this.callMethod(testClass, methodName, null); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], null); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookStaticVoidResultOnBefore() throws Exception { String methodName = "voidNullParameterStatic"; Object returnValue = "returnValue"; long methodId = 7L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, null, new Object[0])).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. this.callMethod(testClass, methodName, null); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookStaticVoidResultOnBeforeNull() throws Exception { String methodName = "voidNullParameterStatic"; long methodId = 7L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, null, new Object[0])).thenReturn(null); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. this.callMethod(testClass, methodName, null); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], null); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookStaticVoidResultOnAfter() throws Exception { String methodName = "voidNullParameterStatic"; Object returnValue = "returnValue"; long methodId = 7L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, null, new Object[0], null)).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. this.callMethod(testClass, methodName, null); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], null); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringNullParameterStatic() throws Exception { String methodName = "stringNullParameterStatic"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringNullParameterStaticResultOnBefore() throws Exception { String methodName = "stringNullParameterStatic"; Object returnValue = "returnValue"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, null, new Object[0])).thenReturn(returnValue); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is(returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringNullParameterStaticResultOnBeforeWrong() throws Exception { String methodName = "stringNullParameterStatic"; Object returnValue = true; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, null, new Object[0])).thenReturn(returnValue); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringNullParameterStaticResultOnAfter() throws Exception { String methodName = "stringNullParameterStatic"; Object returnValue = "returnValue"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, null, new Object[0], methodName)).thenReturn(returnValue); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is(returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringNullParameterStaticResultOnAfterWrong() throws Exception { String methodName = "stringNullParameterStatic"; Object returnValue = true; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, null, new Object[0], methodName)).thenReturn(returnValue); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, null, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, null, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } // non static @Test public void hookNoStatic() throws Exception { String methodName = "stringNullParameter"; long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookNoStaticResultOnBefore() throws Exception { String methodName = "stringNullParameter"; Object returnValue = "returnValue"; long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is(returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookNoStaticResultOnBeforeWrong() throws Exception { String methodName = "stringNullParameter"; Object returnValue = Boolean.valueOf(false); long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookNoStaticResultOnAfter() throws Exception { String methodName = "stringNullParameter"; Object returnValue = "returnValue"; long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName)).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is(returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } @Test public void hookNoStaticResultOnAfterWrong() throws Exception { String methodName = "stringNullParameter"; Object returnValue = Long.valueOf(1L); long methodId = 3L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName)).thenReturn(returnValue); // call this method via reflection as we would get a class cast // exception by casting to the concrete class. Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) methodName)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], methodName); verifyNoMoreInteractions(hookDispatcher); } // primitive @Test public void intNullParameter() throws Exception { String methodName = "intNullParameter"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Integer.valueOf(3))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void intNullParameterResultOnBefore() throws Exception { String methodName = "intNullParameter"; Object returnValue = Integer.valueOf(11); long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is(returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void intNullParameterResultOnBeforeOtherPrimitive() throws Exception { String methodName = "intNullParameter"; Double returnValue = Double.valueOf(4552236.22121D); long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Integer.valueOf(3))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void intNullParameterResultOnBeforeObject() throws Exception { String methodName = "intNullParameter"; Object returnValue = "returnValue"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Integer.valueOf(3))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void intNullParameterResultOnAfter() throws Exception { String methodName = "intNullParameter"; Object returnValue = Integer.valueOf(11); long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3)).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is(returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void intNullParameterResultOnAfterOtherPrimitive() throws Exception { String methodName = "intNullParameter"; Double returnValue = Double.valueOf(4552236.22121D); long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3)).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Integer.valueOf(3))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void intNullParameterResultOnAfterObject() throws Exception { String methodName = "intNullParameter"; Object returnValue = "returnValue"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3)).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Integer.valueOf(3))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void doubleNullParameter() throws Exception { String methodName = "doubleNullParameter"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Double.valueOf(5.3D))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 5.3D); verifyNoMoreInteractions(hookDispatcher); } @Test public void doubleNullParameterResultOnBefore() throws Exception { String methodName = "doubleNullParameter"; Double returnValue = Double.valueOf(45223.412D); long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void doubleNullParameterResultOnBeforeOtherPrimitive() throws Exception { String methodName = "doubleNullParameter"; Float returnValue = Float.valueOf(45223.412F); long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Double.valueOf(5.3D))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 5.3D); verifyNoMoreInteractions(hookDispatcher); } @Test public void doubleNullParameterResultOnAfterObject() throws Exception { String methodName = "doubleNullParameter"; Object returnValue = "whatever"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 5.3D)).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Double.valueOf(5.3D))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 5.3D); verifyNoMoreInteractions(hookDispatcher); } // array @Test public void intArrayNullParameter() throws Exception { String methodName = "intArrayNullParameter"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) new int[] { 1, 2, 3 })); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], new int[] { 1, 2, 3 }); verifyNoMoreInteractions(hookDispatcher); } @Test public void intArrayNullParameterResultBefore() throws Exception { String methodName = "intArrayNullParameter"; int[] returnValue = new int[] { 4, 5, 6, 7, 8, 9 }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void intArrayNullParameterResultBeforeWrongArray() throws Exception { String methodName = "intArrayNullParameter"; long[] returnValue = new long[] { 4, 5, 6, 7, 8, 9 }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) new int[] { 1, 2, 3 })); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], new int[] { 1, 2, 3 }); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringArrayNullParameter() throws Exception { String methodName = "stringArrayNullParameter"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) new String[] { "test123", "bla" })); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], new String[] { "test123", "bla" }); verifyNoMoreInteractions(hookDispatcher); } @Test public void stringArrayNullParameterResultOnAfter() throws Exception { String methodName = "stringArrayNullParameter"; String[] returnValue = new String[] { "something", "totally", "sexy" }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], new String[] { "test123", "bla" })).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], new String[] { "test123", "bla" }); verifyNoMoreInteractions(hookDispatcher); } // parameters @Test public void stringOneParameter() throws Exception { String methodName = "stringOneParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); this.callMethod(testClass, methodName, parameters); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, "stringOneParameter"); verifyNoMoreInteractions(hookDispatcher); } // exception @Test public void unexpectedExceptionTrowing() throws Exception { String methodName = "unexpectedExceptionThrowing"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); try { this.callMethod(testClass, methodName, null); } catch (Throwable t) { // NOPMD } ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(eq(methodId), eq(testClass), eq(new Object[0]), captor.capture()); assertThat(captor.getValue(), is(instanceOf(Exception.class))); verifyNoMoreInteractions(hookDispatcher); } @Test public void unexpectedExceptionNotTrowing() throws Exception { String methodName = "unexpectedExceptionNotThrowing"; Object[] parameters = { "java.lang.Object" }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, Object.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); try { this.callMethod(testClass, methodName, parameters); } catch (Throwable t) { } ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); verify(hookDispatcher).dispatchSpecialMethodAfterBody(eq(methodId), eq(testClass), eq(parameters), captor.capture()); assertThat(captor.getValue(), is(instanceOf(Exception.class))); verifyNoMoreInteractions(hookDispatcher); } @Test public void exceptionHandledResultReturned() throws Exception { String methodName = "exceptionHandledResultReturned"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) 3)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void exceptionHandledResultChanged() throws Exception { String methodName = "exceptionHandledResultReturned"; long methodId = 9L; int returnValue = 112; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3)).thenReturn(returnValue); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) returnValue)); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } } public class ParameterValueSubstitution extends SpecialMethodInstrumenterTest { @BeforeMethod public void setReturnValueDescriptor() { when(sip.getSubstitutionDescriptor()).thenReturn(new SubstitutionDescriptor(false, true)); } // no parameter methods @Test public void noParameters() throws Exception { String methodName = "intNullParameter"; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); when(hookDispatcher.dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0])).thenReturn(9); Object result = this.callMethod(testClass, methodName, null); assertThat(result, is((Object) Integer.valueOf(3))); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[0]); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[0], 3); verifyNoMoreInteractions(hookDispatcher); } @Test public void noChangeStringParameter() throws Exception { String methodName = "returnStringParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(parameters[0])); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, parameters[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void changeStringParameterOnBefore() throws Exception { String methodName = "returnStringParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; final Object parameterValue = "parameterValue"; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = parameterValue; return null; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(parameterValue)); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { parameterValue }); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[] { parameterValue }, parameterValue); verifyNoMoreInteractions(hookDispatcher); } @Test public void changeStringParameterOnAfter() throws Exception { String methodName = "returnStringParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; final Object parameterValue = "parameterValue"; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = parameterValue; return null; } }).when(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, parameters[0]); Object result = this.callMethod(testClass, methodName, parameters); // effectively no changes when afterBody returns the result with parameter substitution assertThat(result, is(parameters[0])); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[] { parameterValue }, parameters[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void changeStringParameterOnBeforeWrongClass() throws Exception { String methodName = "returnStringParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; final Long parameterValue = 10L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = parameterValue; return null; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); Object result = this.callMethod(testClass, methodName, parameters); // wrong class so no subsititution assertThat(result, is(parameters[0])); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { parameterValue }); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, parameters[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void noChangeTwoPrimitveParameters() throws Exception { String methodName = "returnBooleanParameter"; Object[] parameters = { "int", "boolean" }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, int.class, boolean.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(parameters[1])); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, parameters[1]); verifyNoMoreInteractions(hookDispatcher); } @Test public void changeTwoPrimitiveParametersOnBefore() throws Exception { String methodName = "returnBooleanParameter"; Object[] parameters = { "int", "boolean" }; long methodId = 9L; final int intSub = 122563; final boolean boolSub = true; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, int.class, boolean.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = intSub; ((Object[]) invocation.getArguments()[2])[1] = boolSub; return null; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is((Object) true)); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { intSub, boolSub }); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[] { intSub, boolSub }, true); verifyNoMoreInteractions(hookDispatcher); } @Test public void noChangeArrayParameter() throws Exception { String methodName = "returnArrayParameter"; Object[] parameters = { "array" }; long methodId = 9L; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, Object[].class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(parameters[0])); verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, parameters[0]); verifyNoMoreInteractions(hookDispatcher); } @Test public void chnageArrayParameterBefore() throws Exception { String methodName = "returnArrayParameter"; Object[] parameters = { "array" }; long methodId = 9L; final Object[] substitutionParam = new Object[] { "ivan", "tests", "are", "awesome" }; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, Object[].class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = substitutionParam; return null; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is((Object) substitutionParam)); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { substitutionParam }); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[] { substitutionParam }, substitutionParam); verifyNoMoreInteractions(hookDispatcher); } @Test public void changeArrayParameterBeforeWrongArrayType() throws Exception { String methodName = "returnArrayParameter"; Object[] parameters = { "array" }; long methodId = 9L; final int[] substitutionParam = new int[] { 1, 2, 3, 4 }; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, Object[].class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = substitutionParam; return null; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(parameters[0])); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { substitutionParam }); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, parameters, parameters[0]); verifyNoMoreInteractions(hookDispatcher); } } public class ReturnValueAndParameterValueSubstitution extends SpecialMethodInstrumenterTest { @BeforeMethod public void setReturnValueDescriptor() { when(sip.getSubstitutionDescriptor()).thenReturn(new SubstitutionDescriptor(true, true)); } // no parameter methods @Test public void changeStringParameterAndResultOnBefore() throws Exception { String methodName = "returnStringParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; final Object parameterValue = "parameterValue"; final Object returnValue = "returnValue"; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = parameterValue; return returnValue; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(returnValue)); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { parameterValue }); verifyNoMoreInteractions(hookDispatcher); } @Test public void changeStringParameterOnBeforeAndResultOnAfter() throws Exception { String methodName = "returnStringParameter"; Object[] parameters = { "java.lang.String" }; long methodId = 9L; final Object parameterValue = "parameterValue"; final Object returnValue = "returnValue"; when(sip.getId()).thenReturn(methodId); prepareConfigurationMockMethod(config, InstrumentationTestClass.class, methodName, String.class); doAnswer(SPECIAL_INSTRUMENTER_ANSWER).when(instrumenterFactory).getMethodVisitor(eq(sip), Matchers.<MethodVisitor> any(), anyInt(), anyString(), anyString(), anyBoolean()); when(config.getAllInstrumentationPoints()).thenReturn(Collections.<IMethodInstrumentationPoint> singleton(sip)); ClassReader cr = new ClassReader(TEST_CLASS_FQN); prepareWriter(cr, null, false, config); cr.accept(classInstrumenter, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); assertThat(classInstrumenter.isByteCodeAdded(), is(true)); byte b[] = classWriter.toByteArray(); // now call this method Object testClass = this.createInstance(TEST_CLASS_FQN, b); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { ((Object[]) invocation.getArguments()[2])[0] = parameterValue; return null; } }).when(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, parameters); doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return returnValue; } }).when(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[] { parameterValue }, parameterValue); Object result = this.callMethod(testClass, methodName, parameters); assertThat(result, is(returnValue)); // possible bug in mockito, remembers the changed parameter in the invocation verify(hookDispatcher).dispatchSpecialMethodBeforeBody(methodId, testClass, new Object[] { parameterValue }); verify(hookDispatcher).dispatchSpecialMethodAfterBody(methodId, testClass, new Object[] { parameterValue }, parameterValue); verifyNoMoreInteractions(hookDispatcher); } } protected static SpecialMethodInstrumenter getSpecialMethodInstrumenter(MethodVisitor superMethodVisitor, int access, String name, String desc, long id, SubstitutionDescriptor descriptor) { return new SpecialMethodInstrumenter(superMethodVisitor, access, name, desc, id, descriptor) { @Override protected void loadHookDispatcher() { mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(SpecialMethodInstrumenterTest.class), "dispatcher", Type.getDescriptor(IHookDispatcher.class)); } }; } protected void prepareWriter(ClassReader cr, ClassLoader classLoader, boolean enhancedExceptionSensor, MethodInstrumentationConfig... configs) { classWriter = new LoaderAwareClassWriter(cr, ClassWriter.COMPUTE_FRAMES, classLoader); classInstrumenter = new ClassInstrumenter(instrumenterFactory, classWriter, Arrays.asList(configs), enhancedExceptionSensor); } }