From 29584acd3a6b725a4d06cd4a44314962b357fc80 Mon Sep 17 00:00:00 2001 From: Michael Lazar Date: Tue, 9 May 2017 18:20:52 -0400 Subject: [PATCH] Code review refactoring --- CONTROLS.rst | 4 +- rtv/clipboard.py | 32 +- rtv/page.py | 55 ++-- rtv/templates/rtv.cfg | 4 +- .../cassettes/test_copy_to_clipboard_linux.py | 293 ++++++++++++++++++ .../cassettes/test_copy_to_clipboard_osx.yaml | 293 ++++++++++++++++++ tests/test_clipboard.py | 39 +++ tests/test_submission.py | 97 ++++-- 8 files changed, 745 insertions(+), 72 deletions(-) create mode 100644 tests/cassettes/test_copy_to_clipboard_linux.py create mode 100644 tests/cassettes/test_copy_to_clipboard_osx.yaml create mode 100644 tests/test_clipboard.py diff --git a/CONTROLS.rst b/CONTROLS.rst index fd1e8b2..e8ad399 100644 --- a/CONTROLS.rst +++ b/CONTROLS.rst @@ -17,6 +17,8 @@ Basic Commands :``/``: Open a prompt to switch subreddits :``?``: Show the help screen :``q``/``Q``: Quit/Force quit +:``y``: Copy submission permalink to clipboard +:``Y``: Copy submission link to clipboard ---------------------- Authenticated Commands @@ -71,5 +73,3 @@ In submission mode you can view the self text for a submission and browse commen :``o`` or ``ENTER``: Open the comment permalink with your web browser :``SPACE``: Fold the selected comment, or load additional comments :``b``: Display URLs with urlview -:``y``: Copy submission permalink to clipboard -:``Y``: Copy submission link to clipboard diff --git a/rtv/clipboard.py b/rtv/clipboard.py index 612ec0c..0a730e5 100644 --- a/rtv/clipboard.py +++ b/rtv/clipboard.py @@ -1,42 +1,52 @@ # -*- coding: utf-8 -*- -import os -import platform +from __future__ import unicode_literals + +import sys import subprocess from .exceptions import ProgramError + def _subprocess_copy(text, args_list): p = subprocess.Popen(args_list, stdin=subprocess.PIPE, close_fds=True) p.communicate(input=text.encode('utf-8')) + def copy(text): """ Copy text to OS clipboard. """ - if os.name == 'mac' or platform.system() == 'Darwin': - return copy_osx(text) - elif os.name == 'posix' or platform.system() == 'Linux': - return copy_linux(text) + if sys.platform == 'darwin': + copy_osx(text) else: - raise NotImplementedError + # For Linux, BSD, cygwin, etc. + copy_linux(text) + def copy_osx(text): _subprocess_copy(text, ['pbcopy', 'w']) + def copy_linux(text): + def get_command_name(): # Checks for the installation of xsel or xclip for cmd in ['xsel', 'xclip']: cmd_exists = subprocess.call( ['which', cmd], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) is 0 + stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 if cmd_exists: return cmd return None - cmd_args = {'xsel' : ['xsel', '-b', '-i'], - 'xclip' : ['xclip', '-selection', 'c']} + + cmd_args = { + 'xsel': ['xsel', '-b', '-i'], + 'xclip': ['xclip', '-selection', 'c']} cmd_name = get_command_name() + if cmd_name is None: - raise ProgramError("External copy application not installed") + raise ProgramError("External copy application not found,\n" + "try installing either `xsel` or `xclip`") + _subprocess_copy(text, cmd_args.get(cmd_name)) diff --git a/rtv/page.py b/rtv/page.py index 83ed6da..0fb9340 100644 --- a/rtv/page.py +++ b/rtv/page.py @@ -19,6 +19,7 @@ from .__version__ import __version__ _logger = logging.getLogger(__name__) + def logged_in(f): """ Decorator for Page methods that require the user to be authenticated. @@ -49,11 +50,11 @@ class Page(object): self.content = None self.nav = None self.controller = None + self.copy_to_clipboard = copy self.active = True self._row = 0 self._subwindows = None - self.copy_to_clipboard = copy def refresh_content(self, order=None, name=None): raise NotImplementedError @@ -322,41 +323,49 @@ class Page(object): message = 'New Messages' if inbox > 0 else 'No New Messages' self.term.show_notification(message) - @PageController.register(Command('COPY_SUBMISSION_PERMALINK')) - def copy_submission_permalink(self): + @PageController.register(Command('COPY_PERMALINK')) + def copy_permalink(self): """ Copies submission permalink to OS clipboard """ data = self.get_selected_item() url = data.get('permalink') - if url is not None: - try: - self.copy_to_clipboard(url) - self.term.show_notification( - 'Copied {} to clipboard'.format(url), timeout=1) - except ProgramError as e: - _logger.exception(e) - self.term.show_notification( - 'Failed to copy {} to clipboard, {}'.format(url, e)) + if url is None: + self.term.flash() + return - @PageController.register(Command('COPY_SUBMISSION_URL')) - def copy_post_permalink(self): + try: + self.copy_to_clipboard(url) + except (ProgramError, OSError) as e: + _logger.exception(e) + self.term.show_notification( + 'Failed to copy permalink to clipboard\n{0}'.format(e)) + else: + self.term.show_notification( + 'Copied permalink to clipboard', timeout=1) + + @PageController.register(Command('COPY_URL')) + def copy_url(self): """ Copies submission url to OS clipboard """ data = self.get_selected_item() url = data.get('url_full') - if url is not None: - try: - self.copy_to_clipboard(url) - self.term.show_notification( - 'Copied {} to clipboard'.format(url), timeout=1) - except ProgramError as e: - _logger.exception(e) - self.term.show_notification( - 'Failed to copy {} to clipboard, {}'.format(url, e)) + if url is None: + self.term.flash() + return + + try: + self.copy_to_clipboard(url) + except (ProgramError, OSError) as e: + _logger.exception(e) + self.term.show_notification( + 'Failed to copy url to clipboard\n{0}'.format(e)) + else: + self.term.show_notification( + 'Copied url to clipboard', timeout=1) def clear_input_queue(self): """ diff --git a/rtv/templates/rtv.cfg b/rtv/templates/rtv.cfg index 3de6cbc..36fcc7e 100644 --- a/rtv/templates/rtv.cfg +++ b/rtv/templates/rtv.cfg @@ -118,8 +118,8 @@ INBOX = i REFRESH = r, PROMPT = / SAVE = w -COPY_SUBMISSION_PERMALINK = y -COPY_SUBMISSION_URL = Y +COPY_PERMALINK = y +COPY_URL = Y ; Submission page SUBMISSION_TOGGLE_COMMENT = 0x20 diff --git a/tests/cassettes/test_copy_to_clipboard_linux.py b/tests/cassettes/test_copy_to_clipboard_linux.py new file mode 100644 index 0000000..5189008 --- /dev/null +++ b/tests/cassettes/test_copy_to_clipboard_linux.py @@ -0,0 +1,293 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit'] + method: GET + uri: https://www.reddit.com/r/Python/comments/2xmo63.json + response: + body: + string: !!binary | + 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 + dr+5+4GK/qDXGep2xxDi2y2G3/8H261n2bzmAAA= + headers: + Accept-Ranges: [bytes] + Connection: [keep-alive] + Content-Encoding: [gzip] + Content-Length: ['7952'] + Content-Type: [application/json; charset=UTF-8] + Date: ['Tue, 09 May 2017 22:00:58 GMT'] + Server: [snooserv] + Set-Cookie: ['loid=000000000000q8ytgj.2.1494367258728.Z0FBQUFBQlpFandhVzkyMGZRdjNZZlBrN3I0MjdJekZYckhTM3lXNElIOVFNaXdKNW5FY0g5ZlJZVGZVYzMwbkZsWTVYOHpBSkJfekdISmV0eEdObEZwNXB6NzNvLUhwRG4zT3FGQi1iZi1ZWk01dlFQOFdpbTRXbUJqb3RQVHdWM3V2bVV6TGJpdEg; + Domain=reddit.com; Max-Age=63071999; Path=/; expires=Thu, 09-May-2019 22:00:58 + GMT; secure', 'session_tracker=yBtXUs42t54aZ2QFbA.0.1494367258722.Z0FBQUFBQlpFandhT2FRVDJLdm5rSjVfVFNzWEs5TGRXX1FfMkNsYWxabnV4Um9TeHBfd0NiU1dZdTBWMXpxck5jX1ppN3lpa1VPMWNva0dhV2xPb2ZmUmZZQWpOOWZtRk5JNmU2LWstNnU2NlhuTF82bHhxTXkxNEFmZURtd3lBVzRDQUhveUQ1d2U; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:00:58 + GMT; secure', edgebucket=zn5FMmjkuvOO5cnf9e; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload] + Vary: [accept-encoding] + Via: [1.1 varnish] + X-Cache: [MISS] + X-Cache-Hits: ['0'] + X-Moose: [majestic] + X-Served-By: [cache-atl6242-ATL] + X-Timer: ['S1494367259.696060,VS0,VE238'] + access-control-allow-origin: ['*'] + access-control-expose-headers: ['X-Reddit-Tracking, X-Moose'] + cache-control: ['max-age=0, must-revalidate'] + set-cookie: ['loid=000000000000q8ytgj.2.1494367258728.Z0FBQUFBQlpFandhVzkyMGZRdjNZZlBrN3I0MjdJekZYckhTM3lXNElIOVFNaXdKNW5FY0g5ZlJZVGZVYzMwbkZsWTVYOHpBSkJfekdISmV0eEdObEZwNXB6NzNvLUhwRG4zT3FGQi1iZi1ZWk01dlFQOFdpbTRXbUJqb3RQVHdWM3V2bVV6TGJpdEg; + Domain=reddit.com; Max-Age=63071999; Path=/; expires=Thu, 09-May-2019 22:00:58 + GMT; secure', 'session_tracker=yBtXUs42t54aZ2QFbA.0.1494367258722.Z0FBQUFBQlpFandhT2FRVDJLdm5rSjVfVFNzWEs5TGRXX1FfMkNsYWxabnV4Um9TeHBfd0NiU1dZdTBWMXpxck5jX1ppN3lpa1VPMWNva0dhV2xPb2ZmUmZZQWpOOWZtRk5JNmU2LWstNnU2NlhuTF82bHhxTXkxNEFmZURtd3lBVzRDQUhveUQ1d2U; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:00:58 + GMT; secure', edgebucket=zn5FMmjkuvOO5cnf9e; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + x-content-type-options: [nosniff] + x-frame-options: [SAMEORIGIN] + x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=YSHfVCx9q9fs%2FeX7JlLo4oAhbBoilNFYME2ft4wFesBJiQGKwCZ6ufRk3MIReVLMmFb5sCMnF0M%3D'] + x-ua-compatible: [IE=edge] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +- request: + body: grant_type=refresh_token&redirect_uri=http%3A%2F%2F127.0.0.1%3A65000%2F&refresh_token=********** + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Authorization: ['**********'] + Connection: [keep-alive] + Content-Length: ['122'] + Content-Type: [application/x-www-form-urlencoded] + Cookie: [edgebucket=zn5FMmjkuvOO5cnf9e; loid=000000000000q8ytgj.2.1494367258728.Z0FBQUFBQlpFandhVzkyMGZRdjNZZlBrN3I0MjdJekZYckhTM3lXNElIOVFNaXdKNW5FY0g5ZlJZVGZVYzMwbkZsWTVYOHpBSkJfekdISmV0eEdObEZwNXB6NzNvLUhwRG4zT3FGQi1iZi1ZWk01dlFQOFdpbTRXbUJqb3RQVHdWM3V2bVV6TGJpdEg; + session_tracker=yBtXUs42t54aZ2QFbA.0.1494367258722.Z0FBQUFBQlpFandhT2FRVDJLdm5rSjVfVFNzWEs5TGRXX1FfMkNsYWxabnV4Um9TeHBfd0NiU1dZdTBWMXpxck5jX1ppN3lpa1VPMWNva0dhV2xPb2ZmUmZZQWpOOWZtRk5JNmU2LWstNnU2NlhuTF82bHhxTXkxNEFmZURtd3lBVzRDQUhveUQ1d2U] + User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit'] + method: POST + uri: https://api.reddit.com/api/v1/access_token/ + response: + body: {string: '{"access_token": "F9zbMvdk6SvduZkyrcSe7Tp526s", "token_type": + "bearer", "device_id": "None", "expires_in": 3600, "scope": "edit history + identity mysubreddits privatemessages read report save submit subscribe vote"}'} + headers: + Accept-Ranges: [bytes] + Connection: [keep-alive] + Content-Length: ['214'] + Content-Type: [application/json; charset=UTF-8] + Date: ['Tue, 09 May 2017 22:01:00 GMT'] + Server: [snooserv] + Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload] + Via: [1.1 varnish] + X-Cache: [MISS] + X-Cache-Hits: ['0'] + X-Moose: [majestic] + X-Served-By: [cache-atl6239-ATL] + X-Timer: ['S1494367260.216158,VS0,VE60'] + cache-control: ['max-age=0, must-revalidate'] + set-cookie: ['session_tracker=yBtXUs42t54aZ2QFbA.0.1494367260258.Z0FBQUFBQlpFandjRW1pOS1SLTFJU0FSLTlqUjdyQ180WGJNanBWU3lNTWhzVHk5TWZ6eDNUSWllcG14VjJTVGZaM0J6N0pvY0o3MlRtaXJ5ckpGbmFLbFc1clFXamVCTHNhZkh6TVFPa2RIeGJ2Xy1lZ3RtMlc3Rmh2T0JYMGk3UEY0OHE4UUxWMUY; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:01:00 + GMT; secure'] + x-content-type-options: [nosniff] + x-frame-options: [SAMEORIGIN] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Authorization: ['**********'] + Connection: [keep-alive] + User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit'] + method: GET + uri: https://oauth.reddit.com/api/v1/me.json + response: + body: + string: !!binary | + H4sIAB48ElkC/5VUTY/cNgz9KwufF8XOZNsscush1wLpHyBkmbYFS6IqyTM7G+S/l5TtsZwMCvRm + 80Mk33vk98YkQBcs3RCbL0+9sgmfn5oeVZ4jJjZ9bzoCTxlyVHpiQ46zhFhzQRhVCOiNHzjiuvtU + lzBeMELEQDGzv8rDQekbJFRRjxAi9vWbSYJBso1GiMqFOex+R62xCFdsIas44PHlDns12wwpJhjJ + djTn0j9dPUb+aiJavCivseHoi4pGeYloNPkcycJJ7PgeMBqHPoPp2Hv6fPpRRvrAOMFjLHheUHMm + wPeMXrJWx3U0GWUq7CA4gXN18Jx6uoEmJ5UqxxyGqDpkD02mEFDVELQqU2tJTzAzWtDeVqwfNMVJ + c90UReUHjCh+YV8ZWz3K8yvPY+Ll2BjOa08QyBp9q1rObhsErPFTldRTZBrHnENlXFn0KouEWuUX + elZvoAkd+YFAaMHCUMWhHiWeG34+UJjmlgfqTH5E4evnhUHBQ2dDfq+2JM28AOLmPxNRVyCyhlpi + 9EDzzFOh/aA5j1ewNAyc6EErPf4Kj/EtvUOY07jbCiIPyjmR9nuI5AgMTx9ZJ9koexcKGKqQDIrJ + B+68MkViATnH4OqjZygLm/gNDjhQm0a6cjNLjY6lKiz+n6ZYMJEK1NuLOiL6i2F0ftaRILZIFTp+ + hCowHal1tQ4Y37mFONt6JVYhJcxyCA67Upb1fn3gXPlYAReT5QItR+YaeUd/AqPsVIqsUVe5yvCY + 8qPjE4jt6Fo8okDW/oKA6pbFzfzUf/QVUW1viXz5UKc5hUJQs1/qXfhfnvxsLZsGvn18iYKJahX7 + 6igMNfYfr0jWZHkucUgVDXPWewbfcNObQ0Hhz1EnV4PT+LTJZGs4yc0/vVWIsdi4myqdLZxdGUa+ + QVuZ5Rjt6eLjaFitWwrxWRtlI+8b3nw909f897e+6//s//om042Gr2jPooVILZUut3yRN0wqOsXG + 8/lN2ipLqnnVBciXZ1kk7CFTWALhjnM1bmnv2NoqmEYzl9Z8LJCGUX0gfJKueC9ULnieXs+/nz+d + /nh9+U3KFdL0XkJsa/BKSUl4Ob+tCXxvWswywVZ7u8HbZG8SJj1y7yxFs2vzx7/41ILz+AcAAA== + headers: + Accept-Ranges: [bytes] + Connection: [keep-alive] + Content-Encoding: [gzip] + Content-Length: ['853'] + Content-Type: [application/json; charset=UTF-8] + Date: ['Tue, 09 May 2017 22:01:02 GMT'] + Server: [snooserv] + Set-Cookie: ['session_tracker=0xv7VBQrkOXYPJF7lS.0.1494367262415.Z0FBQUFBQlpFandldHJFMjVRNFBwbXNoaEl0bUpBTHZhME9wNk9UN3F0OGVMc2t0Z3dFN1RDRGpDNnBPdHNydlh3Tm1GbE9HTnRwaXFzck1jRGFTRnNlOW5NNHZ6RkpDcm8yZ1NCV2JUOGowWjUxN1FwYjR6a2p6UlhJdFE3TDlFVUZIWENTMjV4SE8; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:01:02 + GMT; secure', edgebucket=v26tNMdbfRFJY6vKZ7; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload] + Vary: [accept-encoding] + Via: [1.1 varnish] + X-Cache: [MISS] + X-Cache-Hits: ['0'] + X-Moose: [majestic] + X-Served-By: [cache-atl6228-ATL] + X-Timer: ['S1494367262.227236,VS0,VE234'] + cache-control: ['private, s-maxage=0, max-age=0, must-revalidate, max-age=0, + must-revalidate'] + expires: ['-1'] + set-cookie: ['session_tracker=0xv7VBQrkOXYPJF7lS.0.1494367262415.Z0FBQUFBQlpFandldHJFMjVRNFBwbXNoaEl0bUpBTHZhME9wNk9UN3F0OGVMc2t0Z3dFN1RDRGpDNnBPdHNydlh3Tm1GbE9HTnRwaXFzck1jRGFTRnNlOW5NNHZ6RkpDcm8yZ1NCV2JUOGowWjUxN1FwYjR6a2p6UlhJdFE3TDlFVUZIWENTMjV4SE8; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:01:02 + GMT; secure', edgebucket=v26tNMdbfRFJY6vKZ7; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + x-content-type-options: [nosniff] + x-frame-options: [SAMEORIGIN] + x-ratelimit-remaining: ['599.0'] + x-ratelimit-reset: ['538'] + x-ratelimit-used: ['1'] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +version: 1 diff --git a/tests/cassettes/test_copy_to_clipboard_osx.yaml b/tests/cassettes/test_copy_to_clipboard_osx.yaml new file mode 100644 index 0000000..5189008 --- /dev/null +++ b/tests/cassettes/test_copy_to_clipboard_osx.yaml @@ -0,0 +1,293 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit'] + method: GET + uri: https://www.reddit.com/r/Python/comments/2xmo63.json + response: + body: + string: !!binary | + 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 + dr+5+4GK/qDXGep2xxDi2y2G3/8H261n2bzmAAA= + headers: + Accept-Ranges: [bytes] + Connection: [keep-alive] + Content-Encoding: [gzip] + Content-Length: ['7952'] + Content-Type: [application/json; charset=UTF-8] + Date: ['Tue, 09 May 2017 22:00:58 GMT'] + Server: [snooserv] + Set-Cookie: ['loid=000000000000q8ytgj.2.1494367258728.Z0FBQUFBQlpFandhVzkyMGZRdjNZZlBrN3I0MjdJekZYckhTM3lXNElIOVFNaXdKNW5FY0g5ZlJZVGZVYzMwbkZsWTVYOHpBSkJfekdISmV0eEdObEZwNXB6NzNvLUhwRG4zT3FGQi1iZi1ZWk01dlFQOFdpbTRXbUJqb3RQVHdWM3V2bVV6TGJpdEg; + Domain=reddit.com; Max-Age=63071999; Path=/; expires=Thu, 09-May-2019 22:00:58 + GMT; secure', 'session_tracker=yBtXUs42t54aZ2QFbA.0.1494367258722.Z0FBQUFBQlpFandhT2FRVDJLdm5rSjVfVFNzWEs5TGRXX1FfMkNsYWxabnV4Um9TeHBfd0NiU1dZdTBWMXpxck5jX1ppN3lpa1VPMWNva0dhV2xPb2ZmUmZZQWpOOWZtRk5JNmU2LWstNnU2NlhuTF82bHhxTXkxNEFmZURtd3lBVzRDQUhveUQ1d2U; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:00:58 + GMT; secure', edgebucket=zn5FMmjkuvOO5cnf9e; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload] + Vary: [accept-encoding] + Via: [1.1 varnish] + X-Cache: [MISS] + X-Cache-Hits: ['0'] + X-Moose: [majestic] + X-Served-By: [cache-atl6242-ATL] + X-Timer: ['S1494367259.696060,VS0,VE238'] + access-control-allow-origin: ['*'] + access-control-expose-headers: ['X-Reddit-Tracking, X-Moose'] + cache-control: ['max-age=0, must-revalidate'] + set-cookie: ['loid=000000000000q8ytgj.2.1494367258728.Z0FBQUFBQlpFandhVzkyMGZRdjNZZlBrN3I0MjdJekZYckhTM3lXNElIOVFNaXdKNW5FY0g5ZlJZVGZVYzMwbkZsWTVYOHpBSkJfekdISmV0eEdObEZwNXB6NzNvLUhwRG4zT3FGQi1iZi1ZWk01dlFQOFdpbTRXbUJqb3RQVHdWM3V2bVV6TGJpdEg; + Domain=reddit.com; Max-Age=63071999; Path=/; expires=Thu, 09-May-2019 22:00:58 + GMT; secure', 'session_tracker=yBtXUs42t54aZ2QFbA.0.1494367258722.Z0FBQUFBQlpFandhT2FRVDJLdm5rSjVfVFNzWEs5TGRXX1FfMkNsYWxabnV4Um9TeHBfd0NiU1dZdTBWMXpxck5jX1ppN3lpa1VPMWNva0dhV2xPb2ZmUmZZQWpOOWZtRk5JNmU2LWstNnU2NlhuTF82bHhxTXkxNEFmZURtd3lBVzRDQUhveUQ1d2U; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:00:58 + GMT; secure', edgebucket=zn5FMmjkuvOO5cnf9e; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + x-content-type-options: [nosniff] + x-frame-options: [SAMEORIGIN] + x-reddit-tracking: ['https://pixel.redditmedia.com/pixel/of_destiny.png?v=YSHfVCx9q9fs%2FeX7JlLo4oAhbBoilNFYME2ft4wFesBJiQGKwCZ6ufRk3MIReVLMmFb5sCMnF0M%3D'] + x-ua-compatible: [IE=edge] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +- request: + body: grant_type=refresh_token&redirect_uri=http%3A%2F%2F127.0.0.1%3A65000%2F&refresh_token=********** + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Authorization: ['**********'] + Connection: [keep-alive] + Content-Length: ['122'] + Content-Type: [application/x-www-form-urlencoded] + Cookie: [edgebucket=zn5FMmjkuvOO5cnf9e; loid=000000000000q8ytgj.2.1494367258728.Z0FBQUFBQlpFandhVzkyMGZRdjNZZlBrN3I0MjdJekZYckhTM3lXNElIOVFNaXdKNW5FY0g5ZlJZVGZVYzMwbkZsWTVYOHpBSkJfekdISmV0eEdObEZwNXB6NzNvLUhwRG4zT3FGQi1iZi1ZWk01dlFQOFdpbTRXbUJqb3RQVHdWM3V2bVV6TGJpdEg; + session_tracker=yBtXUs42t54aZ2QFbA.0.1494367258722.Z0FBQUFBQlpFandhT2FRVDJLdm5rSjVfVFNzWEs5TGRXX1FfMkNsYWxabnV4Um9TeHBfd0NiU1dZdTBWMXpxck5jX1ppN3lpa1VPMWNva0dhV2xPb2ZmUmZZQWpOOWZtRk5JNmU2LWstNnU2NlhuTF82bHhxTXkxNEFmZURtd3lBVzRDQUhveUQ1d2U] + User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit'] + method: POST + uri: https://api.reddit.com/api/v1/access_token/ + response: + body: {string: '{"access_token": "F9zbMvdk6SvduZkyrcSe7Tp526s", "token_type": + "bearer", "device_id": "None", "expires_in": 3600, "scope": "edit history + identity mysubreddits privatemessages read report save submit subscribe vote"}'} + headers: + Accept-Ranges: [bytes] + Connection: [keep-alive] + Content-Length: ['214'] + Content-Type: [application/json; charset=UTF-8] + Date: ['Tue, 09 May 2017 22:01:00 GMT'] + Server: [snooserv] + Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload] + Via: [1.1 varnish] + X-Cache: [MISS] + X-Cache-Hits: ['0'] + X-Moose: [majestic] + X-Served-By: [cache-atl6239-ATL] + X-Timer: ['S1494367260.216158,VS0,VE60'] + cache-control: ['max-age=0, must-revalidate'] + set-cookie: ['session_tracker=yBtXUs42t54aZ2QFbA.0.1494367260258.Z0FBQUFBQlpFandjRW1pOS1SLTFJU0FSLTlqUjdyQ180WGJNanBWU3lNTWhzVHk5TWZ6eDNUSWllcG14VjJTVGZaM0J6N0pvY0o3MlRtaXJ5ckpGbmFLbFc1clFXamVCTHNhZkh6TVFPa2RIeGJ2Xy1lZ3RtMlc3Rmh2T0JYMGk3UEY0OHE4UUxWMUY; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:01:00 + GMT; secure'] + x-content-type-options: [nosniff] + x-frame-options: [SAMEORIGIN] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Authorization: ['**********'] + Connection: [keep-alive] + User-Agent: [rtv test suite PRAW/3.6.1 Python/3.6.1 b'Darwin-14.5.0-x86_64-i386-64bit'] + method: GET + uri: https://oauth.reddit.com/api/v1/me.json + response: + body: + string: !!binary | + H4sIAB48ElkC/5VUTY/cNgz9KwufF8XOZNsscush1wLpHyBkmbYFS6IqyTM7G+S/l5TtsZwMCvRm + 80Mk33vk98YkQBcs3RCbL0+9sgmfn5oeVZ4jJjZ9bzoCTxlyVHpiQ46zhFhzQRhVCOiNHzjiuvtU + lzBeMELEQDGzv8rDQekbJFRRjxAi9vWbSYJBso1GiMqFOex+R62xCFdsIas44PHlDns12wwpJhjJ + djTn0j9dPUb+aiJavCivseHoi4pGeYloNPkcycJJ7PgeMBqHPoPp2Hv6fPpRRvrAOMFjLHheUHMm + wPeMXrJWx3U0GWUq7CA4gXN18Jx6uoEmJ5UqxxyGqDpkD02mEFDVELQqU2tJTzAzWtDeVqwfNMVJ + c90UReUHjCh+YV8ZWz3K8yvPY+Ll2BjOa08QyBp9q1rObhsErPFTldRTZBrHnENlXFn0KouEWuUX + elZvoAkd+YFAaMHCUMWhHiWeG34+UJjmlgfqTH5E4evnhUHBQ2dDfq+2JM28AOLmPxNRVyCyhlpi + 9EDzzFOh/aA5j1ewNAyc6EErPf4Kj/EtvUOY07jbCiIPyjmR9nuI5AgMTx9ZJ9koexcKGKqQDIrJ + B+68MkViATnH4OqjZygLm/gNDjhQm0a6cjNLjY6lKiz+n6ZYMJEK1NuLOiL6i2F0ftaRILZIFTp+ + hCowHal1tQ4Y37mFONt6JVYhJcxyCA67Upb1fn3gXPlYAReT5QItR+YaeUd/AqPsVIqsUVe5yvCY + 8qPjE4jt6Fo8okDW/oKA6pbFzfzUf/QVUW1viXz5UKc5hUJQs1/qXfhfnvxsLZsGvn18iYKJahX7 + 6igMNfYfr0jWZHkucUgVDXPWewbfcNObQ0Hhz1EnV4PT+LTJZGs4yc0/vVWIsdi4myqdLZxdGUa+ + QVuZ5Rjt6eLjaFitWwrxWRtlI+8b3nw909f897e+6//s//om042Gr2jPooVILZUut3yRN0wqOsXG + 8/lN2ipLqnnVBciXZ1kk7CFTWALhjnM1bmnv2NoqmEYzl9Z8LJCGUX0gfJKueC9ULnieXs+/nz+d + /nh9+U3KFdL0XkJsa/BKSUl4Ob+tCXxvWswywVZ7u8HbZG8SJj1y7yxFs2vzx7/41ILz+AcAAA== + headers: + Accept-Ranges: [bytes] + Connection: [keep-alive] + Content-Encoding: [gzip] + Content-Length: ['853'] + Content-Type: [application/json; charset=UTF-8] + Date: ['Tue, 09 May 2017 22:01:02 GMT'] + Server: [snooserv] + Set-Cookie: ['session_tracker=0xv7VBQrkOXYPJF7lS.0.1494367262415.Z0FBQUFBQlpFandldHJFMjVRNFBwbXNoaEl0bUpBTHZhME9wNk9UN3F0OGVMc2t0Z3dFN1RDRGpDNnBPdHNydlh3Tm1GbE9HTnRwaXFzck1jRGFTRnNlOW5NNHZ6RkpDcm8yZ1NCV2JUOGowWjUxN1FwYjR6a2p6UlhJdFE3TDlFVUZIWENTMjV4SE8; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:01:02 + GMT; secure', edgebucket=v26tNMdbfRFJY6vKZ7; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + Strict-Transport-Security: [max-age=15552000; includeSubDomains; preload] + Vary: [accept-encoding] + Via: [1.1 varnish] + X-Cache: [MISS] + X-Cache-Hits: ['0'] + X-Moose: [majestic] + X-Served-By: [cache-atl6228-ATL] + X-Timer: ['S1494367262.227236,VS0,VE234'] + cache-control: ['private, s-maxage=0, max-age=0, must-revalidate, max-age=0, + must-revalidate'] + expires: ['-1'] + set-cookie: ['session_tracker=0xv7VBQrkOXYPJF7lS.0.1494367262415.Z0FBQUFBQlpFandldHJFMjVRNFBwbXNoaEl0bUpBTHZhME9wNk9UN3F0OGVMc2t0Z3dFN1RDRGpDNnBPdHNydlh3Tm1GbE9HTnRwaXFzck1jRGFTRnNlOW5NNHZ6RkpDcm8yZ1NCV2JUOGowWjUxN1FwYjR6a2p6UlhJdFE3TDlFVUZIWENTMjV4SE8; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Wed, 10-May-2017 00:01:02 + GMT; secure', edgebucket=v26tNMdbfRFJY6vKZ7; Domain=reddit.com; Max-Age=63071999; + Path=/; secure] + x-content-type-options: [nosniff] + x-frame-options: [SAMEORIGIN] + x-ratelimit-remaining: ['599.0'] + x-ratelimit-reset: ['538'] + x-ratelimit-used: ['1'] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +version: 1 diff --git a/tests/test_clipboard.py b/tests/test_clipboard.py new file mode 100644 index 0000000..ed98657 --- /dev/null +++ b/tests/test_clipboard.py @@ -0,0 +1,39 @@ +import pytest + +from rtv.clipboard import copy_linux, copy_osx +from rtv.exceptions import ProgramError + + +try: + from unittest import mock +except ImportError: + import mock + + +def test_copy(): + + with mock.patch('subprocess.Popen') as Popen, \ + mock.patch('subprocess.call') as call: + + # Mock out the subprocess calls + p = mock.Mock() + p.communicate = mock.Mock() + Popen.return_value = p + + # If the `which` command can't find a program to use + call.return_value = 1 # Returns an error code + with pytest.raises(ProgramError): + copy_linux('test') + + call.return_value = 0 + copy_linux('test') + assert Popen.call_args[0][0] == ['xsel', '-b', '-i'] + p.communicate.assert_called_with(input='test'.encode('utf-8')) + copy_linux('test ❤') + p.communicate.assert_called_with(input='test ❤'.encode('utf-8')) + + copy_osx('test') + assert Popen.call_args[0][0] == ['pbcopy', 'w'] + p.communicate.assert_called_with(input='test'.encode('utf-8')) + copy_osx('test ❤') + p.communicate.assert_called_with(input='test ❤'.encode('utf-8')) \ No newline at end of file diff --git a/tests/test_submission.py b/tests/test_submission.py index 717a22e..837ceb9 100644 --- a/tests/test_submission.py +++ b/tests/test_submission.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -import os -import platform -import subprocess +import sys import curses +import subprocess + +import pytest from rtv.submission_page import SubmissionPage @@ -448,20 +449,54 @@ def test_submission_urlview(submission_page, terminal, refresh_token): open_urlview.assert_called_with('http://test.url.com ❤') -def test_submission_copy_to_clipboard(submission_page, terminal, refresh_token): - def get_linux_clipboard_content(): +@pytest.mark.skipif(sys.platform != 'darwin', reason='Test uses osx clipboard') +def test_copy_to_clipboard_osx(submission_page, terminal, refresh_token): + + def get_clipboard_content(): + p = subprocess.Popen(['pbpaste', 'r'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + stdout, stderr = p.communicate() + return stdout.decode('utf-8') + + window = terminal.stdscr.subwin + + # Log in + submission_page.config.refresh_token = refresh_token + submission_page.oauth.authorize() + + # Get submission + data = submission_page.content.get(submission_page.nav.absolute_index) + + # Trigger copy command for permalink + submission_page.controller.trigger('y') + assert data.get('permalink') == get_clipboard_content() + window.addstr.assert_called_with(1, 1, b'Copied permalink to clipboard') + + # Trigger copy command for submission + submission_page.controller.trigger('Y') + assert data.get('url_full') == get_clipboard_content() + window.addstr.assert_called_with(1, 1, b'Copied url to clipboard') + + +@pytest.mark.skipif(sys.platform == 'darwin', reason='Test uses linux clipboard') +def test_copy_to_clipboard_linux(submission_page, terminal, refresh_token): + + def get_clipboard_content(): paste_cmd = None for cmd in ['xsel', 'xclip']: cmd_exists = subprocess.call( ['which', cmd], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) is 0 + stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 if cmd_exists: paste_cmd = cmd break - if paste_cmd is not None: - cmd_args = {'xsel' : ['xsel', '-b', '-o'], - 'xclip' : ['xclip', '-selection', 'c', '-o']} + if paste_cmd is not None: + cmd_args = {'xsel': ['xsel', '-b', '-o'], + 'xclip': ['xclip', '-selection', 'c', '-o']} p = subprocess.Popen(cmd_args.get(paste_cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -469,35 +504,29 @@ def test_submission_copy_to_clipboard(submission_page, terminal, refresh_token): stdout, stderr = p.communicate() return stdout.decode('utf-8') - def get_clipboard_content(): - paste_content = None - #Check OS type - os_type = None - if os.name == 'mac' or platform.system() == 'Darwin': - os_type = 'macOs' - elif os.name == 'posix' or platform.system() == 'Linux': - os_type = 'linux' - if os_type is not None: - if os_type == 'macOs': - p = subprocess.Popen(['pbpaste', 'r'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - close_fds=True) - stdout, stderr = p.communicate() - paste_content = stdout.decode('utf-8') - elif os_type == 'linux': - paste_content = get_linux_clipboard_content() - return paste_content + window = terminal.stdscr.subwin # Log in submission_page.config.refresh_token = refresh_token submission_page.oauth.authorize() - #Get submission + + # Get submission data = submission_page.content.get(submission_page.nav.absolute_index) - #Trigger copy command for permalink + + # Trigger copy command for permalink submission_page.controller.trigger('y') - assert data.get('permalink') == get_clipboard_content() - #Trigger copy command for submission + content = get_clipboard_content() + if content is not None: + assert data.get('permalink') == content + window.addstr.assert_called_with(1, 1, b'Copied permalink to clipboard') + else: + window.addstr.assert_called_with(1, 1, b'Failed to copy permalink to clipboard') + + # Trigger copy command for submission submission_page.controller.trigger('Y') - assert data.get('url_full') == get_clipboard_content() + content = get_clipboard_content() + if content is not None: + assert data.get('url_full') == content + window.addstr.assert_called_with(1, 1, b'Copied url to clipboard') + else: + window.addstr.assert_called_with(1, 1, b'Failed to copy url to clipboard')