import pytest from mythril.disassembler.asm import ( disassemble, find_op_code_sequence, get_opcode_from_name, is_sequence_match, ) valid_names = [("PUSH1", 0x60), ("STOP", 0x0), ("RETURN", 0xF3)] @pytest.mark.parametrize("operation_name, hex_value", valid_names) def test_get_opcode(operation_name: str, hex_value: int): # Act return_value = get_opcode_from_name(operation_name) # Assert assert return_value == hex_value def test_get_unknown_opcode(): operation_name = "definitely unknown" # Act with pytest.raises(RuntimeError): get_opcode_from_name(operation_name) sequence_match_test_data = [ # Normal no match ( (["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 1, False, ), # Normal match ( (["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}], 1, True, ), # Out of bounds pattern ( (["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 3, False, ), ( (["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 2, False, ), # Double option match ( (["PUSH1", "PUSH3"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}], 1, True, ), ( (["PUSH1", "PUSH3"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 1, True, ), # Double option no match ( (["PUSH1", "PUSH3"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 0, False, ), ] @pytest.mark.parametrize( "pattern, instruction_list, index, expected_result", sequence_match_test_data ) def test_is_sequence_match(pattern, instruction_list, index, expected_result): # Act return_value = is_sequence_match(pattern, instruction_list, index) # Assert assert return_value == expected_result find_sequence_match_test_data = [ # Normal no match ( (["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], [], ), # Normal match ( (["PUSH1"], ["EQ"]), [ {"opcode": "PUSH1"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}, ], [1, 3], ), ] @pytest.mark.parametrize( "pattern, instruction_list, expected_result", find_sequence_match_test_data ) def test_find_op_code_sequence(pattern, instruction_list, expected_result): # Act return_value = list(find_op_code_sequence(pattern, instruction_list)) # Assert assert return_value == expected_result def test_disassemble(): # Act instruction_list = disassemble(b"\x00\x16\x06") # Assert assert instruction_list[0]["opcode"] == "STOP" assert instruction_list[1]["opcode"] == "AND" assert instruction_list[2]["opcode"] == "MOD"