package net.bytebuddy.utility.visitor;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.implementation.bytecode.StackSize;
import net.bytebuddy.test.utility.MockitoRule;
import net.bytebuddy.test.utility.ObjectPropertyAssertion;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.Arrays;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.*;
public class StackAwareMethodVisitorTest {
@Rule
public TestRule mockitoRule = new MockitoRule(this);
@Mock
private MethodDescription methodDescription;
@Mock
private MethodVisitor methodVisitor;
@Test
public void testDrainSingleSize() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1);
methodVisitor.drainStack();
verify(this.methodVisitor).visitLdcInsn(1);
verify(this.methodVisitor).visitInsn(Opcodes.POP);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testDrainDoubleSize() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1L);
methodVisitor.drainStack();
verify(this.methodVisitor).visitLdcInsn(1L);
verify(this.methodVisitor).visitInsn(Opcodes.POP2);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testDrainOrder() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1);
methodVisitor.visitLdcInsn(1L);
methodVisitor.drainStack();
InOrder inOrder = inOrder(this.methodVisitor);
inOrder.verify(this.methodVisitor).visitLdcInsn(1);
inOrder.verify(this.methodVisitor).visitLdcInsn(1L);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP2);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testDrainRetainTopSingle() throws Exception {
when(methodDescription.getStackSize()).thenReturn(42);
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1L);
methodVisitor.visitLdcInsn(1);
assertThat(methodVisitor.drainStack(Opcodes.ISTORE, Opcodes.ILOAD, StackSize.SINGLE), is(43));
InOrder inOrder = inOrder(this.methodVisitor);
inOrder.verify(this.methodVisitor).visitLdcInsn(1L);
inOrder.verify(this.methodVisitor).visitLdcInsn(1);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.ISTORE, 42);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP2);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.ILOAD, 42);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testDrainRetainTopDouble() throws Exception {
when(methodDescription.getStackSize()).thenReturn(42);
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1);
methodVisitor.visitLdcInsn(1L);
assertThat(methodVisitor.drainStack(Opcodes.LSTORE, Opcodes.LLOAD, StackSize.DOUBLE), is(44));
InOrder inOrder = inOrder(this.methodVisitor);
inOrder.verify(this.methodVisitor).visitLdcInsn(1);
inOrder.verify(this.methodVisitor).visitLdcInsn(1L);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.LSTORE, 42);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.LLOAD, 42);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testDrainFreeListOnly() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1);
methodVisitor.visitVarInsn(Opcodes.ISTORE, 41);
methodVisitor.visitLdcInsn(1);
assertThat(methodVisitor.drainStack(Opcodes.ISTORE, Opcodes.ILOAD, StackSize.SINGLE), is(0));
InOrder inOrder = inOrder(this.methodVisitor);
inOrder.verify(this.methodVisitor).visitLdcInsn(1);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.ISTORE, 41);
inOrder.verify(this.methodVisitor).visitLdcInsn(1);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testDrainFreeList() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitLdcInsn(1);
methodVisitor.visitVarInsn(Opcodes.ISTORE, 41);
methodVisitor.visitLdcInsn(1);
methodVisitor.visitLdcInsn(1);
assertThat(methodVisitor.drainStack(Opcodes.ISTORE, Opcodes.ILOAD, StackSize.SINGLE), is(43));
InOrder inOrder = inOrder(this.methodVisitor);
inOrder.verify(this.methodVisitor).visitLdcInsn(1);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.ISTORE, 41);
inOrder.verify(this.methodVisitor, times(2)).visitLdcInsn(1);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.ISTORE, 42);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP);
inOrder.verify(this.methodVisitor).visitVarInsn(Opcodes.ILOAD, 42);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testManualRegistration() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
Label label = new Label();
methodVisitor.register(label, Arrays.asList(StackSize.DOUBLE, StackSize.SINGLE));
methodVisitor.visitLabel(label);
methodVisitor.drainStack();
InOrder inOrder = inOrder(this.methodVisitor);
inOrder.verify(this.methodVisitor).visitLabel(label);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP);
inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP2);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testStackCanUnderflow() throws Exception {
StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);
methodVisitor.visitInsn(Opcodes.POP);
methodVisitor.drainStack();
verify(this.methodVisitor).visitInsn(Opcodes.POP);
verifyNoMoreInteractions(this.methodVisitor);
}
}