Esempio n. 1
0
class TestHelpView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker, monkeypatch):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller,
                            'maximum_popup_dimensions',
                            return_value=(64, 64))
        mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker", return_value=[])
        self.help_view = HelpView(self.controller, 'Help Menu')

    def test_keypress_any_key(self, widget_size):
        key = "a"
        size = widget_size(self.help_view)
        self.help_view.keypress(size, key)
        assert not self.controller.exit_popup.called

    @pytest.mark.parametrize(
        'key', {*keys_for_command('GO_BACK'), *keys_for_command('HELP')})
    def test_keypress_exit_popup(self, key, widget_size):
        size = widget_size(self.help_view)
        self.help_view.keypress(size, key)
        assert self.controller.exit_popup.called

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.help_view)
        super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')
        self.help_view.keypress(size, key)
        super_keypress.assert_called_once_with(size, expected_key)
Esempio n. 2
0
    def stream_box_view(self, caption: str='', title: str='') -> None:
        self.set_editor_mode()
        self.to_write_box = None
        self.msg_write_box = ReadlineEdit(multiline=True)
        self.msg_write_box.enable_autocomplete(
            func=self.generic_autocomplete,
            key=keys_for_command('AUTOCOMPLETE').pop(),
            key_reverse=keys_for_command('AUTOCOMPLETE_REVERSE').pop()
        )
        self.stream_write_box = ReadlineEdit(
            caption=u"Stream:  ",
            edit_text=caption
        )
        self.title_write_box = ReadlineEdit(caption=u"Topic:  ",
                                            edit_text=title)

        header_write_box = urwid.Columns([
            urwid.LineBox(
                self.stream_write_box, tlcorner=u'─', tline=u'─', lline=u'',
                trcorner=u'┬', blcorner=u'─', rline=u'│',
                bline=u'─', brcorner=u'┴'
            ),
            urwid.LineBox(
                self.title_write_box, tlcorner=u'─', tline=u'─', lline=u'',
                trcorner=u'─', blcorner=u'─', rline=u'',
                bline=u'─', brcorner=u'─'
            ),
        ])
        write_box = [
            (header_write_box, self.options()),
            (self.msg_write_box, self.options()),
        ]
        self.contents = write_box
Esempio n. 3
0
class TestStreamMembersView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker, monkeypatch):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller,
                            'maximum_popup_dimensions',
                            return_value=(64, 64))
        self.controller.model.get_other_subscribers_in_stream.return_value = []
        self.controller.model.user_full_name = ''
        mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker", return_value=[])
        stream_id = 10
        self.stream_members_view = StreamMembersView(self.controller,
                                                     stream_id)

    @pytest.mark.parametrize(
        'key',
        {*keys_for_command('GO_BACK'), *keys_for_command('STREAM_MEMBERS')})
    def test_keypress_exit_popup(self, key, widget_size):
        stream_id = self.stream_members_view.stream_id
        size = widget_size(self.stream_members_view)
        self.stream_members_view.keypress(size, key)
        self.controller.show_stream_info.assert_called_once_with(
            stream_id=stream_id, )

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.stream_members_view)
        super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')
        self.stream_members_view.keypress(size, key)
        super_keypress.assert_called_once_with(size, expected_key)
Esempio n. 4
0
class TestStreamButton:
    @pytest.mark.parametrize("key", keys_for_command("TOGGLE_TOPIC"))
    def test_keypress_ENTER_TOGGLE_TOPIC(self, mocker, stream_button, key, widget_size):
        size = widget_size(stream_button)
        stream_button.view.left_panel = mocker.Mock()
        stream_button.keypress(size, key)

        stream_button.view.left_panel.show_topic_view.assert_called_once_with(
            stream_button
        )

    @pytest.mark.parametrize("key", keys_for_command("TOGGLE_MUTE_STREAM"))
    def test_keypress_TOGGLE_MUTE_STREAM(
        self,
        mocker,
        key,
        widget_size,
        stream_button,
        stream_id=205,
        stream_name="PTEST",
    ):
        size = widget_size(stream_button)
        pop_up = mocker.patch(
            "zulipterminal.core.Controller.stream_muting_confirmation_popup"
        )
        stream_button.keypress(size, key)
        pop_up.assert_called_once_with(stream_id, stream_name)
Esempio n. 5
0
class TestHelpView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker, monkeypatch):
        self.controller = mocker.Mock()
        mocker.patch.object(
            self.controller, "maximum_popup_dimensions", return_value=(64, 64)
        )
        mocker.patch(LISTWALKER, return_value=[])
        self.help_view = HelpView(self.controller, "Help Menu")

    def test_keypress_any_key(self, widget_size):
        key = "a"
        size = widget_size(self.help_view)
        self.help_view.keypress(size, key)
        assert not self.controller.exit_popup.called

    @pytest.mark.parametrize(
        "key", {*keys_for_command("GO_BACK"), *keys_for_command("HELP")}
    )
    def test_keypress_exit_popup(self, key, widget_size):
        size = widget_size(self.help_view)
        self.help_view.keypress(size, key)
        assert self.controller.exit_popup.called

    def test_keypress_navigation(
        self, mocker, widget_size, navigation_key_expected_key_pair
    ):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.help_view)
        super_keypress = mocker.patch(MODULE + ".urwid.ListBox.keypress")
        self.help_view.keypress(size, key)
        super_keypress.assert_called_once_with(size, expected_key)
Esempio n. 6
0
class TestAboutView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller, 'maximum_popup_dimensions',
                            return_value=(64, 64))
        mocker.patch(VIEWS + '.urwid.SimpleFocusListWalker', return_value=[])
        server_version, server_feature_level = MINIMUM_SUPPORTED_SERVER_VERSION

        self.about_view = AboutView(self.controller, 'About',
                                    zt_version=ZT_VERSION,
                                    server_version=server_version,
                                    server_feature_level=server_feature_level,
                                    theme_name='zt_dark',
                                    color_depth=256,
                                    autohide_enabled=False,
                                    footlink_enabled=True)

    @pytest.mark.parametrize('key', {*keys_for_command('GO_BACK'),
                                     *keys_for_command('ABOUT')})
    def test_keypress_exit_popup(self, key, widget_size):
        size = widget_size(self.about_view)
        self.about_view.keypress(size, key)
        assert self.controller.exit_popup.called

    def test_keypress_exit_popup_invalid_key(self, widget_size):
        key = 'a'
        size = widget_size(self.about_view)
        self.about_view.keypress(size, key)
        assert not self.controller.exit_popup.called

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.about_view)
        super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')
        self.about_view.keypress(size, key)
        super_keypress.assert_called_once_with(size, expected_key)

    def test_feature_level_content(self, mocker, zulip_version):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller, 'maximum_popup_dimensions',
                            return_value=(64, 64))
        mocker.patch(VIEWS + '.urwid.SimpleFocusListWalker', return_value=[])
        server_version, server_feature_level = zulip_version

        about_view = AboutView(self.controller, 'About', zt_version=ZT_VERSION,
                               server_version=server_version,
                               server_feature_level=server_feature_level,
                               theme_name='zt_dark',
                               color_depth=256,
                               autohide_enabled=False,
                               footlink_enabled=True)

        assert len(about_view.feature_level_content) == (
            1 if server_feature_level else 0
        )
Esempio n. 7
0
class TestStreamInfoView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker, monkeypatch):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller,
                            'maximum_popup_dimensions',
                            return_value=(64, 64))
        self.controller.model.is_muted_stream.return_value = False
        self.controller.model.is_pinned_stream.return_value = False
        mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker", return_value=[])
        stream_id = 10
        self.controller.model.stream_dict = {
            stream_id: {
                'name': 'books',
                'description': 'hey'
            }
        }
        self.stream_info_view = StreamInfoView(self.controller, stream_id)

    @pytest.mark.parametrize(
        'key',
        {*keys_for_command('GO_BACK'), *keys_for_command('STREAM_DESC')})
    def test_keypress_exit_popup(self, key, widget_size):
        size = widget_size(self.stream_info_view)
        self.stream_info_view.keypress(size, key)
        assert self.controller.exit_popup.called

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.stream_info_view)
        super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')
        self.stream_info_view.keypress(size, key)
        super_keypress.assert_called_once_with(size, expected_key)

    @pytest.mark.parametrize('key', (*keys_for_command('ENTER'), ' '))
    def test_checkbox_toggle_mute_stream(self, mocker, key, widget_size):
        mute_checkbox = self.stream_info_view.widgets[3]
        toggle_mute_status = self.controller.model.toggle_stream_muted_status
        stream_id = self.stream_info_view.stream_id
        size = widget_size(mute_checkbox)

        mute_checkbox.keypress(size, key)

        toggle_mute_status.assert_called_once_with(stream_id)

    @pytest.mark.parametrize('key', (*keys_for_command('ENTER'), ' '))
    def test_checkbox_toggle_pin_stream(self, mocker, key, widget_size):
        pin_checkbox = self.stream_info_view.widgets[4]
        toggle_pin_status = self.controller.model.toggle_stream_pinned_status
        stream_id = self.stream_info_view.stream_id
        size = widget_size(pin_checkbox)

        pin_checkbox.keypress(size, key)

        toggle_pin_status.assert_called_once_with(stream_id)
Esempio n. 8
0
 def __init__(self, panel_view: Any, search_command: str) -> None:
     self.panel_view = panel_view
     self.search_command = search_command
     self.search_text = ("Search [" +
                         ", ".join(keys_for_command(search_command)) +
                         "]: ")
     super(PanelSearchBox, self).__init__(edit_text=self.search_text)
Esempio n. 9
0
class TestEditModeView:
    @pytest.fixture()
    def edit_mode_view(self, mocker):
        controller = mocker.Mock()
        controller.maximum_popup_dimensions.return_value = (64, 64)
        mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker", return_value=[])
        button = mocker.Mock()
        return EditModeView(controller, button)

    @pytest.mark.parametrize(
        "index_in_widgets, mode",
        [
            (0, "change_one"),
            (1, "change_later"),
            (2, "change_all"),
        ],
    )
    @pytest.mark.parametrize("key", keys_for_command("ENTER"))
    def test_select_edit_mode(self, mocker, edit_mode_view, widget_size,
                              index_in_widgets, mode, key):
        radio_button = edit_mode_view.widgets[index_in_widgets]
        size = widget_size(radio_button)

        radio_button.keypress(size, key)

        mode_button = edit_mode_view.edit_mode_button
        mode_button.set_selected_mode.assert_called_once_with(mode)
Esempio n. 10
0
class StreamSearchBox(urwid.Edit):
    """
    Search Box to search streams in real-time.urwid
    """

    search_text = ("Search [" +
                   ", ".join(keys_for_command("SEARCH_STREAMS")) +
                   "]: ")

    def __init__(self, stream_view: Any) -> None:
        self.stream_view = stream_view
        super(StreamSearchBox, self).__init__(edit_text=self.search_text)

    def keypress(self, size: Tuple[int, int], key: str) -> str:
        if is_command_key('ENTER', key) and len(self.stream_view.log):
            self.stream_view.view.controller.editor_mode = False
            self.stream_view.set_focus("body")
            self.stream_view.body.set_focus(0)
        if is_command_key('GO_BACK', key):
            self.stream_view.view.controller.editor_mode = False
            self.set_edit_text(self.search_text)
            self.stream_view.set_focus("body")
            self.stream_view.keypress(size, 'esc')

        return super(StreamSearchBox, self).keypress(size, key)
Esempio n. 11
0
class TestUserButton:
    # FIXME Place this in a general test of a derived class?
    @pytest.mark.parametrize("enter_key", keys_for_command("ENTER"))
    def test_activate_called_once_on_keypress(
        self,
        mocker: MockerFixture,
        enter_key: str,
        widget_size: Callable[[Widget], urwid_Size],
        caption: str = "some user",
        email: str = "some_email",
        user_id: int = 5,
    ) -> None:
        user: Dict[str, Any] = {
            "email": email,
            "user_id": user_id,
            "full_name": caption,
        }
        activate = mocker.patch(MODULE + ".UserButton.activate")
        user_button = UserButton(
            user=user,
            controller=mocker.Mock(),
            view=mocker.Mock(),
            color=mocker.Mock(),
            state_marker="*",
            count=mocker.Mock(),
        )
        size = widget_size(user_button)

        user_button.keypress(size, enter_key)

        assert activate.call_count == 1

    @pytest.mark.parametrize("key", keys_for_command("USER_INFO"))
    def test_keypress_USER_INFO(
        self,
        mocker: MockerFixture,
        user_button: UserButton,
        key: str,
        widget_size: Callable[[Widget], urwid_Size],
    ) -> None:
        size = widget_size(user_button)
        pop_up = mocker.patch("zulipterminal.core.Controller.show_user_info")

        user_button.keypress(size, key)

        pop_up.assert_called_once_with(user_button.user_id)
Esempio n. 12
0
def test_keys_for_command_identity(valid_command: str) -> None:
    """
    Ensures that each call to keys_for_command returns the original keys in a
    new list which validates that the original keys don't get altered
    elsewhere unintentionally.
    """
    assert id(keys.KEY_BINDINGS[valid_command]["keys"]) != id(
        keys.keys_for_command(valid_command))
Esempio n. 13
0
 def __init__(self, controller: Any, width: int, count: int=0) -> None:
     button_text = ("Private messages [" +
                    keys_for_command("ALL_PM").pop() +
                    "]")
     super().__init__(controller, button_text,
                      controller.show_all_pm, count=count,
                      prefix_character='',
                      width=width)
Esempio n. 14
0
 def __init__(self, controller: Any, width: int, count: int=0) -> None:
     button_text = ("All messages   [" +
                    keys_for_command("GO_BACK").pop() +  # FIXME
                    "]")
     super().__init__(controller, button_text,
                      controller.show_all_messages, count=count,
                      prefix_character='',
                      width=width)
Esempio n. 15
0
class TestPopUpView:
    @pytest.fixture(autouse=True)
    def pop_up_view(self, mocker):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller,
                            'maximum_popup_dimensions',
                            return_value=(64, 64))
        self.command = 'COMMAND'
        self.title = 'Generic title'
        self.width = 16
        self.widget = mocker.Mock()
        mocker.patch.object(self.widget, 'rows', return_value=1)
        self.widgets = [
            self.widget,
        ]
        self.list_walker = mocker.patch(VIEWS + '.urwid.SimpleFocusListWalker',
                                        return_value=[])
        self.super_init = mocker.patch(VIEWS + '.urwid.ListBox.__init__')
        self.super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')
        self.pop_up_view = PopUpView(self.controller, self.widgets,
                                     self.command, self.width, self.title)

    def test_init(self):
        assert self.pop_up_view.controller == self.controller
        assert self.pop_up_view.command == self.command
        assert self.pop_up_view.title == self.title
        assert self.pop_up_view.width == self.width
        self.list_walker.assert_called_once_with(self.widgets)
        self.super_init.assert_called_once_with(self.pop_up_view.log)

    @pytest.mark.parametrize('key', keys_for_command('GO_BACK'))
    def test_keypress_GO_BACK(self, key, widget_size):
        size = widget_size(self.pop_up_view)
        self.pop_up_view.keypress(size, key)
        assert self.controller.exit_popup.called

    def test_keypress_command_key(self, mocker, widget_size):
        size = widget_size(self.pop_up_view)
        mocker.patch(
            VIEWS + '.is_command_key',
            side_effect=(lambda command, key: command == self.command))
        self.pop_up_view.keypress(size, 'cmd_key')
        assert self.controller.exit_popup.called

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.pop_up_view)
        # Patch `is_command_key` to not raise an 'Invalid Command' exception
        # when its parameters are (self.command, key) as there is no
        # self.command='COMMAND' command in keys.py.
        mocker.patch(
            VIEWS + '.is_command_key',
            side_effect=(
                lambda command, key: False
                if command == self.command else is_command_key(command, key)))
        self.pop_up_view.keypress(size, key)
        self.super_keypress.assert_called_once_with(size, expected_key)
Esempio n. 16
0
 def __init__(self, controller: Any, width: int, count: int = 0) -> None:
     button_text = ("Mentions         [" +
                    keys_for_command("ALL_MENTIONS").pop() + "]")
     super().__init__(controller,
                      button_text,
                      controller.show_all_mentions,
                      width=width,
                      count=count,
                      prefix_character='')
Esempio n. 17
0
 def __init__(self, panel_view: Any, search_command: str,
              update_function: Callable[..., None]) -> None:
     self.panel_view = panel_view
     self.search_command = search_command
     self.search_text = ("Search [" +
                         ", ".join(keys_for_command(search_command)) +
                         "]: ")
     urwid.connect_signal(self, 'change', update_function)
     super().__init__(edit_text=self.search_text)
Esempio n. 18
0
 def __init__(self, controller: Any, width: int) -> None:
     button_text = ("Starred messages [" +
                    keys_for_command("ALL_STARRED").pop() + "]")
     super().__init__(controller,
                      button_text,
                      controller.show_all_starred,
                      width=width,
                      prefix_character='',
                      count=0)  # Starred messages are already marked read
Esempio n. 19
0
def test_updated_urwid_command_map() -> None:
    urwid_to_zt_mapping = {
        v: k
        for k, v in keys.ZT_TO_URWID_CMD_MAPPING.items()
    }
    # Check if keys in command map are actually the ones in KEY_BINDINGS
    for key, urwid_cmd in keys.command_map._command.items():
        try:
            zt_cmd = urwid_to_zt_mapping[urwid_cmd]
            assert key in keys.keys_for_command(zt_cmd)
        except KeyError:
            pass
Esempio n. 20
0
    def test__stream_box_autocomplete_with_spaces(self, mocker, write_box,
                                                  text, expected_text):
        write_box.stream_box_view(1000)
        write_box.contents[0][0][0].set_edit_text(text)
        write_box.contents[0][0][0].set_edit_pos(len(text))
        write_box.focus_position = 0
        write_box.contents[0][0].focus_col = 0
        size = (20, )

        write_box.keypress(size, keys_for_command('AUTOCOMPLETE').pop())

        assert write_box.contents[0][0][0].edit_text == expected_text
Esempio n. 21
0
 def private_box_view(self, button: Any=None, email: str='') -> None:
     self.set_editor_mode()
     if email == '' and button is not None:
         email = button.email
     self.to_write_box = ReadlineEdit(u"To: ", edit_text=email)
     self.msg_write_box = ReadlineEdit(multiline=True)
     self.msg_write_box.enable_autocomplete(
         func=self.generic_autocomplete,
         key=keys_for_command('AUTOCOMPLETE').pop(),
         key_reverse=keys_for_command('AUTOCOMPLETE_REVERSE').pop()
     )
     to_write_box = urwid.LineBox(
         self.to_write_box, tlcorner=u'─', tline=u'─', lline=u'',
         trcorner=u'─', blcorner=u'─', rline=u'',
         bline=u'─', brcorner=u'─'
     )
     self.contents = [
         (to_write_box, self.options()),
         (self.msg_write_box, self.options()),
     ]
     self.focus_position = 1
Esempio n. 22
0
    def test__topic_box_autocomplete_with_spaces(self, mocker, write_box,
                                                 widget_size, text,
                                                 expected_text, topics):
        write_box.stream_box_view(1000)
        write_box.model.topics_in_stream.return_value = topics
        write_box.contents[0][0][1].set_edit_text(text)
        write_box.contents[0][0][1].set_edit_pos(len(text))
        write_box.focus_position = 0
        write_box.contents[0][0].focus_col = 1
        size = widget_size(write_box)

        write_box.keypress(size, keys_for_command('AUTOCOMPLETE').pop())

        assert write_box.contents[0][0][1].edit_text == expected_text
Esempio n. 23
0
    def mouse_event(self, size: urwid_Size, event: str, button: int, col: int,
                    row: int, focus: bool) -> bool:
        if event == 'mouse press':
            if button == 1:
                self.keypress(size, keys_for_command('ENTER').pop())
                return True
        elif event == 'mouse drag':
            selection_key = "Fn + Alt" if platform == "darwin" else "Shift"
            self.model.controller.view.set_footer_text([
                'Try pressing ', ('code', ' ' + selection_key + ' '),
                ' and dragging to select text.'
            ])
            self.displaying_selection_hint = True
        elif event == 'mouse release' and self.displaying_selection_hint:
            self.model.controller.view.set_footer_text()
            self.displaying_selection_hint = False

        return super().mouse_event(size, event, button, col, row, focus)
Esempio n. 24
0
 def main_view(self) -> Any:
     search_text = ("Search [" +
                    ", ".join(keys_for_command("SEARCH_MESSAGES")) +
                    "]: ")
     self.text_box = ReadlineEdit(search_text + " ")
     # Add some text so that when packing,
     # urwid doesn't hide the widget.
     self.conversation_focus = urwid.Text(" ")
     self.search_bar = urwid.Columns([
         ('pack', self.conversation_focus),
         ('pack', urwid.Text("  ")),
         self.text_box,
     ])
     self.msg_narrow = urwid.Text("DONT HIDE")
     self.recipient_bar = urwid.LineBox(
         self.msg_narrow, title=u"Current message recipients",
         tline=u'─', lline=u'', trcorner=u'─', tlcorner=u'─',
         blcorner=u'─', rline=u'', bline=u'─', brcorner=u'─')
     return [self.search_bar, self.recipient_bar]
Esempio n. 25
0
class TestPopUpConfirmationView:
    @pytest.fixture
    def popup_view(self, mocker, stream_button):
        self.controller = mocker.Mock()
        self.controller.view.LEFT_WIDTH = 27
        self.callback = mocker.Mock()
        self.list_walker = mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker",
                                        return_value=[])
        self.divider = mocker.patch(VIEWS + '.urwid.Divider')
        self.text = mocker.patch(VIEWS + '.urwid.Text')
        self.wrapper_w = mocker.patch(VIEWS + '.urwid.WidgetWrap')
        return PopUpConfirmationView(
            self.controller,
            self.text,
            self.callback,
        )

    def test_init(self, popup_view):
        assert popup_view.controller == self.controller
        assert popup_view.success_callback == self.callback
        self.divider.assert_called_once_with()
        self.list_walker.assert_called_once_with(
            [self.text, self.divider(),
             self.wrapper_w()])

    def test_exit_popup_yes(self, mocker, popup_view):
        popup_view.exit_popup_yes(mocker.Mock())
        self.callback.assert_called_once_with()
        assert self.controller.exit_popup.called

    def test_exit_popup_no(self, mocker, popup_view):
        popup_view.exit_popup_no(mocker.Mock())
        self.callback.assert_not_called()
        assert self.controller.exit_popup.called

    @pytest.mark.parametrize('key', keys_for_command('GO_BACK'))
    def test_exit_popup_GO_BACK(self, mocker, popup_view, key, widget_size):
        size = widget_size(popup_view)
        popup_view.keypress(size, key)
        self.callback.assert_not_called()
        assert self.controller.exit_popup.called
Esempio n. 26
0
class UserSearchBox(urwid.Edit):
    """
    Search Box to search users in real-time.
    """

    search_text = ("Search [" + ", ".join(keys_for_command("SEARCH_PEOPLE")) +
                   "]: ")

    def __init__(self, user_view: Any) -> None:
        self.user_view = user_view
        super(UserSearchBox, self).__init__(edit_text=self.search_text)

    def keypress(self, size: Tuple[int, int], key: str) -> str:
        if is_command_key('ENTER', key):
            self.user_view.view.controller.editor_mode = False
            self.user_view.set_focus("body")
        if is_command_key('GO_BACK', key):
            self.user_view.view.controller.editor_mode = False
            self.set_edit_text(self.search_text)
            self.user_view.set_focus("body")
            self.user_view.keypress(size, 'esc')

        return super(UserSearchBox, self).keypress(size, key)
Esempio n. 27
0
class TestMsgInfoView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker, monkeypatch, message_fixture):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller,
                            'maximum_popup_dimensions',
                            return_value=(64, 64))
        mocker.patch(VIEWS + ".urwid.SimpleFocusListWalker", return_value=[])
        # The subsequent patches (index and initial_data) set
        # show_edit_history_label to False for this autoused fixture.
        self.controller.model.index = {'edited_messages': set()}
        self.controller.model.initial_data = {
            'realm_allow_edit_history': False,
        }
        self.controller.model.formatted_local_time.side_effect = [
            "Tue Mar 13 10:55:22",
            "Tue Mar 13 10:55:37",
        ]
        self.msg_info_view = MsgInfoView(self.controller, message_fixture,
                                         'Message Information', OrderedDict(),
                                         list())

    def test_keypress_any_key(self, widget_size):
        key = "a"
        size = widget_size(self.msg_info_view)
        self.msg_info_view.keypress(size, key)
        assert not self.controller.exit_popup.called

    @pytest.mark.parametrize('key', keys_for_command('EDIT_HISTORY'))
    @pytest.mark.parametrize('realm_allow_edit_history', [True, False])
    @pytest.mark.parametrize('edited_message_id', [
        537286,
        537287,
        537288,
    ],
                             ids=[
                                 'stream_message_id',
                                 'pm_message_id',
                                 'group_pm_message_id',
                             ])
    def test_keypress_edit_history(self, message_fixture, key, widget_size,
                                   realm_allow_edit_history,
                                   edited_message_id):
        self.controller.model.index = {
            'edited_messages': set([edited_message_id]),
        }
        self.controller.model.initial_data = {
            'realm_allow_edit_history': realm_allow_edit_history,
        }
        msg_info_view = MsgInfoView(self.controller,
                                    message_fixture,
                                    title='Message Information',
                                    message_links=OrderedDict(),
                                    time_mentions=list())
        size = widget_size(msg_info_view)

        msg_info_view.keypress(size, key)

        if msg_info_view.show_edit_history_label:
            self.controller.show_edit_history.assert_called_once_with(
                message=message_fixture,
                message_links=OrderedDict(),
                time_mentions=list(),
            )
        else:
            self.controller.show_edit_history.assert_not_called()

    @pytest.mark.parametrize(
        'key', {*keys_for_command('GO_BACK'), *keys_for_command('MSG_INFO')})
    def test_keypress_exit_popup(self, key, widget_size):
        size = widget_size(self.msg_info_view)
        self.msg_info_view.keypress(size, key)
        assert self.controller.exit_popup.called

    def test_height_noreactions(self):
        expected_height = 3
        assert self.msg_info_view.height == expected_height

    # FIXME This is the same parametrize as MessageBox:test_reactions_view
    @pytest.mark.parametrize('to_vary_in_each_message', [{
        'reactions': [{
            'emoji_name': 'thumbs_up',
            'emoji_code': '1f44d',
            'user': {
                'email': '*****@*****.**',
                'full_name': 'Iago',
                'id': 5,
            },
            'reaction_type': 'unicode_emoji'
        }, {
            'emoji_name': 'zulip',
            'emoji_code': 'zulip',
            'user': {
                'email': '*****@*****.**',
                'full_name': 'Iago',
                'id': 5,
            },
            'reaction_type': 'zulip_extra_emoji'
        }, {
            'emoji_name': 'zulip',
            'emoji_code': 'zulip',
            'user': {
                'email': '*****@*****.**',
                'full_name': 'aaron',
                'id': 1,
            },
            'reaction_type': 'zulip_extra_emoji'
        }, {
            'emoji_name': 'heart',
            'emoji_code': '2764',
            'user': {
                'email': '*****@*****.**',
                'full_name': 'Iago',
                'id': 5,
            },
            'reaction_type': 'unicode_emoji'
        }]
    }])
    def test_height_reactions(self, message_fixture, to_vary_in_each_message):
        varied_message = dict(message_fixture, **to_vary_in_each_message)
        self.msg_info_view = MsgInfoView(self.controller, varied_message,
                                         'Message Information', OrderedDict(),
                                         list())
        # 9 = 3 labels + 1 blank line + 1 'Reactions' (category) + 4 reactions.
        expected_height = 9
        assert self.msg_info_view.height == expected_height

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        key, expected_key = navigation_key_expected_key_pair
        size = widget_size(self.msg_info_view)
        super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')
        self.msg_info_view.keypress(size, key)
        super_keypress.assert_called_once_with(size, expected_key)
Esempio n. 28
0
class TestEditHistoryView:
    @pytest.fixture(autouse=True)
    def mock_external_classes(self, mocker):
        self.controller = mocker.Mock()
        mocker.patch.object(self.controller,
                            'maximum_popup_dimensions',
                            return_value=(64, 64))
        self.controller.model.fetch_message_history = (mocker.Mock(
            return_value=[]))
        self.controller.model.formatted_local_time.return_value = (
            "Tue Mar 13 10:55:22")
        mocker.patch(VIEWS + '.urwid.SimpleFocusListWalker', return_value=[])
        # NOTE: Given that the EditHistoryView just uses the message ID from
        # the message data currently, message_fixture is not used to avoid
        # adding extra test runs unnecessarily.
        self.message = {'id': 1}
        self.edit_history_view = EditHistoryView(
            controller=self.controller,
            message=self.message,
            message_links=OrderedDict(),
            time_mentions=list(),
            title='Edit History',
        )

    def test_init(self):
        assert self.edit_history_view.controller == self.controller
        assert self.edit_history_view.message == self.message
        assert self.edit_history_view.message_links == OrderedDict()
        assert self.edit_history_view.time_mentions == list()
        self.controller.model.fetch_message_history.assert_called_once_with(
            message_id=self.message['id'], )

    @pytest.mark.parametrize('key', keys_for_command('MSG_INFO'))
    def test_keypress_exit_popup(self, key, widget_size):
        size = widget_size(self.edit_history_view)

        self.edit_history_view.keypress(size, key)

        assert self.controller.exit_popup.called

    def test_keypress_exit_popup_invalid_key(self, widget_size):
        size = widget_size(self.edit_history_view)
        key = 'a'

        self.edit_history_view.keypress(size, key)

        assert not self.controller.exit_popup.called

    @pytest.mark.parametrize(
        'key',
        {*keys_for_command('EDIT_HISTORY'), *keys_for_command('GO_BACK')})
    def test_keypress_show_msg_info(self, key, widget_size):
        size = widget_size(self.edit_history_view)

        self.edit_history_view.keypress(size, key)

        self.controller.show_msg_info.assert_called_once_with(
            msg=self.message,
            message_links=OrderedDict(),
            time_mentions=list(),
        )

    def test_keypress_navigation(self, mocker, widget_size,
                                 navigation_key_expected_key_pair):
        size = widget_size(self.edit_history_view)
        key, expected_key = navigation_key_expected_key_pair
        super_keypress = mocker.patch(VIEWS + '.urwid.ListBox.keypress')

        self.edit_history_view.keypress(size, key)

        super_keypress.assert_called_once_with(size, expected_key)

    @pytest.mark.parametrize(
        'snapshot',
        [{
            'content': 'Howdy!',
            'timestamp': 1530129134,
            'topic': 'party at my house',
            # ...
        }])
    @pytest.mark.parametrize('user_id, user_name_from_id_called', [
        (1001, True),
        (None, False),
    ],
                             ids=[
                                 'with_user_id',
                                 'without_user_id',
                             ])
    def test__make_edit_block(self,
                              mocker,
                              snapshot,
                              user_id,
                              user_name_from_id_called,
                              tag='(Current Version)'):
        self._get_author_prefix = mocker.patch(
            VIEWS + '.EditHistoryView._get_author_prefix', )
        snapshot = dict(**snapshot, user_id=user_id) if user_id else snapshot

        contents = self.edit_history_view._make_edit_block(snapshot, tag)

        assert isinstance(contents[0], Columns)  # Header.
        assert isinstance(contents[0][0], Text)  # Header: Topic.
        assert isinstance(contents[0][1], Text)  # Header: Tag.
        assert isinstance(contents[1], Columns)  # Subheader.
        assert isinstance(contents[1][0], Text)  # Subheader: Author.
        assert isinstance(contents[1][1], Text)  # Subheader: Timestamp.
        assert isinstance(contents[2], Text)  # Content.
        assert contents[0][1].text == tag
        assert (self.controller.model.user_name_from_id.called ==
                user_name_from_id_called)

    @pytest.mark.parametrize(
        'snapshot',
        [{
            'content': 'Howdy!',
            'timestamp': 1530129134,
            'topic': 'party at my house',
            # ...
        }])
    @pytest.mark.parametrize(
        ['to_vary_in_snapshot', 'tag', 'expected_author_prefix'], [
            (
                {},
                '(Original Version)',
                'Posted',
            ),
            (
                {
                    'prev_content': 'Hi!',
                    'prev_topic': 'no party at my house',
                },
                '',
                'Content & Topic edited',
            ),
            (
                {
                    'prev_content': 'Hi!',
                },
                '',
                'Content edited',
            ),
            (
                {
                    'prev_topic': 'no party at my house',
                },
                '',
                'Topic edited',
            ),
            (
                {
                    'prev_content': 'Howdy!',
                    'prev_topic': 'party at my house',
                },
                '',
                'Edited but no changes made',
            ),
            (
                {
                    'prev_content': 'Hi!',
                    'prev_topic': 'party at my house',
                },
                '',
                'Content edited',
            ),
            (
                {
                    'prev_content': 'Howdy!',
                    'prev_topic': 'no party at my house',
                },
                '',
                'Topic edited',
            ),
        ],
        ids=[
            'posted',
            'content_&_topic_edited',
            'content_edited',
            'topic_edited',
            'false_alarm_content_&_topic',
            'content_edited_with_false_alarm_topic',
            'topic_edited_with_false_alarm_content',
        ])
    def test__get_author_prefix(self, snapshot, to_vary_in_snapshot, tag,
                                expected_author_prefix):
        snapshot = dict(**snapshot, **to_vary_in_snapshot)

        return_value = EditHistoryView._get_author_prefix(snapshot, tag)

        assert return_value == expected_author_prefix
Esempio n. 29
0
    def _handle_message_event(self, event: Event) -> None:
        """
        Handle new messages (eg. add message to the end of the view)
        """
        message = event['message']
        # sometimes `flags` are missing in `event` so initialize
        # an empty list of flags in that case.
        message['flags'] = event.get('flags', [])
        # We need to update the topic order in index, unconditionally.
        if message['type'] == 'stream':
            self._update_topic_index(message['stream_id'], message['subject'])
            # If the topic view is toggled for incoming message's
            # recipient stream, then we re-arrange topic buttons
            # with most recent at the top.
            if (hasattr(self.controller, 'view')
                    and self.controller.view.left_panel.is_in_topic_view
                    and message['stream_id']
                    == self.controller.view.topic_w.stream_button.stream_id):
                self.controller.view.topic_w.update_topics_list(
                    message['stream_id'], message['subject'],
                    message['sender_id'])
                self.controller.update_screen()

        # We can notify user regardless of whether UI is rendered or not,
        # but depend upon the UI to indicate failures.
        failed_command = self.notify_user(message)
        if (failed_command and hasattr(self.controller, 'view')
                and not self._notified_user_of_notification_failure):
            notice_template = (
                "You have enabled notifications, but your notification "
                "command '{}' could not be found."
                "\n\n"
                "The application will continue attempting to run this command "
                "in this session, but will not notify you again."
                "\n\n"
                "Press '{}' to close this window.")
            notice = notice_template.format(failed_command,
                                            keys_for_command("GO_BACK").pop())
            self.controller.popup_with_message(notice, width=50)
            self.controller.update_screen()
            self._notified_user_of_notification_failure = True

        # Index messages before calling set_count.
        self.index = index_messages([message], self, self.index)
        if 'read' not in message['flags']:
            set_count([message['id']], self.controller, 1)

        if (hasattr(self.controller, 'view')
                and self._have_last_message[repr(self.narrow)]):
            if self.msg_list.log:
                last_message = self.msg_list.log[-1].original_widget.message
            else:
                last_message = None
            msg_w_list = create_msg_box_list(self, [message['id']],
                                             last_message=last_message)
            if not msg_w_list:
                return
            else:
                msg_w = msg_w_list[0]

            if not self.narrow:
                self.msg_list.log.append(msg_w)

            elif (self.narrow[0][1] == 'mentioned'
                  and 'mentioned' in message['flags']):
                self.msg_list.log.append(msg_w)

            elif (self.narrow[0][1] == message['type']
                  and len(self.narrow) == 1):
                self.msg_list.log.append(msg_w)

            elif (message['type'] == 'stream'
                  and self.narrow[0][0] == "stream"):
                recipient_stream = message['display_recipient']
                narrow_stream = self.narrow[0][1]
                append_to_stream = recipient_stream == narrow_stream

                if (append_to_stream
                        and (len(self.narrow) == 1 or
                             (len(self.narrow) == 2
                              and self.narrow[1][1] == message['subject']))):
                    self.msg_list.log.append(msg_w)

            elif (message['type'] == 'private' and len(self.narrow) == 1
                  and self.narrow[0][0] == "pm_with"):
                narrow_recipients = self.recipients
                message_recipients = frozenset(
                    [user['id'] for user in message['display_recipient']])
                if narrow_recipients == message_recipients:
                    self.msg_list.log.append(msg_w)
            self.controller.update_screen()
Esempio n. 30
0
        },
        'unread_huddles': {
            frozenset({1001, 11, 12}): 3,
            frozenset({1001, 11, 12, 13}): 2
        },
        'streams': {
            1000: 3,
            99: 1
        }
    }


# --------------- UI Fixtures -----------------------------------------


@pytest.fixture(params=[(key, expected_key) for keys, expected_key in [
    (keys_for_command('GO_UP'), 'up'),
    (keys_for_command('GO_DOWN'), 'down'),
    (keys_for_command('SCROLL_UP'), 'page up'),
    (keys_for_command('SCROLL_DOWN'), 'page down'),
    (keys_for_command('GO_TO_BOTTOM'), 'end'),
] for key in keys],
                ids=lambda param: 'key:{}-expected_key:{}'.format(*param))
def navigation_key_expected_key_pair(request):
    """
    Fixture to generate pairs of navigation keys with their respective
    expected key.
    The expected key is the one which is passed to the super `keypress` calls.
    """
    return request.param