Files
kefu/wechat_rpa/test_classic_instance.py
T
2026-09-21 10:34:06 +08:00

78 lines
3.4 KiB
Python

"""Classic fallback uses the shared instance guard without starting any GUI."""
import unittest
from unittest import mock
import wechat_gui as gui
class ClassicInstanceTests(unittest.TestCase):
def setUp(self):
self.guard = mock.Mock()
self.guard.acquire.return_value = True
self.patch = mock.patch('desktop_instance.DesktopInstanceGuard', return_value=self.guard)
self.patch.start()
self.addCleanup(self.patch.stop)
def test_secondary_only_activates_existing_instance(self):
self.guard.acquire.return_value = False
with mock.patch.object(gui, '_run_classic_primary') as launch:
gui.run_classic_ui()
launch.assert_not_called()
self.guard.request_activation.assert_called_once_with()
self.guard.close.assert_called_once_with()
def test_primary_holds_guard_until_session_returns(self):
def session(guard):
self.assertIs(guard, self.guard)
guard.close.assert_not_called()
with mock.patch.object(gui, '_run_classic_primary', side_effect=session):
gui.run_classic_ui()
self.guard.close.assert_called_once_with()
self.guard.request_activation.assert_not_called()
def test_startup_failure_still_releases_guard(self):
with mock.patch.object(gui, '_run_classic_primary', side_effect=RuntimeError('synthetic startup failure')):
with self.assertRaises(RuntimeError):
gui.run_classic_ui()
self.guard.close.assert_called_once_with()
def test_rejected_update_does_not_create_main_window(self):
with mock.patch('backend_client.startup_sync_config', return_value={'release': {}}), \
mock.patch.object(gui, 'handle_startup_update', return_value=False), \
mock.patch.object(gui, 'App') as app:
gui.run_classic_ui()
app.assert_not_called()
self.guard.close.assert_called_once_with()
def test_activation_is_polled_on_tk_ui_thread(self):
app = mock.Mock()
jobs = []
app.after.side_effect = lambda delay, callback: jobs.append((delay, callback))
self.guard.consume_activation.return_value = True
def loop():
self.assertEqual(jobs[0][0], 200)
jobs.pop(0)[1]()
self.assertEqual(jobs[0][0], 200)
app.mainloop.side_effect = loop
with mock.patch('backend_client.startup_sync_config', return_value={'release': {}}), \
mock.patch.object(gui, 'handle_startup_update', return_value=True), \
mock.patch.object(gui, 'App', return_value=app), \
mock.patch('archive_auto_backup.start_auto_backup') as backup:
gui.run_classic_ui()
app._expand_console.assert_called_once_with()
app.focus_force.assert_called_once_with()
backup.assert_called_once_with()
self.guard.close.assert_called_once_with()
def test_guard_constructor_failure_is_visible_and_does_not_launch(self):
with mock.patch('desktop_instance.DesktopInstanceGuard', side_effect=OSError('synthetic denied')), \
mock.patch.object(gui.messagebox, 'showerror') as error, \
mock.patch.object(gui, '_run_classic_primary') as launch:
gui.run_classic_ui()
launch.assert_not_called()
error.assert_called_once()
self.guard.close.assert_not_called()
if __name__ == '__main__':
unittest.main()