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)
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
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)
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)
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)
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 )
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)
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)
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)
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)
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)
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))
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)
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)
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)
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='')
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)
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
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
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
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
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
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)
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]
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
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)
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)
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
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()
}, '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