1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
"""Configure test fixtures"""
# std imports
import os
import platform
import subprocess
# 3rd party
import pytest
IS_WINDOWS = platform.system() == 'Windows'
all_terms_params = 'xterm screen ansi vt220 rxvt cons25 linux'.split()
many_lines_params = [40, 80]
# we must test a '1' column for conditional in _handle_long_word
many_columns_params = [1, 10]
def envvar_enabled(envvar):
"""
Return True if environment variable is set and enabled
unset values, 'no', 0, and 'false' and treated as False regardless of case
All other values are considered True
"""
value = os.environ.get(envvar, False)
if value is False:
return value
if value.lower() in {'no', 'false'}:
return False
try:
return bool(int(value))
except ValueError:
return True
TEST_FULL = envvar_enabled('TEST_FULL')
TEST_KEYBOARD = envvar_enabled('TEST_KEYBOARD')
TEST_QUICK = envvar_enabled('TEST_QUICK')
TEST_RAW = envvar_enabled('TEST_RAW')
if TEST_FULL:
try:
all_terms_params = [
# use all values of the first column of data in output of 'toe -a'
_term.split(None, 1)[0] for _term in
subprocess.Popen(('toe', '-a'), # pylint: disable=consider-using-with
stdout=subprocess.PIPE,
close_fds=True)
.communicate()[0].splitlines()]
except OSError:
pass
elif IS_WINDOWS:
all_terms_params = ['vtwin10', ]
elif TEST_QUICK:
all_terms_params = 'xterm screen ansi linux'.split()
if TEST_QUICK:
many_lines_params = [80, ]
many_columns_params = [25, ]
@pytest.fixture(autouse=True)
def detect_curses_contamination(request):
"""
Detect when Terminal() is instantiated in parent pytest process.
The curses module can only call setupterm() once per process. If a test
instantiates Terminal() in the parent pytest process (instead of within
@as_subprocess), it contaminates all subsequent tests that try to use
a different terminal kind.
This fixture runs automatically for all tests and fails any test that
initializes curses in the parent process.
"""
if IS_WINDOWS:
# Windows doesn't have the curses singleton limitation
yield
return
# Import here to avoid issues if module not yet imported
import blessed.terminal # pylint: disable=import-outside-toplevel
# Record the state before the test
before = blessed.terminal._CUR_TERM
# Run the test
yield
# Check if curses was initialized during the test
after = blessed.terminal._CUR_TERM
if before is None and after is not None:
# Curses was initialized during this test in the parent process
test_name = request.node.nodeid
pytest.fail(
f"\n{'=' * 70}\n"
f"CURSES CONTAMINATION DETECTED in parent pytest process!\n"
f"Test: {test_name}\n"
f"Terminal kind initialized: {after}\n"
f"\n"
f"This test instantiated Terminal() or TestTerminal() in the parent\n"
f"pytest process instead of within @as_subprocess. This causes curses\n"
f"to be initialized with a specific terminal kind, which cannot be\n"
f"changed for the remainder of the test session, breaking later tests!\n"
f"\n"
f"FIX: Ensure Terminal() instantiation is within @as_subprocess:\n"
f" @as_subprocess\n"
f" def child():\n"
f" term = TestTerminal(...)\n"
f" ...\n"
f" assert ..\n"
f" child()\n"
f"{'=' * 70}\n"
)
@pytest.fixture(params=all_terms_params)
def all_terms(request):
"""Common kind values for all kinds of terminals."""
return request.param
@pytest.fixture(params=many_lines_params)
def many_lines(request):
"""Various number of lines for screen height."""
return request.param
@pytest.fixture(params=many_columns_params)
def many_columns(request):
"""Various number of columns for screen width."""
return request.param
|