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 where_am_i_presenter from cthulhu.plugins.WindowTitleReader.plugin import WindowTitleReader class WindowTitleFallbackRegressionTests(unittest.TestCase): def test_activate_registers_reader_api_and_starts_fallback_tracking(self): plugin = WindowTitleReader() plugin.app = mock.Mock() with ( mock.patch.object(plugin, "_register_keybinding"), mock.patch.object(plugin, "_start_tracking") as startTracking, ): plugin.activate(plugin) plugin.app.getDynamicApiManager.return_value.registerAPI.assert_called_once_with( "WindowTitleReader", plugin, overwrite=True, ) startTracking.assert_called_once_with() def test_poll_schedules_fallback_after_active_window_changes(self): plugin = WindowTitleReader() plugin._pollSourceId = 1 plugin._lastActiveWindowId = 100 activeWindow = mock.Mock(id=200) with ( mock.patch.object(plugin, "_get_active_window", return_value=activeWindow), mock.patch.object(plugin, "_get_current_title", return_value="XTerm"), mock.patch.object(plugin, "_schedule_fallback_title") as scheduleFallback, ): self.assertTrue(plugin._poll_window_title()) scheduleFallback.assert_called_once_with() def test_poll_keeps_previous_window_across_transient_missing_active_window(self): plugin = WindowTitleReader() plugin._pollSourceId = 1 plugin._lastActiveWindowId = 100 with mock.patch.object(plugin, "_get_active_window", return_value=None): self.assertTrue(plugin._poll_window_title()) self.assertEqual(plugin._lastActiveWindowId, 100) def test_fallback_is_empty_when_atspi_exposes_same_title(self): plugin = WindowTitleReader() plugin._pollSourceId = 1 activeWindow = mock.Mock() with ( mock.patch.object(plugin, "_get_active_window", return_value=activeWindow), mock.patch.object(plugin, "_get_current_title", return_value="Terminal"), ): self.assertEqual(plugin.get_fallback_title("Terminal"), "") def test_fallback_replaces_wine_desktop_title(self): plugin = WindowTitleReader() plugin._pollSourceId = 1 activeWindow = mock.Mock() with ( mock.patch.object(plugin, "_get_active_window", return_value=activeWindow), mock.patch.object(plugin, "_get_current_title", return_value="Game Window"), ): self.assertEqual(plugin.get_fallback_title("Wine Desktop"), "Game Window") def test_present_title_uses_fallback_instead_of_atspi_title(self): presenter = where_am_i_presenter.WhereAmIPresenter() script = mock.Mock() script.speechGenerator.generateTitle.return_value = [("Wine Desktop", None)] with ( mock.patch.object(where_am_i_presenter.cthulhu_state, "locusOfFocus", object()), mock.patch.object(where_am_i_presenter.AXObject, "is_dead", return_value=False), mock.patch.object( presenter, "_get_fallback_title", return_value="Game Window", ), ): self.assertTrue(presenter.present_title(script)) script.presentMessage.assert_called_once_with("Game Window") if __name__ == "__main__": unittest.main()