Files
radare2-rlang/python/tests/test_python_plugin.py

129 lines
3.0 KiB
Python

#!/usr/bin/env python3
import json
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
SCRIPT_DIR = Path(__file__).resolve().parent / "scripts"
def run_checked(cmd, *, cwd=REPO_ROOT, env=None, input_text=None):
result = subprocess.run(
cmd,
cwd=cwd,
env=env,
input=input_text,
text=True,
capture_output=True,
)
if result.returncode != 0:
raise RuntimeError(
f"command failed: {' '.join(cmd)}\n"
f"stdout:\n{result.stdout}\n"
f"stderr:\n{result.stderr}"
)
return result
class PythonPluginIntegrationTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.tmpdir = Path(tempfile.mkdtemp(prefix="r2lang-python-tests-"))
cls.home = cls.tmpdir / "home"
cls.xdg_data_home = cls.tmpdir / "share"
cls.plugins_dir = cls.xdg_data_home / "radare2" / "plugins"
cls.home.mkdir(parents=True, exist_ok=True)
cls.plugins_dir.mkdir(parents=True, exist_ok=True)
cls.env = os.environ.copy()
cls.env.update(
{
"HOME": str(cls.home),
"XDG_DATA_HOME": str(cls.xdg_data_home),
"R2_COLOR": "0",
}
)
run_checked(["make", "-C", "python", "py"], env=cls.env)
run_checked(
[
"make",
"-C",
"python",
"python-install",
f"R2PM_PLUGDIR={cls.plugins_dir}",
],
env=cls.env,
)
@classmethod
def tearDownClass(cls):
shutil.rmtree(cls.tmpdir, ignore_errors=True)
def run_r2(self, *args):
result = subprocess.run(
["r2", *args],
cwd=REPO_ROOT,
env=self.env,
text=True,
capture_output=True,
)
self.assertEqual(
result.returncode,
0,
msg=(
f"r2 failed: {' '.join(args)}\n"
f"stdout:\n{result.stdout}\n"
f"stderr:\n{result.stderr}"
),
)
return result
def test_python_lang_plugin_is_visible(self):
result = self.run_r2("-N", "-q", "-c", "Llj", "-")
plugins = json.loads(result.stdout)
self.assertIn("python", {plugin["name"] for plugin in plugins})
def test_basic_script_runs_and_can_issue_commands(self):
result = self.run_r2("-N", "-q", "-i", str(SCRIPT_DIR / "basic.py"), "-")
self.assertEqual(result.stdout.strip(), "5")
def test_io_plugin_can_open_and_read(self):
result = self.run_r2(
"-N",
"-q",
"-I",
str(SCRIPT_DIR / "io_plugin.py"),
"-c",
"p8 4",
"pytestio://33",
)
self.assertEqual(result.stdout.strip(), "41414141")
def test_arch_plugin_can_decode_and_encode(self):
result = self.run_r2(
"-N",
"-q",
"-i",
str(SCRIPT_DIR / "arch_plugin.py"),
"-c",
"wx 031234; e asm.arch=pyarch; e asm.bits=32; pdj 1; pa nop; pa mov r2, 0x33",
"malloc://3",
)
lines = [line.strip() for line in result.stdout.splitlines() if line.strip()]
self.assertGreaterEqual(len(lines), 3, msg=result.stdout)
op = json.loads(lines[0])[0]
self.assertEqual(op["opcode"], "jne 0x1234")
self.assertEqual(op["jump"], 0x1234)
self.assertEqual(op["fail"], 3)
self.assertEqual(lines[1], "00")
self.assertEqual(lines[2], "010233")
if __name__ == "__main__":
unittest.main()