mirror of
https://github.com/radareorg/radare2-r2pipe.git
synced 2026-11-10 04:11:28 -10:00
177 lines
6.0 KiB
Python
177 lines
6.0 KiB
Python
import ctypes
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import r2pipe
|
|
from r2pipe.native import *
|
|
from r2pipe.open_async import open as async_open
|
|
|
|
|
|
class TestR2PipeUnit(unittest.TestCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.curdir = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
def test_version(self):
|
|
self.assertEqual(r2pipe.version(), r2pipe.VERSION)
|
|
|
|
def test_native_r2lib(self):
|
|
lib = r2lib()
|
|
if sys.platform.startswith("win"):
|
|
self.assertIsInstance(lib, ctypes.WinDLL)
|
|
else:
|
|
self.assertIsInstance(lib, ctypes.CDLL)
|
|
|
|
def test_race_io(self):
|
|
os.system("sh race.sh")
|
|
|
|
def test_native_rcore(self):
|
|
c = RCore()
|
|
value = c.cmd_str("o %s/ls; s entry0;pi 1 @e:scr.color=0" % self.curdir).strip()
|
|
c.free()
|
|
self.assertEqual(value, "push rbp")
|
|
|
|
|
|
class TestFilenameArgsParsing(unittest.TestCase):
|
|
"""Test that filename arguments are correctly parsed into -R flags (PR #91)."""
|
|
|
|
def _mock_popen(self):
|
|
"""Create a mock Popen that captures the command and simulates r2."""
|
|
mock_proc = MagicMock()
|
|
mock_proc.stdout.read.return_value = b"\x00"
|
|
mock_proc.stdin.write.return_value = None
|
|
mock_proc.stdin.flush.return_value = None
|
|
mock_proc.poll.return_value = None
|
|
return mock_proc
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_string_with_args_builds_correct_cmd(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
r2pipe.open("/bin/ls arg1 arg2")
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertIn("-Rarg1=arg1", cmd)
|
|
self.assertIn("-Rarg2=arg2", cmd)
|
|
self.assertIn("/bin/ls", cmd)
|
|
self.assertLess(cmd.index("-Rarg1=arg1"), cmd.index("/bin/ls"))
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_list_with_args_builds_correct_cmd(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
r2pipe.open(["/bin/ls", "hello", "world"])
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertIn("-Rarg1=hello", cmd)
|
|
self.assertIn("-Rarg2=world", cmd)
|
|
self.assertIn("/bin/ls", cmd)
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_list_single_element_no_r_args(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
r2pipe.open(["/bin/ls"])
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertNotIn("-Rarg1=", str(cmd))
|
|
self.assertIn("/bin/ls", cmd)
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_plain_filename_no_r_args(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
r2pipe.open("/bin/ls")
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
r_flags = [part for part in cmd if part.startswith("-R")]
|
|
self.assertEqual(r_flags, [])
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_flags_and_file_args_combined(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
r2pipe.open(["/bin/ls", "myarg"], flags=["-d"])
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertIn("-d", cmd)
|
|
self.assertIn("-Rarg1=myarg", cmd)
|
|
self.assertIn("/bin/ls", cmd)
|
|
self.assertLess(cmd.index("-d"), cmd.index("-Rarg1=myarg"))
|
|
self.assertLess(cmd.index("-Rarg1=myarg"), cmd.index("/bin/ls"))
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_pathlike_filename_is_accepted(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
filename = Path("/tmp/test-bin")
|
|
r2pipe.open(filename)
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertIn(os.fspath(filename), cmd)
|
|
r_flags = [part for part in cmd if part.startswith("-R")]
|
|
self.assertEqual(r_flags, [])
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_pathlike_filename_with_spaces_is_not_split(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
filename = Path("/tmp/path with spaces/test-bin")
|
|
r2pipe.open(filename)
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertIn(os.fspath(filename), cmd)
|
|
r_flags = [part for part in cmd if part.startswith("-R")]
|
|
self.assertEqual(r_flags, [])
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_pathlike_list_filename_and_args_are_coerced(self, mock_popen_cls):
|
|
mock_popen_cls.return_value = self._mock_popen()
|
|
|
|
filename = Path("/tmp/test-bin")
|
|
arg = Path("relative-arg")
|
|
r2pipe.open([filename, arg])
|
|
|
|
cmd = mock_popen_cls.call_args[0][0]
|
|
self.assertIn(os.fspath(filename), cmd)
|
|
self.assertIn(f"-Rarg1={os.fspath(arg)}", cmd)
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
def test_http_url_not_split(self, mock_popen_cls):
|
|
r2 = r2pipe.open("http://127.0.0.1:9999 extra")
|
|
|
|
self.assertEqual(r2.uri, "http://127.0.0.1:9999 extra/cmd")
|
|
mock_popen_cls.assert_not_called()
|
|
|
|
@patch("r2pipe.open_sync.Popen")
|
|
@patch("r2pipe.open_sync.socket.socket")
|
|
def test_tcp_url_not_split(self, mock_socket_cls, mock_popen_cls):
|
|
mock_conn = MagicMock()
|
|
mock_socket_cls.return_value = mock_conn
|
|
|
|
r2 = r2pipe.open("tcp://127.0.0.1:9999 extra")
|
|
|
|
self.assertIs(r2.conn, mock_conn)
|
|
mock_conn.connect.assert_called_once_with(("127.0.0.1", 9999))
|
|
mock_popen_cls.assert_not_called()
|
|
|
|
def test_async_pathlike_filename_is_accepted(self):
|
|
filename = Path("/tmp/test-bin")
|
|
r2 = async_open(filename)
|
|
|
|
self.assertEqual(r2._process_start_cmd[-1], os.fspath(filename))
|
|
self.assertEqual([part for part in r2._process_start_cmd if part.startswith("-R")], [])
|
|
r2.close()
|
|
|
|
def test_async_pathlike_filename_with_spaces_is_not_split(self):
|
|
filename = Path("/tmp/path with spaces/test-bin")
|
|
r2 = async_open(filename)
|
|
|
|
self.assertEqual(r2._process_start_cmd[-1], os.fspath(filename))
|
|
self.assertEqual([part for part in r2._process_start_cmd if part.startswith("-R")], [])
|
|
r2.close()
|