summaryrefslogtreecommitdiff
path: root/testing/support.py
blob: f0677194a756bd96f2ba825f586978f69e234e5c (plain)
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
import sys, os

if sys.version_info < (3,):
    __all__ = ['u', 'arraytostring']

    class U(object):
        def __add__(self, other):
            return eval('u'+repr(other).replace(r'\\u', r'\u')
                                       .replace(r'\\U', r'\U'))
    u = U()
    long = long     # for further "from testing.support import long"
    assert u+'a\x00b' == eval(r"u'a\x00b'")
    assert u+'a\u1234b' == eval(r"u'a\u1234b'")
    assert u+'a\U00012345b' == eval(r"u'a\U00012345b'")
    def arraytostring(a):
        return a.tostring()

else:
    __all__ = ['u', 'unicode', 'long', 'arraytostring']
    u = ""
    unicode = str
    long = int
    def arraytostring(a):
        return a.tobytes()


class StdErrCapture(object):
    """Capture writes to sys.stderr (not to the underlying file descriptor)."""
    def __enter__(self):
        try:
            from StringIO import StringIO
        except ImportError:
            from io import StringIO
        self.old_stderr = sys.stderr
        sys.stderr = f = StringIO()
        if hasattr(sys, '__unraisablehook__'):           # work around pytest
            self.old_unraisablebook = sys.unraisablehook # on recent CPythons
            sys.unraisablehook = sys.__unraisablehook__
        return f
    def __exit__(self, *args):
        sys.stderr = self.old_stderr
        if hasattr(self, 'old_unraisablebook'):
            sys.unraisablehook = self.old_unraisablebook


class FdWriteCapture(object):
    """xxx limited to capture at most 512 bytes of output, according
    to the Posix manual."""

    def __init__(self, capture_fd=2):    # stderr by default
        if sys.platform == 'win32':
            import pytest
            pytest.skip("seems not to work, too bad")
        self.capture_fd = capture_fd

    def __enter__(self):
        import os
        self.read_fd, self.write_fd = os.pipe()
        self.copy_fd = os.dup(self.capture_fd)
        os.dup2(self.write_fd, self.capture_fd)
        return self

    def __exit__(self, *args):
        import os
        os.dup2(self.copy_fd, self.capture_fd)
        os.close(self.copy_fd)
        os.close(self.write_fd)
        self._value = os.read(self.read_fd, 512)
        os.close(self.read_fd)

    def getvalue(self):
        return self._value

def _verify(ffi, module_name, preamble, *args, **kwds):
    import imp
    from cffi.recompiler import recompile
    from .udir import udir
    assert module_name not in sys.modules, "module name conflict: %r" % (
        module_name,)
    kwds.setdefault('tmpdir', str(udir))
    outputfilename = recompile(ffi, module_name, preamble, *args, **kwds)
    module = imp.load_dynamic(module_name, outputfilename)
    #
    # hack hack hack: copy all *bound methods* from module.ffi back to the
    # ffi instance.  Then calls like ffi.new() will invoke module.ffi.new().
    for name in dir(module.ffi):
        if not name.startswith('_'):
            attr = getattr(module.ffi, name)
            if attr is not getattr(ffi, name, object()):
                setattr(ffi, name, attr)
    def typeof_disabled(*args, **kwds):
        raise NotImplementedError
    ffi._typeof = typeof_disabled
    for name in dir(ffi):
        if not name.startswith('_') and not hasattr(module.ffi, name):
            setattr(ffi, name, NotImplemented)
    return module.lib


# For testing, we call gcc with "-Werror".  This is fragile because newer
# versions of gcc are always better at producing warnings, particularly for
# auto-generated code.  We need here to adapt and silence them as needed.

if sys.platform == 'win32':
    extra_compile_args = []      # no obvious -Werror equivalent on MSVC
else:
    if (sys.platform == 'darwin' and
          [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]):
        # assume a standard clang or gcc
        extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
                              '-Wno-unused-parameter',
                              '-Wno-unreachable-code']
        # special things for clang
        extra_compile_args.append('-Qunused-arguments')
    else:
        # assume a standard gcc
        extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
                              '-Wno-unused-parameter',
                              '-Wno-unreachable-code']

is_musl = False
if sys.platform == 'linux':
    try:
        from packaging.tags import platform_tags
        is_musl = any(t.startswith('musllinux') for t in platform_tags())
        del platform_tags
    except ImportError:
        pass