test_console.py - toot - Unnamed repository; edit this file 'description' to na… | |
Log | |
Files | |
Refs | |
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', '[email protected]', '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 sto… | |
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': '[email protected]', | |
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[32… | |
182 assert "Accounts:" in out | |
183 assert "\033[32m@thequeen\033[0m Freddy Mercury" in out | |
184 assert "\033[32m@[email protected]\033[0m Mercury Freddy" in o… | |
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': '[email protected]'}, | |
193 {'id': 321, 'acct': 'blixa'}, | |
194 ]) | |
195 | |
196 req2 = Request('POST', 'https://habunek.com/api/v1/accounts/321/foll… | |
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': 'Bear… | |
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': '[email protected]'}, | |
228 {'id': 321, 'acct': 'blixa'}, | |
229 ]) | |
230 | |
231 req2 = Request('POST', 'https://habunek.com/api/v1/accounts/321/unfo… | |
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': 'Bear… | |
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_cre… | |
259 headers={'Authorization': 'Bearer xxx'}) | |
260 | |
261 res = MockResponse({ | |
262 'acct': 'ihabunek', | |
263 'avatar': 'https://files.mastodon.social/accounts/avatars/000/04… | |
264 'avatar_static': 'https://files.mastodon.social/accounts/avatars… | |
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 "[email protected]": u("[email protected]"), | |
311 "[email protected]": u("[email protected]"), | |
312 }, | |
313 "active_user": "[email protected]", | |
314 } | |
315 | |
316 def mock_save(config): | |
317 assert config["users"] == { | |
318 "[email protected]": u("[email protected]") | |
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", ["[email protected]"]) | |
326 | |
327 out, err = capsys.readouterr() | |
328 assert "✓ User [email protected] logged out" in out | |
329 | |
330 | |
331 def test_activate(monkeypatch, capsys): | |
332 def mock_load(): | |
333 return { | |
334 "users": { | |
335 "[email protected]": u("[email protected]"), | |
336 "[email protected]": u("[email protected]"), | |
337 }, | |
338 "active_user": "[email protected]", | |
339 } | |
340 | |
341 def mock_save(config): | |
342 assert config["users"] == { | |
343 "[email protected]": u("[email protected]"), | |
344 "[email protected]": u("[email protected]"), | |
345 } | |
346 assert config["active_user"] == "[email protected]" | |
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", ["[email protected]"]) | |
352 | |
353 out, err = capsys.readouterr() | |
354 assert "✓ User [email protected] active" in out |