1# -*- coding: utf-8 -*-
2# Pitivi video editor
3# Copyright (c) 2016, Jakub Brindza <jakub.brindza@gmail.com>
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU Lesser General Public
7# License as published by the Free Software Foundation; either
8# version 2.1 of the License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13# Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public
16# License along with this program; if not, write to the
17# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18# Boston, MA 02110-1301, USA.
19"""Test the keyboard shortcuts."""
20import os
21import tempfile
22from unittest import mock
23
24from pitivi.shortcuts import ShortcutsManager
25from tests import common
26
27
28class TestShortcutsManager(common.TestCase):
29    """Tests for the ShortcutsManager."""
30
31    def test_groups(self):
32        """Checks the group in which the shortcut ends up."""
33        app = mock.MagicMock()
34        manager = ShortcutsManager(app)
35
36        # Test register_group method
37        manager.register_group("alpha_group", "One", position=20)
38        with self.assertRaises(AssertionError):
39            manager.register_group("alpha_group", "", position=0)
40        manager.register_group("beta_group", "Two", position=10)
41        self.assertEqual(manager.groups, ["beta_group", "alpha_group"])
42
43        # Test grouping using the stripping away group name from action name
44        manager.add("alpha_group.first", ["<Primary>A"], "First action")
45        self.assertIn(("alpha_group.first", "First action"),
46                      manager.group_actions["alpha_group"])
47        manager.add("alpha_group.second", ["<Primary>B"], "Second action")
48        self.assertIn(("alpha_group.second", "Second action"),
49                      manager.group_actions["alpha_group"])
50        manager.add("beta_group.first", ["<Primary>C"], "First beta action")
51        self.assertIn(("beta_group.first", "First beta action"),
52                      manager.group_actions["beta_group"])
53
54        # Test grouping using the group optional argument
55        # if group parameter is set, the action prefix can be anything,
56        # it should be disregarded in favour of the group value.
57        manager.add("anything.third_action", ["<Primary>D"], "Third action",
58                    group="beta_group")
59        self.assertIn(("anything.third_action", "Third action"),
60                      manager.group_actions["beta_group"])
61
62    def test_add_shortcut(self):
63        """Checks the number of calls to set_accels_for_action."""
64        app = mock.MagicMock()
65        with mock.patch("pitivi.shortcuts.xdg_config_home") as xdg_config_home,\
66                tempfile.TemporaryDirectory() as temp_dir:
67            xdg_config_home.return_value = temp_dir
68            manager = ShortcutsManager(app)
69            # Test the add is calling set_accels_for_action(),
70            # since there is no shortcuts.conf in the directory.
71            manager.register_group("general", "General group", position=0)
72            manager.add("prefix.action1", ["<Primary>P"], "Action one")
73            self.assertEqual(app.set_accels_for_action.call_count, 1)
74
75            # Create the temporary shortcuts.conf file
76            # and test that add is not calling set_accels_for_action()
77            open(os.path.sep.join([temp_dir, "shortcuts.conf"]), "w").close()
78            manager2 = ShortcutsManager(app)
79            manager2.register_group("other", "Other group", position=0)
80
81            manager2.add("prefix.action4", ["<Primary>W"],
82                         "Action addition not invoking set_accels_for_action")
83            # No. of calls to set_accels_for_action should be unchanged now
84            # because calling set_accels_for_action isn't allowed with .conf existing
85            self.assertEqual(app.set_accels_for_action.call_count, 1)
86
87    def test_load_save(self):
88        """Checks saved shortcuts are loaded by a new instance."""
89        app = mock.MagicMock()
90        with mock.patch("pitivi.shortcuts.xdg_config_home") as xdg_config_home,\
91                tempfile.TemporaryDirectory() as temp_dir:
92            xdg_config_home.return_value = temp_dir
93            manager = ShortcutsManager(app)
94            # No file exists so set_accels_for_action() is not called.
95            self.assertEqual(app.set_accels_for_action.call_count, 0)
96
97            # Set default shortcuts
98            manager.register_group("group", "Test group", position=0)
99            manager.add("group.action1", ["<Primary>i"], "Action 1")
100            manager.add("group.action2", ["<Shift>p", "<Primary>m"], "Action 2")
101            manager.add("group.action3", ["<Primary><Shift>a", "a"], "Action 3")
102
103            # After saving the shortcuts, the accels should be set when
104            # initializing a ShortcutsManger.
105            app.get_accels_for_action.side_effect = [(["<Primary>i"]),
106                                                     (["<Shift>p", "<Primary>m"]),
107                                                     (["<Primary><Shift>a", "a"])]
108            manager.save()
109            app.reset_mock()
110            unused_manager2 = ShortcutsManager(app)
111            self.assertEqual(app.set_accels_for_action.call_count, 3)
112            calls = [mock.call("group.action1", ["<Primary>i"]),
113                     mock.call("group.action2", ["<Shift>p", "<Primary>m"]),
114                     mock.call("group.action3", ["<Primary><Shift>a", "a"])]
115            app.set_accels_for_action.assert_has_calls(calls, any_order=True)
116
117    def test_reset_accels(self):
118        """Checks if accelerators have been reset to the default settings."""
119        app = mock.MagicMock()
120        with mock.patch("pitivi.shortcuts.xdg_config_home") as xdg_config_home,\
121                tempfile.TemporaryDirectory() as temp_dir,\
122                mock.patch("os.remove") as os_remove_mock:
123            xdg_config_home.return_value = temp_dir
124            manager = ShortcutsManager(app)
125
126            # Set default shortcuts - they will be stored in self.defaults_accelerators.
127            manager.register_group("group", "Test group", position=0)
128            manager.add("group.action1", ["<Primary>i"], "Action 1")
129            manager.add("group.action2", ["<Shift>p"], "Action 2")
130
131            # Test reset of a single action. The shortcuts are saved and no file removed.
132            # Only one call to set_accels_for_action() should be made.
133            app.reset_mock()
134            manager.save = mock.MagicMock()
135            manager.reset_accels(action="group.action1")
136            self.assertEqual(manager.save.call_count, 1)
137            self.assertEqual(os_remove_mock.call_count, 0)
138            self.assertEqual(app.set_accels_for_action.call_count, 1)
139
140            # Test reset of all actions. Nothing is saved and the file is removed.
141            # Both actions should have accelerators set.
142            app.reset_mock()
143            os_remove_mock.reset_mock()
144            manager.save.reset_mock()
145            manager.reset_accels()
146            self.assertEqual(manager.save.call_count, 0)
147            self.assertEqual(os_remove_mock.call_count, 1)
148            self.assertEqual(app.set_accels_for_action.call_count, 2)
149