1""" 2Unit tests for nyx. 3""" 4 5import collections 6import inspect 7import os 8import time 9import unittest 10 11import nyx.curses 12 13from nyx import expand_path, chroot, join, uses_settings 14 15try: 16 # added in python 3.3 17 from unittest.mock import Mock, patch 18except ImportError: 19 from mock import Mock, patch 20 21__all__ = [ 22 'arguments', 23 'curses', 24 'installation', 25 'log', 26 'menu', 27 'panel', 28 'popups', 29 'tracker', 30] 31 32NYX_BASE = os.path.sep.join(__file__.split(os.path.sep)[:-2]) 33OUR_SCREEN_SIZE = None 34TEST_SCREEN_SIZE = nyx.curses.Dimensions(80, 25) 35 36RenderResult = collections.namedtuple('RenderResult', ['content', 'return_value', 'runtime']) 37 38 39def require_curses(func): 40 """ 41 Skips the test unless curses is available with a minimal dimension needed by 42 our tests. 43 """ 44 45 if OUR_SCREEN_SIZE is None: 46 def _check_screen_size(): 47 global OUR_SCREEN_SIZE 48 OUR_SCREEN_SIZE = nyx.curses.screen_size() 49 50 nyx.curses.start(_check_screen_size) 51 52 def wrapped(self, *args, **kwargs): 53 if OUR_SCREEN_SIZE.width < TEST_SCREEN_SIZE.width: 54 self.skipTest("screen isn't wide enough") 55 elif OUR_SCREEN_SIZE.height < TEST_SCREEN_SIZE.height: 56 self.skipTest("screen isn't tall enough") 57 else: 58 with patch('nyx.curses.screen_size', Mock(return_value = TEST_SCREEN_SIZE)): 59 return func(self, *args, **kwargs) 60 61 return wrapped 62 63 64class mock_keybindings(object): 65 """ 66 Mocks the given keyboard inputs. 67 """ 68 69 def __init__(self, *keys): 70 self._mock = patch('nyx.curses.key_input', side_effect = [nyx.curses.KeyInput(key) for key in keys]) 71 72 def __enter__(self, *args): 73 self._mock.__enter__(*args) 74 75 def __exit__(self, *args): 76 self._mock.__exit__(*args) 77 78 79def render(func, *args, **kwargs): 80 """ 81 Runs the given curses function, providing content that's rendered on the 82 screen. If the function starts with an argument named 'subwindow' then it's 83 provided one through :func:`~nyx.curses.draw`. 84 85 :param function func: draw function to be invoked 86 87 :returns: :data:`~test.RenderResult` with information about what was rendered 88 """ 89 90 attr = {} 91 92 def draw_func(): 93 nyx.curses._disable_acs() 94 nyx.curses.CURSES_SCREEN.erase() 95 start_time = time.time() 96 97 func_args = inspect.getargspec(func).args 98 99 if func_args[:1] == ['subwindow'] or func_args[:2] == ['self', 'subwindow']: 100 def _draw(subwindow): 101 return func(subwindow, *args, **kwargs) 102 103 attr['return_value'] = nyx.curses.draw(_draw) 104 else: 105 attr['return_value'] = func(*args, **kwargs) 106 107 attr['runtime'] = time.time() - start_time 108 attr['content'] = nyx.curses.screenshot() 109 110 with patch('nyx.curses.key_input', return_value = nyx.curses.KeyInput(27)): 111 nyx.curses.start(draw_func, transparent_background = True, cursor = False) 112 113 return RenderResult(attr.get('content'), attr.get('return_value'), attr.get('runtime')) 114 115 116class TestBaseUtil(unittest.TestCase): 117 def setUp(self): 118 nyx.CHROOT = None 119 120 def tearDown(self): 121 nyx.CHROOT = None 122 123 @patch('nyx.chroot', Mock(return_value = '')) 124 @patch('nyx.tor_controller', Mock()) 125 @patch('stem.util.system.cwd', Mock(return_value = '/your_cwd')) 126 def test_expand_path(self): 127 self.assertEqual('/absolute/path/to/torrc', expand_path('/absolute/path/to/torrc')) 128 self.assertEqual('/your_cwd/torrc', expand_path('torrc')) 129 130 @patch('nyx.chroot', Mock(return_value = '/chroot')) 131 @patch('nyx.tor_controller', Mock()) 132 @patch('stem.util.system.cwd', Mock(return_value = '/your_cwd')) 133 def test_expand_path_with_chroot(self): 134 self.assertEqual('/chroot/absolute/path/to/torrc', expand_path('/absolute/path/to/torrc')) 135 self.assertEqual('/chroot/your_cwd/torrc', expand_path('torrc')) 136 137 @patch('platform.system', Mock(return_value = 'Linux')) 138 @patch('os.path.exists', Mock(return_value = True)) 139 @uses_settings 140 def test_chroot_uses_config(self, config): 141 config.set('tor_chroot', '/chroot/path') 142 self.assertEqual('/chroot/path', chroot()) 143 config.set('tor_chroot', None) 144 145 @patch('platform.system', Mock(return_value = 'Linux')) 146 @patch('os.path.exists', Mock(return_value = False)) 147 @uses_settings 148 def test_chroot_requires_path_to_exist(self, config): 149 config.set('tor_chroot', '/chroot/path') 150 self.assertEqual('', chroot()) 151 config.set('tor_chroot', None) 152 153 def test_join(self): 154 # check our pydoc examples 155 156 self.assertEqual('This is a looooong', join(['This', 'is', 'a', 'looooong', 'message'], size = 18)) 157 self.assertEqual('This is a', join(['This', 'is', 'a', 'looooong', 'message'], size = 17)) 158 self.assertEqual('', join(['This', 'is', 'a', 'looooong', 'message'], size = 2)) 159 160 # include a joining character 161 162 self.assertEqual('Download: 5 MB, Upload: 3 MB', join(['Download: 5 MB', 'Upload: 3 MB', 'Other: 2 MB'], ', ', 30)) 163