Skip to content

Commit a6813f4

Browse files
committed
model: Fetch and store custom emojis.
* Fetch custom emojis from server which can be used be the user using typeahead. * Model tests amended. * New fixture and test added for custom emojis. Minor note: The emojis are being sorted twice here, once when unicode emojis are stored in the file using the script ( which happens occasionally when it is manually updated ) and again after custom emojis are fetched ( which happens during every load ). The first sorting seems pointless, at first glance, but it improves sorting time since sorted() uses Timsort that can perform better if subsequences of the data are already sorted.
1 parent 8cd406b commit a6813f4

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

tests/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,15 @@ def streams_fixture():
180180
return deepcopy(streams)
181181

182182

183+
@pytest.fixture
184+
def custom_emojis():
185+
return OrderedDict([
186+
('urwid', {'code': '100', 'type': 'realm_emoji'}),
187+
('dancing', {'code': '3', 'type': 'realm_emoji'}),
188+
('snape', {'code': '20', 'type': 'realm_emoji'}),
189+
])
190+
191+
183192
@pytest.fixture
184193
def unicode_emojis():
185194
return OrderedDict([

tests/model/test_model.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
from collections import OrderedDict
23
from copy import deepcopy
34
from typing import Any
45

@@ -25,7 +26,7 @@ def mock_external_classes(self, mocker: Any) -> None:
2526

2627
@pytest.fixture
2728
def model(self, mocker, initial_data, user_profile,
28-
unicode_emojis):
29+
unicode_emojis, custom_emojis):
2930
mocker.patch('zulipterminal.model.Model.get_messages',
3031
return_value='')
3132
self.client.register.return_value = initial_data
@@ -41,11 +42,13 @@ def model(self, mocker, initial_data, user_profile,
4142
self.client.get_profile.return_value = user_profile
4243
mocker.patch('zulipterminal.model.emoji_data',
4344
EMOJI_DATA=unicode_emojis)
45+
mocker.patch('zulipterminal.model.Model.fetch_custom_emojis',
46+
return_value=custom_emojis)
4447
model = Model(self.controller)
4548
return model
4649

4750
def test_init(self, model, initial_data, user_profile,
48-
unicode_emojis):
51+
unicode_emojis, custom_emojis):
4952
assert hasattr(model, 'controller')
5053
assert hasattr(model, 'client')
5154
assert model.narrow == []
@@ -75,7 +78,11 @@ def test_init(self, model, initial_data, user_profile,
7578
assert model.unpinned_streams == []
7679
self.classify_unread_counts.assert_called_once_with(model)
7780
assert model.unread_counts == []
78-
assert model.emoji_data == unicode_emojis
81+
assert unicode_emojis.items() <= model.emoji_data.items()
82+
assert custom_emojis.items() <= model.emoji_data.items()
83+
print(model.emoji_data)
84+
assert model.emoji_data == OrderedDict(sorted(
85+
model.emoji_data.items(), key=lambda e: e[0]))
7986

8087
def test_init_InvalidAPIKey_response(self, mocker, initial_data):
8188
# Both network calls indicate the same response
@@ -1597,3 +1604,47 @@ def test_is_muted_topic(self, topic, is_muted, stream_dict, model):
15971604
]
15981605
assert model.is_muted_topic(stream_id=topic[0],
15991606
topic=topic[1]) == is_muted
1607+
1608+
@pytest.mark.parametrize('response', [
1609+
{
1610+
'emoji': {
1611+
'100': {
1612+
'author_id': 5,
1613+
'deactivated': False,
1614+
'id': '100',
1615+
'name': 'urwid',
1616+
'source_url': '/user_avatars/1/emoji/images/1.png'
1617+
},
1618+
'20': {
1619+
'author_id': 10,
1620+
'deactivated': False,
1621+
'id': '20',
1622+
'name': 'snape',
1623+
'source_url': '/user_avatars/2/emoji/images/2.png'
1624+
},
1625+
'3': {
1626+
'author_id': 5,
1627+
'deactivated': False,
1628+
'id': '3',
1629+
'name': 'dancing',
1630+
'source_url': '/user_avatars/3/emoji/images/3.png'
1631+
},
1632+
'81': {
1633+
'author_id': 5,
1634+
'deactivated': True,
1635+
'id': '81',
1636+
'name': 'green_tick',
1637+
'source_url': '/user_avatars/4/emoji/images/4.png'
1638+
},
1639+
},
1640+
'msg': '',
1641+
'result': 'success'
1642+
}
1643+
])
1644+
def test_fetch_custom_emojis(self, mocker, model, custom_emojis,
1645+
response):
1646+
self.client.get_realm_emoji.return_value = response
1647+
1648+
fetched_custom_emojis = model.fetch_custom_emojis()
1649+
1650+
assert fetched_custom_emojis == custom_emojis

zulipterminal/model.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ def __init__(self, controller: Any) -> None:
126126

127127
self.unread_counts = classify_unread_counts(self)
128128

129-
self.emoji_data = emoji_data.EMOJI_DATA
129+
custom_emojis = self.fetch_custom_emojis()
130+
all_emojis = (list(emoji_data.EMOJI_DATA.items())
131+
+ list(custom_emojis.items()))
132+
self.emoji_data = OrderedDict(sorted(all_emojis, key=lambda e: e[0]))
130133

131134
self.new_user_input = True
132135
self._start_presence_updates()
@@ -344,6 +347,15 @@ def update_stream_message(self, topic: str, msg_id: int,
344347
display_error_if_present(response, self.controller)
345348
return response['result'] == 'success'
346349

350+
def fetch_custom_emojis(self) -> Dict[str, Dict[str, str]]:
351+
response = self.client.get_realm_emoji()
352+
custom_emojis = {}
353+
for emoji_code, emoji in response['emoji'].items():
354+
if not emoji['deactivated']:
355+
custom_emojis[emoji['name']] = {'code': emoji_code,
356+
'type': 'realm_emoji'}
357+
return custom_emojis
358+
347359
def get_messages(self, *,
348360
num_after: int, num_before: int,
349361
anchor: Optional[int]) -> str:

0 commit comments

Comments
 (0)