import sys import unittest from pathlib import Path from unittest import mock sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) from cthulhu import messages from cthulhu.notification_presenter import NotificationPresenter class _FakeMonitor: def __init__(self): self.dismissed = [] self.invoked = [] self.current_generation = 2 def refresh(self, announce_new=False): return True def is_current_entry(self, entry): return entry.source == "mako" and entry.source_generation == self.current_generation def dismiss_notification(self, notification_id): self.dismissed.append(notification_id) return True def invoke_action(self, notification_id, action_key): self.invoked.append((notification_id, action_key)) return True class NotificationPresenterMakoTests(unittest.TestCase): def setUp(self): self.presenter = NotificationPresenter() self.monitor = _FakeMonitor() self.presenter.set_mako_monitor(self.monitor) def test_sync_updates_current_generation_only(self): old_entry = self.presenter.save_notification( "Notification old", source="mako", source_generation=1, notification_id=5, live=False, actions={"default": "Old"}, ) current_entry = self.presenter.save_notification( "Notification current", source="mako", source_generation=2, notification_id=6, live=True, actions={"default": "View"}, ) self.presenter.sync_live_notifications( "mako", { 5: { "message": "Notification replaced", "actions": {"default": "New"}, "app_name": "discord", "summary": "replaced", "body": "", "urgency": 1, "desktop_entry": "discord", } }, source_generation=2, ) self.assertEqual(old_entry.message, "Notification old") self.assertEqual(old_entry.actions, {"default": "Old"}) self.assertFalse(current_entry.live) def test_can_control_entry_and_get_actions_require_current_monitor_generation(self): entry = self.presenter.save_notification( "Notification current", source="mako", source_generation=2, notification_id=6, live=True, actions={"default": "View"}, ) self.assertTrue(self.presenter.can_control_entry(entry)) self.assertEqual(self.presenter.get_actions_for_entry(entry), {"default": "View"}) stale_entry = self.presenter.save_notification( "Notification stale", source="mako", source_generation=1, notification_id=7, live=True, actions={"default": "Open"}, ) self.assertFalse(self.presenter.can_control_entry(stale_entry)) self.assertEqual(self.presenter.get_actions_for_entry(stale_entry), {}) def test_dismiss_and_invoke_action_route_through_monitor(self): entry = self.presenter.save_notification( "Notification current", source="mako", source_generation=2, notification_id=6, live=True, actions={"default": "View"}, ) script = mock.Mock() self.assertTrue(self.presenter.dismiss_entry(script, entry)) self.assertEqual(self.monitor.dismissed, [6]) script.presentMessage.assert_called_with(messages.NOTIFICATION_DISMISSED) script.reset_mock() self.assertTrue(self.presenter.invoke_action_for_entry(script, entry, "default")) self.assertEqual(self.monitor.invoked, [(6, "default")]) script.presentMessage.assert_called_with(messages.NOTIFICATION_ACTION_INVOKED) if __name__ == "__main__": unittest.main()