mirror of
https://github.com/morluto/rea.git
synced 2026-10-19 04:19:54 -05:00
fix(cutter): attribute the host application version
Identify the Cutter host through Qt applicationVersion rather than the embedded Rizin module-version report. Preserve unknown host metadata without backend fallback and reuse the existing per-plugin lifetime observation. Validated 13 Python protocol tests, 66 related CLI/MCP/provider tests, full static/docs gates, and official Linux Cutter 2.5.0 Qt5 public workflows. Native discovery and both Evidence version fields match the independently observed host version; source paths and cleanup remain preserved. The named-tool workflow serialization proxy drops from 8767 to 6912 o200k tokens; this is not model billing. Fixes #4498.
This commit is contained in:
1 parent
2c1dee16df
commit
9a82046b07
2 files changed
+45
-4
No files matched your search
@@ -28,9 +28,9 @@ if os.name == "nt":
|
||||
import cutter
|
||||
|
||||
try:
|
||||
from PySide6.QtCore import QObject, Signal
|
||||
from PySide6.QtCore import QCoreApplication, QObject, Signal
|
||||
except ImportError:
|
||||
from PySide2.QtCore import QObject, Signal
|
||||
from PySide2.QtCore import QCoreApplication, QObject, Signal
|
||||
|
||||
|
||||
MAX_FRAME_BYTES = 16 * 1024 * 1024
|
||||
@@ -326,7 +326,8 @@ class _RequestDispatcher(QObject):
|
||||
self._receipt_lock = threading.Lock()
|
||||
self.current_file = self._read_current_file()
|
||||
try:
|
||||
self.cutter_version = str(cutter.core().getVersionInformation())
|
||||
value = QCoreApplication.applicationVersion()
|
||||
self.cutter_version = value if isinstance(value, str) and value else None
|
||||
except Exception:
|
||||
self.cutter_version = None
|
||||
|
||||
|
||||
+41
-1
@@ -24,6 +24,7 @@ def _install_host_stubs():
|
||||
qtcore = types.ModuleType("PySide6.QtCore")
|
||||
qtcore.QObject = type("QObject", (), {})
|
||||
qtcore.Signal = lambda *_args: types.SimpleNamespace(connect=lambda _handler: None)
|
||||
qtcore.QCoreApplication = types.SimpleNamespace(applicationVersion=lambda: "Cutter test host")
|
||||
pyside = types.ModuleType("PySide6")
|
||||
pyside.QtCore = qtcore
|
||||
sys.modules["PySide6"] = pyside
|
||||
@@ -229,7 +230,6 @@ class DocumentIdentityTest(unittest.TestCase):
|
||||
configuration = {"file.path": first}
|
||||
core = types.SimpleNamespace(
|
||||
getConfig=configuration.__getitem__,
|
||||
getVersionInformation=lambda: "backend fixture",
|
||||
)
|
||||
commands = []
|
||||
with patch.object(bridge.cutter, "core", lambda: core, create=True), patch.object(
|
||||
@@ -280,6 +280,46 @@ class DocumentIdentityTest(unittest.TestCase):
|
||||
self.assertIsNone(bridge._RequestDispatcher._read_current_file())
|
||||
|
||||
|
||||
class HostVersionTest(unittest.TestCase):
|
||||
def test_host_version_reaches_status_and_command_without_backend_attribution(self):
|
||||
backend_reads = []
|
||||
core = types.SimpleNamespace(
|
||||
getConfig=lambda _key: None,
|
||||
getVersionInformation=lambda: backend_reads.append(True) or "Rizin 0.9.1",
|
||||
)
|
||||
application = sys.modules["PySide6.QtCore"].QCoreApplication
|
||||
with patch.object(bridge.cutter, "core", lambda: core, create=True), patch.object(
|
||||
application, "applicationVersion", return_value="2.5.0-HEAD-fixture"
|
||||
), patch.object(bridge.cutter, "cmd", lambda _command: "observed", create=True):
|
||||
dispatcher = bridge._RequestDispatcher()
|
||||
self.assertEqual(dispatcher.cutter_version, "2.5.0-HEAD-fixture")
|
||||
for values in [
|
||||
{"kind": "status"},
|
||||
{"kind": "command", "request_id": str(uuid.uuid4()), "expected_generation": 0, "command": "iI"},
|
||||
]:
|
||||
request = {**values, "_event": threading.Event(), "_cancelled": threading.Event()}
|
||||
reply = {}
|
||||
dispatcher._handle(request, reply)
|
||||
self.assertTrue(request["_event"].is_set())
|
||||
self.assertEqual(reply["cutter_version"], "2.5.0-HEAD-fixture")
|
||||
self.assertEqual(backend_reads, [])
|
||||
|
||||
def test_unavailable_host_version_stays_unknown_without_backend_fallback(self):
|
||||
core = types.SimpleNamespace(
|
||||
getConfig=lambda _key: None,
|
||||
getVersionInformation=lambda: "Rizin 0.9.1",
|
||||
)
|
||||
application = sys.modules["PySide6.QtCore"].QCoreApplication
|
||||
with patch.object(bridge.cutter, "core", lambda: core, create=True):
|
||||
for value in ["", None, object()]:
|
||||
with self.subTest(value=type(value).__name__), patch.object(
|
||||
application, "applicationVersion", return_value=value
|
||||
):
|
||||
self.assertIsNone(bridge._RequestDispatcher().cutter_version)
|
||||
with patch.object(application, "applicationVersion", side_effect=RuntimeError("host unavailable")):
|
||||
self.assertIsNone(bridge._RequestDispatcher().cutter_version)
|
||||
|
||||
|
||||
class ProtocolProducerTest(unittest.TestCase):
|
||||
def test_rejects_legacy_peers_before_ui_dispatch(self):
|
||||
with socket.create_connection(("127.0.0.1", self.server.port), timeout=2) as connection:
|
||||
|
||||
Reference in new issue
Block a user