def METHOD_NAME(
    self, test_dir: str, test_file: str, check_gas_left: bool = True
) -> None:
    test_data = self.load_test(test_dir, test_file)
    target = test_data["target"]
    env = test_data["env"]
    message = self.prepare_message(
        caller=test_data["caller"],
        target=target,
        value=test_data["value"],
        data=test_data["data"],
        gas=test_data["gas"],
        env=env,
    )
    output = self.process_message_call(message, env)
    if test_data["has_post_state"]:
        if check_gas_left:
            assert output.gas_left == test_data["expected_gas_left"]
        assert (
            keccak256(rlp.encode(output.logs))
            == test_data["expected_logs_hash"]
        )
        # We are checking only the storage here and not the whole state, as the
        # balances in the testcases don't change even though some value is
        # transferred along with code invocation. But our evm execution transfers
        # the value as well as executing the code
        for addr in test_data["post_state_addresses"]:
            assert self.storage_root(
                test_data["expected_post_state"], addr
            ) == self.storage_root(env.state, addr)
    else:
        assert output.has_erred is True
    self.close_state(env.state)
    self.close_state(test_data["expected_post_state"])