test_console.py - toot - Unnamed repository; edit this file 'description' to name the repository.
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
test_console.py (11588B)
---
1 # -*- coding: utf-8 -*-
2 import pytest
3 import requests
4 import re
5
6 from requests import Request
7
8 from toot import config, console, User, App
9 from toot.exceptions import ConsoleError
10
11 from tests.utils import MockResponse, Expectations
12
13 app = App('habunek.com', 'https://habunek.com', 'foo', 'bar')
14 user = User('habunek.com', 'ivan@habunek.com', 'xxx')
15
16
17 def uncolorize(text):
18 """Remove ANSI color sequences from a string"""
19 return re.sub(r'\x1b[^m]*m', '', text)
20
21
22 def test_print_usage(capsys):
23 console.print_usage()
24 out, err = capsys.readouterr()
25 assert "toot - a Mastodon CLI client" in out
26
27
28 def test_post_defaults(monkeypatch, capsys):
29 def mock_prepare(request):
30 assert request.method == 'POST'
31 assert request.url == 'https://habunek.com/api/v1/statuses'
32 assert request.headers == {'Authorization': 'Bearer xxx'}
33 assert request.data == {
34 'status': 'Hello world',
35 'visibility': 'public',
36 'media_ids[]': None,
37 }
38
39 def mock_send(*args, **kwargs):
40 return MockResponse({
41 'url': 'http://ivan.habunek.com/'
42 })
43
44 monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
45 monkeypatch.setattr(requests.Session, 'send', mock_send)
46
47 console.run_command(app, user, 'post', ['Hello world'])
48
49 out, err = capsys.readouterr()
50 assert "Toot posted" in out
51
52
53 def test_post_with_options(monkeypatch, capsys):
54 def mock_prepare(request):
55 assert request.method == 'POST'
56 assert request.url == 'https://habunek.com/api/v1/statuses'
57 assert request.headers == {'Authorization': 'Bearer xxx'}
58 assert request.data == {
59 'status': '"Hello world"',
60 'visibility': 'unlisted',
61 'media_ids[]': None,
62 }
63
64 def mock_send(*args, **kwargs):
65 return MockResponse({
66 'url': 'http://ivan.habunek.com/'
67 })
68
69 monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
70 monkeypatch.setattr(requests.Session, 'send', mock_send)
71
72 args = ['"Hello world"', '--visibility', 'unlisted']
73
74 console.run_command(app, user, 'post', args)
75
76 out, err = capsys.readouterr()
77 assert "Toot posted" in out
78
79
80 def test_post_invalid_visibility(monkeypatch, capsys):
81 args = ['Hello world', '--visibility', 'foo']
82
83 with pytest.raises(SystemExit):
84 console.run_command(app, user, 'post', args)
85
86 out, err = capsys.readouterr()
87 assert "invalid visibility value: 'foo'" in err
88
89
90 def test_post_invalid_media(monkeypatch, capsys):
91 args = ['Hello world', '--media', 'does_not_exist.jpg']
92
93 with pytest.raises(SystemExit):
94 console.run_command(app, user, 'post', args)
95
96 out, err = capsys.readouterr()
97 assert "can't open 'does_not_exist.jpg'" in err
98
99
100 def test_timeline(monkeypatch, capsys):
101 def mock_prepare(request):
102 assert request.url == 'https://habunek.com/api/v1/timelines/home'
103 assert request.headers == {'Authorization': 'Bearer xxx'}
104 assert request.params == {}
105
106 def mock_send(*args, **kwargs):
107 return MockResponse([{
108 'account': {
109 'display_name': 'Frank Zappa',
110 'username': 'fz'
111 },
112 'created_at': '2017-04-12T15:53:18.174Z',
113 'content': "<p>The computer can't tell you the emotional story. It can give you the exact mathematical design, but what's missing is the eyebrows.</p>",
114 'reblog': None,
115 }])
116
117 monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
118 monkeypatch.setattr(requests.Session, 'send', mock_send)
119
120 console.run_command(app, user, 'timeline', [])
121
122 out, err = capsys.readouterr()
123 assert "The computer can't tell you the emotional story." in out
124 assert "Frank Zappa @fz" in out
125
126
127 def test_upload(monkeypatch, capsys):
128 def mock_prepare(request):
129 assert request.method == 'POST'
130 assert request.url == 'https://habunek.com/api/v1/media'
131 assert request.headers == {'Authorization': 'Bearer xxx'}
132 assert request.files.get('file') is not None
133
134 def mock_send(*args, **kwargs):
135 return MockResponse({
136 'id': 123,
137 'url': 'https://bigfish.software/123/456',
138 'preview_url': 'https://bigfish.software/789/012',
139 'text_url': 'https://bigfish.software/345/678',
140 'type': 'image',
141 })
142
143 monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
144 monkeypatch.setattr(requests.Session, 'send', mock_send)
145
146 console.run_command(app, user, 'upload', [__file__])
147
148 out, err = capsys.readouterr()
149 assert "Uploading media" in out
150 assert __file__ in out
151
152
153 def test_search(monkeypatch, capsys):
154 def mock_prepare(request):
155 assert request.url == 'https://habunek.com/api/v1/search'
156 assert request.headers == {'Authorization': 'Bearer xxx'}
157 assert request.params == {
158 'q': 'freddy',
159 'resolve': False,
160 }
161
162 def mock_send(*args, **kwargs):
163 return MockResponse({
164 'hashtags': ['foo', 'bar', 'baz'],
165 'accounts': [{
166 'acct': 'thequeen',
167 'display_name': 'Freddy Mercury'
168 }, {
169 'acct': 'thequeen@other.instance',
170 'display_name': 'Mercury Freddy'
171 }],
172 'statuses': [],
173 })
174
175 monkeypatch.setattr(requests.Request, 'prepare', mock_prepare)
176 monkeypatch.setattr(requests.Session, 'send', mock_send)
177
178 console.run_command(app, user, 'search', ['freddy'])
179
180 out, err = capsys.readouterr()
181 assert "Hashtags:\n\033[32m#foo\033[0m, \033[32m#bar\033[0m, \033[32m#baz\033[0m" in out
182 assert "Accounts:" in out
183 assert "\033[32m@thequeen\033[0m Freddy Mercury" in out
184 assert "\033[32m@thequeen@other.instance\033[0m Mercury Freddy" in out
185
186
187 def test_follow(monkeypatch, capsys):
188 req1 = Request('GET', 'https://habunek.com/api/v1/accounts/search',
189 params={'q': 'blixa'},
190 headers={'Authorization': 'Bearer xxx'})
191 res1 = MockResponse([
192 {'id': 123, 'acct': 'blixa@other.acc'},
193 {'id': 321, 'acct': 'blixa'},
194 ])
195
196 req2 = Request('POST', 'https://habunek.com/api/v1/accounts/321/follow',
197 headers={'Authorization': 'Bearer xxx'})
198 res2 = MockResponse()
199
200 expectations = Expectations([req1, req2], [res1, res2])
201 expectations.patch(monkeypatch)
202
203 console.run_command(app, user, 'follow', ['blixa'])
204
205 out, err = capsys.readouterr()
206 assert "You are now following blixa" in out
207
208
209 def test_follow_not_found(monkeypatch, capsys):
210 req = Request('GET', 'https://habunek.com/api/v1/accounts/search',
211 params={'q': 'blixa'}, headers={'Authorization': 'Bearer xxx'})
212 res = MockResponse()
213
214 expectations = Expectations([req], [res])
215 expectations.patch(monkeypatch)
216
217 with pytest.raises(ConsoleError) as ex:
218 console.run_command(app, user, 'follow', ['blixa'])
219 assert "Account not found" == str(ex.value)
220
221
222 def test_unfollow(monkeypatch, capsys):
223 req1 = Request('GET', 'https://habunek.com/api/v1/accounts/search',
224 params={'q': 'blixa'},
225 headers={'Authorization': 'Bearer xxx'})
226 res1 = MockResponse([
227 {'id': 123, 'acct': 'blixa@other.acc'},
228 {'id': 321, 'acct': 'blixa'},
229 ])
230
231 req2 = Request('POST', 'https://habunek.com/api/v1/accounts/321/unfollow',
232 headers={'Authorization': 'Bearer xxx'})
233 res2 = MockResponse()
234
235 expectations = Expectations([req1, req2], [res1, res2])
236 expectations.patch(monkeypatch)
237
238 console.run_command(app, user, 'unfollow', ['blixa'])
239
240 out, err = capsys.readouterr()
241 assert "You are no longer following blixa" in out
242
243
244 def test_unfollow_not_found(monkeypatch, capsys):
245 req = Request('GET', 'https://habunek.com/api/v1/accounts/search',
246 params={'q': 'blixa'}, headers={'Authorization': 'Bearer xxx'})
247 res = MockResponse([])
248
249 expectations = Expectations([req], [res])
250 expectations.patch(monkeypatch)
251
252 with pytest.raises(ConsoleError) as ex:
253 console.run_command(app, user, 'unfollow', ['blixa'])
254 assert "Account not found" == str(ex.value)
255
256
257 def test_whoami(monkeypatch, capsys):
258 req = Request('GET', 'https://habunek.com/api/v1/accounts/verify_credentials',
259 headers={'Authorization': 'Bearer xxx'})
260
261 res = MockResponse({
262 'acct': 'ihabunek',
263 'avatar': 'https://files.mastodon.social/accounts/avatars/000/046/103/original/6a1304e135cac514.jpg?1491312434',
264 'avatar_static': 'https://files.mastodon.social/accounts/avatars/000/046/103/original/6a1304e135cac514.jpg?1491312434',
265 'created_at': '2017-04-04T13:23:09.777Z',
266 'display_name': 'Ivan Habunek',
267 'followers_count': 5,
268 'following_count': 9,
269 'header': '/headers/original/missing.png',
270 'header_static': '/headers/original/missing.png',
271 'id': 46103,
272 'locked': False,
273 'note': 'A developer.',
274 'statuses_count': 19,
275 'url': 'https://mastodon.social/@ihabunek',
276 'username': 'ihabunek'
277 })
278
279 expectations = Expectations([req], [res])
280 expectations.patch(monkeypatch)
281
282 console.run_command(app, user, 'whoami', [])
283
284 out, err = capsys.readouterr()
285 out = uncolorize(out)
286
287 assert "@ihabunek Ivan Habunek" in out
288 assert "A developer." in out
289 assert "https://mastodon.social/@ihabunek" in out
290 assert "ID: 46103" in out
291 assert "Since: 2017-04-04 @ 13:23:09" in out
292 assert "Followers: 5" in out
293 assert "Following: 9" in out
294 assert "Statuses: 19" in out
295
296
297 def u(user_id, access_token="abc"):
298 username, instance = user_id.split("@")
299 return {
300 "instance": instance,
301 "username": username,
302 "access_token": access_token,
303 }
304
305
306 def test_logout(monkeypatch, capsys):
307 def mock_load():
308 return {
309 "users": {
310 "king@gizzard.social": u("king@gizzard.social"),
311 "lizard@wizard.social": u("lizard@wizard.social"),
312 },
313 "active_user": "king@gizzard.social",
314 }
315
316 def mock_save(config):
317 assert config["users"] == {
318 "lizard@wizard.social": u("lizard@wizard.social")
319 }
320 assert config["active_user"] is None
321
322 monkeypatch.setattr(config, "load_config", mock_load)
323 monkeypatch.setattr(config, "save_config", mock_save)
324
325 console.run_command(None, None, "logout", ["king@gizzard.social"])
326
327 out, err = capsys.readouterr()
328 assert "✓ User king@gizzard.social logged out" in out
329
330
331 def test_activate(monkeypatch, capsys):
332 def mock_load():
333 return {
334 "users": {
335 "king@gizzard.social": u("king@gizzard.social"),
336 "lizard@wizard.social": u("lizard@wizard.social"),
337 },
338 "active_user": "king@gizzard.social",
339 }
340
341 def mock_save(config):
342 assert config["users"] == {
343 "king@gizzard.social": u("king@gizzard.social"),
344 "lizard@wizard.social": u("lizard@wizard.social"),
345 }
346 assert config["active_user"] == "lizard@wizard.social"
347
348 monkeypatch.setattr(config, "load_config", mock_load)
349 monkeypatch.setattr(config, "save_config", mock_save)
350
351 console.run_command(None, None, "activate", ["lizard@wizard.social"])
352
353 out, err = capsys.readouterr()
354 assert "✓ User lizard@wizard.social active" in out