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