import urllib.parse import urllib.request BASE = "http://127.0.0.1:8080" def excerpt(text, max_len=180): s = (text or "").replace("\r", " ").replace("\n", " ").strip() if len(s) > max_len: return s[: max_len - 3] + "..." return s def http_get(path, params=None): params = params or {} query = urllib.parse.urlencode(params) url = BASE + path + (("?" + query) if query else "") with urllib.request.urlopen(url, timeout=10) as resp: return resp.read().decode("utf-8", errors="replace") def http_post(path, data=None): data = data or {} body = urllib.parse.urlencode(data).encode("utf-8") req = urllib.request.Request(BASE + path, data=body, method="POST") with urllib.request.urlopen(req, timeout=10) as resp: return resp.read().decode("utf-8", errors="replace") def run_test(name, func): try: result = func() print("PASS", name, "::", excerpt(result)) except Exception as e: print("FAIL", name, "::", str(e)) readonly_script = "\n".join( [ "println('program=' + currentProgram.getName())", "if currentAddress is not None:", " println('addr=' + currentAddress.toString())", "else:", " println('addr=')", ] ) if __name__ == "__main__": run_test("get_project_access_info", lambda: http_get("/get_project_access_info")) run_test("read_region", lambda: http_get("/read_region", {"start": "0007:28ce", "end": "0007:28dd"})) run_test("disassemble_region", lambda: http_get("/disassemble_region", {"start": "0007:28ce", "end": "0007:2900"})) run_test("get_instruction_window", lambda: http_get("/get_instruction_window", {"address": "0007:28ce", "before_count": 2, "after_count": 3})) run_test("search_instructions", lambda: http_get("/search_instructions", {"query": "0007:28ce", "mode": "address", "limit": 5})) run_test("get_data_uses", lambda: http_get("/get_data_uses", {"address": "0007:28ce", "include_operand_scans": "true", "limit": 10})) run_test("analyze_function_boundaries", lambda: http_get("/analyze_function_boundaries", {"start": "0007:28c0", "end": "0007:2910"})) run_test("open_current_program_readonly", lambda: http_post("/open_current_program_readonly", {"version": -1, "make_current": "false"})) run_test("run_readonly_script", lambda: http_post("/run_readonly_script", {"script_text": readonly_script})) run_test("apply_program_edit_plan_dry", lambda: http_post("/apply_program_edit_plan", {"plan": "rename_function_by_address|0007:28ce|tmp_name", "dry_run": "true"})) run_test("create_function_by_address_invalid", lambda: http_post("/create_function_by_address", { "entry": "invalid", "name": "tmp", "body_start": "invalid", "body_end": "invalid", "comment": "smoke", })) run_test("delete_function_by_address_invalid", lambda: http_post("/delete_function_by_address", {"entry": "invalid"})) run_test("rename_functions_by_address_invalid_batch", lambda: http_post("/rename_functions_by_address", {"batch": "not_a_valid_batch_line"})) run_test("set_comments_invalid_batch", lambda: http_post("/set_comments", {"batch": "not_a_valid_batch_line"})) run_test("set_decompiler_comments_invalid_batch", lambda: http_post("/set_decompiler_comments", {"batch": "not_a_valid_batch_line"}))