78 lines
3.4 KiB
Python
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() |