File: terminals.py

package info (click to toggle)
python-invoke 1.4.1%2Bds-0.1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,704 kB
  • sloc: python: 11,377; makefile: 18; sh: 12
file content (78 lines) | stat: -rw-r--r-- 2,936 bytes parent folder | download
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
import fcntl
import termios

from mock import Mock, patch
from pytest import skip, mark

from invoke.terminals import pty_size, bytes_to_read, WINDOWS

# Skip on Windows CI, it may blow up on one of these tests
pytestmark = mark.skipif(
    WINDOWS, reason="Low level terminal tests only work well on POSIX"
)


# NOTE: 'with character_buffered()' tests are in runners.py as it's a lot
# easier to test some aspects in a non-unit sense (e.g. a keyboard-interrupting
# Runner subclass). MEH.


class terminals:
    class pty_size:
        @patch("fcntl.ioctl", wraps=fcntl.ioctl)
        def calls_fcntl_with_TIOCGWINSZ(self, ioctl):
            # Test the default (Unix) implementation because that's all we
            # can realistically do here.
            pty_size()
            assert ioctl.call_args_list[0][0][1] == termios.TIOCGWINSZ

        @patch("sys.stdout")
        @patch("fcntl.ioctl")
        def defaults_to_80x24_when_stdout_not_a_tty(self, ioctl, stdout):
            # Make sure stdout acts like a real stream (means failure is
            # more obvious)
            stdout.fileno.return_value = 1
            # Ensure it fails the isatty() test too
            stdout.isatty.return_value = False
            # Test
            assert pty_size() == (80, 24)

        @patch("sys.stdout")
        @patch("fcntl.ioctl")
        def uses_default_when_stdout_lacks_fileno(self, ioctl, stdout):
            # i.e. when accessing it throws AttributeError
            stdout.fileno.side_effect = AttributeError
            assert pty_size() == (80, 24)

        @patch("sys.stdout")
        @patch("fcntl.ioctl")
        def uses_default_when_stdout_triggers_ioctl_error(self, ioctl, stdout):
            ioctl.side_effect = TypeError
            assert pty_size() == (80, 24)

    class bytes_to_read_:
        @patch("invoke.terminals.fcntl")
        def returns_1_when_stream_lacks_fileno(self, fcntl):
            # A fileno() that exists but returns a non-int is a quick way
            # to fail util.has_fileno().
            assert bytes_to_read(Mock(fileno=lambda: None)) == 1
            assert not fcntl.ioctl.called

        @patch("invoke.terminals.fcntl")
        def returns_1_when_stream_has_fileno_but_is_not_a_tty(self, fcntl):
            # It blows up otherwise anyways (struct.unpack gets mad because
            # result isn't a string of the right length) but let's make
            # ioctl die similarly to the real world case we're testing for
            # here (#425)
            fcntl.ioctl.side_effect = IOError(
                "Operation not supported by device"
            )
            stream = Mock(isatty=lambda: False, fileno=lambda: 17)  # arbitrary
            assert bytes_to_read(stream) == 1
            assert not fcntl.ioctl.called

        def returns_FIONREAD_result_when_stream_is_a_tty(self):
            skip()

        def returns_1_on_windows(self):
            skip()