com.google.test.metric.method.BlockDecomposerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.google.test.metric.method.BlockDecomposerTest.java

Source

/*
 * Copyright 2007 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.test.metric.method;

import static com.google.test.metric.JavaType.VOID;

import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;

import org.objectweb.asm.Label;

import com.google.test.metric.JavaClassRepository;
import com.google.test.metric.JavaType;
import com.google.test.metric.LocalVariableInfo;
import com.google.test.metric.Variable;
import com.google.test.metric.method.op.stack.JSR;
import com.google.test.metric.method.op.stack.Load;
import com.google.test.metric.method.op.stack.RetSub;
import com.google.test.metric.method.op.stack.Return;
import com.google.test.metric.method.op.stack.StackOperation;
import com.google.test.metric.method.op.stack.Store;
import com.google.test.metric.method.op.stack.Throw;
import com.google.test.metric.method.op.turing.Operation;

public class BlockDecomposerTest extends TestCase {

    public void testSimpleLinearMethod() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Return ret = new Return(0, VOID);
        decomposer.addOp(ret);
        decomposer.decomposeIntoBlocks();

        Block block = decomposer.getMainBlock();
        assertEquals(list(ret), block.getOperations());
    }

    public void testUnconditionalBackwardGoto() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label label = new Label();
        Load l1 = load(1);
        Load l2 = load(2);
        decomposer.addOp(l1);
        decomposer.label(label);
        decomposer.addOp(l2);
        decomposer.unconditionalGoto(label);
        decomposer.decomposeIntoBlocks();

        Block main = decomposer.getMainBlock();
        assertEquals(list(l1), main.getOperations());

        assertEquals(1, main.getNextBlocks().size());
        Block next = main.getNextBlocks().get(0);
        assertEquals(list(l2), next.getOperations());
    }

    public void testUnconditionalForwardGoto() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label label = new Label();
        Load l1 = load(1);
        Load l2 = load(2);
        decomposer.addOp(l1);
        decomposer.unconditionalGoto(label);
        decomposer.label(label);
        decomposer.addOp(l2);
        decomposer.decomposeIntoBlocks();

        Block main = decomposer.getMainBlock();
        assertEquals(list(l1), main.getOperations());

        assertEquals(1, main.getNextBlocks().size());
        Block next = main.getNextBlocks().get(0);
        assertEquals(list(l2), next.getOperations());
    }

    public void testConditionalBackwardGoto() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label label = new Label();
        Load l1 = load(1);
        Load l2 = load(2);
        Load l3 = load(3);
        decomposer.addOp(l1);
        decomposer.label(label);
        decomposer.addOp(l2);
        decomposer.conditionalGoto(label);
        decomposer.addOp(l3);
        decomposer.decomposeIntoBlocks();

        Block main = decomposer.getMainBlock();
        Block nextTrue = decomposer.getBlock(label);
        Block nextFlase = nextTrue.getNextBlocks().get(0);
        assertEquals(list(l1), main.getOperations());
        assertEquals(list(l2), nextTrue.getOperations());
        assertEquals(list(l3), nextFlase.getOperations());
    }

    public void testConditionalForwardGoto() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label label = new Label();
        Load l1 = load(1);
        Load l2 = load(2);
        Load l3 = load(3);
        decomposer.addOp(l1); // main
        decomposer.conditionalGoto(label);
        decomposer.addOp(l2); // nextFalse
        decomposer.label(label);
        decomposer.addOp(l3); // nextTrue
        decomposer.decomposeIntoBlocks();

        Block main = decomposer.getMainBlock();
        Block nextFlase = main.getNextBlocks().get(0);
        Block nextTrue = decomposer.getBlock(label);
        assertEquals(list(l1), main.getOperations());
        assertEquals(list(l2), nextFlase.getOperations());
        assertEquals(list(l3), nextTrue.getOperations());
    }

    private <T> List<T> list(T... items) {
        return Arrays.asList(items);
    }

    public void testIgnoreExtraLabels() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Load l1 = load(1);
        Load l2 = load(2);
        decomposer.label(new Label());
        decomposer.addOp(l1);
        decomposer.addOp(l2);
        decomposer.label(new Label());
        decomposer.decomposeIntoBlocks();

        assertEquals(list(l1, l2), decomposer.getMainBlock().getOperations());
    }

    /**
     * load 1
     * jsr mySub
     * load 2
     * return
     *
     * mySub:
     * load 3
     * return;
     */
    public void testJSR() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        decomposer.addOp(load(1));
        Label sub = new Label();
        decomposer.jumpSubroutine(sub, 0);
        decomposer.addOp(load(2));
        decomposer.addOp(new Return(0, VOID));
        decomposer.label(sub);
        decomposer.addOp(load(3));
        decomposer.addOp(new RetSub(0));
        decomposer.decomposeIntoBlocks();

        Block mainBlock = decomposer.getMainBlock();
        assertEquals(0, mainBlock.getNextBlocks().size());
        List<StackOperation> operations = mainBlock.getOperations();
        assertEquals("[load 1{int}, JSR sub_0, load 2{int}, return void]", operations.toString());
        JSR jsr = (JSR) operations.get(1);
        Block subBlock = jsr.getBlock();
        assertEquals("[load 3{int}, RETSUB]", subBlock.getOperations().toString());
    }

    private Load load(int value) {
        return new Load(0, new Constant(value, JavaType.INT));
    }

    public void testSwitch() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Load l1 = load(1);
        Label c1Label = new Label();
        Load c1 = load(2);
        Label defLabel = new Label();
        Load def = load(3);
        decomposer.addOp(l1);
        decomposer.tableSwitch(defLabel, c1Label);
        decomposer.label(c1Label);
        decomposer.addOp(c1);
        decomposer.label(defLabel);
        decomposer.addOp(def);
        decomposer.decomposeIntoBlocks();

        Block main = decomposer.getMainBlock();
        Block c1Block = decomposer.getBlock(c1Label);
        Block defBlock = decomposer.getBlock(defLabel);
        assertEquals(list(l1), main.getOperations());
        assertEquals(list(c1), c1Block.getOperations());
        assertEquals(list(def), defBlock.getOperations());
        assertEquals(list(c1Block, defBlock), main.getNextBlocks());
    }

    public void testTryCatchReturn() throws Exception {
        /*
         * try {        | label:lTry
         *   return 1;  | label:lTryEnd
         * } catch {    | label:lHandle
         *   return 2;
         * }
         */
        Label lTry = new Label();
        Load l1 = load(1);
        Load l2 = load(2);
        Return ret = new Return(1, JavaType.INT);
        Label lTryEnd = new Label();
        Label lHandle = new Label();

        BlockDecomposer decomposer = new BlockDecomposer();
        decomposer.tryCatchBlock(lTry, lTryEnd, lHandle, null);
        decomposer.label(lTry);
        decomposer.addOp(l1);
        decomposer.label(lTryEnd); // the catch label comes before the last instruction.
        decomposer.addOp(ret);
        decomposer.label(lHandle);
        decomposer.addOp(l2);
        decomposer.addOp(ret);
        decomposer.decomposeIntoBlocks();

        Block tryBlock = decomposer.getBlock(lTry);
        Block handleBlock = decomposer.getBlock(lHandle);
        assertEquals(list(), tryBlock.getNextBlocks());
        assertEquals(list(l1, ret), tryBlock.getOperations());
        assertEquals("[load ?{java.lang.Throwable}, load 2{int}, return int]",
                handleBlock.getOperations().toString());
    }

    public void testGetExceptionHandlerBlocks() throws Exception {
        /*
         * try {        | label:lTry
         *   a = 1;
         *   return 1;  | label:lTryEnd
         * } catch {    | label:lHandle
         *   a = 2;
         *   return 2;
         * }
         */
        Label lTry = new Label();
        Load l1 = load(1);
        Load l2 = load(2);
        Store store = new Store(-1, new Variable("a", JavaType.INT, false, false));
        Return ret = new Return(1, JavaType.INT);
        Label lTryEnd = new Label();
        Label lHandle = new Label();

        BlockDecomposer decomposer = new BlockDecomposer();
        decomposer.tryCatchBlock(lTry, lTryEnd, lHandle, null);
        decomposer.label(lTry);
        decomposer.addOp(l1);
        decomposer.addOp(store);
        decomposer.label(lTryEnd); // the catch label comes before the last instruction.
        decomposer.addOp(l1);
        decomposer.addOp(ret);
        decomposer.label(lHandle);
        decomposer.addOp(l2);
        decomposer.addOp(store);
        decomposer.addOp(l2);
        decomposer.addOp(ret);
        decomposer.decomposeIntoBlocks();

        Block mainBlock = decomposer.getMainBlock();
        assertEquals(0, mainBlock.getNextBlocks().size());
        assertEquals(list(l1, store, l1, ret), mainBlock.getOperations());

        Block catchBlock = decomposer.getBlock(lHandle);
        assertEquals(0, catchBlock.getNextBlocks().size());
        assertEquals("[load ?{java.lang.Throwable}, load 2{int}, store a{int}, load 2{int}, return int]",
                catchBlock.getOperations().toString());

        assertEquals("[a{int} <- 1{int}, return 1{int}, a{int} <- 2{int}, return 2{int}]",
                decomposer.getOperations().toString());
    }

    /**
     *   public static class TryCatchFinally {
     *   public void method() {
     *     int b = 1;
     *     try {
     *       b = 2;
     *       return;
     *     } catch (RuntimeException e) {
     *       b = 3;
     *     } finally {
     *       b = 4;
     *     }
     *     b = 5;
     *   }
     *  }
     *
     *
     *  public void method();
     *  Code:
     *   0:   iconst_1
     *   1:   istore_1
     *   2:   iconst_2
     *   3:   istore_1
     *   4:   goto    20
     *   7:   astore_2
     *   8:   iconst_3
     *   9:   istore_1
     *   10:  iconst_4
     *   11:  istore_1
     *   12:  goto    22
     *   15:  astore_3
     *   16:  iconst_4
     *   17:  istore_1
     *   18:  aload_3
     *   19:  athrow
     *   20:  iconst_4
     *   21:  istore_1
     *   22:  iconst_5
     *   23:  istore_1
     *   24:  return
     *  Exception table:
     *   from   to  target type
     *     2     4     7   Class java/lang/RuntimeException
     *     2    10    15   any
     */
    public void testTryCatchFinally() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label tryStart = new Label();
        Label tryEnd = new Label();
        Label runtimeHandler = new Label();
        Label catchEnd = new Label();
        Label finallyHandler = new Label();
        Label l20 = new Label();
        Label l22 = new Label();
        Variable b = new LocalVariableInfo("b", JavaType.INT);
        Variable e = new LocalVariableInfo("e", JavaType.OBJECT);
        Variable any = new LocalVariableInfo("any", JavaType.OBJECT);
        decomposer.tryCatchBlock(tryStart, tryEnd, runtimeHandler, "java/lang/RuntimeException");
        decomposer.tryCatchBlock(tryStart, catchEnd, finallyHandler, null);

        /* 0*/ decomposer.addOp(new Load(0, new Constant(1, JavaType.INT)));
        /* 1*/ decomposer.addOp(new Store(1, b));
        decomposer.label(tryStart);
        /* 2*/ decomposer.addOp(new Load(2, new Constant(2, JavaType.INT)));
        decomposer.label(tryEnd);
        /* 3*/ decomposer.addOp(new Store(3, b));
        /* 4*/ decomposer.unconditionalGoto(l20);
        decomposer.label(runtimeHandler);
        /* 7*/ decomposer.addOp(new Store(7, e));
        /* 8*/ decomposer.addOp(new Load(8, new Constant(3, JavaType.INT)));
        /* 9*/ decomposer.addOp(new Store(9, b));
        decomposer.label(catchEnd);
        /*10*/ decomposer.addOp(new Load(10, new Constant(4, JavaType.INT)));
        /*11*/ decomposer.addOp(new Store(11, b));
        /*12*/ decomposer.unconditionalGoto(l22);
        decomposer.label(finallyHandler);
        /*15*/ decomposer.addOp(new Store(15, any));
        /*16*/ decomposer.addOp(new Load(16, new Constant(4, JavaType.INT)));
        /*17*/ decomposer.addOp(new Store(17, b));
        /*18*/ decomposer.addOp(new Load(18, any));
        /*19*/ decomposer.addOp(new Throw(19));
        decomposer.label(l20);
        /*20*/ decomposer.addOp(new Load(20, new Constant(4, JavaType.INT)));
        /*21*/ decomposer.addOp(new Store(21, b));
        decomposer.label(l22);
        /*22*/ decomposer.addOp(new Load(22, new Constant(4, JavaType.INT)));
        /*23*/ decomposer.addOp(new Store(23, b));
        /*24*/ decomposer.addOp(new Return(24, JavaType.VOID));

        decomposer.decomposeIntoBlocks();

        assertEquals("[load 1{int}, store b{int}, load 2{int}, store b{int}]",
                decomposer.getBlock(tryStart).getOperations().toString());
    }

    public void testMethodWithNothing() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        decomposer.decomposeIntoBlocks();
        List<Operation> operations = decomposer.getOperations();
        assertEquals(0, operations.size());
    }

    public void testTwoJsrSameLabel() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label label = new Label();
        decomposer.jumpSubroutine(label, 0);
        decomposer.jumpSubroutine(label, 0);
        decomposer.decomposeIntoBlocks();

        Block main = decomposer.getMainBlock();
        assertEquals("[JSR sub_0, JSR sub_0]", main.getOperations().toString());
    }

    public void testMultipleHandlersSingleExceptionLoad() throws Exception {
        BlockDecomposer decomposer = new BlockDecomposer();
        Label start = new Label();
        Label end = new Label();
        Label handler = new Label();
        decomposer.tryCatchBlock(start, end, handler, null);
        decomposer.tryCatchBlock(start, end, handler, null);
        decomposer.label(start);
        decomposer.addOp(load(1));
        decomposer.label(end);
        decomposer.addOp(load(2));
        decomposer.label(handler);
        decomposer.addOp(load(3));
        decomposer.decomposeIntoBlocks();

        assertEquals("[load ?{java.lang.Throwable}, load 1{int}, load 2{int}, load 3{int}]",
                decomposer.getMainBlock().getOperations().toString());
    }

    public static class TestClass {
        int value;

        int method() {
            value = 0;
            try {
                value = 1;
                return -1;
            } catch (NullPointerException e) {
                value = 2;
                return -2;
            } finally {
                value = 3;
            }

        }
    }

    public void testExperiment() throws Exception {
        JavaClassRepository repo = new JavaClassRepository();
        repo.getClass(TestClass.class.getCanonicalName());
    }

}