Back to index

unity  6.0.0
test_switcher.py
Go to the documentation of this file.
00001 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
00002 # Copyright 2010 Canonical
00003 # Author: Thomi Richards
00004 #
00005 # This program is free software: you can redistribute it and/or modify it
00006 # under the terms of the GNU General Public License version 3, as published
00007 # by the Free Software Foundation.
00008 
00009 from __future__ import absolute_import
00010 
00011 from autopilot.matchers import Eventually
00012 import logging
00013 from testtools.matchers import Equals, Contains, Not
00014 from time import sleep
00015 
00016 from unity.emulators.switcher import SwitcherMode
00017 from unity.tests import UnityTestCase
00018 
00019 logger = logging.getLogger(__name__)
00020 
00021 class SwitcherTestCase(UnityTestCase):
00022     def set_timeout_setting(self, state):
00023         if type(state) is not bool:
00024             raise TypeError("'state' must be boolean, not %r" % type(state))
00025         self.set_unity_option("alt_tab_timeout", state)
00026         sleep(1)
00027 
00028 
00029 class SwitcherTests(SwitcherTestCase):
00030     """Test the switcher."""
00031 
00032     def setUp(self):
00033         super(SwitcherTests, self).setUp()
00034         self.set_timeout_setting(False)
00035         self.char_map = self.start_app('Character Map')
00036         self.calc = self.start_app('Calculator')
00037         self.mahjongg = self.start_app('Mahjongg')
00038 
00039     def tearDown(self):
00040         super(SwitcherTests, self).tearDown()
00041 
00042     def test_witcher_starts_in_normal_mode(self):
00043         """Switcher must start in normal (i.e.- not details) mode."""
00044         self.start_app("Character Map")
00045         sleep(1)
00046 
00047         self.switcher.initiate()
00048         self.addCleanup(self.switcher.terminate)
00049         self.assertThat(self.switcher.mode, Equals(SwitcherMode.NORMAL))
00050 
00051     def test_first_detail_mode_has_correct_label(self):
00052         """Starting switcher in details mode must show the focused window title."""
00053         app = self.start_app("Text Editor")
00054         sleep(1)
00055 
00056         [title] = [w.title for w in app.get_windows() if w.is_focused]
00057         self.switcher.initiate(SwitcherMode.DETAIL)
00058         self.addCleanup(self.switcher.terminate)
00059 
00060         self.assertThat(self.switcher.controller.view.label, Eventually(Equals(title)))
00061 
00062     def test_switcher_move_next(self):
00063         """Test that pressing the next icon binding moves to the next icon"""
00064         self.switcher.initiate()
00065         self.addCleanup(self.switcher.terminate)
00066 
00067         start = self.switcher.selection_index
00068         self.switcher.next_icon()
00069         self.assertThat(self.switcher.selection_index, Equals(start + 1))
00070 
00071     def test_switcher_move_prev(self):
00072         """Test that pressing the previous icon binding moves to the previous icon"""
00073         self.switcher.initiate()
00074         self.addCleanup(self.switcher.terminate)
00075 
00076         start = self.switcher.selection_index
00077         self.switcher.previous_icon()
00078         self.assertThat(self.switcher.selection_index, Equals(start - 1))
00079 
00080     def test_switcher_scroll_next(self):
00081         """Test that scrolling the mouse wheel down moves to the next icon"""
00082         self.switcher.initiate()
00083         self.addCleanup(self.switcher.terminate)
00084 
00085         start = self.switcher.selection_index
00086         self.switcher.next_via_mouse()
00087 
00088         self.assertThat(self.switcher.selection_index, Equals(start + 1))
00089 
00090     def test_switcher_scroll_prev(self):
00091         """Test that scrolling the mouse wheel up moves to the previous icon"""
00092         self.switcher.initiate()
00093         self.addCleanup(self.switcher.terminate)
00094 
00095         start = self.switcher.selection_index
00096         self.switcher.previous_via_mouse()
00097 
00098         end = self.switcher.selection_index
00099         self.assertThat(end, Equals(start - 1))
00100 
00101         self.switcher.terminate()
00102 
00103     def test_switcher_scroll_next_ignores_fast_events(self):
00104         """Ensures that smoothing is working correctly for next icon scrolling.
00105 
00106         Only the first event in a rapid fire string of events should be acted upon.
00107         The rest ignored.
00108 
00109         """
00110         self.switcher.initiate()
00111         self.addCleanup(self.switcher.terminate)
00112 
00113         # Quickly repeated events should be ignored (except the first)
00114         start = self.switcher.selection_index
00115         self.switcher.next_via_mouse()
00116         self.switcher.next_via_mouse()
00117         self.switcher.next_via_mouse()
00118 
00119         self.assertThat(self.switcher.selection_index, Equals(start + 1))
00120 
00121     def test_switcher_scroll_prev_ignores_fast_events(self):
00122         """Ensures that smoothing is working correctly for previous icon scrolling.
00123 
00124         Only the first event in a rapid fire string of events should be acted upon.
00125         The rest ignored.
00126 
00127         """
00128         self.switcher.initiate()
00129         self.addCleanup(self.switcher.terminate)
00130 
00131         # Quickly repeatead events should be ignored (except the first)
00132         start = self.switcher.selection_index
00133         self.switcher.previous_via_mouse()
00134         self.switcher.previous_via_mouse()
00135         self.switcher.previous_via_mouse()
00136 
00137         self.assertThat(self.switcher.selection_index, Equals(start - 1))
00138 
00139     def test_switcher_arrow_key_does_not_init(self):
00140         """Ensure that Alt+Right does not initiate switcher.
00141 
00142         Regression test for LP:??????
00143 
00144         """
00145         self.keyboard.press('Alt')
00146         self.addCleanup(self.keyboard.release, 'Alt')
00147         self.keyboard.press_and_release('Right')
00148         self.assertThat(self.switcher.visible, Equals(False))
00149 
00150     def test_lazy_switcher_initiate(self):
00151         self.keybinding_hold("switcher/reveal_normal")
00152         self.addCleanup(self.keybinding_release, "switcher/reveal_normal")
00153         self.assertThat(self.switcher.visible, Eventually(Equals(False)))
00154 
00155         self.keybinding_tap("switcher/reveal_normal")
00156         self.addCleanup(self.keybinding, "switcher/cancel")
00157         self.assertThat(self.switcher.visible, Eventually(Equals(True)))
00158 
00159     def test_switcher_cancel(self):
00160         self.switcher.initiate()
00161         self.addCleanup(self.switcher.terminate)
00162 
00163         self.assertThat(self.switcher.visible, Eventually(Equals(True)))
00164         self.switcher.cancel()
00165         self.assertThat(self.switcher.visible, Eventually(Equals(False)))
00166 
00167     def test_lazy_switcher_cancel(self):
00168         self.keybinding_hold("switcher/reveal_normal")
00169         self.addCleanup(self.keybinding_release, "switcher/reveal_normal")
00170         self.assertThat(self.switcher.visible, Eventually(Equals(False)))
00171         self.keybinding_tap("switcher/reveal_normal")
00172         self.assertThat(self.switcher.visible, Eventually(Equals(True)))
00173         self.switcher.cancel()
00174         self.assertThat(self.switcher.visible, Eventually(Equals(False)))
00175 
00176     def test_switcher_appears_on_monitor_with_focused_window(self):
00177         """Tests that the switches appears on the correct monitor.
00178 
00179         This is defined as the monitor with a focused window.
00180 
00181         """
00182         num_monitors = self.screen_geo.get_num_monitors()
00183         if num_monitors == 1:
00184             self.skip("No point testing this on one monitor")
00185 
00186         [calc_win] = self.calc.get_windows()
00187         for monitor in range(num_monitors):
00188             self.screen_geo.drag_window_to_monitor(calc_win, monitor)
00189             self.switcher.initiate()
00190             self.addCleanup(self.switcher.terminate)
00191             self.assertThat(self.switcher.controller.monitor, Eventually(Equals(monitor)))
00192 
00193     def test_switcher_alt_f4_is_disabled(self):
00194         """Tests that alt+f4 does not work while switcher is active."""
00195 
00196         app = self.start_app("Text Editor")
00197         sleep(1)
00198 
00199         self.switcher.initiate(SwitcherMode.DETAIL)
00200         self.addCleanup(self.switcher.terminate)
00201 
00202         self.keyboard.press_and_release("Alt+F4")
00203         [win] = [w for w in app.get_windows()]
00204 
00205         # Need the sleep to allow the window time to close, for jenkins!
00206         sleep(10)
00207         self.assertThat(win.is_valid, Equals(True))
00208 
00209 
00210 class SwitcherWindowsManagementTests(SwitcherTestCase):
00211     """Test the switcher window management."""
00212 
00213     def test_switcher_raises_only_last_focused_window(self):
00214         """Tests that when we do an alt+tab only the previously focused window is raised.
00215 
00216         This is tests by opening 2 Calculators and a Mahjongg.
00217         Then we do a quick alt+tab twice.
00218         Then we close the currently focused window.
00219 
00220         """
00221         mah_win1 = self.start_app_window("Mahjongg")
00222         calc_win = self.start_app_window("Calculator")
00223         mah_win2 = self.start_app_window("Mahjongg")
00224 
00225         self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1])
00226 
00227         self.keybinding("switcher/reveal_normal")
00228         self.assertThat(lambda: calc_win.is_focused, Eventually(Equals(True)))
00229         self.assertVisibleWindowStack([calc_win, mah_win2, mah_win1])
00230 
00231         self.keybinding("switcher/reveal_normal")
00232         self.assertThat(lambda: mah_win2.is_focused, Eventually(Equals(True)))
00233         self.assertVisibleWindowStack([mah_win2, calc_win, mah_win1])
00234 
00235         self.keybinding("window/close")
00236         self.assertThat(lambda: calc_win.is_focused, Eventually(Equals(True)))
00237         self.assertVisibleWindowStack([calc_win, mah_win1])
00238 
00239 
00240 class SwitcherDetailsTests(SwitcherTestCase):
00241     """Test the details mode for the switcher."""
00242     def setUp(self):
00243         super(SwitcherDetailsTests, self).setUp()
00244         self.set_timeout_setting(True)
00245 
00246     def test_details_mode_on_delay(self):
00247         """Test that details mode activates on a timeout."""
00248         initial_workspace = self.workspace.current_workspace
00249         self.addCleanup(self.workspace.switch_to, initial_workspace)
00250         #FIXME: Setup
00251         self.close_all_app('Character Map')
00252         self.workspace.switch_to(1)
00253         self.start_app("Character Map")
00254         sleep(1)
00255         self.start_app("Character Map")
00256         sleep(1)
00257 
00258         # Need to start a different app, so it has focus, so alt-tab goes to
00259         # the character map.
00260         self.start_app('Mahjongg')
00261         sleep(1)
00262         # end setup
00263 
00264         self.switcher.initiate()
00265         self.addCleanup(self.switcher.terminate)
00266         # Wait longer than details mode.
00267         sleep(3)
00268         self.assertThat(self.switcher.mode, Equals(SwitcherMode.DETAIL))
00269 
00270     def test_no_details_for_apps_on_different_workspace(self):
00271         """Tests that details mode does not initiates when there are multiple windows
00272 
00273         of an application spread across different workspaces.
00274         Regression test for LP:933406.
00275 
00276         """
00277         #Fixme: setup
00278         initial_workspace = self.workspace.current_workspace
00279         self.addCleanup(self.workspace.switch_to, initial_workspace)
00280         self.close_all_app('Character Map')
00281         self.workspace.switch_to(1)
00282         self.start_app("Character Map")
00283         sleep(1)
00284         self.workspace.switch_to(2)
00285         self.start_app("Character Map")
00286         sleep(1)
00287         # Need to start a different app, so it has focus, so alt-tab goes to
00288         # the character map.
00289         self.start_app('Mahjongg')
00290         sleep(1)
00291         # end setup
00292 
00293         self.switcher.initiate()
00294         self.addCleanup(self.switcher.terminate)
00295         # Wait longer than details mode.
00296         sleep(3)
00297         self.assertThat(self.switcher.mode, Equals(SwitcherMode.NORMAL))
00298 
00299 
00300 class SwitcherDetailsModeTests(SwitcherTestCase):
00301     """Tests for the details mode of the switcher.
00302 
00303     Tests for initiation with both grave (`) and Down arrow.
00304 
00305     """
00306 
00307     scenarios = [
00308         ('initiate_with_grave', {'initiate_keycode': '`'}),
00309         ('initiate_with_down', {'initiate_keycode': 'Down'}),
00310     ]
00311 
00312     def test_can_start_details_mode(self):
00313         """Must be able to initiate details mode using selected scenario keycode.
00314 
00315         """
00316         self.start_app("Character Map")
00317         self.switcher.initiate()
00318         self.addCleanup(self.switcher.terminate)
00319         self.keyboard.press_and_release(self.initiate_keycode)
00320         self.assertThat(self.switcher.mode, Equals(SwitcherMode.DETAIL))
00321 
00322     def test_next_icon_from_last_detail_works(self):
00323         """Pressing next while showing last switcher item in details mode
00324         must select first item in the model in non-details mode.
00325 
00326         """
00327         self.start_app("Character Map")
00328         self.switcher.initiate()
00329         self.addCleanup(self.switcher.terminate)
00330         while self.switcher.selection_index < len(self.switcher.icons) - 1:
00331             self.switcher.next_icon()
00332         self.keyboard.press_and_release(self.initiate_keycode)
00333         sleep(0.5)
00334         # Make sure we're at the end of the details list for this icon
00335         possible_details = self.switcher.detail_current_count - 1
00336         while self.switcher.detail_selection_index < possible_details:
00337             self.switcher.next_detail()
00338 
00339         self.switcher.next_icon()
00340         self.assertThat(self.switcher.selection_index, Equals(0))
00341 
00342 
00343 class SwitcherWorkspaceTests(SwitcherTestCase):
00344     """Test Switcher behavior with respect to multiple workspaces."""
00345 
00346     def test_switcher_shows_current_workspace_only(self):
00347         """Switcher must show apps from the current workspace only."""
00348         initial_workspace = self.workspace.current_workspace
00349         self.addCleanup(self.workspace.switch_to, initial_workspace)
00350         #FIXME: SETUP
00351         self.close_all_app('Calculator')
00352         self.close_all_app('Character Map')
00353 
00354         self.workspace.switch_to(1)
00355         calc = self.start_app("Calculator")
00356         sleep(1)
00357         self.workspace.switch_to(2)
00358         char_map = self.start_app("Character Map")
00359         sleep(1)
00360         # END SETUP
00361 
00362         self.switcher.initiate()
00363         self.addCleanup(self.switcher.terminate)
00364 
00365         icon_names = [i.tooltip_text for i in self.switcher.icons]
00366         self.assertThat(icon_names, Contains(char_map.name))
00367         self.assertThat(icon_names, Not(Contains(calc.name)))
00368 
00369     def test_switcher_all_mode_shows_all_apps(self):
00370         """Test switcher 'show_all' mode shows apps from all workspaces."""
00371         initial_workspace = self.workspace.current_workspace
00372         self.addCleanup(self.workspace.switch_to, initial_workspace)
00373         self.close_all_app('Calculator')
00374         self.close_all_app('Character Map')
00375 
00376         #FIXME: this is setup
00377         self.workspace.switch_to(1)
00378         calc = self.start_app("Calculator")
00379         sleep(1)
00380         self.workspace.switch_to(2)
00381         char_map = self.start_app("Character Map")
00382         sleep(1)
00383         # END SETUP
00384 
00385         self.switcher.initiate(SwitcherMode.ALL)
00386         self.addCleanup(self.switcher.terminate)
00387 
00388         icon_names = [i.tooltip_text for i in self.switcher.icons]
00389         self.assertThat(icon_names, Contains(calc.name))
00390         self.assertThat(icon_names, Contains(char_map.name))
00391 
00392     def test_switcher_can_switch_to_minimised_window(self):
00393         """Switcher must be able to switch to a minimised window when there's
00394 
00395         another instance of the same application on a different workspace.
00396 
00397         """
00398         initial_workspace = self.workspace.current_workspace
00399         self.addCleanup(self.workspace.switch_to, initial_workspace)
00400         #FIXME this is setup.
00401         # disable automatic gridding of the switcher after a timeout, since it makes
00402         # it harder to write the tests.
00403         self.set_unity_option("alt_tab_timeout", False)
00404         self.close_all_app("Calculator")
00405         self.close_all_app("Mahjongg")
00406 
00407         self.workspace.switch_to(1)
00408         self.start_app("Mahjongg")
00409 
00410         self.workspace.switch_to(3)
00411         mahjongg = self.start_app("Mahjongg")
00412         sleep(1)
00413         self.keybinding("window/minimize")
00414         sleep(1)
00415 
00416         self.start_app("Calculator")
00417         sleep(1)
00418         # END SETUP
00419 
00420         self.switcher.initiate()
00421         while self.switcher.current_icon.tooltip_text != mahjongg.name:
00422             logger.debug("%s -> %s" % (self.switcher.current_icon.tooltip_text, mahjongg.name))
00423             self.switcher.next_icon()
00424             sleep(1)
00425         self.switcher.select()
00426 
00427         #get mahjongg windows - there should be two:
00428         wins = mahjongg.get_windows()
00429         self.assertThat(len(wins), Equals(2))
00430         # Ideally we should be able to find the instance that is on the
00431         # current workspace and ask that one if it is hidden.
00432         self.assertFalse(wins[0].is_hidden)
00433         self.assertFalse(wins[1].is_hidden)