org.jacoco.core.internal.instr.FrameTrackerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.jacoco.core.internal.instr.FrameTrackerTest.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2013 Mountainminds GmbH & Co. KG and Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Marc R. Hoffmann - initial API and implementation
 *    
 *******************************************************************************/
package org.jacoco.core.internal.instr;

import static org.junit.Assert.assertEquals;
import static org.objectweb.asm.Opcodes.*;

import org.jacoco.core.instr.MethodRecorder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.MethodNode;

/**
 * Unit tests for {@link ClassInstrumenter}.
 */
public class FrameTrackerTest {

    private static class FrameBuilder {

        private Object[] stack = new Object[0];
        private Object[] locals = new Object[0];

        FrameBuilder stack(Object... stack) {
            this.stack = stack;
            return this;
        }

        FrameBuilder locals(Object... locals) {
            this.locals = locals;
            return this;
        }

        void accept(MethodVisitor mv) {
            mv.visitFrame(F_NEW, locals.length, locals, stack.length, stack);
        }

    }

    private FrameBuilder before, after;

    private MethodNode mv;

    private Label label;

    @Before
    public void setup() {
        before = new FrameBuilder();
        after = new FrameBuilder();
        mv = new MethodNode(0, "test", "()V", null, null);
        label = new Label();
    }

    @After
    public void verify() {
        MethodRecorder actual = new MethodRecorder();
        MethodVisitor noLabels = new MethodVisitor(Opcodes.ASM4, actual.getVisitor()) {
            @Override
            public void visitLabel(Label label) {
                // Ignore labels inserted by the tracker
            }
        };
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", noLabels);
        before.accept(tracker);
        mv.instructions.accept(tracker);
        tracker.insertFrame();

        MethodRecorder expected = new MethodRecorder();
        before.accept(expected.getVisitor());
        mv.instructions.accept(expected.getVisitor());
        after.accept(expected.getVisitor());

        assertEquals(expected, actual);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitFrameIllegalFrameType() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitFrame(F_APPEND, 0, null, 0, null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitInsnIllegalOpcode() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitInsn(GOTO);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitIntInsnIllegalOpcode() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitIntInsn(NOP, 0);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitVarInsnIllegalOpcode() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitVarInsn(NOP, 0);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitTypeInsnIllegalOpcode() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitTypeInsn(NOP, "A");
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitFieldInsnIllegalOpcode() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitFieldInsn(NOP, "A", "x", "I");
    }

    @Test(expected = IllegalArgumentException.class)
    public void testVisitJumpInsnIllegalOpcode() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitJumpInsn(NOP, new Label());
    }

    @Test(expected = IllegalStateException.class)
    public void testInvalidFrame() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitInsn(POP);
    }

    @Test
    public void testArgumentsConstructor() {
        FrameBuilder expectedFrame = new FrameBuilder();
        expectedFrame.locals(UNINITIALIZED_THIS);
        testArguments(0, "<init>", "()V", expectedFrame);
    }

    @Test
    public void testArgumentsStatic() {
        FrameBuilder expectedFrame = new FrameBuilder();
        testArguments(Opcodes.ACC_STATIC, "test", "()V", expectedFrame);
    }

    @Test
    public void testArgumentsStaticIJZ() {
        FrameBuilder expectedFrame = new FrameBuilder();
        expectedFrame.locals(INTEGER, LONG, INTEGER);
        testArguments(Opcodes.ACC_STATIC, "test", "(IJZ)V", expectedFrame);
    }

    @Test
    public void testArgumentsStaticLArr() {
        FrameBuilder expectedFrame = new FrameBuilder();
        expectedFrame.locals("Foo", "[[S");
        testArguments(Opcodes.ACC_STATIC, "test", "(LFoo;[[S)V", expectedFrame);
    }

    @Test
    public void testArgumentsFD() {
        FrameBuilder expectedFrame = new FrameBuilder();
        expectedFrame.locals("Test", FLOAT, DOUBLE);
        testArguments(0, "test", "(FD)V", expectedFrame);
    }

    private void testArguments(int access, String name, String desc, FrameBuilder expectedFrame) {
        MethodRecorder actual = new MethodRecorder();
        FrameTracker tracker = new FrameTracker("Test", access, name, desc, actual.getVisitor());
        tracker.insertFrame();

        MethodRecorder expected = new MethodRecorder();
        expectedFrame.accept(expected.getVisitor());

        assertEquals(expected, actual);
    }

    @Test
    public void testFrameGaps() {
        before.locals().stack(INTEGER);
        mv.visitVarInsn(ISTORE, 3);
        after.locals(TOP, TOP, TOP, INTEGER).stack();
    }

    @Test
    public void testLargeFrame() {
        before.locals("A", "B", "C", "D", "E").stack("AA", "BB", "CC", "DD", "EE");
        mv.visitInsn(NOP);
        after.locals("A", "B", "C", "D", "E").stack("AA", "BB", "CC", "DD", "EE");
    }

    @Test
    public void AALOAD_multidim_obj() {
        before.locals().stack("[[Ljava/lang/String;", INTEGER);
        mv.visitInsn(AALOAD);
        after.locals().stack("[Ljava/lang/String;");
    }

    @Test
    public void AALOAD_multidim_prim() {
        before.locals().stack("[[I", INTEGER);
        mv.visitInsn(AALOAD);
        after.locals().stack("[I");
    }

    @Test
    public void AASTORE() {
        before.locals().stack("[Ljava/lang/String;", INTEGER, "[Ljava/lang/String;");
        mv.visitInsn(AASTORE);
        after.locals().stack();
    }

    @Test
    public void ACONST_NULL() {
        before.locals().stack();
        mv.visitInsn(ACONST_NULL);
        after.locals().stack(NULL);
    }

    @Test
    public void ALOAD() {
        before.locals(LONG, "X", INTEGER).stack();
        mv.visitVarInsn(ALOAD, 2);
        after.locals(LONG, "X", INTEGER).stack("X");
    }

    @Test
    public void ANEWARRAY() {
        before.locals().stack(INTEGER);
        mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
        after.locals().stack("[Ljava/lang/String;");
    }

    @Test
    public void ANEWARRAY_multidim_obj() {
        before.locals().stack(INTEGER);
        mv.visitTypeInsn(ANEWARRAY, "[Ljava/lang/String;");
        after.locals().stack("[[Ljava/lang/String;");
    }

    @Test
    public void ANEWARRAY_multidim_prim() {
        before.locals().stack(INTEGER);
        mv.visitTypeInsn(ANEWARRAY, "[I");
        after.locals().stack("[[I");
    }

    @Test
    public void ARETURN() {
        before.locals().stack("java/lang/Object");
        mv.visitInsn(ARETURN);
        after.locals().stack();
    }

    @Test
    public void ARRAYLENGTH() {
        before.locals().stack("[Z");
        mv.visitInsn(ARRAYLENGTH);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ASTORE() {
        before.locals(LONG, "X", INTEGER).stack("Y");
        mv.visitVarInsn(ASTORE, 3);
        after.locals(LONG, "X", "Y").stack();
    }

    @Test
    public void ATHROW() {
        before.locals().stack("java/lang/Exception");
        mv.visitInsn(ATHROW);
        after.locals().stack();
    }

    @Test
    public void BALOAD() {
        before.locals().stack("[B", INTEGER);
        mv.visitInsn(BALOAD);
        after.locals().stack(INTEGER);
    }

    @Test
    public void BASTORE() {
        before.locals().stack("[B", INTEGER, INTEGER);
        mv.visitInsn(BASTORE);
        after.locals().stack();
    }

    @Test
    public void BIPUSH() {
        before.locals().stack();
        mv.visitIntInsn(BIPUSH, 123);
        after.locals().stack(INTEGER);
    }

    @Test
    public void CALOAD() {
        before.locals().stack("[C", INTEGER);
        mv.visitInsn(CALOAD);
        after.locals().stack(INTEGER);
    }

    @Test
    public void CASTORE() {
        before.locals().stack("[C", INTEGER, INTEGER);
        mv.visitInsn(CASTORE);
        after.locals().stack();
    }

    @Test
    public void CHECKCAST() {
        before.locals().stack("java/lang/Object");
        mv.visitTypeInsn(CHECKCAST, "java/lang/String");
        after.locals().stack("java/lang/String");
    }

    @Test
    public void D2F() {
        before.locals().stack(DOUBLE);
        mv.visitInsn(D2F);
        after.locals().stack(FLOAT);
    }

    @Test
    public void D2I() {
        before.locals().stack(DOUBLE);
        mv.visitInsn(D2I);
        after.locals().stack(INTEGER);
    }

    @Test
    public void D2L() {
        before.locals().stack(DOUBLE);
        mv.visitInsn(D2L);
        after.locals().stack(LONG);
    }

    @Test
    public void DADD() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DADD);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DALOAD() {
        before.locals().stack("[D", INTEGER);
        mv.visitInsn(DALOAD);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DASTORE() {
        before.locals().stack("[D", INTEGER, DOUBLE);
        mv.visitInsn(DASTORE);
        after.locals().stack();
    }

    @Test
    public void DCMPG() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DCMPG);
        after.locals().stack(INTEGER);
    }

    @Test
    public void DCMPL() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DCMPL);
        after.locals().stack(INTEGER);
    }

    @Test
    public void DCONST_0() {
        before.locals().stack();
        mv.visitInsn(DCONST_0);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DCONST_1() {
        before.locals().stack();
        mv.visitInsn(DCONST_1);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DDIV() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DDIV);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DLOAD() {
        before.locals(DOUBLE).stack();
        mv.visitVarInsn(DLOAD, 0);
        after.locals(DOUBLE).stack(DOUBLE);
    }

    @Test
    public void DMUL() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DMUL);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DNEG() {
        before.locals().stack(DOUBLE);
        mv.visitInsn(DNEG);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DREM() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DREM);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DRETURN() {
        before.locals().stack(DOUBLE);
        mv.visitInsn(DRETURN);
        after.locals().stack();
    }

    @Test
    public void DSTORE() {
        before.locals().stack(DOUBLE);
        mv.visitVarInsn(DSTORE, 0);
        after.locals(DOUBLE).stack();
    }

    @Test
    public void DSUB() {
        before.locals().stack(DOUBLE, DOUBLE);
        mv.visitInsn(DSUB);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void DUP() {
        before.locals().stack("A");
        mv.visitInsn(DUP);
        after.locals().stack("A", "A");
    }

    @Test
    public void DUP2_one_two_word_item() {
        before.locals().stack(LONG);
        mv.visitInsn(DUP2);
        after.locals().stack(LONG, LONG);
    }

    @Test
    public void DUP2_two_one_word_items() {
        before.locals().stack("A", "B");
        mv.visitInsn(DUP2);
        after.locals().stack("A", "B", "A", "B");
    }

    @Test
    public void DUP_X1() {
        before.locals().stack("A", "B");
        mv.visitInsn(DUP_X1);
        after.locals().stack("B", "A", "B");
    }

    @Test
    public void DUP2_X1_one_two_word_item() {
        before.locals().stack("A", LONG);
        mv.visitInsn(DUP2_X1);
        after.locals().stack(LONG, "A", LONG);
    }

    @Test
    public void DUP2_X1_two_one_word_items() {
        before.locals().stack("A", "B", "C");
        mv.visitInsn(DUP2_X1);
        after.locals().stack("B", "C", "A", "B", "C");
    }

    @Test
    public void DUP_X2() {
        before.locals().stack("A", "B", "C");
        mv.visitInsn(DUP_X2);
        after.locals().stack("C", "A", "B", "C");
    }

    @Test
    public void DUP2_X2_one_two_word_item() {
        before.locals().stack("A", "B", LONG);
        mv.visitInsn(DUP2_X2);
        after.locals().stack(LONG, "A", "B", LONG);
    }

    @Test
    public void DUP2_X2_two_one_word_items() {
        before.locals().stack("A", "B", "C", "D");
        mv.visitInsn(DUP2_X2);
        after.locals().stack("C", "D", "A", "B", "C", "D");
    }

    @Test
    public void F2D() {
        before.locals().stack(FLOAT);
        mv.visitInsn(F2D);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void F2I() {
        before.locals().stack(FLOAT);
        mv.visitInsn(F2I);
        after.locals().stack(INTEGER);
    }

    @Test
    public void F2L() {
        before.locals().stack(FLOAT);
        mv.visitInsn(F2L);
        after.locals().stack(LONG);
    }

    @Test
    public void FADD() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FADD);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FALOAD() {
        before.locals().stack("[F", INTEGER);
        mv.visitInsn(FALOAD);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FASTORE() {
        before.locals().stack("[F", INTEGER, FLOAT);
        mv.visitInsn(FASTORE);
        after.locals().stack();
    }

    @Test
    public void FCMPG() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FCMPG);
        after.locals().stack(INTEGER);
    }

    @Test
    public void FCMPL() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FCMPL);
        after.locals().stack(INTEGER);
    }

    @Test
    public void FCONST_0() {
        before.locals().stack();
        mv.visitInsn(FCONST_0);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FCONST_1() {
        before.locals().stack();
        mv.visitInsn(FCONST_1);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FCONST_2() {
        before.locals().stack();
        mv.visitInsn(FCONST_2);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FDIV() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FDIV);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FLOAD() {
        before.locals(FLOAT).stack();
        mv.visitVarInsn(FLOAD, 0);
        after.locals(FLOAT).stack(FLOAT);
    }

    @Test
    public void FMUL() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FMUL);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FNEG() {
        before.locals().stack(FLOAT);
        mv.visitInsn(FNEG);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FREM() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FREM);
        after.locals().stack(FLOAT);
    }

    @Test
    public void FRETURN() {
        before.locals().stack(FLOAT);
        mv.visitInsn(FRETURN);
        after.locals().stack();
    }

    @Test
    public void FSTORE() {
        before.locals().stack(FLOAT);
        mv.visitVarInsn(FSTORE, 0);
        after.locals(FLOAT).stack();
    }

    @Test
    public void FSUB() {
        before.locals().stack(FLOAT, FLOAT);
        mv.visitInsn(FSUB);
        after.locals().stack(FLOAT);
    }

    @Test
    public void GETFIELD() {
        before.locals().stack("Test");
        mv.visitFieldInsn(GETFIELD, "Test", "f", "I");
        after.locals().stack(INTEGER);
    }

    @Test
    public void GETSTATIC() {
        before.locals().stack();
        mv.visitFieldInsn(GETSTATIC, "Test", "f", "Z");
        after.locals().stack(INTEGER);
    }

    @Test
    public void GETSTATIC_float() {
        before.locals().stack();
        mv.visitFieldInsn(GETSTATIC, "Test", "f", "F");
        after.locals().stack(FLOAT);
    }

    @Test
    public void GETSTATIC_double() {
        before.locals().stack();
        mv.visitFieldInsn(GETSTATIC, "Test", "f", "D");
        after.locals().stack(DOUBLE);
    }

    @Test
    public void GOTO() {
        before.locals().stack();
        mv.visitJumpInsn(GOTO, label);
        after.locals().stack();
    }

    @Test
    public void I2B() {
        before.locals().stack(INTEGER);
        mv.visitInsn(I2B);
        after.locals().stack(INTEGER);
    }

    @Test
    public void I2C() {
        before.locals().stack(INTEGER);
        mv.visitInsn(I2C);
        after.locals().stack(INTEGER);
    }

    @Test
    public void I2D() {
        before.locals().stack(INTEGER);
        mv.visitInsn(I2D);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void I2F() {
        before.locals().stack(INTEGER);
        mv.visitInsn(I2F);
        after.locals().stack(FLOAT);
    }

    @Test
    public void I2L() {
        before.locals().stack(INTEGER);
        mv.visitInsn(I2L);
        after.locals().stack(LONG);
    }

    @Test
    public void I2S() {
        before.locals().stack(INTEGER);
        mv.visitInsn(I2S);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IADD() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IADD);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IALOAD() {
        before.locals().stack("[I", INTEGER);
        mv.visitInsn(IALOAD);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IAND() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IAND);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IASTORE() {
        before.locals().stack("[I", INTEGER, INTEGER);
        mv.visitInsn(IASTORE);
        after.locals().stack();
    }

    @Test
    public void ICONST_M1() {
        before.locals().stack();
        mv.visitInsn(ICONST_M1);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ICONST_0() {
        before.locals().stack();
        mv.visitInsn(ICONST_0);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ICONST_1() {
        before.locals().stack();
        mv.visitInsn(ICONST_1);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ICONST_2() {
        before.locals().stack();
        mv.visitInsn(ICONST_2);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ICONST_3() {
        before.locals().stack();
        mv.visitInsn(ICONST_3);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ICONST_4() {
        before.locals().stack();
        mv.visitInsn(ICONST_4);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ICONST_5() {
        before.locals().stack();
        mv.visitInsn(ICONST_5);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IDIV() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IDIV);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IF_ACMPEQ() {
        before.locals().stack("A", "A");
        mv.visitJumpInsn(IF_ACMPEQ, label);
        after.locals().stack();
    }

    @Test
    public void IF_ACMPNE() {
        before.locals().stack("A", "A");
        mv.visitJumpInsn(IF_ACMPNE, label);
        after.locals().stack();
    }

    @Test
    public void IF_ICMPEQ() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitJumpInsn(IF_ICMPEQ, label);
        after.locals().stack();
    }

    @Test
    public void IF_ICMPGE() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitJumpInsn(IF_ICMPGE, label);
        after.locals().stack();
    }

    @Test
    public void IF_ICMPGT() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitJumpInsn(IF_ICMPGT, label);
        after.locals().stack();
    }

    @Test
    public void IF_ICMPLE() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitJumpInsn(IF_ICMPLE, label);
        after.locals().stack();
    }

    @Test
    public void IF_ICMPLT() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitJumpInsn(IF_ICMPLT, label);
        after.locals().stack();
    }

    @Test
    public void IF_ICMPNE() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitJumpInsn(IF_ICMPNE, label);
        after.locals().stack();
    }

    @Test
    public void IFEQ() {
        before.locals().stack(INTEGER);
        mv.visitJumpInsn(IFEQ, label);
        after.locals().stack();
    }

    @Test
    public void IFGE() {
        before.locals().stack(INTEGER);
        mv.visitJumpInsn(IFGE, label);
        after.locals().stack();
    }

    @Test
    public void IFGT() {
        before.locals().stack(INTEGER);
        mv.visitJumpInsn(IFGT, label);
        after.locals().stack();
    }

    @Test
    public void IFLE() {
        before.locals().stack(INTEGER);
        mv.visitJumpInsn(IFLE, label);
        after.locals().stack();
    }

    @Test
    public void IFLT() {
        before.locals().stack(INTEGER);
        mv.visitJumpInsn(IFLT, label);
        after.locals().stack();
    }

    @Test
    public void IFNE() {
        before.locals().stack(INTEGER);
        mv.visitJumpInsn(IFNE, label);
        after.locals().stack();
    }

    @Test
    public void IFNONNULL() {
        before.locals().stack("A");
        mv.visitJumpInsn(IFNONNULL, label);
        after.locals().stack();
    }

    @Test
    public void IFNULL() {
        before.locals().stack("A");
        mv.visitJumpInsn(IFNULL, label);
        after.locals().stack();
    }

    @Test
    public void IINC() {
        before.locals(INTEGER).stack();
        mv.visitIincInsn(0, 1);
        after.locals(INTEGER).stack();
    }

    @Test
    public void ILOAD() {
        before.locals(INTEGER).stack();
        mv.visitVarInsn(ILOAD, 0);
        after.locals(INTEGER).stack(INTEGER);
    }

    @Test
    public void IMUL() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IMUL);
        after.locals().stack(INTEGER);
    }

    @Test
    public void INEG() {
        before.locals().stack(INTEGER);
        mv.visitInsn(INEG);
        after.locals().stack(INTEGER);
    }

    @Test
    public void INSTANCEOF() {
        before.locals().stack("java/lang/String");
        mv.visitTypeInsn(INSTANCEOF, "java/lang/String");
        after.locals().stack(INTEGER);
    }

    @Test
    public void INVOKEDYNAMIC() {
        before.locals().stack("java/lang/String");
        mv.visitInvokeDynamicInsn("foo", "(Ljava/lang/String;)I", new Handle(0, null, null, null));
        after.locals().stack(INTEGER);
    }

    @Test
    public void INVOKEINTERFACE() {
        before.locals().stack("Test");
        mv.visitMethodInsn(INVOKEVIRTUAL, "Test", "getSize", "()I");
        after.locals().stack(INTEGER);
    }

    @Test
    public void INVOKESPECIAL() {
        before.locals().stack("Test", LONG, LONG);
        mv.visitMethodInsn(INVOKEVIRTUAL, "Test", "add", "(JJ)J");
        after.locals().stack(LONG);
    }

    @Test
    public void INVOKESPECIAL_initsuper() {
        before.locals(UNINITIALIZED_THIS).stack(UNINITIALIZED_THIS);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "<init>", "()V");
        after.locals("Test").stack();
    }

    @Test
    public void INVOKESTATIC() {
        before.locals().stack(LONG, LONG);
        mv.visitMethodInsn(INVOKESTATIC, "Test", "add", "(JJ)J");
        after.locals().stack(LONG);
    }

    @Test
    public void INVOKEVIRTUAL() {
        before.locals().stack("Test", INTEGER, DOUBLE);
        mv.visitMethodInsn(INVOKEVIRTUAL, "Test", "run", "(ID)V");
        after.locals().stack();
    }

    @Test
    public void IOR() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IOR);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IREM() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IREM);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IRETURN() {
        before.locals().stack(INTEGER);
        mv.visitInsn(IRETURN);
        after.locals().stack();
    }

    @Test
    public void ISHL() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(ISHL);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ISHR() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(ISHR);
        after.locals().stack(INTEGER);
    }

    @Test
    public void ISSTORE() {
        before.locals().stack(INTEGER);
        mv.visitVarInsn(ISTORE, 0);
        after.locals(INTEGER).stack();
    }

    @Test
    public void ISUB() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(ISUB);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IUSHR() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IUSHR);
        after.locals().stack(INTEGER);
    }

    @Test
    public void IXOR() {
        before.locals().stack(INTEGER, INTEGER);
        mv.visitInsn(IXOR);
        after.locals().stack(INTEGER);
    }

    @Test
    public void L2D() {
        before.locals().stack(LONG);
        mv.visitInsn(L2D);
        after.locals().stack(DOUBLE);
    }

    @Test
    public void L2F() {
        before.locals().stack(LONG);
        mv.visitInsn(L2F);
        after.locals().stack(FLOAT);
    }

    @Test
    public void L2I() {
        before.locals().stack(LONG);
        mv.visitInsn(L2I);
        after.locals().stack(INTEGER);
    }

    @Test
    public void LADD() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LADD);
        after.locals().stack(LONG);
    }

    @Test
    public void LALOAD() {
        before.locals().stack("L[", INTEGER);
        mv.visitInsn(LALOAD);
        after.locals().stack(LONG);
    }

    @Test
    public void LAND() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LAND);
        after.locals().stack(LONG);
    }

    @Test
    public void LASTORE() {
        before.locals().stack("L[", INTEGER, LONG);
        mv.visitInsn(LASTORE);
        after.locals().stack();
    }

    @Test
    public void LCMP() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LCMP);
        after.locals().stack(INTEGER);
    }

    @Test
    public void LCONST_0() {
        before.locals().stack();
        mv.visitInsn(LCONST_0);
        after.locals().stack(LONG);
    }

    @Test
    public void LCONST_1() {
        before.locals().stack();
        mv.visitInsn(LCONST_1);
        after.locals().stack(LONG);
    }

    @Test
    public void LDC_int() {
        before.locals().stack();
        mv.visitLdcInsn(Integer.valueOf(123));
        after.locals().stack(INTEGER);
    }

    @Test
    public void LDC_float() {
        before.locals().stack();
        mv.visitLdcInsn(Float.valueOf(123));
        after.locals().stack(FLOAT);
    }

    @Test
    public void LDC_long() {
        before.locals().stack();
        mv.visitLdcInsn(Long.valueOf(123));
        after.locals().stack(LONG);
    }

    @Test
    public void LDC_double() {
        before.locals().stack();
        mv.visitLdcInsn(Double.valueOf(123));
        after.locals().stack(DOUBLE);
    }

    @Test
    public void LDC_String() {
        before.locals().stack();
        mv.visitLdcInsn("Hello VM!");
        after.locals().stack("java/lang/String");
    }

    @Test
    public void LDC_Class() {
        before.locals().stack();
        mv.visitLdcInsn(Type.getType("[java/lang/Runnable;"));
        after.locals().stack("java/lang/Class");
    }

    @Test(expected = IllegalArgumentException.class)
    public void LDC_invalidType() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitLdcInsn(Byte.valueOf((byte) 123));
    }

    @Test
    public void LDIV() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LDIV);
        after.locals().stack(LONG);
    }

    @Test
    public void LLOAD() {
        before.locals(LONG).stack();
        mv.visitVarInsn(LLOAD, 0);
        after.locals(LONG).stack(LONG);
    }

    @Test
    public void LMUL() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LMUL);
        after.locals().stack(LONG);
    }

    @Test
    public void LNEG() {
        before.locals().stack(LONG);
        mv.visitInsn(LNEG);
        after.locals().stack(LONG);
    }

    @Test
    public void LOOKUPSWITCH() {
        before.locals().stack(INTEGER);
        mv.visitLookupSwitchInsn(new Label(), new int[0], new Label[0]);
        after.locals().stack();
    }

    @Test
    public void LOR() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LOR);
        after.locals().stack(LONG);
    }

    @Test
    public void LREM() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LREM);
        after.locals().stack(LONG);
    }

    @Test
    public void LRETURN() {
        before.locals().stack(LONG);
        mv.visitInsn(LRETURN);
        after.locals().stack();
    }

    @Test
    public void LSHL() {
        before.locals().stack(LONG, INTEGER);
        mv.visitInsn(LSHL);
        after.locals().stack(LONG);
    }

    @Test
    public void LSHR() {
        before.locals().stack(LONG, INTEGER);
        mv.visitInsn(LSHR);
        after.locals().stack(LONG);
    }

    @Test
    public void LSTORE() {
        before.locals().stack(LONG);
        mv.visitVarInsn(LSTORE, 0);
        after.locals(LONG).stack();
    }

    @Test
    public void LSUB() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LSUB);
        after.locals().stack(LONG);
    }

    @Test
    public void LUSHR() {
        before.locals().stack(LONG, INTEGER);
        mv.visitInsn(LUSHR);
        after.locals().stack(LONG);
    }

    @Test
    public void LXOR() {
        before.locals().stack(LONG, LONG);
        mv.visitInsn(LXOR);
        after.locals().stack(LONG);
    }

    @Test
    public void MONITORENTER() {
        before.locals().stack("java/lang/Object");
        mv.visitInsn(MONITORENTER);
        after.locals().stack();
    }

    @Test
    public void MONITOREXIT() {
        before.locals().stack("java/lang/Object");
        mv.visitInsn(MONITOREXIT);
        after.locals().stack();
    }

    @Test
    public void MULTIANEWARRAY() {
        before.locals().stack(INTEGER, INTEGER, INTEGER);
        mv.visitMultiANewArrayInsn("[[[Ljava/lang/String;", 3);
        after.locals().stack("[[[Ljava/lang/String;");
    }

    @Test
    public void NEW() {
        before.locals(LONG).stack(LONG);
        mv.visitTypeInsn(NEW, "Test");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "Test", "<init>", "()V");
        after.locals(LONG).stack(LONG, "Test");
    }

    @Test
    public void NEWARRAY_boolean() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_BOOLEAN);
        after.locals().stack("[Z");
    }

    @Test
    public void NEWARRAY_char() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_CHAR);
        after.locals().stack("[C");
    }

    @Test
    public void NEWARRAY_float() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_FLOAT);
        after.locals().stack("[F");
    }

    @Test
    public void NEWARRAY_double() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_DOUBLE);
        after.locals().stack("[D");
    }

    @Test
    public void NEWARRAY_byte() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_BYTE);
        after.locals().stack("[B");
    }

    @Test
    public void NEWARRAY_short() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_SHORT);
        after.locals().stack("[S");
    }

    @Test
    public void NEWARRAY_int() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_INT);
        after.locals().stack("[I");
    }

    @Test
    public void NEWARRAY_long() {
        before.locals().stack(INTEGER);
        mv.visitIntInsn(NEWARRAY, T_LONG);
        after.locals().stack("[J");
    }

    @Test(expected = IllegalArgumentException.class)
    public void NEWARRAY_invalidOperand() {
        FrameTracker tracker = new FrameTracker("Test", ACC_STATIC, "test", "()V", null);
        tracker.visitFrame(NEW, 0, new Object[0], 1, new Object[] { INTEGER });
        tracker.visitIntInsn(NEWARRAY, -1);
    }

    @Test
    public void NOP() {
        before.locals().stack();
        mv.visitInsn(NOP);
        after.locals().stack();
    }

    @Test
    public void POP() {
        before.locals().stack(INTEGER);
        mv.visitInsn(POP);
        after.locals().stack();
    }

    @Test
    public void POP2_one_two_word_item() {
        before.locals().stack(DOUBLE);
        mv.visitInsn(POP2);
        after.locals().stack();
    }

    @Test
    public void POP2_two_one_word_items() {
        before.locals().stack("A", INTEGER);
        mv.visitInsn(POP2);
        after.locals().stack();
    }

    @Test
    public void PUTFIELD() {
        before.locals().stack("Test", INTEGER);
        mv.visitFieldInsn(PUTFIELD, "Test", "field", "I");
        after.locals().stack();
    }

    @Test
    public void PUTSTATIC() {
        before.locals().stack(INTEGER);
        mv.visitFieldInsn(PUTSTATIC, "Test", "field", "I");
        after.locals().stack();
    }

    @Test
    public void RETURN() {
        before.locals().stack();
        mv.visitInsn(RETURN);
        after.locals().stack();
    }

    @Test
    public void SALOAD() {
        before.locals().stack("[S", INTEGER);
        mv.visitInsn(SALOAD);
        after.locals().stack(INTEGER);
    }

    @Test
    public void SASTORE() {
        before.locals().stack("[S", INTEGER, INTEGER);
        mv.visitInsn(SASTORE);
        after.locals().stack();
    }

    @Test
    public void SIPUSH() {
        before.locals().stack();
        mv.visitIntInsn(SIPUSH, 123);
        after.locals().stack(INTEGER);
    }

    @Test
    public void SWAP() {
        before.locals().stack("A", "B");
        mv.visitInsn(SWAP);
        after.locals().stack("B", "A");
    }

    @Test
    public void TABLESWITCH() {
        before.locals().stack(INTEGER);
        mv.visitTableSwitchInsn(0, 1, new Label(), new Label[0]);
        after.locals().stack();
    }

}