|
1 | 1 | # -*- coding: utf-8 -*- |
2 | | -"""Helper methods for tmuxp unittests. |
| 2 | +"""Helper methods for tmuxp tests. |
3 | 3 |
|
4 | 4 | _CallableContext, WhateverIO, decorator and stdouts are from the case project, |
5 | 5 | https://github.com/celery/case, license BSD 3-clause. |
|
9 | 9 | unicode_literals, with_statement) |
10 | 10 |
|
11 | 11 | import contextlib |
12 | | -import functools |
13 | | -import inspect |
14 | | -import io |
15 | 12 | import logging |
16 | 13 | import os |
17 | | -import sys |
18 | 14 | import tempfile |
19 | | -from contextlib import contextmanager |
20 | | - |
21 | | -from tmuxp import exc |
22 | | -from tmuxp.server import Server |
23 | | - |
24 | | -if sys.version_info < (2, 7): |
25 | | - import unittest2 as unittest |
26 | | -else: |
27 | | - import unittest |
28 | 15 |
|
29 | 16 | logger = logging.getLogger(__name__) |
30 | 17 |
|
@@ -125,253 +112,6 @@ def temp_window(session, *args, **kwargs): |
125 | 112 | return |
126 | 113 |
|
127 | 114 |
|
128 | | -class TestCase(unittest.TestCase): |
129 | | - |
130 | | - """Base TestClass so we don't have to try: unittest2 every module. """ |
131 | | - |
132 | | - @classmethod |
133 | | - def setUpClass(cls): |
134 | | - super(TestCase, cls).setUpClass() # for python 2.6 unittest2 |
135 | | - |
136 | | - |
137 | | -class TmuxTestCase(TestCase): |
138 | | - |
139 | | - """TmuxTestCase class, wraps the TestCase in a :class:`Session`.""" |
140 | | - |
141 | | - #: :class:`Session` object. |
142 | | - session = None |
143 | | - #: Session name for the TestCase. |
144 | | - TEST_SESSION_NAME = None |
145 | | - |
146 | | - def temp_session(self, session_name=None): |
147 | | - return temp_session(self.server, session_name) |
148 | | - |
149 | | - def setUp(self): |
150 | | - """Run bootstrap if :attr:`~.session` is not set.""" |
151 | | - |
152 | | - if not self.TEST_SESSION_NAME or not self.session: |
153 | | - self.bootstrap() |
154 | | - |
155 | | - def bootstrap(self): |
156 | | - """Return tuple of the session_name (generated) and :class:`Session`. |
157 | | -
|
158 | | - Checks to verify if the user has a tmux client open. |
159 | | -
|
160 | | - It will clean up and delete other sessions starting with the |
161 | | - :attr:`TEST_SESSION_PREFIX` ``tmuxp``. |
162 | | -
|
163 | | - Since tmux closes when all sessions are deleted, the bootstrap will see |
164 | | - if there is no other client open aside from a tmuxp_ prefixed session |
165 | | - a dumby session will be made to prevent tmux from closing. |
166 | | -
|
167 | | - """ |
168 | | - self.t = t = Server() |
169 | | - t.socket_name = 'tmuxp_test' |
170 | | - |
171 | | - session_name = 'tmuxp' |
172 | | - if not t.has_session(session_name): |
173 | | - t.cmd('new-session', '-d', '-s', session_name) |
174 | | - |
175 | | - # find current sessions prefixed with tmuxp |
176 | | - old_test_sessions = [ |
177 | | - s.get('session_name') for s in t._sessions |
178 | | - if s.get('session_name').startswith(TEST_SESSION_PREFIX) |
179 | | - ] |
180 | | - |
181 | | - TEST_SESSION_NAME = get_test_session_name(server=t) |
182 | | - |
183 | | - try: |
184 | | - session = t.new_session( |
185 | | - session_name=TEST_SESSION_NAME, |
186 | | - ) |
187 | | - except exc.TmuxpException as e: |
188 | | - raise e |
189 | | - |
190 | | - """ |
191 | | - Make sure that tmuxp can :ref:`test_builder_visually` and switches to |
192 | | - the newly created session for that testcase. |
193 | | - """ |
194 | | - try: |
195 | | - t.switch_client(session.get('session_id')) |
196 | | - pass |
197 | | - except exc.TmuxpException as e: |
198 | | - # t.attach_session(session.get('session_id')) |
199 | | - pass |
200 | | - |
201 | | - for old_test_session in old_test_sessions: |
202 | | - logger.debug( |
203 | | - 'Old test test session %s found. Killing it.' % |
204 | | - old_test_session |
205 | | - ) |
206 | | - t.kill_session(old_test_session) |
207 | | - assert TEST_SESSION_NAME == session.get('session_name') |
208 | | - assert TEST_SESSION_NAME != 'tmuxp' |
209 | | - |
210 | | - self.TEST_SESSION_NAME = TEST_SESSION_NAME |
211 | | - self.server = t |
212 | | - self.session = session |
213 | | - |
214 | | - |
215 | | -StringIO = io.StringIO |
216 | | -_SIO_write = StringIO.write |
217 | | -_SIO_init = StringIO.__init__ |
218 | | - |
219 | | - |
220 | | -def update_wrapper(wrapper, wrapped, *args, **kwargs): |
221 | | - wrapper = functools.update_wrapper(wrapper, wrapped, *args, **kwargs) |
222 | | - wrapper.__wrapped__ = wrapped |
223 | | - return wrapper |
224 | | - |
225 | | - |
226 | | -def wraps(wrapped, |
227 | | - assigned=functools.WRAPPER_ASSIGNMENTS, |
228 | | - updated=functools.WRAPPER_UPDATES): |
229 | | - return functools.partial(update_wrapper, wrapped=wrapped, |
230 | | - assigned=assigned, updated=updated) |
231 | | - |
232 | | - |
233 | | -class _CallableContext(object): |
234 | | - |
235 | | - def __init__(self, context, cargs, ckwargs, fun): |
236 | | - self.context = context |
237 | | - self.cargs = cargs |
238 | | - self.ckwargs = ckwargs |
239 | | - self.fun = fun |
240 | | - |
241 | | - def __call__(self, *args, **kwargs): |
242 | | - return self.fun(*args, **kwargs) |
243 | | - |
244 | | - def __enter__(self): |
245 | | - self.ctx = self.context(*self.cargs, **self.ckwargs) |
246 | | - return self.ctx.__enter__() |
247 | | - |
248 | | - def __exit__(self, *einfo): |
249 | | - if self.ctx: |
250 | | - return self.ctx.__exit__(*einfo) |
251 | | - |
252 | | - |
253 | | -def decorator(predicate): |
254 | | - context = contextmanager(predicate) |
255 | | - |
256 | | - @wraps(predicate) |
257 | | - def take_arguments(*pargs, **pkwargs): |
258 | | - |
259 | | - @wraps(predicate) |
260 | | - def decorator(cls): |
261 | | - if inspect.isclass(cls): |
262 | | - orig_setup = cls.setUp |
263 | | - orig_teardown = cls.tearDown |
264 | | - |
265 | | - @wraps(cls.setUp) |
266 | | - def around_setup(*args, **kwargs): |
267 | | - try: |
268 | | - contexts = args[0].__rb3dc_contexts__ |
269 | | - except AttributeError: |
270 | | - contexts = args[0].__rb3dc_contexts__ = [] |
271 | | - p = context(*pargs, **pkwargs) |
272 | | - p.__enter__() |
273 | | - contexts.append(p) |
274 | | - return orig_setup(*args, **kwargs) |
275 | | - around_setup.__wrapped__ = cls.setUp |
276 | | - cls.setUp = around_setup |
277 | | - |
278 | | - @wraps(cls.tearDown) |
279 | | - def around_teardown(*args, **kwargs): |
280 | | - try: |
281 | | - contexts = args[0].__rb3dc_contexts__ |
282 | | - except AttributeError: |
283 | | - pass |
284 | | - else: |
285 | | - for context in contexts: |
286 | | - context.__exit__(*sys.exc_info()) |
287 | | - orig_teardown(*args, **kwargs) |
288 | | - around_teardown.__wrapped__ = cls.tearDown |
289 | | - cls.tearDown = around_teardown |
290 | | - |
291 | | - return cls |
292 | | - else: |
293 | | - @wraps(cls) |
294 | | - def around_case(self, *args, **kwargs): |
295 | | - with context(*pargs, **pkwargs) as context_args: |
296 | | - context_args = context_args or () |
297 | | - if not isinstance(context_args, tuple): |
298 | | - context_args = (context_args,) |
299 | | - return cls(*(self,) + args + context_args, **kwargs) |
300 | | - return around_case |
301 | | - |
302 | | - if len(pargs) == 1 and callable(pargs[0]): |
303 | | - fun, pargs = pargs[0], () |
304 | | - return decorator(fun) |
305 | | - return _CallableContext(context, pargs, pkwargs, decorator) |
306 | | - assert take_arguments.__wrapped__ |
307 | | - return take_arguments |
308 | | - |
309 | | - |
310 | | -class WhateverIO(StringIO): |
311 | | - |
312 | | - def __init__(self, v=None, *a, **kw): |
313 | | - _SIO_init(self, v.decode() if isinstance(v, bytes) else v, *a, **kw) |
314 | | - |
315 | | - def write(self, data): |
316 | | - _SIO_write(self, data.decode() if isinstance(data, bytes) else data) |
317 | | - |
318 | | - |
319 | | -@decorator |
320 | | -def stdouts(): |
321 | | - """Override `sys.stdout` and `sys.stderr` with `StringIO` |
322 | | - instances. |
323 | | - Decorator example:: |
324 | | - @mock.stdouts |
325 | | - def test_foo(self, stdout, stderr): |
326 | | - something() |
327 | | - self.assertIn('foo', stdout.getvalue()) |
328 | | - Context example:: |
329 | | - with mock.stdouts() as (stdout, stderr): |
330 | | - something() |
331 | | - self.assertIn('foo', stdout.getvalue()) |
332 | | - """ |
333 | | - prev_out, prev_err = sys.stdout, sys.stderr |
334 | | - prev_rout, prev_rerr = sys.__stdout__, sys.__stderr__ |
335 | | - mystdout, mystderr = WhateverIO(), WhateverIO() |
336 | | - sys.stdout = sys.__stdout__ = mystdout |
337 | | - sys.stderr = sys.__stderr__ = mystderr |
338 | | - |
339 | | - try: |
340 | | - yield mystdout, mystderr |
341 | | - finally: |
342 | | - sys.stdout = prev_out |
343 | | - sys.stderr = prev_err |
344 | | - sys.__stdout__ = prev_rout |
345 | | - sys.__stderr__ = prev_rerr |
346 | | - |
347 | | - |
348 | | -@decorator |
349 | | -def mute(): |
350 | | - """Redirect `sys.stdout` and `sys.stderr` to /dev/null, silencent them. |
351 | | - Decorator example:: |
352 | | - @mute |
353 | | - def test_foo(self): |
354 | | - something() |
355 | | - Context example:: |
356 | | - with mute(): |
357 | | - something() |
358 | | - """ |
359 | | - prev_out, prev_err = sys.stdout, sys.stderr |
360 | | - prev_rout, prev_rerr = sys.__stdout__, sys.__stderr__ |
361 | | - devnull = open(os.devnull, 'w') |
362 | | - mystdout, mystderr = devnull, devnull |
363 | | - sys.stdout = sys.__stdout__ = mystdout |
364 | | - sys.stderr = sys.__stderr__ = mystderr |
365 | | - |
366 | | - try: |
367 | | - yield |
368 | | - finally: |
369 | | - sys.stdout = prev_out |
370 | | - sys.stderr = prev_err |
371 | | - sys.__stdout__ = prev_rout |
372 | | - sys.__stderr__ = prev_rerr |
373 | | - |
374 | | - |
375 | 115 | class EnvironmentVarGuard(object): |
376 | 116 |
|
377 | 117 | """Class to help protect the environment variable properly. Can be used as |
|
0 commit comments