Esempio n. 1
0
    def test_call_without_arguments(self):
        module_block = BasicBlock([
            # def callee():
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="callee"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="callee"),
            # result = callee()
            Instr("LOAD_NAME", arg="callee"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="result"),
            # return result
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        callee_block = BasicBlock([
            Instr("LOAD_CONST", arg=0),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(callee_block)

        module_file = "simple_call.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 2
0
    def test_simple_control_dependency_2(self):
        # If condition evaluated to false, with two relevant variables (but no influence on result)
        def func() -> int:
            foo = 1
            bar = 2
            result = 3

            if foo == bar:
                result = 1

            return result

        init_basic_block = BasicBlock([
            # result = 3
            Instr("LOAD_CONST", arg=3),
            Instr("STORE_FAST", arg="result"),
        ])
        return_basic_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(init_basic_block)
        expected_instructions.extend(return_basic_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 3
0
    def test_simple_control_dependency_4(self):
        # If-elif-else with else branch true
        def func() -> int:
            foo = 1
            bar = 2

            if foo == bar:
                result = 1
            elif foo > bar:
                result = 2
            else:
                result = 3

            return result

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        else_block = BasicBlock([
            # result = 3
            Instr("LOAD_CONST", arg=3),
            Instr("STORE_FAST", arg="result")
        ])
        elif_cond = BasicBlock([
            # elif foo == 1:
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.GT),
            Instr("POP_JUMP_IF_FALSE", arg=else_block),
        ])
        if_cond = BasicBlock([
            # if foo == bar
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.EQ),
            Instr("POP_JUMP_IF_FALSE", arg=elif_cond),
        ])
        init_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # bar = 2
            Instr("LOAD_CONST", arg=2),
            Instr("STORE_FAST", arg="bar"),
        ])

        expected_instructions = []
        expected_instructions.extend(init_block)
        expected_instructions.extend(if_cond)
        expected_instructions.extend(elif_cond)
        expected_instructions.extend(else_block)
        expected_instructions.extend(return_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 4
0
    def test_iter_invalid_types(self):
        # Labels are not allowed in basic blocks
        block = BasicBlock()
        block.append(Label())
        with self.assertRaises(ValueError):
            list(block)
        with self.assertRaises(ValueError):
            block.legalize(1)

        # Only one jump allowed and only at the end
        block = BasicBlock()
        block2 = BasicBlock()
        block.extend([Instr("JUMP_ABSOLUTE", block2), Instr("NOP")])
        with self.assertRaises(ValueError):
            list(block)
        with self.assertRaises(ValueError):
            block.legalize(1)

        # jump target must be a BasicBlock
        block = BasicBlock()
        label = Label()
        block.extend([Instr("JUMP_ABSOLUTE", label)])
        with self.assertRaises(ValueError):
            list(block)
        with self.assertRaises(ValueError):
            block.legalize(1)
Esempio n. 5
0
    def test_nested_class(self):
        def func():
            # STORE_DEREF, LOAD_CLOSURE, LOAD_CLASSDEREF
            x = []

            class NestedClass:
                y = x

            class_attr = NestedClass.y

            result = class_attr
            return result

        freevar_x = FreeVar("x")
        cellvar_x = CellVar("x")
        function_block = BasicBlock([
            # x = []
            Instr("BUILD_LIST", arg=0),
            Instr("STORE_DEREF", arg=cellvar_x),

            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # class_attr = NestedClass.y
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("LOAD_ATTR", arg="y"),
            Instr("STORE_FAST", arg="class_attr"),

            # result = class_attr
            Instr("LOAD_FAST", arg="class_attr"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # y = x
            Instr("LOAD_CLASSDEREF", arg=freevar_x),
            Instr("STORE_NAME", arg="y"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_nested_class")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 6
0
    def test_closures(self):
        # Closure function

        freevar_foo = FreeVar("foo")
        cellvar_foo = CellVar("foo")
        module_block = BasicBlock([
            # def outer_function(foo):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="outer_function"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="outer_function"),

            # inner = outer_function('a')
            Instr("LOAD_NAME", arg="outer_function"),
            Instr("LOAD_CONST", arg="a"),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_NAME", arg="inner"),

            # result = inner("abc")
            Instr("LOAD_NAME", arg="inner"),
            Instr("LOAD_CONST", arg="abc"),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_NAME", arg="result"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        outer_function_block = BasicBlock([
            # def inner_function(bar):
            Instr("LOAD_CLOSURE", arg=cellvar_foo),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="outer_function.<locals>.inner_function"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("STORE_FAST", arg="inner_function"),

            # return inner
            Instr("LOAD_FAST", arg="inner_function"),
            Instr("RETURN_VALUE"),
        ])
        inner_function_block = BasicBlock([
            # return foo in bar
            Instr("LOAD_DEREF", arg=freevar_foo),
            Instr("LOAD_FAST", arg="bar"),
            Instr("COMPARE_OP", arg=Compare.IN),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(outer_function_block)
        expected_instructions.extend(inner_function_block)

        module_file = "closure.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(expected_instructions), len(dynamic_slice.sliced_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 7
0
def make_func() -> Function:
    bb0 = BasicBlock("bb0")
    bb1 = BasicBlock("bb1")
    bb0.add_inst(bytecode.CopyInst(Var('v0'), NumLit(SNum(42))))
    bb0.add_inst(
        bytecode.BinopInst(Var('v1'), Binop.ADD, Var('v0'), NumLit(SNum(69))))
    bb0.add_inst(bytecode.JmpInst(bb1))
    bb1.add_inst(bytecode.ReturnInst(Var('v1')))
    return Function([], bb0)
Esempio n. 8
0
    def test_data_dependency_4(self):
        # Explicit attribute dependencies (full cover)
        module_block = BasicBlock([
            # class Foo:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="Foo"),
            # ob.attr1 = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_NAME", arg="ob"),
            Instr("STORE_ATTR", arg="attr1"),
            # ob.attr2 = ob.attr2.append(ob.attr1)
            Instr("LOAD_NAME", arg="ob"),
            Instr("LOAD_ATTR", arg="attr2"),
            Instr("LOAD_METHOD", arg="append"),
            Instr("LOAD_NAME", arg="ob"),
            Instr("LOAD_ATTR", arg="attr1"),
            Instr("CALL_METHOD", arg=1),
            Instr("LOAD_NAME", arg="ob"),
            Instr("STORE_ATTR", arg="attr2"),

            # result = ob.attr2
            Instr("LOAD_NAME", arg="ob"),
            Instr("LOAD_ATTR", arg="attr2"),
            Instr("STORE_NAME", arg="result"),
            # return
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        class_attr_block = BasicBlock([
            # attr2 = [1, 2, 3]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_NAME", arg="attr2"),
            # return
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(class_attr_block)

        module_file = "attribute_dependencies.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 9
0
    def test_call_unused_argument(self):
        # Call with two arguments, one of which is used in the callee

        module_block = BasicBlock([
            # def callee():
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_CONST", arg=('a', 'b')),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="callee"),
            Instr("MAKE_FUNCTION", arg=4),
            Instr("STORE_NAME", arg="callee"),
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_NAME", arg="foo"),
            # bar = 2
            # This argument is not used by the callee and should therefore be excluded.
            # But it is an implicit data dependency of the call and is incorrectly and imprecisely included.
            # Instr("LOAD_CONST", arg=2),
            # Instr("STORE_NAME", arg="bar"),

            # result = callee()
            Instr("LOAD_NAME", arg="callee"),
            Instr("LOAD_NAME", arg="foo"),
            # Instr("LOAD_NAME", arg="bar"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="result"),
            # return result
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        callee_block = BasicBlock([
            # return a
            Instr("LOAD_FAST", arg="a"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(callee_block)

        module_file = "simple_call_arg.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 10
0
def make_branch_func_object() -> Tuple[Function, Tuple[BasicBlock, ...]]:
    bb0 = BasicBlock("bb0")
    bb1 = BasicBlock("bb1")
    bb2 = BasicBlock("bb2")
    bb3 = BasicBlock("bb3")
    bb0.add_inst(bytecode.CopyInst(Var('v0'), NumLit(SNum(42))))
    bb0.add_inst(bytecode.BrInst(Var('x'), bb1))
    bb0.add_inst(bytecode.JmpInst(bb2))
    bb1.add_inst(
        bytecode.BinopInst(Var('v0'), Binop.ADD, Var('v0'), NumLit(SNum(27))))
    bb1.add_inst(bytecode.JmpInst(bb3))
    bb2.add_inst(bytecode.CopyInst(Var('v0'), SymLit(SSym('hi'))))
    bb2.add_inst(bytecode.JmpInst(bb3))
    bb3.add_inst(bytecode.ReturnInst(Var('v0')))
    return Function([Var('x')], bb0), (bb0, bb1, bb2, bb3)
Esempio n. 11
0
    def test_builtin_addresses(self):
        def func():
            test_dict = {1: "one", 2: "two"}
            # noinspection PyListCreation
            test_list = [1, 2]

            test_list.append(3)

            result = test_dict.get(1)
            return result

        function_block = BasicBlock([
            # test_dict = {1: "one", 2: "two"}
            Instr("LOAD_CONST", arg="one"),
            Instr("LOAD_CONST", arg="two"),
            Instr("LOAD_CONST", arg=(1, 2)),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("STORE_FAST", arg="test_dict"),

            # result = test_dict.get(1)
            Instr("LOAD_FAST", arg="test_dict"),
            Instr("LOAD_METHOD", arg="get"),
            Instr("LOAD_CONST", arg=1),
            Instr("CALL_METHOD", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_builtin_addresses")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 12
0
    def test_simple_loop(self):
        def func():
            result = 0
            for i in range(0, 3):
                result += i
            return result

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        loop_header = BasicBlock([
            Instr("FOR_ITER", arg=return_block),
        ])
        loop_block = BasicBlock([
            # result += i
            Instr("STORE_FAST", arg="i"),
            Instr("LOAD_FAST", arg="result"),
            Instr("LOAD_FAST", arg="i"),
            Instr("INPLACE_ADD"),
            Instr("STORE_FAST", arg="result"),
            Instr("JUMP_ABSOLUTE", arg=loop_header),
        ])
        loop_setup = BasicBlock([
            # for i in range(0, 3):
            Instr("LOAD_GLOBAL", arg="range"),
            Instr("LOAD_CONST", arg=0),
            Instr("LOAD_CONST", arg=3),
            Instr("CALL_FUNCTION", arg=2),
            Instr("GET_ITER"),
        ])
        init_block = BasicBlock([
            Instr("LOAD_CONST", arg=0),
            Instr("STORE_FAST", arg="result"),
        ])

        expected_instructions = []
        expected_instructions.extend(init_block)
        expected_instructions.extend(loop_setup)
        expected_instructions.extend(loop_header)
        expected_instructions.extend(loop_block)
        expected_instructions.extend(return_block)

        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_simple_loop")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 13
0
    def test_call_with_arguments(self):
        # Call with two arguments, one of which is used in the callee

        module_block = BasicBlock([
            # def callee():
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_NAME", arg="int"),
            Instr("LOAD_CONST", arg=('a', 'b')),
            Instr("BUILD_CONST_KEY_MAP", arg=2),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="callee"),
            Instr("MAKE_FUNCTION", arg=4),
            Instr("STORE_NAME", arg="callee"),
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_NAME", arg="foo"),
            # bar = 2
            Instr("LOAD_CONST", arg=2),
            Instr("STORE_NAME", arg="bar"),

            # result = callee()
            Instr("LOAD_NAME", arg="callee"),
            Instr("LOAD_NAME", arg="foo"),
            Instr("LOAD_NAME", arg="bar"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="result"),
            # return result
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        callee_block = BasicBlock([
            # return a
            Instr("LOAD_FAST", arg="a"),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        expected_instructions.extend(callee_block)

        module_file = "simple_call_arg.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 14
0
    def test_simple_control_dependency_1(self):
        # If condition evaluated to true, with relevant variable foo
        def func() -> int:
            foo = 1
            result = 3

            if foo == 1:
                result = 1

            return result

        return_basic_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        if_basic_block = BasicBlock([
            # result = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="result"),
        ])
        init_basic_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST", arg=1),
            Instr("STORE_FAST", arg="foo"),
            # if foo == 1
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_CONST", arg=1),
            Instr("COMPARE_OP", arg=Compare.EQ),
            Instr("POP_JUMP_IF_FALSE", arg=return_basic_block),
        ])

        expected_instructions = []
        expected_instructions.extend(init_basic_block)
        expected_instructions.extend(if_basic_block)
        expected_instructions.extend(return_basic_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 15
0
    def test_blocks_broken_jump(self):
        block = BasicBlock()
        code = ControlFlowGraph()
        code[0].append(Instr('JUMP_ABSOLUTE', block))

        expected = textwrap.dedent("""
            block1:
                JUMP_ABSOLUTE <error: unknown block>

        """).lstrip("\n")
        self.check_dump_bytecode(code, expected)
Esempio n. 16
0
    def test_get_block_index(self):
        blocks = ControlFlowGraph()
        block0 = blocks[0]
        block1 = blocks.add_block()
        block2 = blocks.add_block()
        self.assertEqual(blocks.get_block_index(block0), 0)
        self.assertEqual(blocks.get_block_index(block1), 1)
        self.assertEqual(blocks.get_block_index(block2), 2)

        other_block = BasicBlock()
        self.assertRaises(ValueError, blocks.get_block_index, other_block)
Esempio n. 17
0
 def inst_function(
         name: SSym, params: List[Var],
         return_val: Optional[bytecode.Parameter], *insts: Inst,
         ) -> SFunction:
     """Create a function out of the instructions in insts."""
     begin = BasicBlock('bb0')
     for inst in insts:
         begin.add_inst(inst)
     if return_val is not None:
         begin.add_inst(bytecode.ReturnInst(return_val))
     code = Function(params, begin)
     param_syms = [SSym(p.name) for p in params]
     return SFunction(name, param_syms, Nil, code, False)
Esempio n. 18
0
    def test_import_star(self):
        # IMPORT_STAR with access to immutable variable
        main_module_block = BasicBlock([
            # from tests.slicer.example_modules.import_star_def import *
            Instr("IMPORT_NAME",
                  "tests.slicer.example_modules.import_star_def"),
            Instr("IMPORT_STAR"),

            # result = Foo.test
            Instr("LOAD_NAME", arg="star_imported"),
            Instr("STORE_NAME", arg="result"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])
        dependency_module_block = BasicBlock([
            # star_imported = "test"
            Instr("LOAD_CONST", arg="test"),
            Instr("STORE_NAME", arg="star_imported"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(main_module_block)
        expected_instructions.extend(dependency_module_block)

        module_dependency_file = "import_star_def.py"
        module_dependency_path = example_modules_path + module_dependency_file
        instrument_module(module_dependency_path)

        module_file = "import_star_main.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)

        compile_module(module_dependency_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 19
0
    def test_lambda(self):
        def func():
            x = lambda a: a + 10

            result = x(1)
            return result

        function_block = BasicBlock([
            # x = lambda a: a + 10
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_lambda.<locals>.func.<locals>.<lambda>"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="x"),

            # result = x(1)
            Instr("LOAD_FAST", arg="x"),
            Instr("LOAD_CONST", arg=1),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        lambda_block = BasicBlock([
            # lambda a: a + 10
            Instr("LOAD_FAST", arg="a"),
            Instr("LOAD_CONST", arg=10),
            Instr("BINARY_ADD"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(lambda_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_lambda")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 20
0
    def test_invalid_arg(self):
        label = Label()
        block = BasicBlock()

        # EXTENDED_ARG
        self.assertRaises(ValueError, Instr, "EXTENDED_ARG", 0)

        # has_jump()
        self.assertRaises(TypeError, Instr, "JUMP_ABSOLUTE", 1)
        self.assertRaises(TypeError, Instr, "JUMP_ABSOLUTE", 1.0)
        Instr("JUMP_ABSOLUTE", label)
        Instr("JUMP_ABSOLUTE", block)

        # hasfree
        self.assertRaises(TypeError, Instr, "LOAD_DEREF", "x")
        Instr("LOAD_DEREF", CellVar("x"))
        Instr("LOAD_DEREF", FreeVar("x"))

        # haslocal
        self.assertRaises(TypeError, Instr, "LOAD_FAST", 1)
        Instr("LOAD_FAST", "x")

        # hasname
        self.assertRaises(TypeError, Instr, "LOAD_NAME", 1)
        Instr("LOAD_NAME", "x")

        # hasconst
        self.assertRaises(ValueError, Instr, "LOAD_CONST")  # UNSET
        self.assertRaises(ValueError, Instr, "LOAD_CONST", label)
        self.assertRaises(ValueError, Instr, "LOAD_CONST", block)
        Instr("LOAD_CONST", 1.0)
        Instr("LOAD_CONST", object())

        # hascompare
        self.assertRaises(TypeError, Instr, "COMPARE_OP", 1)
        Instr("COMPARE_OP", Compare.EQ)

        # HAVE_ARGUMENT
        self.assertRaises(ValueError, Instr, "CALL_FUNCTION", -1)
        self.assertRaises(TypeError, Instr, "CALL_FUNCTION", 3.0)
        Instr("CALL_FUNCTION", 3)

        # test maximum argument
        self.assertRaises(ValueError, Instr, "CALL_FUNCTION", 2147483647 + 1)
        instr = Instr("CALL_FUNCTION", 2147483647)
        self.assertEqual(instr.arg, 2147483647)

        # not HAVE_ARGUMENT
        self.assertRaises(ValueError, Instr, "NOP", 0)
        Instr("NOP")
Esempio n. 21
0
    def test_with_extended_arg(self):
        def func():
            p = [1, 2, 3, 4, 5, 6]
            # noinspection PyUnusedLocal
            unused = p
            q, r, *s, t = p  # With extended argument

            result = q, r
            return result

        module_block = BasicBlock([
            # p = [1, 2, 3, 4, 5, 6]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("LOAD_CONST", arg=4),
            Instr("LOAD_CONST", arg=5),
            Instr("LOAD_CONST", arg=6),
            Instr("BUILD_LIST", arg=6),
            Instr("STORE_FAST", arg="p"),
            # q, r, *s, t = p
            Instr("LOAD_FAST", arg="p"),
            # Instr("EXTENDED_ARG", arg=1),  # EXTENDED_ARG can not be in a slice
            Instr("UNPACK_EX", arg=258),
            Instr("STORE_FAST", arg="q"),
            Instr("STORE_FAST", arg="r"),

            # result = q
            Instr("LOAD_FAST", arg="q"),
            Instr("LOAD_FAST", arg="r"),
            Instr("BUILD_TUPLE", arg=2),
            Instr("STORE_FAST", arg="result"),
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(module_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_with_extended_arg")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 22
0
    def test_mod_untraced_object(self):
        def func():
            lst = [('foo', '3'), ('bar', '1'), ('foobar', '2')]
            lst.sort(
            )  # This is incorrectly excluded, since it is not known that the method modifies the list

            result = lst
            return result

        function_block = BasicBlock([
            # lst = [('foo', '3'), ('bar', '1'), ('foobar', '2')]
            Instr("LOAD_CONST", arg=('foo', '3')),
            Instr("LOAD_CONST", arg=('bar', '1')),
            Instr("LOAD_CONST", arg=('foobar', '2')),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_FAST", arg="lst"),

            # lst.sort()
            # This is incorrectly excluded, since it is not known that the method modifies the list
            Instr("LOAD_FAST", arg="lst"),
            Instr("LOAD_METHOD", arg="sort"),
            Instr("CALL_METHOD", arg=0),
            Instr("POP_TOP"),

            # result = lst
            Instr("LOAD_FAST", arg="lst"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        dynamic_slice = slice_function_at_return(
            func.__code__, test_name="test_mod_untraced_object")
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 23
0
    def test_dunder_definition(self):
        def func():
            class NestedClass:
                def __init__(
                    self
                ):  # Definition of dunder methods wrongly excluded, these are not explicitly loaded
                    self.x = 1

            result = NestedClass()
            return result

        function_block = BasicBlock([
            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # result = NestedClass()
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # Definition of dunder methods are wrongly excluded, since these are not explicitly loaded
            # def __init__(self):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr(
                "LOAD_CONST",
                arg=
                "IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
                "func.<locals>.NestedClass.__init__"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="__init__"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        init_block = BasicBlock([
            # self.x = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        expected_instructions.extend(init_block)
        dynamic_slice = slice_function_at_return(
            func.__code__, test_name="test_dunder_definition")
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 24
0
    def test_exception(self):
        # Exception
        def func():
            foo = 1
            bar = 0

            try:
                result = 0 / 0
            except ZeroDivisionError:
                result = foo + bar

            return result

        self.assertEqual(func(), 1)

        dummy_block = BasicBlock([])

        return_block = BasicBlock([
            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE")
        ])
        try_block = BasicBlock([
            # result = foo / bar <- did somehow effect slicing criterion...
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("BINARY_TRUE_DIVIDE"),

            # except ZeroDivisionError:
            Instr("DUP_TOP"),
            Instr("LOAD_GLOBAL", arg="ZeroDivisionError"),
            Instr("COMPARE_OP", arg=Compare.EXC_MATCH),
            Instr("POP_JUMP_IF_FALSE", arg=dummy_block),
        ])
        except_block = BasicBlock([
            # result = foo + bar
            Instr("LOAD_FAST", arg="foo"),
            Instr("LOAD_FAST", arg="bar"),
            Instr("BINARY_ADD"),
            Instr("STORE_FAST", arg="result"),
            Instr("JUMP_FORWARD", arg=dummy_block),
        ])
        function_block = BasicBlock([
            # foo = 1
            Instr("LOAD_CONST",
                  arg=1),  # <- excluded because no stack simulation
            Instr("STORE_FAST", arg="foo"),
            # bar = 0
            Instr("LOAD_CONST",
                  arg=0),  # <- excluded because no stack simulation
            Instr("STORE_FAST", arg="bar"),

            # try:
            # Instr("SETUP_FINALLY", arg=try_block),
        ])

        expected_instructions = []
        expected_instructions.extend(return_block)
        expected_instructions.extend(except_block)
        expected_instructions.extend(function_block)
        expected_instructions.extend(try_block)

        dynamic_slice = slice_function_at_return(func.__code__)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 25
0
    def test_nested_class_2(self):
        # Critical test to ensure that the attributes converted to variables
        # are taken from the correct scope.

        def func():
            # STORE_DEREF, LOAD_CLOSURE, LOAD_CLASSDEREF
            x1 = [1]
            x2 = [2]

            class Bar:
                foo = x1  # included!

                class Foo:
                    foo = x2  # NOT included
                    y = x2  # included

                y = Foo.y  # NOT included

            class_attr = Bar.foo
            class_attr2 = Bar.Foo.y

            result = class_attr + class_attr2
            return result

        freevar_x1 = FreeVar("x1")
        cellvar_x1 = CellVar("x1")
        freevar_x2 = FreeVar("x2")
        cellvar_x2 = CellVar("x2")
        function_block = BasicBlock([
            # x1 = [1]
            Instr("LOAD_CONST", arg=1),
            Instr("BUILD_LIST", arg=1),
            Instr("STORE_DEREF", arg=cellvar_x1),
            # x2 = [2]
            Instr("LOAD_CONST", arg=2),
            Instr("BUILD_LIST", arg=1),
            Instr("STORE_DEREF", arg=cellvar_x2),

            # class Bar:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x1),
            Instr("LOAD_CLOSURE", arg=freevar_x2),
            Instr("BUILD_TUPLE", arg=2),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Bar"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="Bar"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="Bar"),

            # class_attr = Bar.y
            Instr("LOAD_FAST", arg="Bar"),
            Instr("LOAD_ATTR", arg="foo"),
            Instr("STORE_FAST", arg="class_attr"),

            # class_attr2 = Bar.Foo.y
            Instr("LOAD_FAST", arg="Bar"),
            Instr("LOAD_ATTR", arg="Foo"),
            Instr("LOAD_ATTR", arg="y"),
            Instr("STORE_FAST", arg="class_attr2"),

            # result = class_attr + class_attr2
            Instr("LOAD_FAST", arg="class_attr"),
            Instr("LOAD_FAST", arg="class_attr2"),
            Instr("BINARY_ADD"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        bar_block = BasicBlock([
            # class Foo:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CLOSURE", arg=cellvar_x2),
            Instr("BUILD_TUPLE", arg=1),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("MAKE_FUNCTION", arg=8),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="Foo"),

            # foo = x1
            Instr("LOAD_CLASSDEREF", arg=freevar_x1),
            Instr("STORE_NAME", arg="foo"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        foo_block = BasicBlock([
            # y = x2
            Instr("LOAD_CLASSDEREF", arg=freevar_x2),
            Instr("STORE_NAME", arg="y"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(foo_block)
        expected_instructions.extend(bar_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_nested_class_2")
        self.assertEqual(func(), [1, 2])
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 26
0
 def test_copy(self):
     block = BasicBlock([Instr("NOP")])
     next_block = BasicBlock()
     block.next_block = next_block
     self.assertEqual(block, block.copy())
     self.assertIs(next_block, block.copy().next_block)
Esempio n. 27
0
 def test_slice(self):
     block = BasicBlock([Instr("NOP")])
     next_block = BasicBlock()
     block.next_block = next_block
     self.assertEqual(block, block[:])
     self.assertIs(next_block, block[:].next_block)
Esempio n. 28
0
    def test_equal_variable_names(self):
        # Data dependencies across modules (explicit, full cover)
        main_module_block = BasicBlock([
            # class Foo:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="Foo"),

            # duplicate_var = "foo_dup"
            Instr("LOAD_CONST", arg="foo_dup"),
            Instr("STORE_NAME", arg="duplicate_var"),

            # import tests.slicer.integration.example_modules.equal_variable_names_def
            # Instr("LOAD_CONST", arg=0),
            # Instr("LOAD_CONST", arg=None),
            # Instr("IMPORT_NAME", arg="tests.slicer.integration.example_modules.equal_variable_names_def"),
            # Instr("STORE_NAME", arg="tests"),

            # test = duplicate_var
            Instr("LOAD_NAME", arg="duplicate_var"),
            Instr("STORE_NAME", arg="test"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),

            # result = Foo.test
            Instr("LOAD_NAME", arg="Foo"),
            Instr("LOAD_ATTR", arg="test"),
            Instr("STORE_NAME", arg="result"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])
        dependency_module_block = BasicBlock([
            # duplicate_var = "bar_dup"
            # Instr("LOAD_CONST", arg="bar_dup"),
            # Instr("STORE_NAME", arg="duplicate_var"),

            # Instr("LOAD_CONST", arg=None),
            # Instr("RETURN_VALUE")
        ])

        expected_instructions = []
        expected_instructions.extend(main_module_block)
        expected_instructions.extend(dependency_module_block)

        module_dependency_file = "equal_variable_names_def.py"
        module_dependency_path = example_modules_path + module_dependency_file
        instrument_module(module_dependency_path)

        module_file = "equal_variable_names_main.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)

        compile_module(module_dependency_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 29
0
    def test_object_modification_call(self):
        def func():
            class NestedClass:
                def __init__(self):
                    self.x = 1

                def inc_x(self):
                    self.x = self.x + 1

            ob = NestedClass()
            ob.inc_x()

            result = ob.x
            return result

        function_block = BasicBlock([
            # class NestedClass:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_FAST", arg="NestedClass"),

            # ob = NestedClass()
            Instr("LOAD_FAST", arg="NestedClass"),
            Instr("CALL_FUNCTION", arg=0),
            Instr("STORE_FAST", arg="ob"),

            # ob.inc_x()
            Instr("LOAD_FAST", arg="ob"),
            Instr("LOAD_METHOD", arg="inc_x"),
            Instr("CALL_METHOD", arg=0),

            # result = ob.x
            Instr("LOAD_FAST", arg="ob"),
            Instr("LOAD_ATTR", arg="x"),
            Instr("STORE_FAST", arg="result"),

            # return result
            Instr("LOAD_FAST", arg="result"),
            Instr("RETURN_VALUE"),
        ])

        nested_class_block = BasicBlock([
            # Definition of dunder methods are wrongly excluded, since these are not explicitly loaded
            # def __init__(self):
            # Instr("LOAD_CONST", arg=dummy_code_object),
            # Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
            #                         "func.<locals>.NestedClass.__init__"),
            # Instr("MAKE_FUNCTION", arg=0),
            # Instr("STORE_NAME", arg="__init__"),

            # def inc_x(self):
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="IntegrationTestLanguageFeatures.test_object_modification_call.<locals>."
                                    "func.<locals>.NestedClass.inc_x"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("STORE_NAME", arg="inc_x"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        init_block = BasicBlock([
            # self.x = 1
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),

            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        inc_x_block = BasicBlock([
            # self.x = self.x + 1
            Instr("LOAD_FAST", arg="self"),
            Instr("LOAD_ATTR", arg="x"),
            Instr("LOAD_CONST", arg=1),
            Instr("BINARY_ADD"),
            Instr("LOAD_FAST", arg="self"),
            Instr("STORE_ATTR", arg="x"),

            # This "None return" is not included, because the return value is not used
            # Instr("LOAD_CONST", arg=None),
            # Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(function_block)
        expected_instructions.extend(nested_class_block)
        expected_instructions.extend(init_block)
        expected_instructions.extend(inc_x_block)
        dynamic_slice = slice_function_at_return(func.__code__, test_name="test_object_modification_call")
        self.assertEqual(len(dynamic_slice.sliced_instructions), len(expected_instructions))
        self.assertTrue(compare(dynamic_slice.sliced_instructions, expected_instructions))
Esempio n. 30
0
    def test_data_dependency_6(self):
        # Data dependencies across modules (explicit, full cover)
        main_module_block = BasicBlock([
            # from tests.slicer.integration.example_modules.module_dependency_def import module_list, Foo
            Instr("LOAD_CONST", arg=0),
            Instr("LOAD_CONST", arg=('module_list', 'unused_list', 'Foo')),
            Instr("IMPORT_NAME",
                  arg="tests.slicer.example_modules.module_dependency_def"),
            Instr("IMPORT_FROM", arg="module_list"),
            Instr("STORE_NAME", arg="module_list"),
            # Instr("IMPORT_FROM", arg="unused_list"),
            # Instr("STORE_NAME", arg="unused_list"),
            Instr("IMPORT_FROM", arg="Foo"),
            Instr("STORE_NAME", arg="Foo"),

            # result = module_list + Foo.get_class_list()
            Instr("LOAD_NAME", arg="module_list"),
            Instr("LOAD_NAME", arg="Foo"),
            Instr("LOAD_METHOD", arg="get_class_list"),
            Instr("CALL_METHOD", arg=0),
            Instr("BINARY_ADD"),
            Instr("STORE_NAME", arg="result"),
            # return
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE")
        ])
        dependency_module_block = BasicBlock([
            # module_list = [1, 2, 3]
            Instr("LOAD_CONST", arg=1),
            Instr("LOAD_CONST", arg=2),
            Instr("LOAD_CONST", arg=3),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_NAME", arg="module_list"),

            # class Foo:
            Instr("LOAD_BUILD_CLASS"),
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("LOAD_CONST", arg="Foo"),
            Instr("CALL_FUNCTION", arg=2),
            Instr("STORE_NAME", arg="Foo"),

            # class_list = [4, 5, 6]
            Instr("LOAD_CONST", arg=7),
            Instr("LOAD_CONST", arg=8),
            Instr("LOAD_CONST", arg=9),
            Instr("BUILD_LIST", arg=3),
            Instr("STORE_NAME", arg="class_list"),

            # @staticmethod
            Instr("LOAD_NAME", arg="staticmethod"),

            # def get_class_list():
            Instr("LOAD_CONST", arg=dummy_code_object),
            Instr("LOAD_CONST", arg="Foo.get_class_list"),
            Instr("MAKE_FUNCTION", arg=0),
            Instr("CALL_FUNCTION", arg=1),
            Instr("STORE_NAME", arg="get_class_list"),

            # return Foo.class_list
            Instr("LOAD_GLOBAL", arg="Foo"),
            Instr("LOAD_ATTR", arg="class_list"),
            Instr("RETURN_VALUE"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
            Instr("LOAD_CONST", arg=None),
            Instr("RETURN_VALUE"),
        ])

        expected_instructions = []
        expected_instructions.extend(main_module_block)
        expected_instructions.extend(dependency_module_block)

        module_dependency_file = "module_dependency_def.py"
        module_dependency_path = example_modules_path + module_dependency_file
        instrument_module(module_dependency_path)

        module_file = "module_dependency_main.py"
        module_path = example_modules_path + module_file
        dynamic_slice = slice_module_at_return(module_path)

        compile_module(module_dependency_path)
        self.assertEqual(len(dynamic_slice.sliced_instructions),
                         len(expected_instructions))
        self.assertTrue(
            compare(dynamic_slice.sliced_instructions, expected_instructions))