Skip to main content
Glama
test_modify.py10.4 kB
"""测试 api_modify.py 中的工具。 测试逻辑: 1. 使用 fixtures 获取有效的函数/全局变量地址 2. 测试注释、重命名等修改操作 3. 注意:这些测试会修改 IDB 数据库 Proxy 参数对应: - set_comment: items (List of {address, comment}) - rename_function: address (str), new_name - rename_local_variable: function_address (str), old_name, new_name - rename_global_variable: old_name, new_name - patch_bytes: items (List of {address, bytes}) 运行方式: pytest -m modify # 只运行 modify 模块测试 pytest test_modify.py # 运行此文件所有测试 """ import pytest pytestmark = pytest.mark.modify class TestSetComment: """设置注释测试。""" def test_set_comment_single(self, tool_caller, first_function_address): """测试设置单个注释。""" test_comment = "Test comment from pytest" # API 接受 items: List[{address, comment}] result = tool_caller("set_comment", { "items": [{"address": hex(first_function_address), "comment": test_comment}] }) assert isinstance(result, list) assert len(result) == 1 if "error" not in result[0]: # API 返回 changed 字段 assert "changed" in result[0] def test_set_comment_batch(self, tool_caller, functions_cache): """测试批量设置注释。""" if len(functions_cache) < 3: pytest.skip("Not enough functions") items = [ {"address": f["start_ea"], "comment": f"Batch comment {i}"} for i, f in enumerate(functions_cache[:3]) ] result = tool_caller("set_comment", {"items": items}) assert isinstance(result, list) assert len(result) == 3 def test_set_comment_clear(self, tool_caller, first_function_address): """测试清除注释。""" addr = hex(first_function_address) # 先设置注释 tool_caller("set_comment", { "items": [{"address": addr, "comment": "To be cleared"}] }) # 然后清除 result = tool_caller("set_comment", { "items": [{"address": addr, "comment": ""}] }) assert isinstance(result, list) def test_set_comment_multiple_different(self, tool_caller, functions_cache): """测试设置不同的注释到不同地址。""" if len(functions_cache) < 2: pytest.skip("Not enough functions") items = [ {"address": functions_cache[0]["start_ea"], "comment": "Comment A"}, {"address": functions_cache[1]["start_ea"], "comment": "Comment B"}, ] result = tool_caller("set_comment", {"items": items}) assert isinstance(result, list) assert len(result) == 2 class TestRenameFunction: """重命名函数测试。""" def test_rename_function(self, tool_caller, first_function): """测试重命名函数。""" old_name = first_function["name"] # start_ea 是 hex 字符串,去掉 0x 前缀用于名称 addr_str = first_function['start_ea'].replace('0x', '').replace('0X', '') new_name = f"test_renamed_{addr_str}" # Proxy 参数: address (str), new_name result = tool_caller("rename_function", { "address": first_function["start_ea"], "new_name": new_name }) if "error" not in result: assert "changed" in result # 恢复原名 tool_caller("rename_function", { "address": first_function["start_ea"], "new_name": old_name }) else: # 如果失败,打印调试信息 print(f"rename_function failed: {result}") # 可能是数据库状态问题,尝试通过函数名 result2 = tool_caller("rename_function", { "address": old_name, "new_name": new_name }) if "error" not in result2: # 恢复原名 tool_caller("rename_function", { "address": new_name, "new_name": old_name }) def test_rename_function_by_name(self, tool_caller, first_function): """测试通过函数名重命名(回退测试)。""" old_name = first_function["name"] new_name = f"test_by_name_{old_name[:8]}" result = tool_caller("rename_function", { "address": old_name, "new_name": new_name }) # 恢复原名(无论成功与否都尝试) if "error" not in result: tool_caller("rename_function", { "address": new_name, "new_name": old_name }) def test_rename_function_invalid_name(self, tool_caller, first_function): """测试使用无效名称(以数字开头)。""" result = tool_caller("rename_function", { "address": first_function["start_ea"], "new_name": "123invalid" }) # Proxy 转发到 API 验证 C 标识符,应该返回错误 assert "error" in result def test_rename_function_empty_name(self, tool_caller, first_function): """测试空名称。""" result = tool_caller("rename_function", { "address": first_function["start_ea"], "new_name": "" }) assert "error" in result class TestRenameLocalVariable: """重命名局部变量测试。""" def test_rename_local_variable(self, tool_caller, first_function_address): """测试重命名局部变量。""" # API 参数: function_address (str), old_name, new_name result = tool_caller("rename_local_variable", { "function_address": hex(first_function_address), "old_name": "v1", "new_name": "test_var" }) # 可能成功或失败(取决于是否有该变量) assert isinstance(result, dict) class TestRenameGlobalVariable: """重命名全局变量测试。""" def test_rename_global_variable(self, tool_caller, first_global): """测试重命名全局变量。""" old_name = first_global["name"] # ea 是 hex 字符串,去掉 0x 前缀用于名称 addr_str = first_global['ea'].replace('0x', '').replace('0X', '') new_name = f"test_global_{addr_str}" # API 参数: old_name, new_name result = tool_caller("rename_global_variable", { "old_name": old_name, "new_name": new_name }) if "error" not in result and result.get("changed"): # 恢复原名 tool_caller("rename_global_variable", { "old_name": new_name, "new_name": old_name }) def test_rename_global_variable_not_found(self, tool_caller): """测试重命名不存在的全局变量。""" result = tool_caller("rename_global_variable", { "old_name": "nonexistent_global_xyz123", "new_name": "new_name" }) assert "error" in result class TestPatchBytes: """字节补丁测试。 注意:这些测试会修改数据库,使用先读后恢复的策略。 """ def test_patch_bytes_and_restore(self, tool_caller, first_function_address): """测试补丁并恢复字节。""" addr = first_function_address # 1. 读取原始字节 read_result = tool_caller("get_bytes", { "addr": hex(addr), "size": 4 }) if not isinstance(read_result, list) or not read_result: pytest.skip("Cannot read bytes") original_bytes = read_result[0].get("bytes", []) if not original_bytes: pytest.skip("No bytes read") # 2. 打补丁 (NOP: 0x90) nop_bytes = [0x90] * len(original_bytes) patch_result = tool_caller("patch_bytes", { "items": [{"address": addr, "bytes": nop_bytes}] }) assert isinstance(patch_result, list) assert len(patch_result) == 1 # 3. 恢复原始字节 restore_result = tool_caller("patch_bytes", { "items": [{"address": addr, "bytes": original_bytes}] }) assert isinstance(restore_result, list) def test_patch_bytes_hex_string(self, tool_caller, first_function_address): """测试使用十六进制字符串补丁。""" addr = first_function_address # 读取原始 read_result = tool_caller("get_bytes", { "addr": hex(addr), "size": 2 }) if not isinstance(read_result, list) or not read_result: pytest.skip("Cannot read bytes") original = read_result[0].get("bytes", []) # 用 hex string 格式打补丁 result = tool_caller("patch_bytes", { "items": [{"address": addr, "bytes": "90 90"}] }) assert isinstance(result, list) # 恢复 tool_caller("patch_bytes", { "items": [{"address": addr, "bytes": original}] }) def test_patch_bytes_invalid_address(self, tool_caller): """测试无效地址。""" result = tool_caller("patch_bytes", { "items": [{"address": "invalid", "bytes": [0x90]}] }) assert isinstance(result, list) assert result[0].get("error") is not None def test_patch_bytes_empty_bytes(self, tool_caller, first_function_address): """测试空字节。""" result = tool_caller("patch_bytes", { "items": [{"address": first_function_address, "bytes": []}] }) assert isinstance(result, list) assert result[0].get("error") is not None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jelasin/IDA-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server