A Foreign Function Interface package for calling C libraries from Python.
# -*- coding: utf-8 -*-
#
# CFFI documentation build configuration file, created by
# sphinx-quickstart on Thu Jun 14 16:37:47 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys, os

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.append(os.path.abspath('.'))

# -- General configuration -----------------------------------------------------

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

# The suffix of source filenames.
source_suffix = '.rst'

# The encoding of source files.
#source_encoding = 'utf-8'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'CFFI'
copyright = u'2012-2018, Armin Rigo, Maciej Fijalkowski'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.17'
# The full version, including alpha/beta/rc tags.
release = '1.17.0.dev0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None

# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'

# List of documents that shouldn't be included in the build.
#unused_docs = []

# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []

# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None

# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True

# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True

# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'

# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []


# -- Options for HTML output ---------------------------------------------------

# The theme to use for HTML and HTML Help pages.  Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
#html_theme = 'default'

# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []

# The name for this set of Sphinx documents.  If None, it defaults to
# "<project> v<release> documentation".
#html_title = None

# A shorter title for the navigation bar.  Default is the same as html_title.
#html_short_title = None

# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None

# The name of an image file (within the static path) to use as favicon of the
# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']

# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True

# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}

# If false, no module index is generated.
#html_use_modindex = True

# If false, no index is generated.
#html_use_index = True

# If true, the index is split into individual pages for each letter.
#html_split_index = False

# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True

# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it.  The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''

# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''

# Output file base name for HTML help builder.
htmlhelp_basename = 'CFFIdoc'


# -- Options for LaTeX output --------------------------------------------------

# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'

# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
  ('index', 'CFFI.tex', u'CFFI Documentation',
   u'Armin Rigo, Maciej Fijalkowski', 'manual'),
]

# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None

# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False

# Additional stuff for the LaTeX preamble.
#latex_preamble = ''

# Documents to append as an appendix to all manuals.
#latex_appendices = []

# If false, no module index is generated.
#latex_use_modindex = True

doc/source/conf.py
python-cffi/cffi
import sys, os, platform
import subprocess
import errno

# the setuptools distutils shim should make distutils available, but this will definitely do
# it, since setuptools is now required at build-time
import setuptools


sources = ['src/c/_cffi_backend.c']
libraries = ['ffi']
include_dirs = ['/usr/include/ffi',
                '/usr/include/libffi']    # may be changed by pkg-config
define_macros = [('FFI_BUILDING', '1')]   # for linking with libffi static library
library_dirs = []
extra_compile_args = []
extra_link_args = []


def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False):
    pkg_config = os.environ.get('PKG_CONFIG','pkg-config')
    try:
        p = subprocess.Popen([pkg_config, option, 'libffi'],
                             stdout=subprocess.PIPE)
    except OSError as e:
        if e.errno not in [errno.ENOENT, errno.EACCES]:
            raise
    else:
        t = p.stdout.read().decode().strip()
        p.stdout.close()
        if p.wait() == 0:
            res = t.split()
            # '-I/usr/...' -> '/usr/...'
            for x in res:
                assert x.startswith(result_prefix)
            res = [x[len(result_prefix):] for x in res]
            #print 'PKG_CONFIG:', option, res
            #
            sysroot = sysroot and os.environ.get('PKG_CONFIG_SYSROOT_DIR', '')
            if sysroot:
                # old versions of pkg-config don't support this env var,
                # so here we emulate its effect if needed
                res = [path if path.startswith(sysroot)
                            else sysroot + path
                         for path in res]
            #
            resultlist[:] = res

no_compiler_found = False
def no_working_compiler_found():
    sys.stderr.write("""
    No working compiler found, or bogus compiler options passed to
    the compiler from Python's standard "distutils" module.  See
    the error messages above.  Likely, the problem is not related
    to CFFI but generic to the setup.py of any Python package that
    tries to compile C code.  (Hints: on OS/X 10.8, for errors about
    -mno-fused-madd see http://stackoverflow.com/questions/22313407/
    Otherwise, see https://wiki.python.org/moin/CompLangPython or
    the IRC channel #python on irc.libera.chat.)

    Trying to continue anyway.  If you are trying to install CFFI from
    a build done in a different context, you can ignore this warning.
    \n""")
    global no_compiler_found
    no_compiler_found = True

def get_config():
    from distutils.core import Distribution
    from distutils.sysconfig import get_config_vars
    get_config_vars()      # workaround for a bug of distutils, e.g. on OS/X
    config = Distribution().get_command_obj('config')
    return config

def ask_supports_thread():
    config = get_config()
    ok = (sys.platform != 'win32' and
          config.try_compile('__thread int some_threadlocal_variable_42;'))
    if ok:
        define_macros.append(('USE__THREAD', None))
    else:
        ok1 = config.try_compile('int some_regular_variable_42;')
        if not ok1:
            no_working_compiler_found()
        else:
            sys.stderr.write("Note: will not use '__thread' in the C code\n")
            _safe_to_ignore()

def ask_supports_sync_synchronize():
    if sys.platform == 'win32' or no_compiler_found:
        return
    config = get_config()
    ok = config.try_link('int main(void) { __sync_synchronize(); return 0; }')
    if ok:
        define_macros.append(('HAVE_SYNC_SYNCHRONIZE', None))
    else:
        sys.stderr.write("Note: will not use '__sync_synchronize()'"
                         " in the C code\n")
        _safe_to_ignore()

def _safe_to_ignore():
    sys.stderr.write("***** The above error message can be safely ignored.\n\n")

def uses_msvc():
    config = get_config()
    return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif')

def use_pkg_config():
    if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'):
        use_homebrew_for_libffi()

    _ask_pkg_config(include_dirs,       '--cflags-only-I', '-I', sysroot=True)
    _ask_pkg_config(extra_compile_args, '--cflags-only-other')
    _ask_pkg_config(library_dirs,       '--libs-only-L', '-L', sysroot=True)
    _ask_pkg_config(extra_link_args,    '--libs-only-other')
    _ask_pkg_config(libraries,          '--libs-only-l', '-l')

def use_homebrew_for_libffi():
    # We can build by setting:
    # PKG_CONFIG_PATH = $(brew --prefix libffi)/lib/pkgconfig
    with os.popen('brew --prefix libffi') as brew_prefix_cmd:
        prefix = brew_prefix_cmd.read().strip()
    pkgconfig = os.path.join(prefix, 'lib', 'pkgconfig')
    os.environ['PKG_CONFIG_PATH'] = (
        os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig)

if sys.platform == "win32" and uses_msvc():
    if platform.machine() == "ARM64":
        include_dirs.append(os.path.join("src/c/libffi_arm64/include"))
        library_dirs.append(os.path.join("src/c/libffi_arm64"))
    else:
        COMPILE_LIBFFI = 'src/c/libffi_x86_x64'    # from the CPython distribution
        assert os.path.isdir(COMPILE_LIBFFI), "directory not found!"
        include_dirs[:] = [COMPILE_LIBFFI]
        libraries[:] = []
        _filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)]
        _filenames = [filename for filename in _filenames
                            if filename.endswith('.c')]
        if sys.maxsize > 2**32:
            # 64-bit: unlist win32.c, and add instead win64.obj.  If the obj
            # happens to get outdated at some point in the future, you need to
            # rebuild it manually from win64.asm.
            _filenames.remove('win32.c')
            extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj'))
        sources.extend(os.path.join(COMPILE_LIBFFI, filename)
                    for filename in _filenames)
else:
    use_pkg_config()
    ask_supports_thread()
    ask_supports_sync_synchronize()

if 'darwin' in sys.platform:
    # priority is given to `pkg_config`, but always fall back on SDK's libffi.
    extra_compile_args += ['-iwithsysroot/usr/include/ffi']

if 'freebsd' in sys.platform:
    include_dirs.append('/usr/local/include')
    library_dirs.append('/usr/local/lib')

forced_extra_objs = os.environ.get('CFFI_FORCE_STATIC', [])
if forced_extra_objs:
    forced_extra_objs = forced_extra_objs.split(';')


if __name__ == '__main__':
    from setuptools import setup, Distribution, Extension

    class CFFIDistribution(Distribution):
        def has_ext_modules(self):
            # Event if we don't have extension modules (e.g. on PyPy) we want to
            # claim that we do so that wheels get properly tagged as Python
            # specific.  (thanks dstufft!)
            return True

    # On PyPy, cffi is preinstalled and it is not possible, at least for now,
    # to install a different version.  We work around it by making the setup()
    # arguments mostly empty in this case.
    cpython = ('_cffi_backend' not in sys.builtin_module_names)

    install_requires = []
    if cpython:
        install_requires.append('pycparser')

    setup(
        name='cffi',
        description='Foreign Function Interface for Python calling C code.',
        long_description="""
CFFI
====

Foreign Function Interface for Python calling C code.
Please see the `Documentation <http://cffi.readthedocs.org/>`_.

Contact
-------

`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
""",
        version='1.17.0.dev0',
        python_requires='>=3.8',
        packages=['cffi'] if cpython else [],
        package_dir={"": "src"},
        package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h', 
                               '_embedding.h', '_cffi_errors.h']}
                     if cpython else {},
        zip_safe=False,

        url='http://cffi.readthedocs.org',
        author='Armin Rigo, Maciej Fijalkowski',
        author_email='python-cffi@googlegroups.com',

        license='MIT',

        distclass=CFFIDistribution,
        ext_modules=[Extension(
            name='_cffi_backend',
            include_dirs=include_dirs,
            sources=sources,
            libraries=libraries,
            define_macros=define_macros,
            library_dirs=library_dirs,
            extra_compile_args=extra_compile_args,
            extra_link_args=extra_link_args,
            extra_objects=forced_extra_objs,
        )] if cpython else [],

        install_requires=install_requires,

        entry_points = {
            "distutils.setup_keywords": [
                "cffi_modules = cffi.setuptools_ext:cffi_modules",
            ],
        },

        classifiers=[
            'Programming Language :: Python',
            'Programming Language :: Python :: 3',
            'Programming Language :: Python :: 3.8',
            'Programming Language :: Python :: 3.9',
            'Programming Language :: Python :: 3.10',
            'Programming Language :: Python :: 3.11',
            'Programming Language :: Python :: 3.12',
            'Programming Language :: Python :: Implementation :: CPython',
            'Programming Language :: Python :: Implementation :: PyPy',
            'License :: OSI Approved :: MIT License',
        ],
    )

setup.py
python-cffi/cffi
import pytest
import sys

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

def _setup_path():
    import os, sys
    sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
_setup_path()
from _cffi_backend import *
from _cffi_backend import _get_types, _get_common_types
try:
    from _cffi_backend import _testfunc
except ImportError:
    def _testfunc(num):
        pytest.skip("_testunc() not available")
from _cffi_backend import __version__

# ____________________________________________________________

import sys
assert __version__ == "1.17.0.dev0", ("This test_c.py file is for testing a version"
                                 " of cffi that differs from the one that we"
                                 " get from 'import _cffi_backend'")
if sys.version_info < (3,):
    type_or_class = "type"
    mandatory_b_prefix = ''
    mandatory_u_prefix = 'u'
    bytechr = chr
    bitem2bchr = lambda x: x
    class U(object):
        def __add__(self, other):
            return eval('u'+repr(other).replace(r'\\u', r'\u')
                                       .replace(r'\\U', r'\U'))
    u = U()
    str2bytes = str
    strict_compare = False
else:
    type_or_class = "class"
    long = int
    unicode = str
    unichr = chr
    mandatory_b_prefix = 'b'
    mandatory_u_prefix = ''
    bytechr = lambda n: bytes([n])
    bitem2bchr = bytechr
    u = ""
    str2bytes = lambda s: bytes(s, "ascii")
    strict_compare = True

def size_of_int():
    BInt = new_primitive_type("int")
    return sizeof(BInt)

def size_of_long():
    BLong = new_primitive_type("long")
    return sizeof(BLong)

def size_of_ptr():
    BInt = new_primitive_type("int")
    BPtr = new_pointer_type(BInt)
    return sizeof(BPtr)


def find_and_load_library(name, flags=RTLD_NOW):
    import ctypes.util
    if name is None:
        path = None
    else:
        path = ctypes.util.find_library(name)
        if path is None and sys.platform == 'darwin' and sys.version_info[:2] == (3, 8):
            pytest.xfail("find_library usually broken on MacOS Python 3.8")
        if path is None and name == 'c':
            assert sys.platform == 'win32'
            assert (sys.version_info >= (3,) or
                    '__pypy__' in sys.builtin_module_names)
            pytest.skip("dlopen(None) cannot work on Windows "
                         "with PyPy or Python 3")
    return load_library(path, flags)

def test_load_library():
    x = find_and_load_library('c')
    assert repr(x).startswith("<clibrary '")
    x = find_and_load_library('c', RTLD_NOW | RTLD_GLOBAL)
    assert repr(x).startswith("<clibrary '")
    x = find_and_load_library('c', RTLD_LAZY)
    assert repr(x).startswith("<clibrary '")

def test_all_rtld_symbols():
    import sys
    FFI_DEFAULT_ABI        # these symbols must be defined
    FFI_CDECL
    RTLD_LAZY
    RTLD_NOW
    RTLD_GLOBAL
    RTLD_LOCAL
    if sys.platform.startswith("linux"):
        RTLD_NODELETE
        RTLD_NOLOAD
        if not is_musl:
            RTLD_DEEPBIND

def test_new_primitive_type():
    pytest.raises(KeyError, new_primitive_type, "foo")
    p = new_primitive_type("signed char")
    assert repr(p) == "<ctype 'signed char'>"

def check_dir(p, expected):
    got = [name for name in dir(p) if not name.startswith('_')]
    assert got == sorted(expected)

def test_inspect_primitive_type():
    p = new_primitive_type("signed char")
    assert p.kind == "primitive"
    assert p.cname == "signed char"
    check_dir(p, ['cname', 'kind'])

def test_cast_to_signed_char():
    p = new_primitive_type("signed char")
    x = cast(p, -65 + 17*256)
    assert repr(x) == "<cdata 'signed char' -65>"
    assert repr(type(x)) == "<%s '_cffi_backend._CDataBase'>" % type_or_class
    assert int(x) == -65
    x = cast(p, -66 + (1<<199)*256)
    assert repr(x) == "<cdata 'signed char' -66>"
    assert int(x) == -66
    assert (x == cast(p, -66)) is True
    assert (x != cast(p, -66)) is False
    q = new_primitive_type("short")
    assert (x == cast(q, -66)) is True
    assert (x != cast(q, -66)) is False

def test_sizeof_type():
    pytest.raises(TypeError, sizeof, 42.5)
    p = new_primitive_type("short")
    assert sizeof(p) == 2

def test_integer_types():
    for name in ['signed char', 'short', 'int', 'long', 'long long']:
        p = new_primitive_type(name)
        size = sizeof(p)
        min = -(1 << (8*size-1))
        max = (1 << (8*size-1)) - 1
        assert int(cast(p, min)) == min
        assert int(cast(p, max)) == max
        assert int(cast(p, min - 1)) == max
        assert int(cast(p, max + 1)) == min
        pytest.raises(TypeError, cast, p, None)
        assert long(cast(p, min - 1)) == max
        assert int(cast(p, b'\x08')) == 8
        assert int(cast(p, u+'\x08')) == 8
    for name in ['char', 'short', 'int', 'long', 'long long']:
        p = new_primitive_type('unsigned ' + name)
        size = sizeof(p)
        max = (1 << (8*size)) - 1
        assert int(cast(p, 0)) == 0
        assert int(cast(p, max)) == max
        assert int(cast(p, -1)) == max
        assert int(cast(p, max + 1)) == 0
        assert long(cast(p, -1)) == max
        assert int(cast(p, b'\xFE')) == 254
        assert int(cast(p, u+'\xFE')) == 254

def test_no_float_on_int_types():
    p = new_primitive_type('long')
    pytest.raises(TypeError, float, cast(p, 42))
    pytest.raises(TypeError, complex, cast(p, 42))

def test_float_types():
    INF = 1E200 * 1E200
    for name in ["float", "double"]:
        p = new_primitive_type(name)
        assert bool(cast(p, 0)) is False      # since 1.7
        assert bool(cast(p, -0.0)) is False   # since 1.7
        assert bool(cast(p, 1e-42)) is True
        assert bool(cast(p, -1e-42)) is True
        assert bool(cast(p, INF))
        assert bool(cast(p, -INF))
        assert bool(cast(p, float("nan")))
        assert int(cast(p, -150)) == -150
        assert int(cast(p, 61.91)) == 61
        assert long(cast(p, 61.91)) == 61
        assert type(int(cast(p, 61.91))) is int
        assert type(int(cast(p, 1E22))) is long
        assert type(long(cast(p, 61.91))) is long
        assert type(long(cast(p, 1E22))) is long
        pytest.raises(OverflowError, int, cast(p, INF))
        pytest.raises(OverflowError, int, cast(p, -INF))
        assert float(cast(p, 1.25)) == 1.25
        assert float(cast(p, INF)) == INF
        assert float(cast(p, -INF)) == -INF
        if name == "float":
            assert float(cast(p, 1.1)) != 1.1     # rounding error
            assert float(cast(p, 1E200)) == INF   # limited range

        assert cast(p, -1.1) == cast(p, -1.1)
        assert repr(float(cast(p, -0.0))) == '-0.0'
        assert float(cast(p, b'\x09')) == 9.0
        assert float(cast(p, u+'\x09')) == 9.0
        assert float(cast(p, True)) == 1.0
        pytest.raises(TypeError, cast, p, None)

def test_complex_types():
    INF = 1E200 * 1E200
    for name in ["float", "double"]:
        p = new_primitive_type(name + " _Complex")
        assert bool(cast(p, 0)) is False
        assert bool(cast(p, INF))
        assert bool(cast(p, -INF))
        assert bool(cast(p, 0j)) is False
        assert bool(cast(p, INF*1j))
        assert bool(cast(p, -INF*1j))
        # "can't convert complex to float", like CPython's "float(0j)"
        pytest.raises(TypeError, int, cast(p, -150))
        pytest.raises(TypeError, long, cast(p, -150))
        pytest.raises(TypeError, float, cast(p, -150))
        assert complex(cast(p, 1.25)) == 1.25
        assert complex(cast(p, 1.25j)) == 1.25j
        assert complex(cast(p, complex(0,INF))) == complex(0,INF)
        assert complex(cast(p, -INF)) == -INF
        if name == "float":
            assert complex(cast(p, 1.1j)) != 1.1j         # rounding error
            assert complex(cast(p, 1E200+3j)) == INF+3j   # limited range
            assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # limited range

        assert cast(p, -1.1j) == cast(p, -1.1j)
        assert repr(complex(cast(p, -0.0)).real) == '-0.0'
        #assert repr(complex(cast(p, -0j))) == '-0j'   # http://bugs.python.org/issue29602
        assert complex(cast(p, b'\x09')) == 9.0 + 0j
        assert complex(cast(p, u+'\x09')) == 9.0 + 0j
        assert complex(cast(p, True)) == 1.0 + 0j
        pytest.raises(TypeError, cast, p, None)
        #
        pytest.raises(TypeError, cast, new_primitive_type(name), 1+0j)
        #
        for basetype in ["char", "int", "uint64_t", "float",
                         "double", "long double"]:
            baseobj = cast(new_primitive_type(basetype), 65)
            pytest.raises(TypeError, complex, baseobj)
        #
        BArray = new_array_type(new_pointer_type(p), 10)
        x = newp(BArray, None)
        x[5] = 12.34 + 56.78j
        assert type(x[5]) is complex
        assert abs(x[5] - (12.34 + 56.78j)) < 1e-5
        assert (x[5] == 12.34 + 56.78j) == (name == "double")  # rounding error
        #
        class Foo:
            def __complex__(self):
                return 2 + 3j
        assert complex(Foo()) == 2 + 3j
        assert complex(cast(p, Foo())) == 2 + 3j
    pytest.raises(TypeError, cast, new_primitive_type("int"), 1+0j)

def test_character_type():
    p = new_primitive_type("char")
    assert bool(cast(p, 'A')) is True
    assert bool(cast(p, '\x00')) is False    # since 1.7
    assert cast(p, '\x00') == cast(p, -17*256)
    assert int(cast(p, 'A')) == 65
    assert long(cast(p, 'A')) == 65
    assert type(int(cast(p, 'A'))) is int
    assert type(long(cast(p, 'A'))) is long
    assert str(cast(p, 'A')) == repr(cast(p, 'A'))
    assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix
    assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix
    assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix

def test_pointer_type():
    p = new_primitive_type("int")
    assert repr(p) == "<ctype 'int'>"
    p = new_pointer_type(p)
    assert repr(p) == "<ctype 'int *'>"
    p = new_pointer_type(p)
    assert repr(p) == "<ctype 'int * *'>"
    p = new_pointer_type(p)
    assert repr(p) == "<ctype 'int * * *'>"

def test_inspect_pointer_type():
    p1 = new_primitive_type("int")
    p2 = new_pointer_type(p1)
    assert p2.kind == "pointer"
    assert p2.cname == "int *"
    assert p2.item is p1
    check_dir(p2, ['cname', 'kind', 'item'])
    p3 = new_pointer_type(p2)
    assert p3.item is p2

def test_pointer_to_int():
    BInt = new_primitive_type("int")
    pytest.raises(TypeError, newp, BInt)
    pytest.raises(TypeError, newp, BInt, None)
    BPtr = new_pointer_type(BInt)
    p = newp(BPtr)
    assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
    p = newp(BPtr, None)
    assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
    p = newp(BPtr, 5000)
    assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
    q = cast(BPtr, p)
    assert repr(q).startswith("<cdata 'int *' 0x")
    assert p == q
    assert hash(p) == hash(q)
    e = pytest.raises(TypeError, newp, new_array_type(BPtr, None), None)
    assert str(e.value) == (
        "expected new array length or list/tuple/str, not NoneType")

def test_pointer_bool():
    BInt = new_primitive_type("int")
    BPtr = new_pointer_type(BInt)
    p = cast(BPtr, 0)
    assert bool(p) is False
    p = cast(BPtr, 42)
    assert bool(p) is True

def test_pointer_to_pointer():
    BInt = new_primitive_type("int")
    BPtr = new_pointer_type(BInt)
    BPtrPtr = new_pointer_type(BPtr)
    p = newp(BPtrPtr, None)
    assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr()

def test_reading_pointer_to_int():
    BInt = new_primitive_type("int")
    BPtr = new_pointer_type(BInt)
    p = newp(BPtr, None)
    assert p[0] == 0
    p = newp(BPtr, 5000)
    assert p[0] == 5000
    with pytest.raises(IndexError):
        p[1]
    with pytest.raises(IndexError):
        p[-1]

def test_reading_pointer_to_float():
    BFloat = new_primitive_type("float")
    pytest.raises(TypeError, newp, BFloat, None)
    BPtr = new_pointer_type(BFloat)
    p = newp(BPtr, None)
    assert p[0] == 0.0 and type(p[0]) is float
    p = newp(BPtr, 1.25)
    assert p[0] == 1.25 and type(p[0]) is float
    p = newp(BPtr, 1.1)
    assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5   # rounding errors

def test_cast_float_to_int():
    for type in ["int", "unsigned int", "long", "unsigned long",
                 "long long", "unsigned long long"]:
        p = new_primitive_type(type)
        assert int(cast(p, 4.2)) == 4
        pytest.raises(TypeError, newp, new_pointer_type(p), 4.2)

def test_newp_integer_types():
    for name in ['signed char', 'short', 'int', 'long', 'long long']:
        p = new_primitive_type(name)
        pp = new_pointer_type(p)
        size = sizeof(p)
        min = -(1 << (8*size-1))
        max = (1 << (8*size-1)) - 1
        assert newp(pp, min)[0] == min
        assert newp(pp, max)[0] == max
        pytest.raises(OverflowError, newp, pp, min - 2 ** 32)
        pytest.raises(OverflowError, newp, pp, min - 2 ** 64)
        pytest.raises(OverflowError, newp, pp, max + 2 ** 32)
        pytest.raises(OverflowError, newp, pp, max + 2 ** 64)
        pytest.raises(OverflowError, newp, pp, min - 1)
        pytest.raises(OverflowError, newp, pp, max + 1)
        pytest.raises(OverflowError, newp, pp, min - 1 - 2 ** 32)
        pytest.raises(OverflowError, newp, pp, min - 1 - 2 ** 64)
        pytest.raises(OverflowError, newp, pp, max + 1)
        pytest.raises(OverflowError, newp, pp, max + 1 + 2 ** 32)
        pytest.raises(OverflowError, newp, pp, max + 1 + 2 ** 64)
        pytest.raises(TypeError, newp, pp, 1.0)
    for name in ['char', 'short', 'int', 'long', 'long long']:
        p = new_primitive_type('unsigned ' + name)
        pp = new_pointer_type(p)
        size = sizeof(p)
        max = (1 << (8*size)) - 1
        assert newp(pp, 0)[0] == 0
        assert newp(pp, max)[0] == max
        pytest.raises(OverflowError, newp, pp, -1)
        pytest.raises(OverflowError, newp, pp, max + 1)

def test_reading_pointer_to_char():
    BChar = new_primitive_type("char")
    pytest.raises(TypeError, newp, BChar, None)
    BPtr = new_pointer_type(BChar)
    p = newp(BPtr, None)
    assert p[0] == b'\x00'
    p = newp(BPtr, b'A')
    assert p[0] == b'A'
    pytest.raises(TypeError, newp, BPtr, 65)
    pytest.raises(TypeError, newp, BPtr, b"foo")
    pytest.raises(TypeError, newp, BPtr, u+"foo")
    c = cast(BChar, b'A')
    assert str(c) == repr(c)
    assert int(c) == ord(b'A')
    pytest.raises(TypeError, cast, BChar, b'foo')
    pytest.raises(TypeError, cast, BChar, u+'foo')
    e = pytest.raises(TypeError, newp, new_array_type(BPtr, None), 12.3)
    assert str(e.value) == (
        "expected new array length or list/tuple/str, not float")

def test_reading_pointer_to_pointer():
    BVoidP = new_pointer_type(new_void_type())
    BCharP = new_pointer_type(new_primitive_type("char"))
    BInt = new_primitive_type("int")
    BIntPtr = new_pointer_type(BInt)
    BIntPtrPtr = new_pointer_type(BIntPtr)
    q = newp(BIntPtr, 42)
    assert q[0] == 42
    p = newp(BIntPtrPtr, None)
    assert p[0] is not None
    assert p[0] == cast(BVoidP, 0)
    assert p[0] == cast(BCharP, 0)
    assert p[0] != None
    assert repr(p[0]) == "<cdata 'int *' NULL>"
    p[0] = q
    assert p[0] != cast(BVoidP, 0)
    assert p[0] != cast(BCharP, 0)
    assert p[0][0] == 42
    q[0] += 1
    assert p[0][0] == 43
    p = newp(BIntPtrPtr, q)
    assert p[0][0] == 43

def test_load_standard_library():
    if sys.platform == "win32":
        pytest.raises(OSError, find_and_load_library, None)
        return
    x = find_and_load_library(None)
    BVoidP = new_pointer_type(new_void_type())
    assert x.load_function(BVoidP, 'strcpy')
    pytest.raises(AttributeError, x.load_function,
                   BVoidP, 'xxx_this_function_does_not_exist')
    # the next one is from 'libm', not 'libc', but we assume
    # that it is already loaded too, so it should work
    assert x.load_function(BVoidP, 'sqrt')
    #
    x.close_lib()
    pytest.raises(ValueError, x.load_function, BVoidP, 'sqrt')
    x.close_lib()

def test_no_len_on_nonarray():
    p = new_primitive_type("int")
    pytest.raises(TypeError, len, cast(p, 42))

def test_cmp_none():
    p = new_primitive_type("int")
    x = cast(p, 42)
    assert (x == None) is False
    assert (x != None) is True
    assert (x == ["hello"]) is False
    assert (x != ["hello"]) is True
    y = cast(p, 0)
    assert (y == None) is False

def test_invalid_indexing():
    p = new_primitive_type("int")
    x = cast(p, 42)
    with pytest.raises(TypeError):
        x[0]

def test_default_str():
    BChar = new_primitive_type("char")
    x = cast(BChar, 42)
    assert str(x) == repr(x)
    BInt = new_primitive_type("int")
    x = cast(BInt, 42)
    assert str(x) == repr(x)
    BArray = new_array_type(new_pointer_type(BInt), 10)
    x = newp(BArray, None)
    assert str(x) == repr(x)

def test_default_unicode():
    BInt = new_primitive_type("int")
    x = cast(BInt, 42)
    assert unicode(x) == unicode(repr(x))
    BArray = new_array_type(new_pointer_type(BInt), 10)
    x = newp(BArray, None)
    assert unicode(x) == unicode(repr(x))

def test_cast_from_cdataint():
    BInt = new_primitive_type("int")
    x = cast(BInt, 0)
    y = cast(new_pointer_type(BInt), x)
    assert bool(y) is False
    #
    x = cast(BInt, 42)
    y = cast(BInt, x)
    assert int(y) == 42
    y = cast(new_primitive_type("char"), x)
    assert int(y) == 42
    y = cast(new_primitive_type("float"), x)
    assert float(y) == 42.0
    #
    z = cast(BInt, 42.5)
    assert int(z) == 42
    z = cast(BInt, y)
    assert int(z) == 42

def test_void_type():
    p = new_void_type()
    assert p.kind == "void"
    assert p.cname == "void"
    check_dir(p, ['kind', 'cname'])

def test_array_type():
    p = new_primitive_type("int")
    assert repr(p) == "<ctype 'int'>"
    #
    pytest.raises(TypeError, new_array_type, new_pointer_type(p), "foo")
    pytest.raises(ValueError, new_array_type, new_pointer_type(p), -42)
    #
    p1 = new_array_type(new_pointer_type(p), None)
    assert repr(p1) == "<ctype 'int[]'>"
    pytest.raises(ValueError, new_array_type, new_pointer_type(p1), 42)
    #
    p1 = new_array_type(new_pointer_type(p), 42)
    p2 = new_array_type(new_pointer_type(p1), 25)
    assert repr(p2) == "<ctype 'int[25][42]'>"
    p2 = new_array_type(new_pointer_type(p1), None)
    assert repr(p2) == "<ctype 'int[][42]'>"
    #
    pytest.raises(OverflowError,
                   new_array_type, new_pointer_type(p), sys.maxsize+1)
    pytest.raises(OverflowError,
                   new_array_type, new_pointer_type(p), sys.maxsize // 3)

def test_inspect_array_type():
    p = new_primitive_type("int")
    p1 = new_array_type(new_pointer_type(p), None)
    assert p1.kind == "array"
    assert p1.cname == "int[]"
    assert p1.item is p
    assert p1.length is None
    check_dir(p1, ['cname', 'kind', 'item', 'length'])
    p1 = new_array_type(new_pointer_type(p), 42)
    assert p1.kind == "array"
    assert p1.cname == "int[42]"
    assert p1.item is p
    assert p1.length == 42
    check_dir(p1, ['cname', 'kind', 'item', 'length'])

def test_array_instance():
    LENGTH = 1423
    p = new_primitive_type("int")
    p1 = new_array_type(new_pointer_type(p), LENGTH)
    a = newp(p1, None)
    assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % (
        LENGTH, LENGTH * size_of_int())
    assert len(a) == LENGTH
    for i in range(LENGTH):
        assert a[i] == 0
    with pytest.raises(IndexError):
        a[LENGTH]
    with pytest.raises(IndexError):
        a[-1]
    for i in range(LENGTH):
        a[i] = i * i + 1
    for i in range(LENGTH):
        assert a[i] == i * i + 1
    with pytest.raises(IndexError) as e:
        a[LENGTH+100] = 500
    assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value)
    pytest.raises(TypeError, int, a)

def test_array_of_unknown_length_instance():
    p = new_primitive_type("int")
    p1 = new_array_type(new_pointer_type(p), None)
    pytest.raises(TypeError, newp, p1, None)
    pytest.raises(ValueError, newp, p1, -42)
    a = newp(p1, 42)
    assert len(a) == 42
    for i in range(42):
        a[i] -= i
    for i in range(42):
        assert a[i] == -i
    with pytest.raises(IndexError):
        a[42]
    with pytest.raises(IndexError):
        a[-1]
    with pytest.raises(IndexError):
        a[42] = 123
    with pytest.raises(IndexError):
        a[-1] = 456

def test_array_of_unknown_length_instance_with_initializer():
    p = new_primitive_type("int")
    p1 = new_array_type(new_pointer_type(p), None)
    a = newp(p1, list(range(42)))
    assert len(a) == 42
    a = newp(p1, tuple(range(142)))
    assert len(a) == 142

def test_array_initializer():
    p = new_primitive_type("int")
    p1 = new_array_type(new_pointer_type(p), None)
    a = newp(p1, list(range(100, 142)))
    for i in range(42):
        assert a[i] == 100 + i
    #
    p2 = new_array_type(new_pointer_type(p), 43)
    a = newp(p2, tuple(range(100, 142)))
    for i in range(42):
        assert a[i] == 100 + i
    assert a[42] == 0      # extra uninitialized item

def test_array_add():
    p = new_primitive_type("int")
    p1 = new_array_type(new_pointer_type(p), 5)    # int[5]
    p2 = new_array_type(new_pointer_type(p1), 3)   # int[3][5]
    a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]])
    assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
        3*5*size_of_int(),)
    assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x")
    assert 0 + a == a + 0 != 1 + a == a + 1
    assert repr(a[0]).startswith("<cdata 'int[5]' 0x")
    assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x")
    assert repr(a[0] + 0).startswith("<cdata 'int *' 0x")
    assert type(a[0][0]) is int
    assert type((a[0] + 0)[0]) is int

def test_array_sub():
    BInt = new_primitive_type("int")
    BArray = new_array_type(new_pointer_type(BInt), 5)   # int[5]
    a = newp(BArray, None)
    p = a + 1
    assert p - a == 1
    assert p - (a+0) == 1
    assert a == (p - 1)
    BPtr = new_pointer_type(new_primitive_type("short"))
    q = newp(BPtr, None)
    with pytest.raises(TypeError):
        p - q
    with pytest.raises(TypeError):
        q - p
    with pytest.raises(TypeError):
        a - q
    with pytest.raises(TypeError) as e:
        q - a
    assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'"

def test_ptr_sub_unaligned():
    BInt = new_primitive_type("int")
    BIntPtr = new_pointer_type(BInt)
    a = cast(BIntPtr, 1240)
    for bi in range(1430, 1438):
        b = cast(BIntPtr, bi)
        if ((bi - 1240) % size_of_int()) == 0:
            assert b - a == (bi - 1240) // size_of_int()
            assert a - b == (1240 - bi) // size_of_int()
        else:
            with pytest.raises(ValueError):
                b - a
            with pytest.raises(ValueError):
                a - b

def test_cast_primitive_from_cdata():
    p = new_primitive_type("int")
    n = cast(p, cast(p, -42))
    assert int(n) == -42
    #
    p = new_primitive_type("unsigned int")
    n = cast(p, cast(p, 42))
    assert int(n) == 42
    #
    p = new_primitive_type("long long")
    n = cast(p, cast(p, -(1<<60)))
    assert int(n) == -(1<<60)
    #
    p = new_primitive_type("unsigned long long")
    n = cast(p, cast(p, 1<<63))
    assert int(n) == 1<<63
    #
    p = new_primitive_type("float")
    n = cast(p, cast(p, 42.5))
    assert float(n) == 42.5
    #
    p = new_primitive_type("char")
    n = cast(p, cast(p, "A"))
    assert int(n) == ord("A")

def test_new_primitive_from_cdata():
    p = new_primitive_type("int")
    p1 = new_pointer_type(p)
    n = newp(p1, cast(p, -42))
    assert n[0] == -42
    #
    p = new_primitive_type("unsigned int")
    p1 = new_pointer_type(p)
    n = newp(p1, cast(p, 42))
    assert n[0] == 42
    #
    p = new_primitive_type("float")
    p1 = new_pointer_type(p)
    n = newp(p1, cast(p, 42.5))
    assert n[0] == 42.5
    #
    p = new_primitive_type("char")
    p1 = new_pointer_type(p)
    n = newp(p1, cast(p, "A"))
    assert n[0] == b"A"

def test_cast_between_pointers():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntA = new_array_type(BIntP, None)
    a = newp(BIntA, [40, 41, 42, 43, 44])
    BShortP = new_pointer_type(new_primitive_type("short"))
    b = cast(BShortP, a)
    c = cast(BIntP, b)
    assert c[3] == 43
    BLongLong = new_primitive_type("long long")
    d = cast(BLongLong, c)
    e = cast(BIntP, d)
    assert e[3] == 43
    f = cast(BIntP, int(d))
    assert f[3] == 43
    #
    b = cast(BShortP, 0)
    assert not b
    c = cast(BIntP, b)
    assert not c
    assert int(cast(BLongLong, c)) == 0

def test_alignof():
    BInt = new_primitive_type("int")
    assert alignof(BInt) == sizeof(BInt)
    BPtr = new_pointer_type(BInt)
    assert alignof(BPtr) == sizeof(BPtr)
    BArray = new_array_type(BPtr, None)
    assert alignof(BArray) == alignof(BInt)

def test_new_struct_type():
    BStruct = new_struct_type("foo")
    assert repr(BStruct) == "<ctype 'foo'>"
    BStruct = new_struct_type("struct foo")
    assert repr(BStruct) == "<ctype 'struct foo'>"
    BPtr = new_pointer_type(BStruct)
    assert repr(BPtr) == "<ctype 'struct foo *'>"
    pytest.raises(ValueError, sizeof, BStruct)
    pytest.raises(ValueError, alignof, BStruct)

def test_new_union_type():
    BUnion = new_union_type("union foo")
    assert repr(BUnion) == "<ctype 'union foo'>"
    BPtr = new_pointer_type(BUnion)
    assert repr(BPtr) == "<ctype 'union foo *'>"

def test_complete_struct():
    BLong = new_primitive_type("long")
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    BStruct = new_struct_type("struct foo")
    assert BStruct.kind == "struct"
    assert BStruct.cname == "struct foo"
    assert BStruct.fields is None
    check_dir(BStruct, ['cname', 'kind', 'fields'])
    #
    complete_struct_or_union(BStruct, [('a1', BLong, -1),
                                       ('a2', BChar, -1),
                                       ('a3', BShort, -1)])
    d = BStruct.fields
    assert len(d) == 3
    assert d[0][0] == 'a1'
    assert d[0][1].type is BLong
    assert d[0][1].offset == 0
    assert d[0][1].bitshift == -1
    assert d[0][1].bitsize == -1
    assert d[1][0] == 'a2'
    assert d[1][1].type is BChar
    assert d[1][1].offset == sizeof(BLong)
    assert d[1][1].bitshift == -1
    assert d[1][1].bitsize == -1
    assert d[2][0] == 'a3'
    assert d[2][1].type is BShort
    assert d[2][1].offset == sizeof(BLong) + sizeof(BShort)
    assert d[2][1].bitshift == -1
    assert d[2][1].bitsize == -1
    assert sizeof(BStruct) == 2 * sizeof(BLong)
    assert alignof(BStruct) == alignof(BLong)

def test_complete_union():
    BLong = new_primitive_type("long")
    BChar = new_primitive_type("char")
    BUnion = new_union_type("union foo")
    assert BUnion.kind == "union"
    assert BUnion.cname == "union foo"
    assert BUnion.fields is None
    complete_struct_or_union(BUnion, [('a1', BLong, -1),
                                      ('a2', BChar, -1)])
    d = BUnion.fields
    assert len(d) == 2
    assert d[0][0] == 'a1'
    assert d[0][1].type is BLong
    assert d[0][1].offset == 0
    assert d[1][0] == 'a2'
    assert d[1][1].type is BChar
    assert d[1][1].offset == 0
    assert sizeof(BUnion) == sizeof(BLong)
    assert alignof(BUnion) == alignof(BLong)

def test_struct_instance():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    p = cast(BStructPtr, 42)
    with pytest.raises(AttributeError) as e:
        p.a1    # opaque
    assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
                            "cannot read fields")
    with pytest.raises(AttributeError) as e:
        p.a1 = 10    # opaque
    assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
                            "cannot write fields")

    complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                       ('a2', BInt, -1)])
    p = newp(BStructPtr, None)
    s = p[0]
    assert s.a1 == 0
    s.a2 = 123
    assert s.a1 == 0
    assert s.a2 == 123
    with pytest.raises(OverflowError):
        s.a1 = sys.maxsize+1
    assert s.a1 == 0
    with pytest.raises(AttributeError) as e:
        p.foobar
    assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
    with pytest.raises(AttributeError) as e:
        p.foobar = 42
    assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
    with pytest.raises(AttributeError) as e:
        s.foobar
    assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
    with pytest.raises(AttributeError) as e:
        s.foobar = 42
    assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
    j = cast(BInt, 42)
    with pytest.raises(AttributeError) as e:
        j.foobar
    assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
    with pytest.raises(AttributeError) as e:
        j.foobar = 42
    assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
    j = cast(new_pointer_type(BInt), 42)
    with pytest.raises(AttributeError) as e:
        j.foobar
    assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
    with pytest.raises(AttributeError) as e:
        j.foobar = 42
    assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
    pp = newp(new_pointer_type(BStructPtr), p)
    with pytest.raises(AttributeError) as e:
        pp.a1
    assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
    with pytest.raises(AttributeError) as e:
        pp.a1 = 42
    assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"

def test_union_instance():
    BInt = new_primitive_type("int")
    BUInt = new_primitive_type("unsigned int")
    BUnion = new_union_type("union bar")
    complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)])
    p = newp(new_pointer_type(BUnion), [-42])
    bigval = -42 + (1 << (8*size_of_int()))
    assert p.a1 == -42
    assert p.a2 == bigval
    p = newp(new_pointer_type(BUnion), {'a2': bigval})
    assert p.a1 == -42
    assert p.a2 == bigval
    pytest.raises(OverflowError, newp, new_pointer_type(BUnion),
                   {'a1': bigval})
    p = newp(new_pointer_type(BUnion), [])
    assert p.a1 == p.a2 == 0

def test_struct_pointer():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                       ('a2', BInt, -1)])
    p = newp(BStructPtr, None)
    assert p.a1 == 0      # read/write via the pointer (C equivalent: '->')
    p.a2 = 123
    assert p.a1 == 0
    assert p.a2 == 123

def test_struct_init_list():
    BVoidP = new_pointer_type(new_void_type())
    BInt = new_primitive_type("int")
    BIntPtr = new_pointer_type(BInt)
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                       ('a2', BInt, -1),
                                       ('a3', BInt, -1),
                                       ('p4', BIntPtr, -1)])
    s = newp(BStructPtr, [123, 456])
    assert s.a1 == 123
    assert s.a2 == 456
    assert s.a3 == 0
    assert s.p4 == cast(BVoidP, 0)
    assert s.p4 != 0
    #
    s = newp(BStructPtr, {'a2': 41122, 'a3': -123})
    assert s.a1 == 0
    assert s.a2 == 41122
    assert s.a3 == -123
    assert s.p4 == cast(BVoidP, 0)
    #
    pytest.raises(KeyError, newp, BStructPtr, {'foobar': 0})
    #
    p = newp(BIntPtr, 14141)
    s = newp(BStructPtr, [12, 34, 56, p])
    assert s.p4 == p
    assert s.p4
    #
    s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)])
    assert s.p4 == cast(BVoidP, 0)
    assert not s.p4
    #
    pytest.raises(TypeError, newp, BStructPtr, [12, 34, 56, None])

def test_array_in_struct():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BArrayInt5 = new_array_type(new_pointer_type(BInt), 5)
    complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)])
    s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]])
    assert s.a1[2] == 27
    assert repr(s.a1).startswith("<cdata 'int[5]' 0x")

def test_offsetof():
    def offsetof(BType, fieldname):
        return typeoffsetof(BType, fieldname)[1]
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    pytest.raises(TypeError, offsetof, BInt, "abc")
    pytest.raises(TypeError, offsetof, BStruct, "abc")
    complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)])
    assert offsetof(BStruct, 'abc') == 0
    assert offsetof(BStruct, 'def') == size_of_int()
    pytest.raises(KeyError, offsetof, BStruct, "ghi")
    assert offsetof(new_pointer_type(BStruct), "def") == size_of_int()

def test_function_type():
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BInt, BInt), BInt, False)
    assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"
    BFunc2 = new_function_type((), BFunc, False)
    assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>"

def test_inspect_function_type():
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BInt, BInt), BInt, False)
    assert BFunc.kind == "function"
    assert BFunc.cname == "int(*)(int, int)"
    assert BFunc.args == (BInt, BInt)
    assert BFunc.result is BInt
    assert BFunc.ellipsis is False
    assert BFunc.abi == FFI_DEFAULT_ABI

def test_function_type_taking_struct():
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                       ('a2', BShort, -1)])
    BFunc = new_function_type((BStruct,), BShort, False)
    assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>"

def test_function_void_result():
    BVoid = new_void_type()
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BInt, BInt), BVoid, False)
    assert repr(BFunc) == "<ctype 'void(*)(int, int)'>"

def test_function_void_arg():
    BVoid = new_void_type()
    BInt = new_primitive_type("int")
    pytest.raises(TypeError, new_function_type, (BVoid,), BInt, False)

def test_call_function_0():
    BSignedChar = new_primitive_type("signed char")
    BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False)
    f = cast(BFunc0, _testfunc(0))
    assert f(40, 2) == 42
    assert f(-100, -100) == -200 + 256
    pytest.raises(OverflowError, f, 128, 0)
    pytest.raises(OverflowError, f, 0, 128)

def test_call_function_0_pretend_bool_result():
    BSignedChar = new_primitive_type("signed char")
    BBool = new_primitive_type("_Bool")
    BFunc0 = new_function_type((BSignedChar, BSignedChar), BBool, False)
    f = cast(BFunc0, _testfunc(0))
    assert f(40, -39) is True
    assert f(40, -40) is False
    pytest.raises(ValueError, f, 40, 2)

def test_call_function_1():
    BInt = new_primitive_type("int")
    BLong = new_primitive_type("long")
    BFunc1 = new_function_type((BInt, BLong), BLong, False)
    f = cast(BFunc1, _testfunc(1))
    assert f(40, 2) == 42
    assert f(-100, -100) == -200
    int_max = (1 << (8*size_of_int()-1)) - 1
    long_max = (1 << (8*size_of_long()-1)) - 1
    if int_max == long_max:
        assert f(int_max, 1) == - int_max - 1
    else:
        assert f(int_max, 1) == int_max + 1

def test_call_function_2():
    BLongLong = new_primitive_type("long long")
    BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False)
    f = cast(BFunc2, _testfunc(2))
    longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1
    assert f(longlong_max - 42, 42) == longlong_max
    assert f(43, longlong_max - 42) == - longlong_max - 1

def test_call_function_3():
    BFloat = new_primitive_type("float")
    BDouble = new_primitive_type("double")
    BFunc3 = new_function_type((BFloat, BDouble), BDouble, False)
    f = cast(BFunc3, _testfunc(3))
    assert f(1.25, 5.1) == 1.25 + 5.1     # exact
    res = f(1.3, 5.1)
    assert res != 6.4 and abs(res - 6.4) < 1E-5    # inexact

def test_call_function_4():
    BFloat = new_primitive_type("float")
    BDouble = new_primitive_type("double")
    BFunc4 = new_function_type((BFloat, BDouble), BFloat, False)
    f = cast(BFunc4, _testfunc(4))
    res = f(1.25, 5.1)
    assert res != 6.35 and abs(res - 6.35) < 1E-5    # inexact

def test_call_function_5():
    BVoid = new_void_type()
    BFunc5 = new_function_type((), BVoid, False)
    f = cast(BFunc5, _testfunc(5))
    f()   # did not crash

def test_call_function_6():
    BInt = new_primitive_type("int")
    BIntPtr = new_pointer_type(BInt)
    BFunc6 = new_function_type((BIntPtr,), BIntPtr, False)
    f = cast(BFunc6, _testfunc(6))
    x = newp(BIntPtr, 42)
    res = f(x)
    assert typeof(res) is BIntPtr
    assert res[0] == 42 - 1000
    #
    BIntArray = new_array_type(BIntPtr, None)
    BFunc6bis = new_function_type((BIntArray,), BIntPtr, False)
    f = cast(BFunc6bis, _testfunc(6))
    #
    res = f([142])
    assert typeof(res) is BIntPtr
    assert res[0] == 142 - 1000
    #
    res = f((143,))
    assert typeof(res) is BIntPtr
    assert res[0] == 143 - 1000
    #
    x = newp(BIntArray, [242])
    res = f(x)
    assert typeof(res) is BIntPtr
    assert res[0] == 242 - 1000
    #
    pytest.raises(TypeError, f, 123456)
    pytest.raises(TypeError, f, "foo")
    pytest.raises(TypeError, f, u+"bar")

def test_call_function_7():
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                       ('a2', BShort, -1)])
    BFunc7 = new_function_type((BStruct,), BShort, False)
    f = cast(BFunc7, _testfunc(7))
    res = f({'a1': b'A', 'a2': -4042})
    assert res == -4042 + ord(b'A')
    #
    x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
    res = f(x[0])
    assert res == -4042 + ord(b'A')

def test_call_function_20():
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                       ('a2', BShort, -1)])
    BFunc20 = new_function_type((BStructPtr,), BShort, False)
    f = cast(BFunc20, _testfunc(20))
    x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
    # can't pass a 'struct foo'
    pytest.raises(TypeError, f, x[0])

def test_call_function_21():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a', BInt, -1),
                                       ('b', BInt, -1),
                                       ('c', BInt, -1),
                                       ('d', BInt, -1),
                                       ('e', BInt, -1),
                                       ('f', BInt, -1),
                                       ('g', BInt, -1),
                                       ('h', BInt, -1),
                                       ('i', BInt, -1),
                                       ('j', BInt, -1)])
    BFunc21 = new_function_type((BStruct,), BInt, False)
    f = cast(BFunc21, _testfunc(21))
    res = f(list(range(13, 3, -1)))
    lst = [(n << i) for (i, n) in enumerate(range(13, 3, -1))]
    assert res == sum(lst)

def test_call_function_22():
    BInt = new_primitive_type("int")
    BArray10 = new_array_type(new_pointer_type(BInt), 10)
    BStruct = new_struct_type("struct foo")
    BStructP = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BArray10, -1)])
    BFunc22 = new_function_type((BStruct, BStruct), BStruct, False)
    f = cast(BFunc22, _testfunc(22))
    p1 = newp(BStructP, {'a': list(range(100, 110))})
    p2 = newp(BStructP, {'a': list(range(1000, 1100, 10))})
    res = f(p1[0], p2[0])
    for i in range(10):
        assert res.a[i] == p1.a[i] - p2.a[i]

def test_call_function_23():
    BVoid = new_void_type()          # declaring the function as int(void*)
    BVoidP = new_pointer_type(BVoid)
    BInt = new_primitive_type("int")
    BFunc23 = new_function_type((BVoidP,), BInt, False)
    f = cast(BFunc23, _testfunc(23))
    res = f(b"foo")
    assert res == 1000 * ord(b'f')
    res = f(cast(BVoidP, 0))        # NULL
    assert res == -42
    pytest.raises(TypeError, f, None)
    pytest.raises(TypeError, f, 0)
    pytest.raises(TypeError, f, 0.0)

def test_call_function_23_bis():
    # declaring the function as int(unsigned char*)
    BUChar = new_primitive_type("unsigned char")
    BUCharP = new_pointer_type(BUChar)
    BInt = new_primitive_type("int")
    BFunc23 = new_function_type((BUCharP,), BInt, False)
    f = cast(BFunc23, _testfunc(23))
    res = f(b"foo")
    assert res == 1000 * ord(b'f')

def test_call_function_23_bool_array():
    # declaring the function as int(_Bool*)
    BBool = new_primitive_type("_Bool")
    BBoolP = new_pointer_type(BBool)
    BInt = new_primitive_type("int")
    BFunc23 = new_function_type((BBoolP,), BInt, False)
    f = cast(BFunc23, _testfunc(23))
    res = f(b"\x01\x01")
    assert res == 1000
    pytest.raises(ValueError, f, b"\x02\x02")

def test_cannot_pass_struct_with_array_of_length_0():
    BInt = new_primitive_type("int")
    BArray0 = new_array_type(new_pointer_type(BInt), 0)
    BStruct = new_struct_type("struct foo")
    BStructP = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BArray0)])
    BFunc = new_function_type((BStruct,), BInt, False)
    pytest.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123))
    BFunc2 = new_function_type((BInt,), BStruct, False)
    pytest.raises(NotImplementedError, cast(BFunc2, 123), 123)

def test_call_function_9():
    BInt = new_primitive_type("int")
    BFunc9 = new_function_type((BInt,), BInt, True)    # vararg
    f = cast(BFunc9, _testfunc(9))
    assert f(0) == 0
    assert f(1, cast(BInt, 42)) == 42
    assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42
    pytest.raises(TypeError, f, 1, 42)
    pytest.raises(TypeError, f, 2, None)
    # promotion of chars and shorts to ints
    BSChar = new_primitive_type("signed char")
    BUChar = new_primitive_type("unsigned char")
    BSShort = new_primitive_type("short")
    assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192

def test_call_function_24():
    BFloat = new_primitive_type("float")
    BFloatComplex = new_primitive_type("float _Complex")
    BFunc3 = new_function_type((BFloat, BFloat), BFloatComplex, False)
    if 0:   # libffi returning nonsense silently, so logic disabled for now
        f = cast(BFunc3, _testfunc(24))
        result = f(1.25, 5.1)
        assert type(result) == complex
        assert result.real == 1.25   # exact
        assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact
    else:
        f = cast(BFunc3, _testfunc(9))
        pytest.raises(NotImplementedError, f, 12.3, 34.5)

def test_call_function_25():
    BDouble = new_primitive_type("double")
    BDoubleComplex = new_primitive_type("double _Complex")
    BFunc3 = new_function_type((BDouble, BDouble), BDoubleComplex, False)
    if 0:   # libffi returning nonsense silently, so logic disabled for now
        f = cast(BFunc3, _testfunc(25))
        result = f(1.25, 5.1)
        assert type(result) == complex
        assert result.real == 1.25   # exact
        assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-10) # inexact
    else:
        f = cast(BFunc3, _testfunc(9))
        pytest.raises(NotImplementedError, f, 12.3, 34.5)

def test_cannot_call_with_a_autocompleted_struct():
    BSChar = new_primitive_type("signed char")
    BDouble = new_primitive_type("double")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('c', BDouble, -1, 8),
                                       ('a', BSChar, -1, 2),
                                       ('b', BSChar, -1, 0)])
    BFunc = new_function_type((BStruct,), BDouble)   # internally not callable
    dummy_func = cast(BFunc, 42)
    e = pytest.raises(NotImplementedError, dummy_func, "?")
    msg = ("ctype 'struct foo' not supported as argument.  It is a struct "
           'declared with "...;", but the C calling convention may depend '
           "on the missing fields; or, it contains anonymous struct/unions.  "
           "Such structs are only supported as argument if the function is "
           "'API mode' and non-variadic (i.e. declared inside ffibuilder."
           "cdef()+ffibuilder.set_source() and not taking a final '...' "
           "argument)")
    assert str(e.value) == msg

def test_new_charp():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    x = newp(BCharA, 42)
    assert len(x) == 42
    x = newp(BCharA, b"foobar")
    assert len(x) == 7

def test_load_and_call_function():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BLong = new_primitive_type("long")
    BFunc = new_function_type((BCharP,), BLong, False)
    ll = find_and_load_library('c')
    strlen = ll.load_function(BFunc, "strlen")
    input = newp(new_array_type(BCharP, None), b"foobar")
    assert strlen(input) == 6
    #
    assert strlen(b"foobarbaz") == 9
    #
    BVoidP = new_pointer_type(new_void_type())
    strlenaddr = ll.load_function(BVoidP, "strlen")
    assert strlenaddr == cast(BVoidP, strlen)

def test_read_variable():
    ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
    ## https://bugs.pypy.org/issue1643
    if not sys.platform.startswith("linux"):
        pytest.skip("untested")
    BVoidP = new_pointer_type(new_void_type())
    ll = find_and_load_library('c')
    stderr = ll.read_variable(BVoidP, "stderr")
    assert stderr == cast(BVoidP, _testfunc(8))
    #
    ll.close_lib()
    pytest.raises(ValueError, ll.read_variable, BVoidP, "stderr")

def test_read_variable_as_unknown_length_array():
    ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
    ## https://bugs.pypy.org/issue1643
    if not sys.platform.startswith("linux"):
        pytest.skip("untested")
    BCharP = new_pointer_type(new_primitive_type("char"))
    BArray = new_array_type(BCharP, None)
    ll = find_and_load_library('c')
    stderr = ll.read_variable(BArray, "stderr")
    assert repr(stderr).startswith("<cdata 'char *' 0x")
    # ^^ and not 'char[]', which is basically not allowed and would crash

def test_write_variable():
    ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
    ## https://bugs.pypy.org/issue1643
    if not sys.platform.startswith("linux") or is_musl:
        pytest.skip("untested")
    BVoidP = new_pointer_type(new_void_type())
    ll = find_and_load_library('c')
    stderr = ll.read_variable(BVoidP, "stderr")
    ll.write_variable(BVoidP, "stderr", cast(BVoidP, 0))
    assert ll.read_variable(BVoidP, "stderr") is not None
    assert not ll.read_variable(BVoidP, "stderr")
    ll.write_variable(BVoidP, "stderr", stderr)
    assert ll.read_variable(BVoidP, "stderr") == stderr
    #
    ll.close_lib()
    pytest.raises(ValueError, ll.write_variable, BVoidP, "stderr", stderr)

def test_callback():
    BInt = new_primitive_type("int")
    def make_callback():
        def cb(n):
            return n + 1
        BFunc = new_function_type((BInt,), BInt, False)
        return callback(BFunc, cb, 42)    # 'cb' and 'BFunc' go out of scope
    f = make_callback()
    assert f(-142) == -141
    assert repr(f).startswith(
        "<cdata 'int(*)(int)' calling <function ")
    assert "cb at 0x" in repr(f)
    e = pytest.raises(TypeError, f)
    assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0"

def test_callback_exception():
    try:
        import cStringIO
    except ImportError:
        import io as cStringIO    # Python 3
    import linecache
    def matches(istr, ipattern, ipattern38, ipattern311=None):
        if sys.version_info >= (3, 8):
            ipattern = ipattern38
        if sys.version_info >= (3, 11):
            ipattern = ipattern311 or ipattern38
        str, pattern = istr, ipattern
        while '$' in pattern:
            i = pattern.index('$')
            assert str[:i] == pattern[:i]
            j = str.find(pattern[i+1], i)
            assert i + 1 <= j <= str.find('\n', i)
            str = str[j:]
            pattern = pattern[i+1:]
        assert str == pattern
        return True
    def check_value(x):
        if x == 10000:
            raise ValueError(42)
    def Zcb1(x):
        check_value(x)
        return x * 3
    BShort = new_primitive_type("short")
    BFunc = new_function_type((BShort,), BShort, False)
    f = callback(BFunc, Zcb1, -42)
    #
    seen = []
    oops_result = None
    def oops(*args):
        seen.append(args)
        return oops_result
    ff = callback(BFunc, Zcb1, -42, oops)
    #
    orig_stderr = sys.stderr
    orig_getline = linecache.getline
    try:
        linecache.getline = lambda *args: 'LINE'    # hack: speed up PyPy tests
        sys.stderr = cStringIO.StringIO()
        if hasattr(sys, '__unraisablehook__'):          # work around pytest
            sys.unraisablehook = sys.__unraisablehook__ # on recent CPythons
        assert f(100) == 300
        assert sys.stderr.getvalue() == ''
        assert f(10000) == -42
        assert matches(sys.stderr.getvalue(), """\
From cffi callback <function$Zcb1 at 0x$>:
Traceback (most recent call last):
  File "$", line $, in Zcb1
    $
  File "$", line $, in check_value
    $
ValueError: 42
""", """\
Exception ignored from cffi callback <function$Zcb1 at 0x$>:
Traceback (most recent call last):
  File "$", line $, in Zcb1
    $
  File "$", line $, in check_value
    $
ValueError: 42
""")
        sys.stderr = cStringIO.StringIO()
        bigvalue = 20000
        assert f(bigvalue) == -42
        assert matches(sys.stderr.getvalue(), """\
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
OverflowError: integer 60000 does not fit 'short'
""", """\
Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
Traceback (most recent call last):
  File "$", line $, in test_callback_exception
    $
OverflowError: integer 60000 does not fit 'short'
""")
        sys.stderr = cStringIO.StringIO()
        bigvalue = 20000
        assert len(seen) == 0
        assert ff(bigvalue) == -42
        assert sys.stderr.getvalue() == ""
        assert len(seen) == 1
        exc, val, tb = seen[0]
        assert exc is OverflowError
        assert str(val) == "integer 60000 does not fit 'short'"
        #
        sys.stderr = cStringIO.StringIO()
        bigvalue = 20000
        del seen[:]
        oops_result = 81
        assert ff(bigvalue) == 81
        oops_result = None
        assert sys.stderr.getvalue() == ""
        assert len(seen) == 1
        exc, val, tb = seen[0]
        assert exc is OverflowError
        assert str(val) == "integer 60000 does not fit 'short'"
        #
        sys.stderr = cStringIO.StringIO()
        bigvalue = 20000
        del seen[:]
        oops_result = "xy"     # not None and not an int!
        assert ff(bigvalue) == -42
        oops_result = None
        assert matches(sys.stderr.getvalue(), """\
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
OverflowError: integer 60000 does not fit 'short'

During the call to 'onerror', another exception occurred:

TypeError: $integer$
""", """\
Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
Traceback (most recent call last):
  File "$", line $, in test_callback_exception
    $
OverflowError: integer 60000 does not fit 'short'
Exception ignored during handling of the above exception by 'onerror':
Traceback (most recent call last):
  File "$", line $, in test_callback_exception
    $
TypeError: $integer$
""")
        #
        sys.stderr = cStringIO.StringIO()
        seen = "not a list"    # this makes the oops() function crash
        assert ff(bigvalue) == -42
        # the $ after the AttributeError message are for the suggestions that
        # will be added in Python 3.10
        assert matches(sys.stderr.getvalue(), """\
From cffi callback <function$Zcb1 at 0x$>:
Trying to convert the result back to C:
OverflowError: integer 60000 does not fit 'short'

During the call to 'onerror', another exception occurred:

Traceback (most recent call last):
  File "$", line $, in oops
    $
AttributeError: 'str' object has no attribute 'append$
""", """\
Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
Traceback (most recent call last):
  File "$", line $, in test_callback_exception
    $
OverflowError: integer 60000 does not fit 'short'
Exception ignored during handling of the above exception by 'onerror':
Traceback (most recent call last):
  File "$", line $, in oops
    $
AttributeError: 'str' object has no attribute 'append$
""", """\
Exception ignored from cffi callback <function$Zcb1 at 0x$>, trying to convert the result back to C:
Traceback (most recent call last):
  File "$", line $, in test_callback_exception
    $
OverflowError: integer 60000 does not fit 'short'
Exception ignored during handling of the above exception by 'onerror':
Traceback (most recent call last):
  File "$", line $, in oops
    $
    $
AttributeError: 'str' object has no attribute 'append$
""")
    finally:
        sys.stderr = orig_stderr
        linecache.getline = orig_getline

def test_callback_return_type():
    for rettype in ["signed char", "short", "int", "long", "long long",
                    "unsigned char", "unsigned short", "unsigned int",
                    "unsigned long", "unsigned long long"]:
        BRet = new_primitive_type(rettype)
        def cb(n):
            return n + 1
        BFunc = new_function_type((BRet,), BRet)
        f = callback(BFunc, cb, 42)
        assert f(41) == 42
        if rettype.startswith("unsigned "):
            min = 0
            max = (1 << (8*sizeof(BRet))) - 1
        else:
            min = -(1 << (8*sizeof(BRet)-1))
            max = (1 << (8*sizeof(BRet)-1)) - 1
        assert f(min) == min + 1
        assert f(max - 1) == max
        assert f(max) == 42

def test_a_lot_of_callbacks():
    BIGNUM = 10000
    if 'PY_DOT_PY' in globals(): BIGNUM = 100   # tests on py.py
    #
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BInt,), BInt, False)
    def make_callback(m):
        def cb(n):
            return n + m
        return callback(BFunc, cb, 42)    # 'cb' goes out of scope
    #
    flist = [make_callback(i) for i in range(BIGNUM)]
    for i, f in enumerate(flist):
        assert f(-142) == -142 + i

def test_callback_receiving_tiny_struct():
    BSChar = new_primitive_type("signed char")
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BSChar, -1),
                                       ('b', BSChar, -1)])
    def cb(s):
        return s.a + 10 * s.b
    BFunc = new_function_type((BStruct,), BInt)
    f = callback(BFunc, cb)
    p = newp(BStructPtr, [-2, -4])
    n = f(p[0])
    assert n == -42

def test_callback_returning_tiny_struct():
    BSChar = new_primitive_type("signed char")
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BSChar, -1),
                                       ('b', BSChar, -1)])
    def cb(n):
        return newp(BStructPtr, [-n, -3*n])[0]
    BFunc = new_function_type((BInt,), BStruct)
    f = callback(BFunc, cb)
    s = f(10)
    assert typeof(s) is BStruct
    assert repr(s) == "<cdata 'struct foo' owning 2 bytes>"
    assert s.a == -10
    assert s.b == -30

def test_callback_receiving_struct():
    BSChar = new_primitive_type("signed char")
    BInt = new_primitive_type("int")
    BDouble = new_primitive_type("double")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BSChar, -1),
                                       ('b', BDouble, -1)])
    def cb(s):
        return s.a + int(s.b)
    BFunc = new_function_type((BStruct,), BInt)
    f = callback(BFunc, cb)
    p = newp(BStructPtr, [-2, 44.444])
    n = f(p[0])
    assert n == 42

def test_callback_returning_struct():
    BSChar = new_primitive_type("signed char")
    BInt = new_primitive_type("int")
    BDouble = new_primitive_type("double")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BSChar, -1),
                                       ('b', BDouble, -1)])
    def cb(n):
        return newp(BStructPtr, [-n, 1E-42])[0]
    BFunc = new_function_type((BInt,), BStruct)
    f = callback(BFunc, cb)
    s = f(10)
    assert typeof(s) is BStruct
    assert repr(s) in ["<cdata 'struct foo' owning 12 bytes>",
                       "<cdata 'struct foo' owning 16 bytes>"]
    assert s.a == -10
    assert s.b == 1E-42

def test_callback_receiving_big_struct():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BInt, -1),
                                       ('b', BInt, -1),
                                       ('c', BInt, -1),
                                       ('d', BInt, -1),
                                       ('e', BInt, -1),
                                       ('f', BInt, -1),
                                       ('g', BInt, -1),
                                       ('h', BInt, -1),
                                       ('i', BInt, -1),
                                       ('j', BInt, -1)])
    def cb(s):
        for i, name in enumerate("abcdefghij"):
            assert getattr(s, name) == 13 - i
        return 42
    BFunc = new_function_type((BStruct,), BInt)
    f = callback(BFunc, cb)
    p = newp(BStructPtr, list(range(13, 3, -1)))
    n = f(p[0])
    assert n == 42

def test_callback_returning_big_struct():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a', BInt, -1),
                                       ('b', BInt, -1),
                                       ('c', BInt, -1),
                                       ('d', BInt, -1),
                                       ('e', BInt, -1),
                                       ('f', BInt, -1),
                                       ('g', BInt, -1),
                                       ('h', BInt, -1),
                                       ('i', BInt, -1),
                                       ('j', BInt, -1)])
    def cb():
        return newp(BStructPtr, list(range(13, 3, -1)))[0]
    BFunc = new_function_type((), BStruct)
    f = callback(BFunc, cb)
    s = f()
    assert typeof(s) is BStruct
    assert repr(s) in ["<cdata 'struct foo' owning 40 bytes>",
                       "<cdata 'struct foo' owning 80 bytes>"]
    for i, name in enumerate("abcdefghij"):
        assert getattr(s, name) == 13 - i

def test_callback_returning_void():
    BVoid = new_void_type()
    BFunc = new_function_type((), BVoid, False)
    def cb():
        seen.append(42)
    f = callback(BFunc, cb)
    seen = []
    f()
    assert seen == [42]
    pytest.raises(TypeError, callback, BFunc, cb, -42)

def test_enum_type():
    BUInt = new_primitive_type("unsigned int")
    BEnum = new_enum_type("foo", (), (), BUInt)
    assert repr(BEnum) == "<ctype 'foo'>"
    assert BEnum.kind == "enum"
    assert BEnum.cname == "foo"
    assert BEnum.elements == {}
    #
    BInt = new_primitive_type("int")
    BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
    assert BEnum.kind == "enum"
    assert BEnum.cname == "enum foo"
    assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
    # 'elements' is not the real dict, but merely a copy
    BEnum.elements[2] = '??'
    assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
    #
    BEnum = new_enum_type("enum bar", ('ab', 'cd'), (5, 5), BUInt)
    assert BEnum.elements == {5: 'ab'}
    assert BEnum.relements == {'ab': 5, 'cd': 5}

def test_cast_to_enum():
    BInt = new_primitive_type("int")
    BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
    assert sizeof(BEnum) == sizeof(BInt)
    e = cast(BEnum, 0)
    assert repr(e) == "<cdata 'enum foo' 0: def>"
    assert repr(cast(BEnum, -42)) == "<cdata 'enum foo' -42>"
    assert repr(cast(BEnum, -20)) == "<cdata 'enum foo' -20: ab>"
    assert string(e) == 'def'
    assert string(cast(BEnum, -20)) == 'ab'
    assert int(cast(BEnum, 1)) == 1
    assert int(cast(BEnum, 0)) == 0
    assert int(cast(BEnum, -242 + 2**128)) == -242
    assert string(cast(BEnum, -242 + 2**128)) == '-242'
    #
    BUInt = new_primitive_type("unsigned int")
    BEnum = new_enum_type("enum bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
    e = cast(BEnum, -1)
    assert repr(e) == "<cdata 'enum bar' 4294967295>"     # unsigned int
    #
    BLong = new_primitive_type("long")
    BEnum = new_enum_type("enum baz", (), (), BLong)
    assert sizeof(BEnum) == sizeof(BLong)
    e = cast(BEnum, -1)
    assert repr(e) == "<cdata 'enum baz' -1>"

def test_enum_with_non_injective_mapping():
    BInt = new_primitive_type("int")
    BEnum = new_enum_type("enum foo", ('ab', 'cd'), (7, 7), BInt)
    e = cast(BEnum, 7)
    assert repr(e) == "<cdata 'enum foo' 7: ab>"
    assert string(e) == 'ab'

def test_enum_in_struct():
    BInt = new_primitive_type("int")
    BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
    BStruct = new_struct_type("struct bar")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BEnum, -1)])
    p = newp(BStructPtr, [-20])
    assert p.a1 == -20
    p = newp(BStructPtr, [12])
    assert p.a1 == 12
    e = pytest.raises(TypeError, newp, BStructPtr, [None])
    msg = str(e.value)
    assert ("an integer is required" in msg or  # CPython
            "unsupported operand type for int(): 'NoneType'" in msg or  # old PyPys
            "expected integer, got NoneType object" in msg) # newer PyPys
    with pytest.raises(TypeError):
        p.a1 = "def"
    if sys.version_info < (3,):
        BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt)
        assert string(cast(BEnum2, 5)) == 'abc'
        assert type(string(cast(BEnum2, 5))) is str

def test_enum_overflow():
    max_uint = 2 ** (size_of_int()*8) - 1
    max_int = max_uint // 2
    max_ulong = 2 ** (size_of_long()*8) - 1
    max_long = max_ulong // 2
    for BPrimitive in [new_primitive_type("int"),
                       new_primitive_type("unsigned int"),
                       new_primitive_type("long"),
                       new_primitive_type("unsigned long")]:
        for x in [max_uint, max_int, max_ulong, max_long]:
            for testcase in [x, x+1, -x-1, -x-2]:
                if int(cast(BPrimitive, testcase)) == testcase:
                    # fits
                    BEnum = new_enum_type("foo", ("AA",), (testcase,),
                                          BPrimitive)
                    assert int(cast(BEnum, testcase)) == testcase
                else:
                    # overflows
                    pytest.raises(OverflowError, new_enum_type,
                                   "foo", ("AA",), (testcase,), BPrimitive)

def test_callback_returning_enum():
    BInt = new_primitive_type("int")
    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
    def cb(n):
        if n & 1:
            return cast(BEnum, n)
        else:
            return n
    BFunc = new_function_type((BInt,), BEnum)
    f = callback(BFunc, cb)
    assert f(0) == 0
    assert f(1) == 1
    assert f(-20) == -20
    assert f(20) == 20
    assert f(21) == 21

def test_callback_returning_enum_unsigned():
    BInt = new_primitive_type("int")
    BUInt = new_primitive_type("unsigned int")
    BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
    def cb(n):
        if n & 1:
            return cast(BEnum, n)
        else:
            return n
    BFunc = new_function_type((BInt,), BEnum)
    f = callback(BFunc, cb)
    assert f(0) == 0
    assert f(1) == 1
    assert f(-21) == 2**32 - 21
    assert f(20) == 20
    assert f(21) == 21

def test_callback_returning_char():
    BInt = new_primitive_type("int")
    BChar = new_primitive_type("char")
    def cb(n):
        return bytechr(n)
    BFunc = new_function_type((BInt,), BChar)
    f = callback(BFunc, cb)
    assert f(0) == b'\x00'
    assert f(255) == b'\xFF'

def _hacked_pypy_uni4():
    pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
    return 'PY_DOT_PY' in globals() and not pyuni4

def test_callback_returning_wchar_t():
    BInt = new_primitive_type("int")
    BWChar = new_primitive_type("wchar_t")
    def cb(n):
        if n == -1:
            return u+'\U00012345'
        if n == -2:
            raise ValueError
        return unichr(n)
    BFunc = new_function_type((BInt,), BWChar)
    f = callback(BFunc, cb)
    assert f(0) == unichr(0)
    assert f(255) == unichr(255)
    assert f(0x1234) == u+'\u1234'
    if sizeof(BWChar) == 4 and not _hacked_pypy_uni4():
        assert f(-1) == u+'\U00012345'
    assert f(-2) == u+'\x00'   # and an exception printed to stderr

def test_struct_with_bitfields():
    BLong = new_primitive_type("long")
    BStruct = new_struct_type("struct foo")
    LONGBITS = 8 * sizeof(BLong)
    complete_struct_or_union(BStruct, [('a1', BLong, 1),
                                       ('a2', BLong, 2),
                                       ('a3', BLong, 3),
                                       ('a4', BLong, LONGBITS - 5)])
    d = BStruct.fields
    assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
    assert d[3][1].offset == sizeof(BLong)
    def f(m, r):
        if sys.byteorder == 'little':
            return r
        else:
            return LONGBITS - m - r
    assert d[0][1].bitshift == f(1, 0)
    assert d[0][1].bitsize == 1
    assert d[1][1].bitshift == f(2, 1)
    assert d[1][1].bitsize == 2
    assert d[2][1].bitshift == f(3, 3)
    assert d[2][1].bitsize == 3
    assert d[3][1].bitshift == f(LONGBITS - 5, 0)
    assert d[3][1].bitsize == LONGBITS - 5
    assert sizeof(BStruct) == 2 * sizeof(BLong)
    assert alignof(BStruct) == alignof(BLong)

def test_bitfield_instance():
    BInt = new_primitive_type("int")
    BUnsignedInt = new_primitive_type("unsigned int")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BInt, 1),
                                       ('a2', BUnsignedInt, 2),
                                       ('a3', BInt, 3)])
    p = newp(new_pointer_type(BStruct), None)
    p.a1 = -1
    assert p.a1 == -1
    p.a1 = 0
    with pytest.raises(OverflowError):
        p.a1 = 2
    assert p.a1 == 0
    #
    p.a1 = -1
    p.a2 = 3
    p.a3 = -4
    with pytest.raises(OverflowError):
        p.a3 = 4
    with pytest.raises(OverflowError) as e:
        p.a3 = -5
    assert str(e.value) == ("value -5 outside the range allowed by the "
                            "bit field width: -4 <= x <= 3")
    assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4
    #
    # special case for convenience: "int x:1", while normally signed,
    # allows also setting the value "1" (it still gets read back as -1)
    p.a1 = 1
    assert p.a1 == -1
    with pytest.raises(OverflowError) as e:
        p.a1 = -2
    assert str(e.value) == ("value -2 outside the range allowed by the "
                            "bit field width: -1 <= x <= 1")

def test_bitfield_instance_init():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BInt, 1)])
    p = newp(new_pointer_type(BStruct), [-1])
    assert p.a1 == -1
    p = newp(new_pointer_type(BStruct), {'a1': -1})
    assert p.a1 == -1
    #
    BUnion = new_union_type("union bar")
    complete_struct_or_union(BUnion, [('a1', BInt, 1)])
    p = newp(new_pointer_type(BUnion), [-1])
    assert p.a1 == -1

def test_weakref():
    import _weakref
    BInt = new_primitive_type("int")
    BPtr = new_pointer_type(BInt)
    rlist = [_weakref.ref(BInt),
             _weakref.ref(newp(BPtr, 42)),
             _weakref.ref(cast(BPtr, 42)),
             _weakref.ref(cast(BInt, 42)),
             _weakref.ref(buffer(newp(BPtr, 42))),
             ]
    for i in range(5):
        import gc; gc.collect()
        if [r() for r in rlist] == [None for r in rlist]:
            break

def test_no_inheritance():
    BInt = new_primitive_type("int")
    try:
        class foo(type(BInt)): pass
    except TypeError:
        pass
    else:
        raise AssertionError
    x = cast(BInt, 42)
    try:
        class foo(type(x)): pass
    except TypeError:
        pass
    else:
        raise AssertionError

def test_assign_string():
    BChar = new_primitive_type("char")
    BArray1 = new_array_type(new_pointer_type(BChar), 5)
    BArray2 = new_array_type(new_pointer_type(BArray1), 5)
    a = newp(BArray2, [b"abc", b"de", b"ghij"])
    assert string(a[1]) == b"de"
    assert string(a[2]) == b"ghij"
    a[2] = b"."
    assert string(a[2]) == b"."
    a[2] = b"12345"
    assert string(a[2]) == b"12345"
    with pytest.raises(IndexError) as e:
        a[2] = b"123456"
    assert 'char[5]' in str(e.value)
    assert 'got 6 characters' in str(e.value)

def test_add_error():
    x = cast(new_primitive_type("int"), 42)
    with pytest.raises(TypeError):
        x + 1
    with pytest.raises(TypeError):
        x - 1

def test_void_errors():
    pytest.raises(ValueError, alignof, new_void_type())
    pytest.raises(TypeError, newp, new_pointer_type(new_void_type()), None)

def test_too_many_items():
    BChar = new_primitive_type("char")
    BArray = new_array_type(new_pointer_type(BChar), 5)
    pytest.raises(IndexError, newp, BArray, tuple(b'123456'))
    pytest.raises(IndexError, newp, BArray, list(b'123456'))
    pytest.raises(IndexError, newp, BArray, b'123456')
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [])
    pytest.raises(TypeError, newp, new_pointer_type(BStruct), b'')
    pytest.raises(ValueError, newp, new_pointer_type(BStruct), [b'1'])

def test_more_type_errors():
    BInt = new_primitive_type("int")
    BChar = new_primitive_type("char")
    BArray = new_array_type(new_pointer_type(BChar), 5)
    pytest.raises(TypeError, newp, BArray, 12.34)
    BArray = new_array_type(new_pointer_type(BInt), 5)
    pytest.raises(TypeError, newp, BArray, 12.34)
    BFloat = new_primitive_type("float")
    pytest.raises(TypeError, cast, BFloat, newp(BArray, None))

def test_more_overflow_errors():
    BUInt = new_primitive_type("unsigned int")
    pytest.raises(OverflowError, newp, new_pointer_type(BUInt), -1)
    pytest.raises(OverflowError, newp, new_pointer_type(BUInt), 2**32)

def test_newp_copying():
    """Test that we can do newp(<type>, <cdata of the given type>) for most
    types, including same-type arrays.
    """
    BInt = new_primitive_type("int")
    p = newp(new_pointer_type(BInt), cast(BInt, 42))
    assert p[0] == 42
    #
    BUInt = new_primitive_type("unsigned int")
    p = newp(new_pointer_type(BUInt), cast(BUInt, 42))
    assert p[0] == 42
    #
    BChar = new_primitive_type("char")
    p = newp(new_pointer_type(BChar), cast(BChar, '!'))
    assert p[0] == b'!'
    #
    BFloat = new_primitive_type("float")
    p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25))
    assert p[0] == 12.25
    #
    BStruct = new_struct_type("struct foo_s")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BInt, -1)])
    s1 = newp(BStructPtr, [42])
    p1 = newp(new_pointer_type(BStructPtr), s1)
    assert p1[0] == s1
    #
    BArray = new_array_type(new_pointer_type(BInt), None)
    a1 = newp(BArray, [1, 2, 3, 4])
    pytest.raises(TypeError, newp, BArray, a1)
    BArray6 = new_array_type(new_pointer_type(BInt), 6)
    a1 = newp(BArray6, [10, 20, 30])
    a2 = newp(BArray6, a1)
    assert list(a2) == [10, 20, 30, 0, 0, 0]
    #
    s1 = newp(BStructPtr, [42])
    s2 = newp(BStructPtr, s1[0])
    assert s2.a1 == 42
    #
    BUnion = new_union_type("union foo_u")
    BUnionPtr = new_pointer_type(BUnion)
    complete_struct_or_union(BUnion, [('a1', BInt, -1)])
    u1 = newp(BUnionPtr, [42])
    u2 = newp(BUnionPtr, u1[0])
    assert u2.a1 == 42
    #
    BFunc = new_function_type((BInt,), BUInt)
    p1 = cast(BFunc, 42)
    p2 = newp(new_pointer_type(BFunc), p1)
    assert p2[0] == p1

def test_string():
    BChar = new_primitive_type("char")
    assert string(cast(BChar, 42)) == b'*'
    assert string(cast(BChar, 0)) == b'\x00'
    BCharP = new_pointer_type(BChar)
    BArray = new_array_type(BCharP, 10)
    a = newp(BArray, b"hello")
    assert len(a) == 10
    assert string(a) == b"hello"
    p = a + 2
    assert string(p) == b"llo"
    assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd"
    pytest.raises(RuntimeError, string, cast(BCharP, 0))
    assert string(a, 4) == b"hell"
    assert string(a, 5) == b"hello"
    assert string(a, 6) == b"hello"

def test_string_byte():
    BByte = new_primitive_type("signed char")
    assert string(cast(BByte, 42)) == b'*'
    assert string(cast(BByte, 0)) == b'\x00'
    BArray = new_array_type(new_pointer_type(BByte), None)
    a = newp(BArray, [65, 66, 67])
    assert type(string(a)) is bytes and string(a) == b'ABC'
    #
    BByte = new_primitive_type("unsigned char")
    assert string(cast(BByte, 42)) == b'*'
    assert string(cast(BByte, 0)) == b'\x00'
    BArray = new_array_type(new_pointer_type(BByte), None)
    a = newp(BArray, [65, 66, 67])
    assert type(string(a)) is bytes and string(a) == b'ABC'
    if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
        assert string(a, 8).startswith(b'ABC')  # may contain additional garbage

def test_string_wchar():
    for typename in ["wchar_t", "char16_t", "char32_t"]:
        _test_string_wchar_variant(typename)

def _test_string_wchar_variant(typename):
    BWChar = new_primitive_type(typename)
    assert string(cast(BWChar, 42)) == u+'*'
    assert string(cast(BWChar, 0x4253)) == u+'\u4253'
    assert string(cast(BWChar, 0)) == u+'\x00'
    BArray = new_array_type(new_pointer_type(BWChar), None)
    a = newp(BArray, [u+'A', u+'B', u+'C'])
    assert type(string(a)) is unicode and string(a) == u+'ABC'
    if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
        try:
            # may contain additional garbage
            assert string(a, 8).startswith(u+'ABC')
        except ValueError:    # garbage contains values > 0x10FFFF
            assert sizeof(BWChar) == 4

def test_string_typeerror():
    BShort = new_primitive_type("short")
    BArray = new_array_type(new_pointer_type(BShort), None)
    a = newp(BArray, [65, 66, 67])
    pytest.raises(TypeError, string, a)

def test_bug_convert_to_ptr():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BDouble = new_primitive_type("double")
    x = cast(BDouble, 42)
    pytest.raises(TypeError, newp, new_pointer_type(BCharP), x)

def test_set_struct_fields():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharArray10 = new_array_type(BCharP, 10)
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)])
    p = newp(BStructPtr, None)
    assert string(p.a1) == b''
    p.a1 = b'foo'
    assert string(p.a1) == b'foo'
    assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7
    p.a1 = [b'x', b'y']
    assert string(p.a1) == b'xyo'

def test_invalid_function_result_types():
    BFunc = new_function_type((), new_void_type())
    BArray = new_array_type(new_pointer_type(BFunc), 5)        # works
    new_function_type((), BFunc)    # works
    new_function_type((), new_primitive_type("int"))
    new_function_type((), new_pointer_type(BFunc))
    BUnion = new_union_type("union foo_u")
    complete_struct_or_union(BUnion, [])
    BFunc = new_function_type((), BUnion)
    pytest.raises(NotImplementedError, cast(BFunc, 123))
    pytest.raises(TypeError, new_function_type, (), BArray)

def test_struct_return_in_func():
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    BFloat = new_primitive_type("float")
    BDouble = new_primitive_type("double")
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo_s")
    complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                       ('a2', BShort, -1)])
    BFunc10 = new_function_type((BInt,), BStruct)
    f = cast(BFunc10, _testfunc(10))
    s = f(40)
    assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>"
    assert s.a1 == bytechr(40)
    assert s.a2 == 40 * 40
    #
    BStruct11 = new_struct_type("struct test11")
    complete_struct_or_union(BStruct11, [('a1', BInt, -1),
                                         ('a2', BInt, -1)])
    BFunc11 = new_function_type((BInt,), BStruct11)
    f = cast(BFunc11, _testfunc(11))
    s = f(40)
    assert repr(s) == "<cdata 'struct test11' owning 8 bytes>"
    assert s.a1 == 40
    assert s.a2 == 40 * 40
    #
    BStruct12 = new_struct_type("struct test12")
    complete_struct_or_union(BStruct12, [('a1', BDouble, -1),
                                         ])
    BFunc12 = new_function_type((BInt,), BStruct12)
    f = cast(BFunc12, _testfunc(12))
    s = f(40)
    assert repr(s) == "<cdata 'struct test12' owning 8 bytes>"
    assert s.a1 == 40.0
    #
    BStruct13 = new_struct_type("struct test13")
    complete_struct_or_union(BStruct13, [('a1', BInt, -1),
                                         ('a2', BInt, -1),
                                         ('a3', BInt, -1)])
    BFunc13 = new_function_type((BInt,), BStruct13)
    f = cast(BFunc13, _testfunc(13))
    s = f(40)
    assert repr(s) == "<cdata 'struct test13' owning 12 bytes>"
    assert s.a1 == 40
    assert s.a2 == 40 * 40
    assert s.a3 == 40 * 40 * 40
    #
    BStruct14 = new_struct_type("struct test14")
    complete_struct_or_union(BStruct14, [('a1', BFloat, -1),
                                         ])
    BFunc14 = new_function_type((BInt,), BStruct14)
    f = cast(BFunc14, _testfunc(14))
    s = f(40)
    assert repr(s) == "<cdata 'struct test14' owning 4 bytes>"
    assert s.a1 == 40.0
    #
    BStruct15 = new_struct_type("struct test15")
    complete_struct_or_union(BStruct15, [('a1', BFloat, -1),
                                         ('a2', BInt, -1)])
    BFunc15 = new_function_type((BInt,), BStruct15)
    f = cast(BFunc15, _testfunc(15))
    s = f(40)
    assert repr(s) == "<cdata 'struct test15' owning 8 bytes>"
    assert s.a1 == 40.0
    assert s.a2 == 40 * 40
    #
    BStruct16 = new_struct_type("struct test16")
    complete_struct_or_union(BStruct16, [('a1', BFloat, -1),
                                         ('a2', BFloat, -1)])
    BFunc16 = new_function_type((BInt,), BStruct16)
    f = cast(BFunc16, _testfunc(16))
    s = f(40)
    assert repr(s) == "<cdata 'struct test16' owning 8 bytes>"
    assert s.a1 == 40.0
    assert s.a2 == -40.0
    #
    BStruct17 = new_struct_type("struct test17")
    complete_struct_or_union(BStruct17, [('a1', BInt, -1),
                                         ('a2', BFloat, -1)])
    BFunc17 = new_function_type((BInt,), BStruct17)
    f = cast(BFunc17, _testfunc(17))
    s = f(40)
    assert repr(s) == "<cdata 'struct test17' owning 8 bytes>"
    assert s.a1 == 40
    assert s.a2 == 40.0 * 40.0
    #
    BStruct17Ptr = new_pointer_type(BStruct17)
    BFunc18 = new_function_type((BStruct17Ptr,), BInt)
    f = cast(BFunc18, _testfunc(18))
    x = f([[40, 2.5]])
    assert x == 42
    x = f([{'a2': 43.1}])
    assert x == 43

def test_cast_with_functionptr():
    BFunc = new_function_type((), new_void_type())
    BFunc2 = new_function_type((), new_primitive_type("short"))
    BCharP = new_pointer_type(new_primitive_type("char"))
    BIntP = new_pointer_type(new_primitive_type("int"))
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BFunc, -1)])
    newp(BStructPtr, [cast(BFunc, 0)])
    newp(BStructPtr, [cast(BCharP, 0)])
    pytest.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)])
    pytest.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)])

def test_wchar():
    _test_wchar_variant("wchar_t")
    if sys.platform.startswith("linux"):
        BWChar = new_primitive_type("wchar_t")
        assert sizeof(BWChar) == 4
        # wchar_t is often signed on Linux, but not always (e.g. on ARM)
        assert int(cast(BWChar, -1)) in (-1, 4294967295)

def test_char16():
    BChar16 = new_primitive_type("char16_t")
    assert sizeof(BChar16) == 2
    _test_wchar_variant("char16_t")
    assert int(cast(BChar16, -1)) == 0xffff       # always unsigned

def test_char32():
    BChar32 = new_primitive_type("char32_t")
    assert sizeof(BChar32) == 4
    _test_wchar_variant("char32_t")
    assert int(cast(BChar32, -1)) == 0xffffffff   # always unsigned

def _test_wchar_variant(typename):
    BWChar = new_primitive_type(typename)
    BInt = new_primitive_type("int")
    pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
    wchar4 = {2: False, 4: True}[sizeof(BWChar)]
    assert str(cast(BWChar, 0x45)) == "<cdata '%s' %s'E'>" % (
        typename, mandatory_u_prefix)
    assert str(cast(BWChar, 0x1234)) == "<cdata '%s' %s'\u1234'>" % (
        typename, mandatory_u_prefix)
    if not _hacked_pypy_uni4():
        if wchar4:
            x = cast(BWChar, 0x12345)
            assert str(x) == "<cdata '%s' %s'\U00012345'>" % (
                typename, mandatory_u_prefix)
            assert int(x) == 0x12345
        else:
            x = cast(BWChar, 0x18345)
            assert str(x) == "<cdata '%s' %s'\u8345'>" % (
                typename, mandatory_u_prefix)
            assert int(x) == 0x8345
    #
    BWCharP = new_pointer_type(BWChar)
    BStruct = new_struct_type("struct foo_s")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BWChar, -1),
                                       ('a2', BWCharP, -1)])
    s = newp(BStructPtr)
    s.a1 = u+'\x00'
    assert s.a1 == u+'\x00'
    with pytest.raises(TypeError):
        s.a1 = b'a'
    with pytest.raises(TypeError):
        s.a1 = bytechr(0xFF)
    s.a1 = u+'\u1234'
    assert s.a1 == u+'\u1234'
    if pyuni4:
        if wchar4:
            s.a1 = u+'\U00012345'
            assert s.a1 == u+'\U00012345'
    elif wchar4:
        if not _hacked_pypy_uni4():
            s.a1 = cast(BWChar, 0x12345)
            assert s.a1 == u+'\ud808\udf45'
            s.a1 = u+'\ud807\udf44'
            assert s.a1 == u+'\U00011f44'
    else:
        with pytest.raises(TypeError):
            s.a1 = u+'\U00012345'
    #
    BWCharArray = new_array_type(BWCharP, None)
    a = newp(BWCharArray, u+'hello \u1234 world')
    assert len(a) == 14   # including the final null
    assert string(a) == u+'hello \u1234 world'
    a[13] = u+'!'
    assert string(a) == u+'hello \u1234 world!'
    assert str(a) == repr(a)
    assert a[6] == u+'\u1234'
    a[6] = u+'-'
    assert string(a) == u+'hello - world!'
    assert str(a) == repr(a)
    #
    if wchar4 and not _hacked_pypy_uni4():
        u1 = u+'\U00012345\U00012346\U00012347'
        a = newp(BWCharArray, u1)
        assert len(a) == 4
        assert string(a) == u1
        assert len(list(a)) == 4
        expected = [u+'\U00012345', u+'\U00012346', u+'\U00012347', unichr(0)]
        assert list(a) == expected
        got = [a[i] for i in range(4)]
        assert got == expected
        with pytest.raises(IndexError):
            a[4]
    #
    w = cast(BWChar, 'a')
    assert repr(w) == "<cdata '%s' %s'a'>" % (typename, mandatory_u_prefix)
    assert str(w) == repr(w)
    assert string(w) == u+'a'
    assert int(w) == ord('a')
    w = cast(BWChar, 0x1234)
    assert repr(w) == "<cdata '%s' %s'\u1234'>" % (typename, mandatory_u_prefix)
    assert str(w) == repr(w)
    assert string(w) == u+'\u1234'
    assert int(w) == 0x1234
    w = cast(BWChar, u+'\u8234')
    assert repr(w) == "<cdata '%s' %s'\u8234'>" % (typename, mandatory_u_prefix)
    assert str(w) == repr(w)
    assert string(w) == u+'\u8234'
    assert int(w) == 0x8234
    w = cast(BInt, u+'\u1234')
    assert repr(w) == "<cdata 'int' 4660>"
    if wchar4 and not _hacked_pypy_uni4():
        w = cast(BWChar, u+'\U00012345')
        assert repr(w) == "<cdata '%s' %s'\U00012345'>" % (
            typename, mandatory_u_prefix)
        assert str(w) == repr(w)
        assert string(w) == u+'\U00012345'
        assert int(w) == 0x12345
        w = cast(BInt, u+'\U00012345')
        assert repr(w) == "<cdata 'int' 74565>"
    pytest.raises(TypeError, cast, BInt, u+'')
    pytest.raises(TypeError, cast, BInt, u+'XX')
    assert int(cast(BInt, u+'a')) == ord('a')
    #
    a = newp(BWCharArray, u+'hello - world')
    p = cast(BWCharP, a)
    assert string(p) == u+'hello - world'
    p[6] = u+'\u2345'
    assert string(p) == u+'hello \u2345 world'
    #
    s = newp(BStructPtr, [u+'\u1234', p])
    assert s.a1 == u+'\u1234'
    assert s.a2 == p
    assert str(s.a2) == repr(s.a2)
    assert string(s.a2) == u+'hello \u2345 world'
    #
    q = cast(BWCharP, 0)
    assert str(q) == repr(q)
    pytest.raises(RuntimeError, string, q)
    #
    def cb(p):
        assert repr(p).startswith("<cdata '%s *' 0x" % typename)
        return len(string(p))
    BFunc = new_function_type((BWCharP,), BInt, False)
    f = callback(BFunc, cb, -42)
    assert f(u+'a\u1234b') == 3
    #
    if wchar4 and not pyuni4 and not _hacked_pypy_uni4():
        # try out-of-range wchar_t values
        x = cast(BWChar, 1114112)
        pytest.raises(ValueError, string, x)
        x = cast(BWChar, -1)
        pytest.raises(ValueError, string, x)

def test_wchar_variants_mix():
    BWChar  = new_primitive_type("wchar_t")
    BChar16 = new_primitive_type("char16_t")
    BChar32 = new_primitive_type("char32_t")
    assert int(cast(BChar32, cast(BChar16, -2))) == 0xfffe
    assert int(cast(BWChar, cast(BChar16, -2))) == 0xfffe
    assert int(cast(BChar16, cast(BChar32, 0x0001f345))) == 0xf345
    assert int(cast(BChar16, cast(BWChar, 0x0001f345))) == 0xf345
    #
    BChar16A = new_array_type(new_pointer_type(BChar16), None)
    BChar32A = new_array_type(new_pointer_type(BChar32), None)
    x = cast(BChar32, 'A')
    pytest.raises(TypeError, newp, BChar16A, [x])
    x = cast(BChar16, 'A')
    pytest.raises(TypeError, newp, BChar32A, [x])
    #
    a = newp(BChar16A, u+'\U00012345')
    assert len(a) == 3
    a = newp(BChar32A, u+'\U00012345')
    assert len(a) == 2   # even if the Python unicode string above is 2 chars

def test_keepalive_struct():
    # exception to the no-keepalive rule: p=newp(BStructPtr) returns a
    # pointer owning the memory, and p[0] returns a pointer to the
    # struct that *also* owns the memory
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1),
                                       ('a2', new_primitive_type("int"), -1),
                                       ('a3', new_primitive_type("int"), -1)])
    p = newp(BStructPtr)
    assert repr(p) == "<cdata 'struct foo *' owning 12 bytes>"
    q = p[0]
    assert repr(q) == "<cdata 'struct foo' owning 12 bytes>"
    q.a1 = 123456
    assert p.a1 == 123456
    r = cast(BStructPtr, p)
    assert repr(r[0]).startswith("<cdata 'struct foo &' 0x")
    del p
    import gc; gc.collect()
    assert q.a1 == 123456
    assert repr(q) == "<cdata 'struct foo' owning 12 bytes>"
    assert q.a1 == 123456

def test_nokeepalive_struct():
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    BStructPtrPtr = new_pointer_type(BStructPtr)
    complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)])
    p = newp(BStructPtr)
    pp = newp(BStructPtrPtr)
    pp[0] = p
    s = pp[0][0]
    assert repr(s).startswith("<cdata 'struct foo &' 0x")

def test_owning_repr():
    BInt = new_primitive_type("int")
    BArray = new_array_type(new_pointer_type(BInt), None)   # int[]
    p = newp(BArray, 7)
    assert repr(p) == "<cdata 'int[]' owning 28 bytes>"
    assert sizeof(p) == 28
    #
    BArray = new_array_type(new_pointer_type(BInt), 7)   # int[7]
    p = newp(BArray, None)
    assert repr(p) == "<cdata 'int[7]' owning 28 bytes>"
    assert sizeof(p) == 28

def test_cannot_dereference_void():
    BVoidP = new_pointer_type(new_void_type())
    p = cast(BVoidP, 123456)
    with pytest.raises(TypeError):
        p[0]
    p = cast(BVoidP, 0)
    with pytest.raises((TypeError, RuntimeError)):
        p[0]

def test_iter():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BArray = new_array_type(BIntP, None)   # int[]
    p = newp(BArray, 7)
    assert list(p) == list(iter(p)) == [0] * 7
    #
    pytest.raises(TypeError, iter, cast(BInt, 5))
    pytest.raises(TypeError, iter, cast(BIntP, 123456))

def test_cmp():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BVoidP = new_pointer_type(new_void_type())
    p = newp(BIntP, 123)
    q = cast(BInt, 124)
    assert (p == q) is False
    assert (p != q) is True
    assert (q == p) is False
    assert (q != p) is True
    if strict_compare:
        with pytest.raises(TypeError): p < q
        with pytest.raises(TypeError): p <= q
        with pytest.raises(TypeError): q < p
        with pytest.raises(TypeError): q <= p
        with pytest.raises(TypeError): p > q
        with pytest.raises(TypeError): p >= q
    r = cast(BVoidP, p)
    assert (p <  r) is False
    assert (p <= r) is True
    assert (p == r) is True
    assert (p != r) is False
    assert (p >  r) is False
    assert (p >= r) is True
    s = newp(BIntP, 125)
    assert (p == s) is False
    assert (p != s) is True
    assert (p < s) is (p <= s) is (s > p) is (s >= p)
    assert (p > s) is (p >= s) is (s < p) is (s <= p)
    assert (p < s) ^ (p > s)

def test_buffer():
    try:
        import __builtin__
    except ImportError:
        import builtins as __builtin__
    BShort = new_primitive_type("short")
    s = newp(new_pointer_type(BShort), 100)
    assert sizeof(s) == size_of_ptr()
    assert sizeof(BShort) == 2
    assert len(buffer(s)) == 2
    #
    BChar = new_primitive_type("char")
    BCharArray = new_array_type(new_pointer_type(BChar), None)
    c = newp(BCharArray, b"hi there")
    #
    buf = buffer(c)
    assert repr(buf).startswith('<_cffi_backend.buffer object at 0x')
    assert bytes(buf) == b"hi there\x00"
    assert type(buf) is buffer
    if sys.version_info < (3,):
        assert str(buf) == "hi there\x00"
        assert unicode(buf) == u+"hi there\x00"
    else:
        assert str(buf) == repr(buf)
    # --mb_length--
    assert len(buf) == len(b"hi there\x00")
    # --mb_item--
    for i in range(-12, 12):
        try:
            expected = b"hi there\x00"[i]
        except IndexError:
            with pytest.raises(IndexError):
                buf[i]
        else:
            assert buf[i] == bitem2bchr(expected)
    # --mb_slice--
    assert buf[:] == b"hi there\x00"
    for i in range(-12, 12):
        assert buf[i:] == b"hi there\x00"[i:]
        assert buf[:i] == b"hi there\x00"[:i]
        for j in range(-12, 12):
            assert buf[i:j] == b"hi there\x00"[i:j]
    # --misc--
    assert list(buf) == list(map(bitem2bchr, b"hi there\x00"))
    # --mb_as_buffer--
    if hasattr(__builtin__, 'buffer'):          # Python <= 2.7
        pytest.raises(TypeError, __builtin__.buffer, c)
        bf1 = __builtin__.buffer(buf)
        assert len(bf1) == len(buf) and bf1[3] == "t"
    if hasattr(__builtin__, 'memoryview'):      # Python >= 2.7
        pytest.raises(TypeError, memoryview, c)
        mv1 = memoryview(buf)
        assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t"))
    # --mb_ass_item--
    expected = list(map(bitem2bchr, b"hi there\x00"))
    for i in range(-12, 12):
        try:
            expected[i] = bytechr(i & 0xff)
        except IndexError:
            with pytest.raises(IndexError):
                buf[i] = bytechr(i & 0xff)
        else:
            buf[i] = bytechr(i & 0xff)
        assert list(buf) == expected
    # --mb_ass_slice--
    buf[:] = b"hi there\x00"
    assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00"))
    with pytest.raises(ValueError):
        buf[:] = b"shorter"
    with pytest.raises(ValueError):
        buf[:] = b"this is much too long!"
    buf[4:2] = b""   # no effect, but should work
    assert buf[:] == b"hi there\x00"
    buf[:2] = b"HI"
    assert buf[:] == b"HI there\x00"
    buf[:2] = b"hi"
    expected = list(map(bitem2bchr, b"hi there\x00"))
    x = 0
    for i in range(-12, 12):
        for j in range(-12, 12):
            start = i if i >= 0 else i + len(buf)
            stop  = j if j >= 0 else j + len(buf)
            start = max(0, min(len(buf), start))
            stop  = max(0, min(len(buf), stop))
            sample = bytechr(x & 0xff) * (stop - start)
            x += 1
            buf[i:j] = sample
            expected[i:j] = map(bitem2bchr, sample)
            assert list(buf) == expected

def test_getcname():
    BUChar = new_primitive_type("unsigned char")
    BArray = new_array_type(new_pointer_type(BUChar), 123)
    assert getcname(BArray, "<-->") == "unsigned char<-->[123]"

def test_errno():
    BVoid = new_void_type()
    BFunc5 = new_function_type((), BVoid)
    f = cast(BFunc5, _testfunc(5))
    set_errno(50)
    f()
    assert get_errno() == 65
    f(); f()
    assert get_errno() == 95

def test_errno_callback():
    if globals().get('PY_DOT_PY'):
        pytest.skip("cannot run this test on py.py (e.g. fails on Windows)")
    set_errno(95)
    def cb():
        e = get_errno()
        set_errno(e - 6)
    BVoid = new_void_type()
    BFunc5 = new_function_type((), BVoid)
    f = callback(BFunc5, cb)
    f()
    assert get_errno() == 89
    f(); f()
    assert get_errno() == 77

def test_cast_to_array():
    # not valid in C!  extension to get a non-owning <cdata 'int[3]'>
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BArray = new_array_type(BIntP, 3)
    x = cast(BArray, 0)
    assert repr(x) == "<cdata 'int[3]' NULL>"

def test_cast_invalid():
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [])
    p = cast(new_pointer_type(BStruct), 123456)
    s = p[0]
    pytest.raises(TypeError, cast, BStruct, s)

def test_bug_float_convertion():
    BDouble = new_primitive_type("double")
    BDoubleP = new_pointer_type(BDouble)
    pytest.raises(TypeError, newp, BDoubleP, "foobar")

def test_bug_delitem():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    x = newp(BCharP)
    with pytest.raises(TypeError):
        del x[0]

def test_bug_delattr():
    BLong = new_primitive_type("long")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BLong, -1)])
    x = newp(new_pointer_type(BStruct))
    with pytest.raises(AttributeError):
        del x.a1

def test_variable_length_struct():
    pytest.skip("later")
    BLong = new_primitive_type("long")
    BArray = new_array_type(new_pointer_type(BLong), None)
    BStruct = new_struct_type("struct foo")
    BStructP = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BLong, -1),
                                       ('a2', BArray, -1)])
    assert sizeof(BStruct) == size_of_long()
    assert alignof(BStruct) == alignof(BLong)
    #
    pytest.raises(TypeError, newp, BStructP, None)
    x = newp(BStructP, 5)
    assert sizeof(x) == 6 * size_of_long()
    x[4] = 123
    assert x[4] == 123
    with pytest.raises(IndexError):
        x[5]
    assert len(x.a2) == 5
    #
    pytest.raises(TypeError, newp, BStructP, [123])
    x = newp(BStructP, [123, 5])
    assert x.a1 == 123
    assert len(x.a2) == 5
    assert list(x.a2) == [0] * 5
    #
    x = newp(BStructP, {'a2': 5})
    assert x.a1 == 0
    assert len(x.a2) == 5
    assert list(x.a2) == [0] * 5
    #
    x = newp(BStructP, [123, (4, 5)])
    assert x.a1 == 123
    assert len(x.a2) == 2
    assert list(x.a2) == [4, 5]
    #
    x = newp(BStructP, {'a2': (4, 5)})
    assert x.a1 == 0
    assert len(x.a2) == 2
    assert list(x.a2) == [4, 5]

def test_autocast_int():
    BInt = new_primitive_type("int")
    BIntPtr = new_pointer_type(BInt)
    BLongLong = new_primitive_type("long long")
    BULongLong = new_primitive_type("unsigned long long")
    BULongLongPtr = new_pointer_type(BULongLong)
    x = newp(BIntPtr, cast(BInt, 42))
    assert x[0] == 42
    x = newp(BIntPtr, cast(BLongLong, 42))
    assert x[0] == 42
    x = newp(BIntPtr, cast(BULongLong, 42))
    assert x[0] == 42
    x = newp(BULongLongPtr, cast(BInt, 42))
    assert x[0] == 42
    pytest.raises(OverflowError, newp, BULongLongPtr, cast(BInt, -42))
    x = cast(BInt, cast(BInt, 42))
    assert int(x) == 42
    x = cast(BInt, cast(BLongLong, 42))
    assert int(x) == 42
    x = cast(BInt, cast(BULongLong, 42))
    assert int(x) == 42
    x = cast(BULongLong, cast(BInt, 42))
    assert int(x) == 42
    x = cast(BULongLong, cast(BInt, -42))
    assert int(x) == 2 ** 64 - 42
    x = cast(BIntPtr, cast(BInt, 42))
    assert int(cast(BInt, x)) == 42

def test_autocast_float():
    BFloat = new_primitive_type("float")
    BDouble = new_primitive_type("float")
    BFloatPtr = new_pointer_type(BFloat)
    x = newp(BFloatPtr, cast(BDouble, 12.5))
    assert x[0] == 12.5
    x = cast(BFloat, cast(BDouble, 12.5))
    assert float(x) == 12.5

def test_longdouble():
    py_py = 'PY_DOT_PY' in globals()
    BInt = new_primitive_type("int")
    BLongDouble = new_primitive_type("long double")
    BLongDoublePtr = new_pointer_type(BLongDouble)
    BLongDoubleArray = new_array_type(BLongDoublePtr, None)
    a = newp(BLongDoubleArray, 1)
    x = a[0]
    if not py_py:
        assert repr(x).startswith("<cdata 'long double' 0.0")
    assert float(x) == 0.0
    assert int(x) == 0
    #
    b = newp(BLongDoubleArray, [1.23])
    x = b[0]
    if not py_py:
        assert repr(x).startswith("<cdata 'long double' 1.23")
    assert float(x) == 1.23
    assert int(x) == 1
    #
    BFunc19 = new_function_type((BLongDouble, BInt), BLongDouble)
    f = cast(BFunc19, _testfunc(19))
    start = lstart = 1.5
    for i in range(107):
        start = 4 * start - start * start
        lstart = f(lstart, 1)
    lother = f(1.5, 107)
    if not py_py:
        assert float(lstart) == float(lother)
        assert repr(lstart) == repr(lother)
        if sizeof(BLongDouble) > sizeof(new_primitive_type("double")):
            assert float(lstart) != start
            assert repr(lstart).startswith("<cdata 'long double' ")
    #
    c = newp(BLongDoubleArray, [lstart])
    x = c[0]
    assert float(f(lstart, 107)) == float(f(x, 107))

def test_get_array_of_length_zero():
    for length in [0, 5, 10]:
        BLong = new_primitive_type("long")
        BLongP = new_pointer_type(BLong)
        BArray0 = new_array_type(BLongP, length)
        BStruct = new_struct_type("struct foo")
        BStructPtr = new_pointer_type(BStruct)
        complete_struct_or_union(BStruct, [('a1', BArray0, -1)])
        p = newp(BStructPtr, None)
        if length == 0:
            assert repr(p.a1).startswith("<cdata 'long *' 0x")
        else:
            assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length)

def test_nested_anonymous_struct():
    BInt = new_primitive_type("int")
    BChar = new_primitive_type("char")
    BStruct = new_struct_type("struct foo")
    BInnerStruct = new_struct_type("struct foo")
    complete_struct_or_union(BInnerStruct, [('a1', BInt, -1),
                                            ('a2', BChar, -1)])
    complete_struct_or_union(BStruct, [('', BInnerStruct, -1),
                                       ('a3', BChar, -1)])
    assert sizeof(BInnerStruct) == sizeof(BInt) * 2   # with alignment
    assert sizeof(BStruct) == sizeof(BInt) * 3        # 'a3' is placed after
    d = BStruct.fields
    assert len(d) == 3
    assert d[0][0] == 'a1'
    assert d[0][1].type is BInt
    assert d[0][1].offset == 0
    assert d[0][1].bitshift == -1
    assert d[0][1].bitsize == -1
    assert d[1][0] == 'a2'
    assert d[1][1].type is BChar
    assert d[1][1].offset == sizeof(BInt)
    assert d[1][1].bitshift == -1
    assert d[1][1].bitsize == -1
    assert d[2][0] == 'a3'
    assert d[2][1].type is BChar
    assert d[2][1].offset == sizeof(BInt) * 2
    assert d[2][1].bitshift == -1
    assert d[2][1].bitsize == -1

def test_nested_anonymous_struct_2():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    BInnerUnion = new_union_type("union bar")
    complete_struct_or_union(BInnerUnion, [('a1', BInt, -1),
                                           ('a2', BInt, -1)])
    complete_struct_or_union(BStruct, [('b1', BInt, -1),
                                       ('', BInnerUnion, -1),
                                       ('b2', BInt, -1)])
    assert sizeof(BInnerUnion) == sizeof(BInt)
    assert sizeof(BStruct) == sizeof(BInt) * 3
    fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields]
    assert fields == [
        ('b1', 0 * sizeof(BInt), 0),
        ('a1', 1 * sizeof(BInt), 0),
        ('a2', 1 * sizeof(BInt), 1),
        ('b2', 2 * sizeof(BInt), 0),
    ]

def test_sizeof_union():
    # a union has the largest alignment of its members, and a total size
    # that is the largest of its items *possibly further aligned* if
    # another smaller item has a larger alignment...
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    assert sizeof(BShort) == alignof(BShort) == 2
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BChar),
                                       ('a2', BChar),
                                       ('a3', BChar)])
    assert sizeof(BStruct) == 3 and alignof(BStruct) == 1
    BUnion = new_union_type("union u")
    complete_struct_or_union(BUnion, [('s', BStruct),
                                      ('i', BShort)])
    assert sizeof(BUnion) == 4
    assert alignof(BUnion) == 2

def test_unaligned_struct():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('b', BInt, -1, 1)],
                             None, 5, 1)

def test_CData_CType():
    CData, CType = _get_types()
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    nullchr = cast(BChar, 0)
    chrref = newp(BCharP, None)
    assert isinstance(nullchr, CData)
    assert isinstance(chrref, CData)
    assert not isinstance(BChar, CData)
    assert not isinstance(nullchr, CType)
    assert not isinstance(chrref, CType)
    assert isinstance(BChar, CType)

def test_no_cdata_float():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BUInt = new_primitive_type("unsigned int")
    BUIntP = new_pointer_type(BUInt)
    BFloat = new_primitive_type("float")
    pytest.raises(TypeError, newp, BIntP, cast(BFloat, 0.0))
    pytest.raises(TypeError, newp, BUIntP, cast(BFloat, 0.0))

def test_bool():
    BBool = new_primitive_type("_Bool")
    BBoolP = new_pointer_type(BBool)
    assert int(cast(BBool, False)) == 0
    assert int(cast(BBool, True)) == 1
    assert bool(cast(BBool, False)) is False    # since 1.7
    assert bool(cast(BBool, True)) is True
    assert int(cast(BBool, 3)) == 1
    assert int(cast(BBool, long(3))) == 1
    assert int(cast(BBool, long(10)**4000)) == 1
    assert int(cast(BBool, -0.1)) == 1
    assert int(cast(BBool, -0.0)) == 0
    assert int(cast(BBool, '\x00')) == 0
    assert int(cast(BBool, '\xff')) == 1
    assert newp(BBoolP, False)[0] == 0
    assert newp(BBoolP, True)[0] == 1
    assert newp(BBoolP, 0)[0] == 0
    assert newp(BBoolP, 1)[0] == 1
    pytest.raises(TypeError, newp, BBoolP, 1.0)
    pytest.raises(TypeError, newp, BBoolP, '\x00')
    pytest.raises(OverflowError, newp, BBoolP, 2)
    pytest.raises(OverflowError, newp, BBoolP, -1)
    BCharP = new_pointer_type(new_primitive_type("char"))
    p = newp(BCharP, b'\x01')
    q = cast(BBoolP, p)
    assert q[0] is True
    p = newp(BCharP, b'\x00')
    q = cast(BBoolP, p)
    assert q[0] is False
    pytest.raises(TypeError, string, cast(BBool, False))
    BDouble = new_primitive_type("double")
    assert int(cast(BBool, cast(BDouble, 0.1))) == 1
    assert int(cast(BBool, cast(BDouble, 0.0))) == 0
    BBoolA = new_array_type(BBoolP, None)
    p = newp(BBoolA, b'\x01\x00')
    assert p[0] is True
    assert p[1] is False

def test_bool_forbidden_cases():
    BBool = new_primitive_type("_Bool")
    BBoolP = new_pointer_type(BBool)
    BBoolA = new_array_type(BBoolP, None)
    BCharP = new_pointer_type(new_primitive_type("char"))
    p = newp(BCharP, b'X')
    q = cast(BBoolP, p)
    with pytest.raises(ValueError):
        q[0]
    pytest.raises(TypeError, newp, BBoolP, b'\x00')
    assert newp(BBoolP, 0)[0] is False
    assert newp(BBoolP, 1)[0] is True
    pytest.raises(OverflowError, newp, BBoolP, 2)
    pytest.raises(OverflowError, newp, BBoolP, -1)
    pytest.raises(ValueError, newp, BBoolA, b'\x00\x01\x02')
    pytest.raises(OverflowError, newp, BBoolA, [0, 1, 2])
    pytest.raises(TypeError, string, newp(BBoolP, 1))
    pytest.raises(TypeError, string, newp(BBoolA, [1]))

def test_typeoffsetof():
    BChar = new_primitive_type("char")
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                       ('a2', BChar, -1),
                                       ('a3', BChar, -1)])
    pytest.raises(TypeError, typeoffsetof, BStructPtr, None)
    pytest.raises(TypeError, typeoffsetof, BStruct, None)
    assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0)
    assert typeoffsetof(BStruct, 'a1') == (BChar, 0)
    assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1)
    assert typeoffsetof(BStruct, 'a3') == (BChar, 2)
    assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1)
    assert typeoffsetof(BStruct, u+'a3') == (BChar, 2)
    pytest.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1)
    pytest.raises(KeyError, typeoffsetof, BStructPtr, 'a4')
    pytest.raises(KeyError, typeoffsetof, BStruct, 'a5')
    pytest.raises(TypeError, typeoffsetof, BStruct, 42)
    pytest.raises(TypeError, typeoffsetof, BChar, 'a1')

def test_typeoffsetof_array():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BArray = new_array_type(BIntP, None)
    pytest.raises(TypeError, typeoffsetof, BArray, None)
    pytest.raises(TypeError, typeoffsetof, BArray, 'a1')
    assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int())
    assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int())
    assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int())
    MAX = sys.maxsize // size_of_int()
    assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int())
    assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int())
    pytest.raises(OverflowError, typeoffsetof, BArray, MAX + 1)

def test_typeoffsetof_no_bitfield():
    BInt = new_primitive_type("int")
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BInt, 4)])
    pytest.raises(TypeError, typeoffsetof, BStruct, 'a1')

def test_rawaddressof():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BStruct = new_struct_type("struct foo")
    BStructPtr = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('a1', BChar, -1),
                                       ('a2', BChar, -1),
                                       ('a3', BChar, -1)])
    p = newp(BStructPtr)
    assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>"
    s = p[0]
    assert repr(s) == "<cdata 'struct foo' owning 3 bytes>"
    a = rawaddressof(BStructPtr, s, 0)
    assert repr(a).startswith("<cdata 'struct foo *' 0x")
    pytest.raises(TypeError, rawaddressof, BStruct, s, 0)
    b = rawaddressof(BCharP, s, 0)
    assert b == cast(BCharP, p)
    c = rawaddressof(BStructPtr, a, 0)
    assert c == a
    pytest.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0)
    #
    d = rawaddressof(BCharP, s, 1)
    assert d == cast(BCharP, p) + 1
    #
    e = cast(BCharP, 109238)
    f = rawaddressof(BCharP, e, 42)
    assert f == e + 42
    #
    BCharA = new_array_type(BCharP, None)
    e = newp(BCharA, 50)
    f = rawaddressof(BCharP, e, 42)
    assert f == e + 42

def test_newp_signed_unsigned_char():
    BCharArray = new_array_type(
        new_pointer_type(new_primitive_type("char")), None)
    p = newp(BCharArray, b"foo")
    assert len(p) == 4
    assert list(p) == [b"f", b"o", b"o", b"\x00"]
    #
    BUCharArray = new_array_type(
        new_pointer_type(new_primitive_type("unsigned char")), None)
    p = newp(BUCharArray, b"fo\xff")
    assert len(p) == 4
    assert list(p) == [ord("f"), ord("o"), 0xff, 0]
    #
    BSCharArray = new_array_type(
        new_pointer_type(new_primitive_type("signed char")), None)
    p = newp(BSCharArray, b"fo\xff")
    assert len(p) == 4
    assert list(p) == [ord("f"), ord("o"), -1, 0]

def test_newp_from_bytearray_doesnt_work():
    BCharArray = new_array_type(
        new_pointer_type(new_primitive_type("char")), None)
    pytest.raises(TypeError, newp, BCharArray, bytearray(b"foo"))
    p = newp(BCharArray, 5)
    buffer(p)[:] = bytearray(b"foo.\x00")
    assert len(p) == 5
    assert list(p) == [b"f", b"o", b"o", b".", b"\x00"]
    p[1:3] = bytearray(b"XY")
    assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"]

def test_string_assignment_to_byte_array():
    BByteArray = new_array_type(
        new_pointer_type(new_primitive_type("unsigned char")), None)
    p = newp(BByteArray, 5)
    p[0:3] = bytearray(b"XYZ")
    assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0]

# XXX hack
if sys.version_info >= (3,):
    try:
        import posix, io
        posix.fdopen = io.open
    except ImportError:
        pass   # win32

def test_FILE():
    if sys.platform == "win32":
        pytest.skip("testing FILE not implemented")
    #
    BFILE = new_struct_type("struct _IO_FILE")
    BFILEP = new_pointer_type(BFILE)
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BCharP, BFILEP), BInt, False)
    BFunc2 = new_function_type((BFILEP, BCharP), BInt, True)
    ll = find_and_load_library('c')
    fputs = ll.load_function(BFunc, "fputs")
    fscanf = ll.load_function(BFunc2, "fscanf")
    #
    import posix
    fdr, fdw = posix.pipe()
    fr1 = posix.fdopen(fdr, 'rb', 256)
    fw1 = posix.fdopen(fdw, 'wb', 256)
    #
    fw1.write(b"X")
    res = fputs(b"hello world\n", fw1)
    assert res >= 0
    fw1.flush()     # should not be needed
    #
    p = newp(new_array_type(BCharP, 100), None)
    res = fscanf(fr1, b"%s\n", p)
    assert res == 1
    assert string(p) == b"Xhello"
    fr1.close()
    fw1.close()

def test_FILE_only_for_FILE_arg():
    if sys.platform == "win32":
        pytest.skip("testing FILE not implemented")
    #
    B_NOT_FILE = new_struct_type("struct NOT_FILE")
    B_NOT_FILEP = new_pointer_type(B_NOT_FILE)
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False)
    ll = find_and_load_library('c')
    fputs = ll.load_function(BFunc, "fputs")
    #
    import posix
    fdr, fdw = posix.pipe()
    fr1 = posix.fdopen(fdr, 'r')
    fw1 = posix.fdopen(fdw, 'w')
    #
    e = pytest.raises(TypeError, fputs, b"hello world\n", fw1)
    assert str(e.value).startswith(
        "initializer for ctype 'struct NOT_FILE *' must "
        "be a cdata pointer, not ")

def test_FILE_object():
    if sys.platform == "win32":
        pytest.skip("testing FILE not implemented")
    #
    BFILE = new_struct_type("FILE")
    BFILEP = new_pointer_type(BFILE)
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BCharP, BFILEP), BInt, False)
    BFunc2 = new_function_type((BFILEP,), BInt, False)
    ll = find_and_load_library('c')
    fputs = ll.load_function(BFunc, "fputs")
    fileno = ll.load_function(BFunc2, "fileno")
    #
    import posix
    fdr, fdw = posix.pipe()
    fw1 = posix.fdopen(fdw, 'wb', 256)
    #
    fw1p = cast(BFILEP, fw1)
    fw1.write(b"X")
    fw1.flush()
    res = fputs(b"hello\n", fw1p)
    assert res >= 0
    res = fileno(fw1p)
    assert (res == fdw) == (sys.version_info < (3,))
    fw1.close()
    #
    data = posix.read(fdr, 256)
    assert data == b"Xhello\n"
    posix.close(fdr)

def test_errno_saved():
    set_errno(42)
    # a random function that will reset errno to 0 (at least on non-windows)
    import os; os.stat('.')
    #
    res = get_errno()
    assert res == 42

def test_GetLastError():
    if sys.platform != "win32":
        pytest.skip("GetLastError(): only for Windows")
    #
    lib = find_and_load_library('KERNEL32.DLL')
    BInt = new_primitive_type("int")
    BVoid = new_void_type()
    BFunc1 = new_function_type((BInt,), BVoid, False)
    BFunc2 = new_function_type((), BInt, False)
    SetLastError = lib.load_function(BFunc1, "SetLastError")
    GetLastError = lib.load_function(BFunc2, "GetLastError")
    #
    SetLastError(42)
    # a random function that will reset the real GetLastError() to 0
    import nt; nt.stat('.')
    #
    res = GetLastError()
    assert res == 42
    #
    SetLastError(2)
    code, message = getwinerror()
    assert code == 2
    assert message == "The system cannot find the file specified"
    #
    code, message = getwinerror(1155)
    assert code == 1155
    assert message == ("No application is associated with the "
                       "specified file for this operation")

def test_nonstandard_integer_types():
    for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t',
                     'uint32_t', 'int64_t', 'uint64_t', 'intptr_t',
                     'uintptr_t', 'ptrdiff_t', 'size_t', 'ssize_t',
                     'int_least8_t',  'uint_least8_t',
                     'int_least16_t', 'uint_least16_t',
                     'int_least32_t', 'uint_least32_t',
                     'int_least64_t', 'uint_least64_t',
                     'int_fast8_t',  'uint_fast8_t',
                     'int_fast16_t', 'uint_fast16_t',
                     'int_fast32_t', 'uint_fast32_t',
                     'int_fast64_t', 'uint_fast64_t',
                     'intmax_t', 'uintmax_t']:
        new_primitive_type(typename)    # works

def test_cannot_convert_unicode_to_charp():
    BCharP = new_pointer_type(new_primitive_type("char"))
    BCharArray = new_array_type(BCharP, None)
    pytest.raises(TypeError, newp, BCharArray, u+'foobar')

def test_buffer_keepalive():
    BCharP = new_pointer_type(new_primitive_type("char"))
    BCharArray = new_array_type(BCharP, None)
    buflist = []
    for i in range(20):
        c = newp(BCharArray, str2bytes("hi there %d" % i))
        buflist.append(buffer(c))
    import gc; gc.collect()
    for i in range(20):
        buf = buflist[i]
        assert buf[:] == str2bytes("hi there %d\x00" % i)

def test_slice():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntArray = new_array_type(BIntP, None)
    c = newp(BIntArray, 5)
    assert len(c) == 5
    assert repr(c) == "<cdata 'int[]' owning 20 bytes>"
    d = c[1:4]
    assert len(d) == 3
    assert repr(d) == "<cdata 'int[]' sliced length 3>"
    d[0] = 123
    d[2] = 456
    assert c[1] == 123
    assert c[3] == 456
    assert d[2] == 456
    with pytest.raises(IndexError):
        d[3]
    with pytest.raises(IndexError):
        d[-1]

def test_slice_ptr():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntArray = new_array_type(BIntP, None)
    c = newp(BIntArray, 5)
    d = (c+1)[0:2]
    assert len(d) == 2
    assert repr(d) == "<cdata 'int[]' sliced length 2>"
    d[1] += 50
    assert c[2] == 50

def test_slice_array_checkbounds():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntArray = new_array_type(BIntP, None)
    c = newp(BIntArray, 5)
    c[0:5]
    assert len(c[5:5]) == 0
    with pytest.raises(IndexError):
        c[-1:1]
    cp = c + 0
    cp[-1:1]

def test_nonstandard_slice():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntArray = new_array_type(BIntP, None)
    c = newp(BIntArray, 5)
    with pytest.raises(IndexError) as e:
        c[:5]
    assert str(e.value) == "slice start must be specified"
    with pytest.raises(IndexError) as e:
        c[4:]
    assert str(e.value) == "slice stop must be specified"
    with pytest.raises(IndexError) as e:
        c[1:2:3]
    assert str(e.value) == "slice with step not supported"
    with pytest.raises(IndexError) as e:
        c[1:2:1]
    assert str(e.value) == "slice with step not supported"
    with pytest.raises(IndexError) as e:
        c[4:2]
    assert str(e.value) == "slice start > stop"
    with pytest.raises(IndexError) as e:
        c[6:6]
    assert str(e.value) == "index too large (expected 6 <= 5)"

def test_setslice():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntArray = new_array_type(BIntP, None)
    c = newp(BIntArray, 5)
    c[1:3] = [100, 200]
    assert list(c) == [0, 100, 200, 0, 0]
    cp = c + 3
    cp[-1:1] = [300, 400]
    assert list(c) == [0, 100, 300, 400, 0]
    cp[-1:1] = iter([500, 600])
    assert list(c) == [0, 100, 500, 600, 0]
    with pytest.raises(ValueError):
        cp[-1:1] = [1000]
    assert list(c) == [0, 100, 1000, 600, 0]
    with pytest.raises(ValueError):
        cp[-1:1] = (700, 800, 900)
    assert list(c) == [0, 100, 700, 800, 0]

def test_setslice_array():
    BIntP = new_pointer_type(new_primitive_type("int"))
    BIntArray = new_array_type(BIntP, None)
    c = newp(BIntArray, 5)
    d = newp(BIntArray, [10, 20, 30])
    c[1:4] = d
    assert list(c) == [0, 10, 20, 30, 0]
    #
    BShortP = new_pointer_type(new_primitive_type("short"))
    BShortArray = new_array_type(BShortP, None)
    d = newp(BShortArray, [40, 50])
    c[1:3] = d
    assert list(c) == [0, 40, 50, 30, 0]

def test_cdata_name_module_doc():
    p = new_primitive_type("signed char")
    x = cast(p, 17)
    assert x.__module__ == '_cffi_backend'
    assert x.__name__ == '<cdata>'
    assert hasattr(x, '__doc__')

def test_different_types_of_ptr_equality():
    BVoidP = new_pointer_type(new_void_type())
    BIntP = new_pointer_type(new_primitive_type("int"))
    x = cast(BVoidP, 12345)
    assert x == cast(BIntP, 12345)
    assert x != cast(BIntP, 12344)
    assert hash(x) == hash(cast(BIntP, 12345))

def test_new_handle():
    import _weakref
    BVoidP = new_pointer_type(new_void_type())
    BCharP = new_pointer_type(new_primitive_type("char"))
    class mylist(list):
        pass
    o = mylist([2, 3, 4])
    x = newp_handle(BVoidP, o)
    assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>"
    assert x
    assert from_handle(x) is o
    assert from_handle(cast(BCharP, x)) is o
    wr = _weakref.ref(o)
    del o
    import gc; gc.collect()
    assert wr() is not None
    assert from_handle(x) == list((2, 3, 4))
    assert from_handle(cast(BCharP, x)) == list((2, 3, 4))
    del x
    for i in range(3):
        if wr() is not None:
            import gc; gc.collect()
    assert wr() is None
    pytest.raises(RuntimeError, from_handle, cast(BCharP, 0))

def test_new_handle_cycle():
    import _weakref
    BVoidP = new_pointer_type(new_void_type())
    class A(object):
        pass
    o = A()
    o.cycle = newp_handle(BVoidP, o)
    wr = _weakref.ref(o)
    del o
    for i in range(3):
        if wr() is not None:
            import gc; gc.collect()
    assert wr() is None

def _test_bitfield_details(flag):
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    BInt = new_primitive_type("int")
    BUInt = new_primitive_type("unsigned int")
    BStruct = new_struct_type("struct foo1")
    complete_struct_or_union(BStruct, [('a', BChar, -1),
                                       ('b1', BInt, 9),
                                       ('b2', BUInt, 7),
                                       ('c', BChar, -1)], -1, -1, -1, flag)
    if not (flag & SF_MSVC_BITFIELDS):   # gcc, any variant
        assert typeoffsetof(BStruct, 'c') == (BChar, 3)
        assert sizeof(BStruct) == 4
    else:               # msvc
        assert typeoffsetof(BStruct, 'c') == (BChar, 8)
        assert sizeof(BStruct) == 12
    assert alignof(BStruct) == 4
    #
    p = newp(new_pointer_type(BStruct), None)
    p.a = b'A'
    p.b1 = -201
    p.b2 = 99
    p.c = b'\x9D'
    raw = buffer(p)[:]
    if sys.byteorder == 'little':
        if flag & SF_MSVC_BITFIELDS:
            assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00'
        elif flag & SF_GCC_LITTLE_ENDIAN:
            assert raw == b'A7\xC7\x9D'
        elif flag & SF_GCC_BIG_ENDIAN:
            assert raw == b'A\xE3\x9B\x9D'
        else:
            raise AssertionError("bad flag")
    else:
        if flag & SF_MSVC_BITFIELDS:
            assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00'
        elif flag & SF_GCC_LITTLE_ENDIAN:
            assert raw == b'A\xC77\x9D'
        elif flag & SF_GCC_BIG_ENDIAN:
            assert raw == b'A\x9B\xE3\x9D'
        else:
            raise AssertionError("bad flag")
    #
    BStruct = new_struct_type("struct foo2")
    complete_struct_or_union(BStruct, [('a', BChar, -1),
                                       ('',  BShort, 9),
                                       ('c', BChar, -1)], -1, -1, -1, flag)
    assert typeoffsetof(BStruct, 'c') == (BChar, 4)
    if flag & SF_MSVC_BITFIELDS:
        assert sizeof(BStruct) == 6
        assert alignof(BStruct) == 2
    elif flag & SF_GCC_X86_BITFIELDS:
        assert sizeof(BStruct) == 5
        assert alignof(BStruct) == 1
    elif flag & SF_GCC_ARM_BITFIELDS:
        assert sizeof(BStruct) == 6
        assert alignof(BStruct) == 2
    else:
        raise AssertionError("bad flag")
    #
    BStruct = new_struct_type("struct foo2")
    complete_struct_or_union(BStruct, [('a', BChar, -1),
                                       ('',  BInt, 0),
                                       ('',  BInt, 0),
                                       ('c', BChar, -1)], -1, -1, -1, flag)
    if flag & SF_MSVC_BITFIELDS:
        assert typeoffsetof(BStruct, 'c') == (BChar, 1)
        assert sizeof(BStruct) == 2
        assert alignof(BStruct) == 1
    elif flag & SF_GCC_X86_BITFIELDS:
        assert typeoffsetof(BStruct, 'c') == (BChar, 4)
        assert sizeof(BStruct) == 5
        assert alignof(BStruct) == 1
    elif flag & SF_GCC_ARM_BITFIELDS:
        assert typeoffsetof(BStruct, 'c') == (BChar, 4)
        assert sizeof(BStruct) == 8
        assert alignof(BStruct) == 4
    else:
        raise AssertionError("bad flag")


SF_MSVC_BITFIELDS     = 0x01
SF_GCC_ARM_BITFIELDS  = 0x02
SF_GCC_X86_BITFIELDS  = 0x10

SF_GCC_BIG_ENDIAN     = 0x04
SF_GCC_LITTLE_ENDIAN  = 0x40

SF_PACKED             = 0x08

def test_bitfield_as_x86_gcc():
    _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_LITTLE_ENDIAN)

def test_bitfield_as_msvc():
    _test_bitfield_details(flag=SF_MSVC_BITFIELDS|SF_GCC_LITTLE_ENDIAN)

def test_bitfield_as_arm_gcc():
    _test_bitfield_details(flag=SF_GCC_ARM_BITFIELDS|SF_GCC_LITTLE_ENDIAN)

def test_bitfield_as_ppc_gcc():
    # PowerPC uses the same format as X86, but is big-endian
    _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_BIG_ENDIAN)


def buffer_warning(cdata):
    import warnings
    buf = buffer(cdata)
    bytes = len(buf)
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        buffer(cdata, bytes)
        assert len(w) == 0
        buffer(cdata, bytes + 1)
        assert len(w) <= 1
        return len(w) == 1

def test_struct_array_no_length():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BArray = new_array_type(BIntP, None)
    BStruct = new_struct_type("foo")
    pytest.raises(TypeError, complete_struct_or_union,
                   BStruct, [('x', BArray),
                             ('y', BInt)])
    #
    BStruct = new_struct_type("foo")
    complete_struct_or_union(BStruct, [('x', BInt),
                                       ('y', BArray)])
    assert sizeof(BStruct) == size_of_int()
    d = BStruct.fields
    assert len(d) == 2
    assert d[0][0] == 'x'
    assert d[0][1].type is BInt
    assert d[0][1].offset == 0
    assert d[0][1].bitshift == -1
    assert d[0][1].bitsize == -1
    assert d[1][0] == 'y'
    assert d[1][1].type is BArray
    assert d[1][1].offset == size_of_int()
    assert d[1][1].bitshift == -2
    assert d[1][1].bitsize == -1
    #
    p = newp(new_pointer_type(BStruct))
    p.x = 42
    assert p.x == 42
    assert typeof(p.y) is BArray
    assert len(p.y) == 0
    assert p.y == cast(BIntP, p) + 1
    #
    p = newp(new_pointer_type(BStruct), [100])
    assert p.x == 100
    assert len(p.y) == 0
    #
    # Tests for
    #    ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
    #    ffi.new("struct_with_var_array *", [field.., array_size])
    plist = []
    for i in range(20):
        if i % 2 == 0:
            p = newp(new_pointer_type(BStruct), [100, [200, i, 400]])
        else:
            p = newp(new_pointer_type(BStruct), [100, 3])
            p.y[1] = i
            p.y[0] = 200
            assert p.y[2] == 0
            p.y[2] = 400
        assert len(p.y) == 3
        assert len(p[0].y) == 3
        assert len(buffer(p)) == sizeof(BInt) * 4
        assert sizeof(p[0]) == sizeof(BInt) * 4
        plist.append(p)
    for i in range(20):
        p = plist[i]
        assert p.x == 100
        assert p.y[0] == 200
        assert p.y[1] == i
        assert p.y[2] == 400
        assert list(p.y) == [200, i, 400]
    #
    # the following assignment works, as it normally would, for any array field
    p.y = [501, 601]
    assert list(p.y) == [501, 601, 400]
    p[0].y = [500, 600]
    assert list(p[0].y) == [500, 600, 400]
    assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
        sizeof(BStruct) + 3 * sizeof(BInt),)
    assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
        sizeof(BStruct) + 3 * sizeof(BInt),)
    assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
    #
    # from a non-owning pointer, we can't get the length
    q = cast(new_pointer_type(BStruct), p)
    assert q.y[0] == 500
    assert q[0].y[0] == 500
    pytest.raises(TypeError, len, q.y)
    pytest.raises(TypeError, len, q[0].y)
    assert typeof(q.y) is BIntP
    assert typeof(q[0].y) is BIntP
    assert sizeof(q[0]) == sizeof(BStruct)
    #
    # error cases
    with pytest.raises(IndexError):
        p.y[4]
    with pytest.raises(TypeError):
        p.y = cast(BIntP, 0)
    with pytest.raises(TypeError):
        p.y = 15
    with pytest.raises(TypeError):
        p.y = None
    #
    # accepting this may be specified by the C99 standard,
    # or a GCC strangeness...
    BStruct2 = new_struct_type("bar")
    complete_struct_or_union(BStruct2, [('f', BStruct),
                                        ('n', BInt)])
    p = newp(new_pointer_type(BStruct2), {'n': 42})
    assert p.n == 42
    #
    # more error cases
    pytest.raises(TypeError, newp, new_pointer_type(BStruct), [100, None])
    BArray4 = new_array_type(BIntP, 4)
    BStruct4 = new_struct_type("test4")
    complete_struct_or_union(BStruct4, [('a', BArray4)])   # not varsized
    pytest.raises(TypeError, newp, new_pointer_type(BStruct4), [None])
    pytest.raises(TypeError, newp, new_pointer_type(BStruct4), [4])
    p = newp(new_pointer_type(BStruct4), [[10, 20, 30]])
    assert p.a[0] == 10
    assert p.a[1] == 20
    assert p.a[2] == 30
    assert p.a[3] == 0
    assert buffer_warning(p)
    #
    # struct of struct of varsized array
    BStruct2 = new_struct_type("bar")
    complete_struct_or_union(BStruct2, [('head', BInt),
                                        ('tail', BStruct)])
    for i in range(2):   # try to detect heap overwrites
        p = newp(new_pointer_type(BStruct2), [100, [200, list(range(50))]])
        assert p.tail.y[49] == 49
    assert buffer_warning(p)
    assert not buffer_warning(cast(new_pointer_type(BStruct2), p))
    assert not buffer_warning(cast(BIntP, p))

def test_more_buffer_warning():
    BChar = new_primitive_type("unsigned char")
    BCharP = new_pointer_type(BChar)
    BArray = new_array_type(BCharP, 10)   # char[10]
    p = newp(BArray)
    assert buffer_warning(p)
    assert not buffer_warning(cast(BCharP, p))
    p = newp(BCharP)
    assert buffer_warning(p)
    assert not buffer_warning(cast(BCharP, p))


def test_struct_array_no_length_explicit_position():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BArray = new_array_type(BIntP, None)
    BStruct = new_struct_type("foo")
    complete_struct_or_union(BStruct, [('x', BArray, -1, 0), # actually 3 items
                                       ('y', BInt, -1, 12)])
    p = newp(new_pointer_type(BStruct), [[10, 20], 30])
    assert p.x[0] == 10
    assert p.x[1] == 20
    assert p.x[2] == 0
    assert p.y == 30
    p = newp(new_pointer_type(BStruct), {'x': [40], 'y': 50})
    assert p.x[0] == 40
    assert p.x[1] == 0
    assert p.x[2] == 0
    assert p.y == 50
    p = newp(new_pointer_type(BStruct), {'y': 60})
    assert p.x[0] == 0
    assert p.x[1] == 0
    assert p.x[2] == 0
    assert p.y == 60
    #
    # This "should" work too, allocating a larger structure
    # (a bit strange in this case, but useful in general)
    plist = []
    for i in range(20):
        p = newp(new_pointer_type(BStruct), [[10, 20, 30, 40, 50, 60, 70]])
        plist.append(p)
    for i in range(20):
        p = plist[i]
        assert p.x[0] == 10
        assert p.x[1] == 20
        assert p.x[2] == 30
        assert p.x[3] == 40 == p.y
        assert p.x[4] == 50
        assert p.x[5] == 60
        assert p.x[6] == 70

def test_struct_array_not_aligned():
    # struct a { int x; char y; char z[]; };
    # ends up of size 8, but 'z' is at offset 5
    BChar = new_primitive_type("char")
    BInt = new_primitive_type("int")
    BCharP = new_pointer_type(BChar)
    BArray = new_array_type(BCharP, None)
    BStruct = new_struct_type("foo")
    complete_struct_or_union(BStruct, [('x', BInt),
                                       ('y', BChar),
                                       ('z', BArray)])
    assert sizeof(BStruct) == 2 * size_of_int()
    def offsetof(BType, fieldname):
        return typeoffsetof(BType, fieldname)[1]
    base = offsetof(BStruct, 'z')
    assert base == size_of_int() + 1
    #
    p = newp(new_pointer_type(BStruct), {'z': 3})
    assert sizeof(p[0]) == base + 3
    q = newp(new_pointer_type(BStruct), {'z': size_of_int()})
    assert sizeof(q) == size_of_ptr()
    assert sizeof(q[0]) == base + size_of_int()
    assert len(p.z) == 3
    assert len(p[0].z) == 3
    assert len(q.z) == size_of_int()
    assert len(q[0].z) == size_of_int()

def test_ass_slice():
    BChar = new_primitive_type("char")
    BArray = new_array_type(new_pointer_type(BChar), None)
    p = newp(BArray, b"foobar")
    p[2:5] = [b"*", b"Z", b"T"]
    p[1:3] = b"XY"
    assert list(p) == [b"f", b"X", b"Y", b"Z", b"T", b"r", b"\x00"]
    with pytest.raises(TypeError):
        p[1:5] = u+'XYZT'
    with pytest.raises(TypeError):
        p[1:5] = [1, 2, 3, 4]
    #
    for typename in ["wchar_t", "char16_t", "char32_t"]:
        BUniChar = new_primitive_type(typename)
        BArray = new_array_type(new_pointer_type(BUniChar), None)
        p = newp(BArray, u+"foobar")
        p[2:5] = [u+"*", u+"Z", u+"T"]
        p[1:3] = u+"XY"
        assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
        with pytest.raises(TypeError):
            p[1:5] = b'XYZT'
        with pytest.raises(TypeError):
            p[1:5] = [1, 2, 3, 4]

def test_void_p_arithmetic():
    BVoid = new_void_type()
    BInt = new_primitive_type("intptr_t")
    p = cast(new_pointer_type(BVoid), 100000)
    assert int(cast(BInt, p)) == 100000
    assert int(cast(BInt, p + 42)) == 100042
    assert int(cast(BInt, p - (-42))) == 100042
    assert (p + 42) - p == 42
    q = cast(new_pointer_type(new_primitive_type("char")), 100000)
    with pytest.raises(TypeError):
        p - q
    with pytest.raises(TypeError):
        q - p
    with pytest.raises(TypeError):
        p + cast(new_primitive_type('int'), 42)
    with pytest.raises(TypeError):
        p - cast(new_primitive_type('int'), 42)

def test_sizeof_sliced_array():
    BInt = new_primitive_type("int")
    BArray = new_array_type(new_pointer_type(BInt), 10)
    p = newp(BArray, None)
    assert sizeof(p[2:9]) == 7 * sizeof(BInt)

def test_packed():
    BLong = new_primitive_type("long")
    BChar = new_primitive_type("char")
    BShort = new_primitive_type("short")
    for extra_args in [(SF_PACKED,), (0, 1)]:
        BStruct = new_struct_type("struct foo")
        complete_struct_or_union(BStruct, [('a1', BLong, -1),
                                           ('a2', BChar, -1),
                                           ('a3', BShort, -1)],
                                 None, -1, -1, *extra_args)
        d = BStruct.fields
        assert len(d) == 3
        assert d[0][0] == 'a1'
        assert d[0][1].type is BLong
        assert d[0][1].offset == 0
        assert d[0][1].bitshift == -1
        assert d[0][1].bitsize == -1
        assert d[1][0] == 'a2'
        assert d[1][1].type is BChar
        assert d[1][1].offset == sizeof(BLong)
        assert d[1][1].bitshift == -1
        assert d[1][1].bitsize == -1
        assert d[2][0] == 'a3'
        assert d[2][1].type is BShort
        assert d[2][1].offset == sizeof(BLong) + sizeof(BChar)
        assert d[2][1].bitshift == -1
        assert d[2][1].bitsize == -1
        assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
        assert alignof(BStruct) == 1
    #
    BStruct2 = new_struct_type("struct foo")
    complete_struct_or_union(BStruct2, [('b1', BChar, -1),
                                        ('b2', BLong, -1)],
                             None, -1, -1, 0, 2)
    d = BStruct2.fields
    assert len(d) == 2
    assert d[0][0] == 'b1'
    assert d[0][1].type is BChar
    assert d[0][1].offset == 0
    assert d[0][1].bitshift == -1
    assert d[0][1].bitsize == -1
    assert d[1][0] == 'b2'
    assert d[1][1].type is BLong
    assert d[1][1].offset == 2
    assert d[1][1].bitshift == -1
    assert d[1][1].bitsize == -1
    assert sizeof(BStruct2) == 2 + sizeof(BLong)
    assert alignof(BStruct2) == 2

def test_packed_with_bitfields():
    if sys.platform == "win32":
        pytest.skip("testing gcc behavior")
    BLong = new_primitive_type("long")
    BChar = new_primitive_type("char")
    BStruct = new_struct_type("struct foo")
    pytest.raises(NotImplementedError,
                   complete_struct_or_union,
                   BStruct, [('a1', BLong, 30),
                             ('a2', BChar, 5)],
                   None, -1, -1, SF_PACKED)

def test_from_buffer():
    import array
    a = array.array('H', [10000, 20000, 30000])
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    c = from_buffer(BCharA, a)
    assert typeof(c) is BCharA
    assert len(c) == 6
    assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>"
    p = new_pointer_type(new_primitive_type("unsigned short"))
    cast(p, c)[1] += 500
    assert list(a) == [10000, 20500, 30000]

def test_from_buffer_not_str_unicode():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    p1 = from_buffer(BCharA, b"foo")
    assert p1 == from_buffer(BCharA, b"foo")
    import gc; gc.collect()
    assert p1 == from_buffer(BCharA, b"foo")
    pytest.raises(TypeError, from_buffer, BCharA, u+"foo")
    try:
        from __builtin__ import buffer
    except ImportError:
        pass
    else:
        # Python 2 only
        contents = from_buffer(BCharA, buffer(b"foo"))
        assert len(contents) == len(p1)
        for i in range(len(contents)):
            assert contents[i] == p1[i]
        p4 = buffer(u+"foo")
        contents = from_buffer(BCharA, buffer(u+"foo"))
        assert len(contents) == len(p4)
        for i in range(len(contents)):
            assert contents[i] == p4[i]
    try:
        from __builtin__ import memoryview
    except ImportError:
        pass
    else:
        contents = from_buffer(BCharA, memoryview(b"foo"))
        assert len(contents) == len(p1)
        for i in range(len(contents)):
            assert contents[i] == p1[i]


def test_from_buffer_bytearray():
    a = bytearray(b"xyz")
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    p = from_buffer(BCharA, a)
    assert typeof(p) is BCharA
    assert len(p) == 3
    assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
    assert p[2] == b"z"
    p[2] = b"."
    assert a[2] == ord(".")
    a[2] = ord("?")
    assert p[2] == b"?"

def test_from_buffer_more_cases():
    try:
        from _cffi_backend import _testbuff
    except ImportError:
        pytest.skip("not for pypy")
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    #
    def check1(bufobj, expected):
        c = from_buffer(BCharA, bufobj)
        assert typeof(c) is BCharA
        if sys.version_info >= (3,):
            expected = [bytes(c, "ascii") for c in expected]
        assert list(c) == list(expected)
    #
    def check(methods, expected, expected_for_memoryview=None):
        if sys.version_info >= (3,):
            if methods <= 7:
                return
            if expected_for_memoryview is not None:
                expected = expected_for_memoryview
        class X(object):
            pass
        _testbuff(X, methods)
        bufobj = X()
        check1(bufobj, expected)
        try:
            from __builtin__ import buffer
            bufobjb = buffer(bufobj)
        except (TypeError, ImportError):
            pass
        else:
            check1(bufobjb, expected)
        try:
            bufobjm = memoryview(bufobj)
        except (TypeError, NameError):
            pass
        else:
            check1(bufobjm, expected_for_memoryview or expected)
    #
    check(1, "RDB")
    check(2, "WRB")
    check(4, "CHB")
    check(8, "GTB")
    check(16, "ROB")
    #
    check(1 | 2,  "RDB")
    check(1 | 4,  "RDB")
    check(2 | 4,  "CHB")
    check(1 | 8,  "RDB", "GTB")
    check(1 | 16, "RDB", "ROB")
    check(2 | 8,  "WRB", "GTB")
    check(2 | 16, "WRB", "ROB")
    check(4 | 8,  "CHB", "GTB")
    check(4 | 16, "CHB", "ROB")

def test_from_buffer_require_writable():
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    p1 = from_buffer(BCharA, b"foo", False)
    assert p1 == from_buffer(BCharA, b"foo", False)
    pytest.raises((TypeError, BufferError), from_buffer, BCharA, b"foo", True)
    ba = bytearray(b"foo")
    p1 = from_buffer(BCharA, ba, True)
    p1[0] = b"g"
    assert ba == b"goo"

def test_from_buffer_types():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BIntA = new_array_type(BIntP, None)
    lst = [-12345678, 87654321, 489148]
    bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
    lst2 = lst + [42, -999999999]
    bytestring2 = bytearray(buffer(newp(BIntA, lst2))[:] + b'XYZ')
    #
    p1 = from_buffer(BIntA, bytestring)      # int[]
    assert typeof(p1) is BIntA
    assert len(p1) == 3
    assert p1[0] == lst[0]
    assert p1[1] == lst[1]
    assert p1[2] == lst[2]
    with pytest.raises(IndexError):
        p1[3]
    with pytest.raises(IndexError):
        p1[-1]
    #
    pytest.raises(TypeError, from_buffer, BInt, bytestring)
    #
    p2 = from_buffer(BIntP, bytestring)      # int *
    assert p2 == p1 or 'PY_DOT_PY' in globals()
    # note: on py.py ^^^, bytearray buffers are not emulated well enough
    assert typeof(p2) is BIntP
    assert p2[0] == lst[0]
    assert p2[1] == lst[1]
    assert p2[2] == lst[2]
    # hopefully does not crash, but doesn't raise an exception:
    p2[3]
    p2[-1]
    # not enough data even for one, but this is not enforced:
    from_buffer(BIntP, b"")
    #
    BIntA2 = new_array_type(BIntP, 2)
    p2 = from_buffer(BIntA2, bytestring)     # int[2]
    assert typeof(p2) is BIntA2
    assert len(p2) == 2
    assert p2[0] == lst[0]
    assert p2[1] == lst[1]
    with pytest.raises(IndexError):
        p2[2]
    with pytest.raises(IndexError):
        p2[-1]
    assert p2 == p1 or 'PY_DOT_PY' in globals()
    #
    BIntA4 = new_array_type(BIntP, 4)        # int[4]: too big
    pytest.raises(ValueError, from_buffer, BIntA4, bytestring)
    #
    BStruct = new_struct_type("foo")
    complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                       ('a2', BInt, -1)])
    BStructP = new_pointer_type(BStruct)
    BStructA = new_array_type(BStructP, None)
    p1 = from_buffer(BStructA, bytestring2)   # struct[]
    assert len(p1) == 2
    assert typeof(p1) is BStructA
    assert p1[0].a1 == lst2[0]
    assert p1[0].a2 == lst2[1]
    assert p1[1].a1 == lst2[2]
    assert p1[1].a2 == lst2[3]
    with pytest.raises(IndexError):
        p1[2]
    with pytest.raises(IndexError):
        p1[-1]
    assert repr(p1) == "<cdata 'foo[]' buffer len 2 from 'bytearray' object>"
    #
    p2 = from_buffer(BStructP, bytestring2)    # 'struct *'
    assert p2 == p1 or 'PY_DOT_PY' in globals()
    assert typeof(p2) is BStructP
    assert p2.a1 == lst2[0]
    assert p2.a2 == lst2[1]
    assert p2[0].a1 == lst2[0]
    assert p2[0].a2 == lst2[1]
    assert p2[1].a1 == lst2[2]
    assert p2[1].a2 == lst2[3]
    # does not crash:
    p2[2]
    p2[-1]
    # not enough data even for one, but this is not enforced:
    from_buffer(BStructP, b"")
    from_buffer(BStructP, b"1234567")
    #
    release(p1)
    assert repr(p1) == "<cdata 'foo[]' buffer RELEASED>"
    #
    BEmptyStruct = new_struct_type("empty")
    complete_struct_or_union(BEmptyStruct, [], Ellipsis, 0)
    assert sizeof(BEmptyStruct) == 0
    BEmptyStructP = new_pointer_type(BEmptyStruct)
    BEmptyStructA = new_array_type(BEmptyStructP, None)
    pytest.raises(ZeroDivisionError, from_buffer,      # empty[]
                                      BEmptyStructA, bytestring)
    #
    BEmptyStructA5 = new_array_type(BEmptyStructP, 5)
    p1 = from_buffer(BEmptyStructA5, bytestring)   # struct empty[5]
    assert typeof(p1) is BEmptyStructA5
    assert len(p1) == 5
    assert (cast(BIntP, p1) == from_buffer(BIntA, bytestring)
            or 'PY_DOT_PY' in globals())
    #
    BVarStruct = new_struct_type("varfoo")
    BVarStructP = new_pointer_type(BVarStruct)
    complete_struct_or_union(BVarStruct, [('a1', BInt, -1),
                                          ('va', BIntA, -1)])
    with pytest.raises(TypeError):
        from_buffer(BVarStruct, bytestring)
    pv = from_buffer(BVarStructP, bytestring)    # varfoo *
    assert pv.a1 == lst[0]
    assert pv.va[0] == lst[1]
    assert pv.va[1] == lst[2]
    assert sizeof(pv[0]) == 1 * size_of_int()
    with pytest.raises(TypeError):
        len(pv.va)
    # hopefully does not crash, but doesn't raise an exception:
    pv.va[2]
    pv.va[-1]
    # not enough data even for one, but this is not enforced:
    from_buffer(BVarStructP, b"")
    assert repr(pv) == "<cdata 'varfoo *' buffer from 'bytearray' object>"
    assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
    #
    release(pv)
    assert repr(pv) == "<cdata 'varfoo *' buffer RELEASED>"
    assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
    #
    pv = from_buffer(BVarStructP, bytestring)    # make a fresh one
    with pytest.raises(ValueError):
        release(pv[0])

def test_issue483():
    BInt = new_primitive_type("int")
    BIntP = new_pointer_type(BInt)
    BIntA = new_array_type(BIntP, None)
    lst = list(range(25))
    bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
    p1 = from_buffer(BIntA, bytestring)      # int[]
    assert len(buffer(p1)) == 25 * size_of_int()
    assert sizeof(p1) == 25 * size_of_int()
    #
    p2 = from_buffer(BIntP, bytestring)
    assert sizeof(p2) == size_of_ptr()
    assert len(buffer(p2)) == size_of_int()  # first element only, by default

def test_memmove():
    Short = new_primitive_type("short")
    ShortA = new_array_type(new_pointer_type(Short), None)
    Char = new_primitive_type("char")
    CharA = new_array_type(new_pointer_type(Char), None)
    p = newp(ShortA, [-1234, -2345, -3456, -4567, -5678])
    memmove(p, p + 1, 4)
    assert list(p) == [-2345, -3456, -3456, -4567, -5678]
    p[2] = 999
    memmove(p + 2, p, 6)
    assert list(p) == [-2345, -3456, -2345, -3456, 999]
    memmove(p + 4, newp(CharA, b"\x71\x72"), 2)
    if sys.byteorder == 'little':
        assert list(p) == [-2345, -3456, -2345, -3456, 0x7271]
    else:
        assert list(p) == [-2345, -3456, -2345, -3456, 0x7172]

def test_memmove_buffer():
    import array
    Short = new_primitive_type("short")
    ShortA = new_array_type(new_pointer_type(Short), None)
    a = array.array('H', [10000, 20000, 30000])
    p = newp(ShortA, 5)
    memmove(p, a, 6)
    assert list(p) == [10000, 20000, 30000, 0, 0]
    memmove(p + 1, a, 6)
    assert list(p) == [10000, 10000, 20000, 30000, 0]
    b = array.array('h', [-1000, -2000, -3000])
    memmove(b, a, 4)
    assert b.tolist() == [10000, 20000, -3000]
    assert a.tolist() == [10000, 20000, 30000]
    p[0] = 999
    p[1] = 998
    p[2] = 997
    p[3] = 996
    p[4] = 995
    memmove(b, p, 2)
    assert b.tolist() == [999, 20000, -3000]
    memmove(b, p + 2, 4)
    assert b.tolist() == [997, 996, -3000]
    p[2] = -p[2]
    p[3] = -p[3]
    memmove(b, p + 2, 6)
    assert b.tolist() == [-997, -996, 995]

def test_memmove_readonly_readwrite():
    SignedChar = new_primitive_type("signed char")
    SignedCharA = new_array_type(new_pointer_type(SignedChar), None)
    p = newp(SignedCharA, 5)
    memmove(p, b"abcde", 3)
    assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0]
    memmove(p, bytearray(b"ABCDE"), 2)
    assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0]
    pytest.raises((TypeError, BufferError), memmove, b"abcde", p, 3)
    ba = bytearray(b"xxxxx")
    memmove(dest=ba, src=p, n=3)
    assert ba == bytearray(b"ABcxx")
    memmove(ba, b"EFGH", 4)
    assert ba == bytearray(b"EFGHx")

def test_memmove_sign_check():
    SignedChar = new_primitive_type("signed char")
    SignedCharA = new_array_type(new_pointer_type(SignedChar), None)
    p = newp(SignedCharA, 5)
    pytest.raises(ValueError, memmove, p, p + 1, -1)   # not segfault

def test_memmove_bad_cdata():
    BInt = new_primitive_type("int")
    p = cast(BInt, 42)
    pytest.raises(TypeError, memmove, p, bytearray(b'a'), 1)
    pytest.raises(TypeError, memmove, bytearray(b'a'), p, 1)

def test_dereference_null_ptr():
    BInt = new_primitive_type("int")
    BIntPtr = new_pointer_type(BInt)
    p = cast(BIntPtr, 0)
    with pytest.raises(RuntimeError):
        p[0]
    with pytest.raises(RuntimeError):
        p[0] = 42
    with pytest.raises(RuntimeError):
        p[42]
    with pytest.raises(RuntimeError):
        p[42] = -1

def test_mixup():
    BStruct1 = new_struct_type("foo")
    BStruct2 = new_struct_type("foo")   # <= same name as BStruct1
    BStruct3 = new_struct_type("bar")
    BStruct1Ptr = new_pointer_type(BStruct1)
    BStruct2Ptr = new_pointer_type(BStruct2)
    BStruct3Ptr = new_pointer_type(BStruct3)
    BStruct1PtrPtr = new_pointer_type(BStruct1Ptr)
    BStruct2PtrPtr = new_pointer_type(BStruct2Ptr)
    BStruct3PtrPtr = new_pointer_type(BStruct3Ptr)
    pp1 = newp(BStruct1PtrPtr)
    pp2 = newp(BStruct2PtrPtr)
    pp3 = newp(BStruct3PtrPtr)
    pp1[0] = pp1[0]
    with pytest.raises(TypeError) as e:
        pp3[0] = pp1[0]
    assert str(e.value).startswith("initializer for ctype 'bar *' must be a ")
    assert str(e.value).endswith(", not cdata 'foo *'")
    with pytest.raises(TypeError) as e:
        pp2[0] = pp1[0]
    assert str(e.value) == ("initializer for ctype 'foo *' appears indeed to "
                            "be 'foo *', but the types are different (check "
                            "that you are not e.g. mixing up different ffi "
                            "instances)")

def test_stdcall_function_type():
    assert FFI_CDECL == FFI_DEFAULT_ABI
    try:
        stdcall = FFI_STDCALL
    except NameError:
        stdcall = FFI_DEFAULT_ABI
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BInt, BInt), BInt, False, stdcall)
    if stdcall != FFI_DEFAULT_ABI:
        assert repr(BFunc) == "<ctype 'int(__stdcall *)(int, int)'>"
    else:
        assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"

def test_get_common_types():
    d = {}
    _get_common_types(d)
    assert d['bool'] == '_Bool'

def test_unpack():
    BChar = new_primitive_type("char")
    BArray = new_array_type(new_pointer_type(BChar), 10)   # char[10]
    p = newp(BArray, b"abc\x00def")
    p0 = p
    assert unpack(p, 10) == b"abc\x00def\x00\x00\x00"
    assert unpack(p+1, 5) == b"bc\x00de"

    for typename in ["wchar_t", "char16_t", "char32_t"]:
        BWChar = new_primitive_type(typename)
        BArray = new_array_type(new_pointer_type(BWChar), 10)   # wchar_t[10]
        p = newp(BArray, u"abc\x00def")
        assert unpack(p, 10) == u"abc\x00def\x00\x00\x00"

    for typename, samples in [
            ("uint8_t",  [0, 2**8-1]),
            ("uint16_t", [0, 2**16-1]),
            ("uint32_t", [0, 2**32-1]),
            ("uint64_t", [0, 2**64-1]),
            ("int8_t",  [-2**7, 2**7-1]),
            ("int16_t", [-2**15, 2**15-1]),
            ("int32_t", [-2**31, 2**31-1]),
            ("int64_t", [-2**63, 2**63-1]),
            ("_Bool", [False, True]),
            ("float", [0.0, 10.5]),
            ("double", [12.34, 56.78]),
            ]:
        BItem = new_primitive_type(typename)
        BArray = new_array_type(new_pointer_type(BItem), 10)
        p = newp(BArray, samples)
        result = unpack(p, len(samples))
        assert result == samples
        for i in range(len(samples)):
            assert result[i] == p[i] and type(result[i]) is type(p[i])
            assert (type(result[i]) is bool) == (type(samples[i]) is bool)
    #
    BInt = new_primitive_type("int")
    pytest.raises(TypeError, unpack, p)
    pytest.raises(TypeError, unpack, b"foobar", 6)
    pytest.raises(TypeError, unpack, cast(BInt, 42), 1)
    #
    BPtr = new_pointer_type(BInt)
    random_ptr = cast(BPtr, -424344)
    other_ptr = cast(BPtr, 54321)
    BArray = new_array_type(new_pointer_type(BPtr), None)
    lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2)
    assert lst == [random_ptr, other_ptr]
    #
    BFunc = new_function_type((BInt, BInt), BInt, False)
    BFuncPtr = new_pointer_type(BFunc)
    lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2)
    assert len(lst) == 2
    assert not lst[0] and not lst[1]
    assert typeof(lst[0]) is BFunc
    #
    BStruct = new_struct_type("foo")
    BStructPtr = new_pointer_type(BStruct)
    e = pytest.raises(ValueError, unpack, cast(BStructPtr, 42), 5)
    assert str(e.value) == "'foo *' points to items of unknown size"
    complete_struct_or_union(BStruct, [('a1', BInt, -1),
                                       ('a2', BInt, -1)])
    array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]])
    lst = unpack(array_of_structs, 2)
    assert typeof(lst[0]) is BStruct
    assert lst[0].a1 == 4 and lst[1].a2 == 7
    #
    pytest.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0)
    pytest.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10)
    #
    pytest.raises(ValueError, unpack, p0, -1)
    pytest.raises(ValueError, unpack, p, -1)

def test_cdata_dir():
    BInt = new_primitive_type("int")
    p = cast(BInt, 42)
    check_dir(p, [])
    p = newp(new_array_type(new_pointer_type(BInt), None), 5)
    check_dir(p, [])
    BStruct = new_struct_type("foo")
    p = cast(new_pointer_type(BStruct), 0)
    check_dir(p, [])    # opaque
    complete_struct_or_union(BStruct, [('a2', BInt, -1),
                                       ('a1', BInt, -1)])
    check_dir(p, ['a1', 'a2'])   # always sorted
    p = newp(new_pointer_type(BStruct), None)
    check_dir(p, ['a1', 'a2'])
    check_dir(p[0], ['a1', 'a2'])
    pp = newp(new_pointer_type(new_pointer_type(BStruct)), p)
    check_dir(pp, [])
    check_dir(pp[0], ['a1', 'a2'])
    check_dir(pp[0][0], ['a1', 'a2'])

def test_char_pointer_conversion():
    import warnings
    assert __version__.startswith("1."), (
        "the warning will be an error if we ever release cffi 2.x")
    BCharP = new_pointer_type(new_primitive_type("char"))
    BIntP = new_pointer_type(new_primitive_type("int"))
    BVoidP = new_pointer_type(new_void_type())
    BUCharP = new_pointer_type(new_primitive_type("unsigned char"))
    z1 = cast(BCharP, 0)
    z2 = cast(BIntP, 0)
    z3 = cast(BVoidP, 0)
    z4 = cast(BUCharP, 0)
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        newp(new_pointer_type(BIntP), z1)    # warn
        assert len(w) == 1
        newp(new_pointer_type(BVoidP), z1)   # fine
        assert len(w) == 1
        newp(new_pointer_type(BCharP), z2)   # warn
        assert len(w) == 2
        newp(new_pointer_type(BVoidP), z2)   # fine
        assert len(w) == 2
        newp(new_pointer_type(BCharP), z3)   # fine
        assert len(w) == 2
        newp(new_pointer_type(BIntP), z3)    # fine
        assert len(w) == 2
        newp(new_pointer_type(BCharP), z4)   # fine (ignore signedness here)
        assert len(w) == 2
        newp(new_pointer_type(BUCharP), z1)  # fine (ignore signedness here)
        assert len(w) == 2
        newp(new_pointer_type(BUCharP), z3)  # fine
        assert len(w) == 2
    # check that the warnings are associated with lines in this file
    assert w[1].lineno == w[0].lineno + 4

def test_primitive_comparison():
    def assert_eq(a, b):
        assert (a == b) is True
        assert (b == a) is True
        assert (a != b) is False
        assert (b != a) is False
        assert (a < b) is False
        assert (a <= b) is True
        assert (a > b) is False
        assert (a >= b) is True
        assert (b < a) is False
        assert (b <= a) is True
        assert (b > a) is False
        assert (b >= a) is True
        assert hash(a) == hash(b)
    def assert_lt(a, b, check_hash=True):
        assert (a == b) is False
        assert (b == a) is False
        assert (a != b) is True
        assert (b != a) is True
        assert (a < b) is True
        assert (a <= b) is True
        assert (a > b) is False
        assert (a >= b) is False
        assert (b < a) is False
        assert (b <= a) is False
        assert (b > a) is True
        assert (b >= a) is True
        if check_hash:
            assert hash(a) != hash(b)    # (or at least, it is unlikely)
    def assert_gt(a, b, check_hash=True):
        assert_lt(b, a, check_hash)
    def assert_ne(a, b):
        assert (a == b) is False
        assert (b == a) is False
        assert (a != b) is True
        assert (b != a) is True
        if strict_compare:
            with pytest.raises(TypeError): a < b
            with pytest.raises(TypeError): a <= b
            with pytest.raises(TypeError): a > b
            with pytest.raises(TypeError): a >= b
            with pytest.raises(TypeError): b < a
            with pytest.raises(TypeError): b <= a
            with pytest.raises(TypeError): b > a
            with pytest.raises(TypeError): b >= a
        elif a < b:
            assert_lt(a, b)
        else:
            assert_lt(b, a)
    assert_eq(5, 5)
    assert_lt(3, 5)
    assert_ne('5', 5)
    #
    t1 = new_primitive_type("char")
    t2 = new_primitive_type("int")
    t3 = new_primitive_type("unsigned char")
    t4 = new_primitive_type("unsigned int")
    t5 = new_primitive_type("float")
    t6 = new_primitive_type("double")
    assert_eq(cast(t1, 65), b'A')
    assert_lt(cast(t1, 64), b'\x99')
    assert_gt(cast(t1, 200), b'A')
    assert_ne(cast(t1, 65), 65)
    assert_eq(cast(t2, -25), -25)
    assert_lt(cast(t2, -25), -24)
    assert_gt(cast(t2, -25), -26)
    assert_eq(cast(t3, 65), 65)
    assert_ne(cast(t3, 65), b'A')
    assert_ne(cast(t3, 65), cast(t1, 65))
    assert_gt(cast(t4, -1), -1, check_hash=False)
    assert_gt(cast(t4, -1), cast(t2, -1), check_hash=False)
    assert_gt(cast(t4, -1), 99999)
    assert_eq(cast(t4, -1), 256 ** size_of_int() - 1)
    assert_eq(cast(t5, 3.0), 3)
    assert_eq(cast(t5, 3.5), 3.5)
    assert_lt(cast(t5, 3.3), 3.3)   # imperfect rounding
    assert_eq(cast(t6, 3.3), 3.3)
    assert_eq(cast(t5, 3.5), cast(t6, 3.5))
    assert_lt(cast(t5, 3.1), cast(t6, 3.1))   # imperfect rounding
    assert_eq(cast(t5, 7.0), cast(t3, 7))
    assert_lt(cast(t5, 3.1), 3.101)
    assert_gt(cast(t5, 3.1), 3)

def test_explicit_release_new():
    # release() on a ffi.new() object has no effect on CPython, but
    # really releases memory on PyPy.  We can't test that effect
    # though, because a released cdata is not marked.
    BIntP = new_pointer_type(new_primitive_type("int"))
    p = newp(BIntP)
    p[0] = 42
    with pytest.raises(IndexError):
        p[1]
    release(p)
    # here, reading p[0] might give garbage or segfault...
    release(p)   # no effect
    #
    BStruct = new_struct_type("struct foo")
    BStructP = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('p', BIntP, -1)])
    pstruct = newp(BStructP)
    assert pstruct.p == cast(BIntP, 0)
    release(pstruct)
    # here, reading pstruct.p might give garbage or segfault...
    release(pstruct)   # no effect

def test_explicit_release_new_contextmgr():
    BIntP = new_pointer_type(new_primitive_type("int"))
    with newp(BIntP) as p:
        p[0] = 42
        assert p[0] == 42
    # here, reading p[0] might give garbage or segfault...
    release(p)   # no effect

def test_explicit_release_badtype():
    BIntP = new_pointer_type(new_primitive_type("int"))
    p = cast(BIntP, 12345)
    pytest.raises(ValueError, release, p)
    pytest.raises(ValueError, release, p)
    BStruct = new_struct_type("struct foo")
    BStructP = new_pointer_type(BStruct)
    complete_struct_or_union(BStruct, [('p', BIntP, -1)])
    pstruct = newp(BStructP)
    pytest.raises(ValueError, release, pstruct[0])

def test_explicit_release_badtype_contextmgr():
    BIntP = new_pointer_type(new_primitive_type("int"))
    p = cast(BIntP, 12345)
    with pytest.raises(ValueError):
        with p:
            pass
    with pytest.raises(ValueError):
        with p:
            pass

def test_explicit_release_gc():
    BIntP = new_pointer_type(new_primitive_type("int"))
    seen = []
    intp1 = newp(BIntP, 12345)
    p1 = cast(BIntP, intp1)
    p = gcp(p1, seen.append)
    assert seen == []
    release(p)
    assert seen == [p1]
    assert p1[0] == 12345
    assert p[0] == 12345  # true so far, but might change to raise RuntimeError
    release(p)   # no effect

def test_explicit_release_gc_contextmgr():
    BIntP = new_pointer_type(new_primitive_type("int"))
    seen = []
    intp1 = newp(BIntP, 12345)
    p1 = cast(BIntP, intp1)
    p = gcp(p1, seen.append)
    with p:
        assert p[0] == 12345
        assert seen == []
    assert seen == [p1]
    assert p1[0] == 12345
    assert p[0] == 12345  # true so far, but might change to raise RuntimeError
    release(p)   # no effect

def test_explicit_release_from_buffer():
    a = bytearray(b"xyz")
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    p = from_buffer(BCharA, a)
    assert p[2] == b"z"
    assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
    release(p)
    assert p[2] == b"z"  # true so far, but might change to raise RuntimeError
    assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
    release(p)   # no effect

def test_explicit_release_from_buffer_contextmgr():
    a = bytearray(b"xyz")
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    p = from_buffer(BCharA, a)
    with p:
        assert p[2] == b"z"
    assert p[2] == b"z"  # true so far, but might change to raise RuntimeError
    assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
    release(p)   # no effect

def test_explicit_release_bytearray_on_cpython():
    if '__pypy__' in sys.builtin_module_names:
        pytest.skip("pypy's bytearray are never locked")
    a = bytearray(b"xyz")
    BChar = new_primitive_type("char")
    BCharP = new_pointer_type(BChar)
    BCharA = new_array_type(BCharP, None)
    a += b't' * 10
    p = from_buffer(BCharA, a)
    with pytest.raises(BufferError):
        a += b'u' * 100
    release(p)
    a += b'v' * 100
    release(p)   # no effect
    a += b'w' * 1000
    assert a == bytearray(b"xyz" + b't' * 10 + b'v' * 100 + b'w' * 1000)

def test_int_doesnt_give_bool():
    BBool = new_primitive_type("_Bool")
    x = int(cast(BBool, 42))
    assert type(x) is int and x == 1
    x = long(cast(BBool, 42))
    assert type(x) is long and x == 1
    with pytest.raises(TypeError):
        float(cast(BBool, 42))
    with pytest.raises(TypeError):
        complex(cast(BBool, 42))

def test_cannot_call_null_function_pointer():
    BInt = new_primitive_type("int")
    BFunc = new_function_type((BInt, BInt), BInt, False)
    f = cast(BFunc, 0)
    with pytest.raises(RuntimeError):
        f(40, 2)

def test_huge_structure():
    BChar = new_primitive_type("char")
    BArray = new_array_type(new_pointer_type(BChar), sys.maxsize)
    assert sizeof(BArray) == sys.maxsize
    BStruct = new_struct_type("struct foo")
    complete_struct_or_union(BStruct, [('a1', BArray, -1)])
    assert sizeof(BStruct) == sys.maxsize

def test_get_types():
    import _cffi_backend
    CData, CType = _get_types()
    assert CData is _cffi_backend._CDataBase
    assert CType is _cffi_backend.CType

def test_type_available_with_correct_names():
    import _cffi_backend
    check_names = [
        'CType',
        'CField',
        'CLibrary',
        '_CDataBase',
        'FFI',
        'Lib',
        'buffer',
    ]
    if '__pypy__' in sys.builtin_module_names:
        check_names += [
            '__CData_iterator',
            '__FFIGlobSupport',
            '__FFIAllocator',
            '__FFIFunctionWrapper',
        ]
    else:
        check_names += [
            '__CDataOwn',
            '__CDataOwnGC',
            '__CDataFromBuf',
            '__CDataGCP',
            '__CData_iterator',
            '__FFIGlobSupport',
        ]
    for name in check_names:
        tp = getattr(_cffi_backend, name)
        assert isinstance(tp, type)
        assert (tp.__module__, tp.__name__) == ('_cffi_backend', name)

def test_unaligned_types():
    BByteArray = new_array_type(
        new_pointer_type(new_primitive_type("unsigned char")), None)
    pbuf = newp(BByteArray, 40)
    buf = buffer(pbuf)
    #
    for name in ['short', 'int', 'long', 'long long', 'float', 'double',
                 'float _Complex', 'double _Complex']:
        p = new_primitive_type(name)
        if name.endswith(' _Complex'):
            num = cast(p, 1.23 - 4.56j)
        else:
            num = cast(p, 0x0123456789abcdef)
        size = sizeof(p)
        buf[0:40] = b"\x00" * 40
        pbuf1 = cast(new_pointer_type(p), pbuf + 1)
        pbuf1[0] = num
        assert pbuf1[0] == num
        assert buf[0] == b'\x00'
        assert buf[1 + size] == b'\x00'

src/c/test_c.py
python-cffi/cffi
__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
           'FFIError']

from .api import FFI
from .error import CDefError, FFIError, VerificationError, VerificationMissing
from .error import PkgConfigError

__version__ = "1.17.0.dev0"
__version_info__ = (1, 17, 0, 'dev0')

# The verifier module file names are based on the CRC32 of a string that
# contains the following version number.  It may be older than __version__
# if nothing is clearly incompatible.
__version_verifier_modules__ = "0.8.6"

src/cffi/__init__.py
python-cffi/cffi

try:
    # this works on Python < 3.12
    from imp import *

except ImportError:
    # this is a limited emulation for Python >= 3.12.
    # Note that this is used only for tests or for the old ffi.verify().
    # This is copied from the source code of Python 3.11.

    from _imp import (acquire_lock, release_lock,
                      is_builtin, is_frozen)

    from importlib._bootstrap import _load

    from importlib import machinery
    import os
    import sys
    import tokenize

    SEARCH_ERROR = 0
    PY_SOURCE = 1
    PY_COMPILED = 2
    C_EXTENSION = 3
    PY_RESOURCE = 4
    PKG_DIRECTORY = 5
    C_BUILTIN = 6
    PY_FROZEN = 7
    PY_CODERESOURCE = 8
    IMP_HOOK = 9

    def get_suffixes():
        extensions = [(s, 'rb', C_EXTENSION)
                      for s in machinery.EXTENSION_SUFFIXES]
        source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES]
        bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES]
        return extensions + source + bytecode

    def find_module(name, path=None):
        if not isinstance(name, str):
            raise TypeError("'name' must be a str, not {}".format(type(name)))
        elif not isinstance(path, (type(None), list)):
            # Backwards-compatibility
            raise RuntimeError("'path' must be None or a list, "
                               "not {}".format(type(path)))

        if path is None:
            if is_builtin(name):
                return None, None, ('', '', C_BUILTIN)
            elif is_frozen(name):
                return None, None, ('', '', PY_FROZEN)
            else:
                path = sys.path

        for entry in path:
            package_directory = os.path.join(entry, name)
            for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]:
                package_file_name = '__init__' + suffix
                file_path = os.path.join(package_directory, package_file_name)
                if os.path.isfile(file_path):
                    return None, package_directory, ('', '', PKG_DIRECTORY)
            for suffix, mode, type_ in get_suffixes():
                file_name = name + suffix
                file_path = os.path.join(entry, file_name)
                if os.path.isfile(file_path):
                    break
            else:
                continue
            break  # Break out of outer loop when breaking out of inner loop.
        else:
            raise ImportError(name, name=name)

        encoding = None
        if 'b' not in mode:
            with open(file_path, 'rb') as file:
                encoding = tokenize.detect_encoding(file.readline)[0]
        file = open(file_path, mode, encoding=encoding)
        return file, file_path, (suffix, mode, type_)

    def load_dynamic(name, path, file=None):
        loader = machinery.ExtensionFileLoader(name, path)
        spec = machinery.ModuleSpec(name=name, loader=loader, origin=path)
        return _load(spec)

src/cffi/_imp_emulation.py
python-cffi/cffi
"""
Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful
error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken.

This is a compromise to avoid a hard-dep on setuptools for Python >= 3.12, since many users don't need runtime compilation support from CFFI.
"""
import sys

try:
    # import setuptools first; this is the most robust way to ensure its embedded distutils is available
    # (the .pth shim should usually work, but this is even more robust)
    import setuptools
except Exception as ex:
    if sys.version_info >= (3, 12):
        # Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal
        raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex

    # silently ignore on older Pythons (support fallback to stdlib distutils where available)
else:
    del setuptools

try:
    # bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils
    from distutils import log, sysconfig
    from distutils.ccompiler import CCompiler
    from distutils.command.build_ext import build_ext
    from distutils.core import Distribution, Extension
    from distutils.dir_util import mkpath
    from distutils.errors import DistutilsSetupError, CompileError, LinkError
    from distutils.log import set_threshold, set_verbosity

    if sys.platform == 'win32':
        from distutils.msvc9compiler import MSVCCompiler
except Exception as ex:
    if sys.version_info >= (3, 12):
        raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex

    # anything older, just let the underlying distutils import error fly
    raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex

del sys

src/cffi/_shimmed_dist_utils.py
python-cffi/cffi
import sys, types
from .lock import allocate_lock
from .error import CDefError
from . import model

try:
    callable
except NameError:
    # Python 3.1
    from collections import Callable
    callable = lambda x: isinstance(x, Callable)

try:
    basestring
except NameError:
    # Python 3.x
    basestring = str

_unspecified = object()



class FFI(object):
    r'''
    The main top-level class that you instantiate once, or once per module.

    Example usage:

        ffi = FFI()
        ffi.cdef("""
            int printf(const char *, ...);
        """)

        C = ffi.dlopen(None)   # standard library
        -or-
        C = ffi.verify()  # use a C compiler: verify the decl above is right

        C.printf("hello, %s!\n", ffi.new("char[]", "world"))
    '''

    def __init__(self, backend=None):
        """Create an FFI instance.  The 'backend' argument is used to
        select a non-default backend, mostly for tests.
        """
        if backend is None:
            # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
            # _cffi_backend.so compiled.
            import _cffi_backend as backend
            from . import __version__
            if backend.__version__ != __version__:
                # bad version!  Try to be as explicit as possible.
                if hasattr(backend, '__file__'):
                    # CPython
                    raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r.  When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r.  The two versions should be equal; check your installation." % (
                        __version__, __file__,
                        backend.__version__, backend.__file__))
                else:
                    # PyPy
                    raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r.  This interpreter comes with a built-in '_cffi_backend' module, which is version %s.  The two versions should be equal; check your installation." % (
                        __version__, __file__, backend.__version__))
            # (If you insist you can also try to pass the option
            # 'backend=backend_ctypes.CTypesBackend()', but don't
            # rely on it!  It's probably not going to work well.)

        from . import cparser
        self._backend = backend
        self._lock = allocate_lock()
        self._parser = cparser.Parser()
        self._cached_btypes = {}
        self._parsed_types = types.ModuleType('parsed_types').__dict__
        self._new_types = types.ModuleType('new_types').__dict__
        self._function_caches = []
        self._libraries = []
        self._cdefsources = []
        self._included_ffis = []
        self._windows_unicode = None
        self._init_once_cache = {}
        self._cdef_version = None
        self._embedding = None
        self._typecache = model.get_typecache(backend)
        if hasattr(backend, 'set_ffi'):
            backend.set_ffi(self)
        for name in list(backend.__dict__):
            if name.startswith('RTLD_'):
                setattr(self, name, getattr(backend, name))
        #
        with self._lock:
            self.BVoidP = self._get_cached_btype(model.voidp_type)
            self.BCharA = self._get_cached_btype(model.char_array_type)
        if isinstance(backend, types.ModuleType):
            # _cffi_backend: attach these constants to the class
            if not hasattr(FFI, 'NULL'):
                FFI.NULL = self.cast(self.BVoidP, 0)
                FFI.CData, FFI.CType = backend._get_types()
        else:
            # ctypes backend: attach these constants to the instance
            self.NULL = self.cast(self.BVoidP, 0)
            self.CData, self.CType = backend._get_types()
        self.buffer = backend.buffer

    def cdef(self, csource, override=False, packed=False, pack=None):
        """Parse the given C source.  This registers all declared functions,
        types, and global variables.  The functions and global variables can
        then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'.
        The types can be used in 'ffi.new()' and other functions.
        If 'packed' is specified as True, all structs declared inside this
        cdef are packed, i.e. laid out without any field alignment at all.
        Alternatively, 'pack' can be a small integer, and requests for
        alignment greater than that are ignored (pack=1 is equivalent to
        packed=True).
        """
        self._cdef(csource, override=override, packed=packed, pack=pack)

    def embedding_api(self, csource, packed=False, pack=None):
        self._cdef(csource, packed=packed, pack=pack, dllexport=True)
        if self._embedding is None:
            self._embedding = ''

    def _cdef(self, csource, override=False, **options):
        if not isinstance(csource, str):    # unicode, on Python 2
            if not isinstance(csource, basestring):
                raise TypeError("cdef() argument must be a string")
            csource = csource.encode('ascii')
        with self._lock:
            self._cdef_version = object()
            self._parser.parse(csource, override=override, **options)
            self._cdefsources.append(csource)
            if override:
                for cache in self._function_caches:
                    cache.clear()
            finishlist = self._parser._recomplete
            if finishlist:
                self._parser._recomplete = []
                for tp in finishlist:
                    tp.finish_backend_type(self, finishlist)

    def dlopen(self, name, flags=0):
        """Load and return a dynamic library identified by 'name'.
        The standard C library can be loaded by passing None.
        Note that functions and types declared by 'ffi.cdef()' are not
        linked to a particular library, just like C headers; in the
        library we only look for the actual (untyped) symbols.
        """
        if not (isinstance(name, basestring) or
                name is None or
                isinstance(name, self.CData)):
            raise TypeError("dlopen(name): name must be a file name, None, "
                            "or an already-opened 'void *' handle")
        with self._lock:
            lib, function_cache = _make_ffi_library(self, name, flags)
            self._function_caches.append(function_cache)
            self._libraries.append(lib)
        return lib

    def dlclose(self, lib):
        """Close a library obtained with ffi.dlopen().  After this call,
        access to functions or variables from the library will fail
        (possibly with a segmentation fault).
        """
        type(lib).__cffi_close__(lib)

    def _typeof_locked(self, cdecl):
        # call me with the lock!
        key = cdecl
        if key in self._parsed_types:
            return self._parsed_types[key]
        #
        if not isinstance(cdecl, str):    # unicode, on Python 2
            cdecl = cdecl.encode('ascii')
        #
        type = self._parser.parse_type(cdecl)
        really_a_function_type = type.is_raw_function
        if really_a_function_type:
            type = type.as_function_pointer()
        btype = self._get_cached_btype(type)
        result = btype, really_a_function_type
        self._parsed_types[key] = result
        return result

    def _typeof(self, cdecl, consider_function_as_funcptr=False):
        # string -> ctype object
        try:
            result = self._parsed_types[cdecl]
        except KeyError:
            with self._lock:
                result = self._typeof_locked(cdecl)
        #
        btype, really_a_function_type = result
        if really_a_function_type and not consider_function_as_funcptr:
            raise CDefError("the type %r is a function type, not a "
                            "pointer-to-function type" % (cdecl,))
        return btype

    def typeof(self, cdecl):
        """Parse the C type given as a string and return the
        corresponding <ctype> object.
        It can also be used on 'cdata' instance to get its C type.
        """
        if isinstance(cdecl, basestring):
            return self._typeof(cdecl)
        if isinstance(cdecl, self.CData):
            return self._backend.typeof(cdecl)
        if isinstance(cdecl, types.BuiltinFunctionType):
            res = _builtin_function_type(cdecl)
            if res is not None:
                return res
        if (isinstance(cdecl, types.FunctionType)
                and hasattr(cdecl, '_cffi_base_type')):
            with self._lock:
                return self._get_cached_btype(cdecl._cffi_base_type)
        raise TypeError(type(cdecl))

    def sizeof(self, cdecl):
        """Return the size in bytes of the argument.  It can be a
        string naming a C type, or a 'cdata' instance.
        """
        if isinstance(cdecl, basestring):
            BType = self._typeof(cdecl)
            return self._backend.sizeof(BType)
        else:
            return self._backend.sizeof(cdecl)

    def alignof(self, cdecl):
        """Return the natural alignment size in bytes of the C type
        given as a string.
        """
        if isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl)
        return self._backend.alignof(cdecl)

    def offsetof(self, cdecl, *fields_or_indexes):
        """Return the offset of the named field inside the given
        structure or array, which must be given as a C type name.
        You can give several field names in case of nested structures.
        You can also give numeric values which correspond to array
        items, in case of an array type.
        """
        if isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl)
        return self._typeoffsetof(cdecl, *fields_or_indexes)[1]

    def new(self, cdecl, init=None):
        """Allocate an instance according to the specified C type and
        return a pointer to it.  The specified C type must be either a
        pointer or an array: ``new('X *')`` allocates an X and returns
        a pointer to it, whereas ``new('X[n]')`` allocates an array of
        n X'es and returns an array referencing it (which works
        mostly like a pointer, like in C).  You can also use
        ``new('X[]', n)`` to allocate an array of a non-constant
        length n.

        The memory is initialized following the rules of declaring a
        global variable in C: by default it is zero-initialized, but
        an explicit initializer can be given which can be used to
        fill all or part of the memory.

        When the returned <cdata> object goes out of scope, the memory
        is freed.  In other words the returned <cdata> object has
        ownership of the value of type 'cdecl' that it points to.  This
        means that the raw data can be used as long as this object is
        kept alive, but must not be used for a longer time.  Be careful
        about that when copying the pointer to the memory somewhere
        else, e.g. into another structure.
        """
        if isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl)
        return self._backend.newp(cdecl, init)

    def new_allocator(self, alloc=None, free=None,
                      should_clear_after_alloc=True):
        """Return a new allocator, i.e. a function that behaves like ffi.new()
        but uses the provided low-level 'alloc' and 'free' functions.

        'alloc' is called with the size as argument.  If it returns NULL, a
        MemoryError is raised.  'free' is called with the result of 'alloc'
        as argument.  Both can be either Python function or directly C
        functions.  If 'free' is None, then no free function is called.
        If both 'alloc' and 'free' are None, the default is used.

        If 'should_clear_after_alloc' is set to False, then the memory
        returned by 'alloc' is assumed to be already cleared (or you are
        fine with garbage); otherwise CFFI will clear it.
        """
        compiled_ffi = self._backend.FFI()
        allocator = compiled_ffi.new_allocator(alloc, free,
                                               should_clear_after_alloc)
        def allocate(cdecl, init=None):
            if isinstance(cdecl, basestring):
                cdecl = self._typeof(cdecl)
            return allocator(cdecl, init)
        return allocate

    def cast(self, cdecl, source):
        """Similar to a C cast: returns an instance of the named C
        type initialized with the given 'source'.  The source is
        casted between integers or pointers of any type.
        """
        if isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl)
        return self._backend.cast(cdecl, source)

    def string(self, cdata, maxlen=-1):
        """Return a Python string (or unicode string) from the 'cdata'.
        If 'cdata' is a pointer or array of characters or bytes, returns
        the null-terminated string.  The returned string extends until
        the first null character, or at most 'maxlen' characters.  If
        'cdata' is an array then 'maxlen' defaults to its length.

        If 'cdata' is a pointer or array of wchar_t, returns a unicode
        string following the same rules.

        If 'cdata' is a single character or byte or a wchar_t, returns
        it as a string or unicode string.

        If 'cdata' is an enum, returns the value of the enumerator as a
        string, or 'NUMBER' if the value is out of range.
        """
        return self._backend.string(cdata, maxlen)

    def unpack(self, cdata, length):
        """Unpack an array of C data of the given length,
        returning a Python string/unicode/list.

        If 'cdata' is a pointer to 'char', returns a byte string.
        It does not stop at the first null.  This is equivalent to:
        ffi.buffer(cdata, length)[:]

        If 'cdata' is a pointer to 'wchar_t', returns a unicode string.
        'length' is measured in wchar_t's; it is not the size in bytes.

        If 'cdata' is a pointer to anything else, returns a list of
        'length' items.  This is a faster equivalent to:
        [cdata[i] for i in range(length)]
        """
        return self._backend.unpack(cdata, length)

   #def buffer(self, cdata, size=-1):
   #    """Return a read-write buffer object that references the raw C data
   #    pointed to by the given 'cdata'.  The 'cdata' must be a pointer or
   #    an array.  Can be passed to functions expecting a buffer, or directly
   #    manipulated with:
   #
   #        buf[:]          get a copy of it in a regular string, or
   #        buf[idx]        as a single character
   #        buf[:] = ...
   #        buf[idx] = ...  change the content
   #    """
   #    note that 'buffer' is a type, set on this instance by __init__

    def from_buffer(self, cdecl, python_buffer=_unspecified,
                    require_writable=False):
        """Return a cdata of the given type pointing to the data of the
        given Python object, which must support the buffer interface.
        Note that this is not meant to be used on the built-in types
        str or unicode (you can build 'char[]' arrays explicitly)
        but only on objects containing large quantities of raw data
        in some other format, like 'array.array' or numpy arrays.

        The first argument is optional and default to 'char[]'.
        """
        if python_buffer is _unspecified:
            cdecl, python_buffer = self.BCharA, cdecl
        elif isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl)
        return self._backend.from_buffer(cdecl, python_buffer,
                                         require_writable)

    def memmove(self, dest, src, n):
        """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest.

        Like the C function memmove(), the memory areas may overlap;
        apart from that it behaves like the C function memcpy().

        'src' can be any cdata ptr or array, or any Python buffer object.
        'dest' can be any cdata ptr or array, or a writable Python buffer
        object.  The size to copy, 'n', is always measured in bytes.

        Unlike other methods, this one supports all Python buffer including
        byte strings and bytearrays---but it still does not support
        non-contiguous buffers.
        """
        return self._backend.memmove(dest, src, n)

    def callback(self, cdecl, python_callable=None, error=None, onerror=None):
        """Return a callback object or a decorator making such a
        callback object.  'cdecl' must name a C function pointer type.
        The callback invokes the specified 'python_callable' (which may
        be provided either directly or via a decorator).  Important: the
        callback object must be manually kept alive for as long as the
        callback may be invoked from the C level.
        """
        def callback_decorator_wrap(python_callable):
            if not callable(python_callable):
                raise TypeError("the 'python_callable' argument "
                                "is not callable")
            return self._backend.callback(cdecl, python_callable,
                                          error, onerror)
        if isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
        if python_callable is None:
            return callback_decorator_wrap                # decorator mode
        else:
            return callback_decorator_wrap(python_callable)  # direct mode

    def getctype(self, cdecl, replace_with=''):
        """Return a string giving the C type 'cdecl', which may be itself
        a string or a <ctype> object.  If 'replace_with' is given, it gives
        extra text to append (or insert for more complicated C types), like
        a variable name, or '*' to get actually the C type 'pointer-to-cdecl'.
        """
        if isinstance(cdecl, basestring):
            cdecl = self._typeof(cdecl)
        replace_with = replace_with.strip()
        if (replace_with.startswith('*')
                and '&[' in self._backend.getcname(cdecl, '&')):
            replace_with = '(%s)' % replace_with
        elif replace_with and not replace_with[0] in '[(':
            replace_with = ' ' + replace_with
        return self._backend.getcname(cdecl, replace_with)

    def gc(self, cdata, destructor, size=0):
        """Return a new cdata object that points to the same
        data.  Later, when this new cdata object is garbage-collected,
        'destructor(old_cdata_object)' will be called.

        The optional 'size' gives an estimate of the size, used to
        trigger the garbage collection more eagerly.  So far only used
        on PyPy.  It tells the GC that the returned object keeps alive
        roughly 'size' bytes of external memory.
        """
        return self._backend.gcp(cdata, destructor, size)

    def _get_cached_btype(self, type):
        assert self._lock.acquire(False) is False
        # call me with the lock!
        try:
            BType = self._cached_btypes[type]
        except KeyError:
            finishlist = []
            BType = type.get_cached_btype(self, finishlist)
            for type in finishlist:
                type.finish_backend_type(self, finishlist)
        return BType

    def verify(self, source='', tmpdir=None, **kwargs):
        """Verify that the current ffi signatures compile on this
        machine, and return a dynamic library object.  The dynamic
        library can be used to call functions and access global
        variables declared in this 'ffi'.  The library is compiled
        by the C compiler: it gives you C-level API compatibility
        (including calling macros).  This is unlike 'ffi.dlopen()',
        which requires binary compatibility in the signatures.
        """
        from .verifier import Verifier, _caller_dir_pycache
        #
        # If set_unicode(True) was called, insert the UNICODE and
        # _UNICODE macro declarations
        if self._windows_unicode:
            self._apply_windows_unicode(kwargs)
        #
        # Set the tmpdir here, and not in Verifier.__init__: it picks
        # up the caller's directory, which we want to be the caller of
        # ffi.verify(), as opposed to the caller of Veritier().
        tmpdir = tmpdir or _caller_dir_pycache()
        #
        # Make a Verifier() and use it to load the library.
        self.verifier = Verifier(self, source, tmpdir, **kwargs)
        lib = self.verifier.load_library()
        #
        # Save the loaded library for keep-alive purposes, even
        # if the caller doesn't keep it alive itself (it should).
        self._libraries.append(lib)
        return lib

    def _get_errno(self):
        return self._backend.get_errno()
    def _set_errno(self, errno):
        self._backend.set_errno(errno)
    errno = property(_get_errno, _set_errno, None,
                     "the value of 'errno' from/to the C calls")

    def getwinerror(self, code=-1):
        return self._backend.getwinerror(code)

    def _pointer_to(self, ctype):
        with self._lock:
            return model.pointer_cache(self, ctype)

    def addressof(self, cdata, *fields_or_indexes):
        """Return the address of a <cdata 'struct-or-union'>.
        If 'fields_or_indexes' are given, returns the address of that
        field or array item in the structure or array, recursively in
        case of nested structures.
        """
        try:
            ctype = self._backend.typeof(cdata)
        except TypeError:
            if '__addressof__' in type(cdata).__dict__:
                return type(cdata).__addressof__(cdata, *fields_or_indexes)
            raise
        if fields_or_indexes:
            ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes)
        else:
            if ctype.kind == "pointer":
                raise TypeError("addressof(pointer)")
            offset = 0
        ctypeptr = self._pointer_to(ctype)
        return self._backend.rawaddressof(ctypeptr, cdata, offset)

    def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes):
        ctype, offset = self._backend.typeoffsetof(ctype, field_or_index)
        for field1 in fields_or_indexes:
            ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1)
            offset += offset1
        return ctype, offset

    def include(self, ffi_to_include):
        """Includes the typedefs, structs, unions and enums defined
        in another FFI instance.  Usage is similar to a #include in C,
        where a part of the program might include types defined in
        another part for its own usage.  Note that the include()
        method has no effect on functions, constants and global
        variables, which must anyway be accessed directly from the
        lib object returned by the original FFI instance.
        """
        if not isinstance(ffi_to_include, FFI):
            raise TypeError("ffi.include() expects an argument that is also of"
                            " type cffi.FFI, not %r" % (
                                type(ffi_to_include).__name__,))
        if ffi_to_include is self:
            raise ValueError("self.include(self)")
        with ffi_to_include._lock:
            with self._lock:
                self._parser.include(ffi_to_include._parser)
                self._cdefsources.append('[')
                self._cdefsources.extend(ffi_to_include._cdefsources)
                self._cdefsources.append(']')
                self._included_ffis.append(ffi_to_include)

    def new_handle(self, x):
        return self._backend.newp_handle(self.BVoidP, x)

    def from_handle(self, x):
        return self._backend.from_handle(x)

    def release(self, x):
        self._backend.release(x)

    def set_unicode(self, enabled_flag):
        """Windows: if 'enabled_flag' is True, enable the UNICODE and
        _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR
        to be (pointers to) wchar_t.  If 'enabled_flag' is False,
        declare these types to be (pointers to) plain 8-bit characters.
        This is mostly for backward compatibility; you usually want True.
        """
        if self._windows_unicode is not None:
            raise ValueError("set_unicode() can only be called once")
        enabled_flag = bool(enabled_flag)
        if enabled_flag:
            self.cdef("typedef wchar_t TBYTE;"
                      "typedef wchar_t TCHAR;"
                      "typedef const wchar_t *LPCTSTR;"
                      "typedef const wchar_t *PCTSTR;"
                      "typedef wchar_t *LPTSTR;"
                      "typedef wchar_t *PTSTR;"
                      "typedef TBYTE *PTBYTE;"
                      "typedef TCHAR *PTCHAR;")
        else:
            self.cdef("typedef char TBYTE;"
                      "typedef char TCHAR;"
                      "typedef const char *LPCTSTR;"
                      "typedef const char *PCTSTR;"
                      "typedef char *LPTSTR;"
                      "typedef char *PTSTR;"
                      "typedef TBYTE *PTBYTE;"
                      "typedef TCHAR *PTCHAR;")
        self._windows_unicode = enabled_flag

    def _apply_windows_unicode(self, kwds):
        defmacros = kwds.get('define_macros', ())
        if not isinstance(defmacros, (list, tuple)):
            raise TypeError("'define_macros' must be a list or tuple")
        defmacros = list(defmacros) + [('UNICODE', '1'),
                                       ('_UNICODE', '1')]
        kwds['define_macros'] = defmacros

    def _apply_embedding_fix(self, kwds):
        # must include an argument like "-lpython2.7" for the compiler
        def ensure(key, value):
            lst = kwds.setdefault(key, [])
            if value not in lst:
                lst.append(value)
        #
        if '__pypy__' in sys.builtin_module_names:
            import os
            if sys.platform == "win32":
                # we need 'libpypy-c.lib'.  Current distributions of
                # pypy (>= 4.1) contain it as 'libs/python27.lib'.
                pythonlib = "python{0[0]}{0[1]}".format(sys.version_info)
                if hasattr(sys, 'prefix'):
                    ensure('library_dirs', os.path.join(sys.prefix, 'libs'))
            else:
                # we need 'libpypy-c.{so,dylib}', which should be by
                # default located in 'sys.prefix/bin' for installed
                # systems.
                if sys.version_info < (3,):
                    pythonlib = "pypy-c"
                else:
                    pythonlib = "pypy3-c"
                if hasattr(sys, 'prefix'):
                    ensure('library_dirs', os.path.join(sys.prefix, 'bin'))
            # On uninstalled pypy's, the libpypy-c is typically found in
            # .../pypy/goal/.
            if hasattr(sys, 'prefix'):
                ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal'))
        else:
            if sys.platform == "win32":
                template = "python%d%d"
                if hasattr(sys, 'gettotalrefcount'):
                    template += '_d'
            else:
                try:
                    import sysconfig
                except ImportError:    # 2.6
                    from cffi._shimmed_dist_utils import sysconfig
                template = "python%d.%d"
                if sysconfig.get_config_var('DEBUG_EXT'):
                    template += sysconfig.get_config_var('DEBUG_EXT')
            pythonlib = (template %
                    (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
            if hasattr(sys, 'abiflags'):
                pythonlib += sys.abiflags
        ensure('libraries', pythonlib)
        if sys.platform == "win32":
            ensure('extra_link_args', '/MANIFEST')

    def set_source(self, module_name, source, source_extension='.c', **kwds):
        import os
        if hasattr(self, '_assigned_source'):
            raise ValueError("set_source() cannot be called several times "
                             "per ffi object")
        if not isinstance(module_name, basestring):
            raise TypeError("'module_name' must be a string")
        if os.sep in module_name or (os.altsep and os.altsep in module_name):
            raise ValueError("'module_name' must not contain '/': use a dotted "
                             "name to make a 'package.module' location")
        self._assigned_source = (str(module_name), source,
                                 source_extension, kwds)

    def set_source_pkgconfig(self, module_name, pkgconfig_libs, source,
                             source_extension='.c', **kwds):
        from . import pkgconfig
        if not isinstance(pkgconfig_libs, list):
            raise TypeError("the pkgconfig_libs argument must be a list "
                            "of package names")
        kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs)
        pkgconfig.merge_flags(kwds, kwds2)
        self.set_source(module_name, source, source_extension, **kwds)

    def distutils_extension(self, tmpdir='build', verbose=True):
        from cffi._shimmed_dist_utils import mkpath
        from .recompiler import recompile
        #
        if not hasattr(self, '_assigned_source'):
            if hasattr(self, 'verifier'):     # fallback, 'tmpdir' ignored
                return self.verifier.get_extension()
            raise ValueError("set_source() must be called before"
                             " distutils_extension()")
        module_name, source, source_extension, kwds = self._assigned_source
        if source is None:
            raise TypeError("distutils_extension() is only for C extension "
                            "modules, not for dlopen()-style pure Python "
                            "modules")
        mkpath(tmpdir)
        ext, updated = recompile(self, module_name,
                                 source, tmpdir=tmpdir, extradir=tmpdir,
                                 source_extension=source_extension,
                                 call_c_compiler=False, **kwds)
        if verbose:
            if updated:
                sys.stderr.write("regenerated: %r\n" % (ext.sources[0],))
            else:
                sys.stderr.write("not modified: %r\n" % (ext.sources[0],))
        return ext

    def emit_c_code(self, filename):
        from .recompiler import recompile
        #
        if not hasattr(self, '_assigned_source'):
            raise ValueError("set_source() must be called before emit_c_code()")
        module_name, source, source_extension, kwds = self._assigned_source
        if source is None:
            raise TypeError("emit_c_code() is only for C extension modules, "
                            "not for dlopen()-style pure Python modules")
        recompile(self, module_name, source,
                  c_file=filename, call_c_compiler=False, **kwds)

    def emit_python_code(self, filename):
        from .recompiler import recompile
        #
        if not hasattr(self, '_assigned_source'):
            raise ValueError("set_source() must be called before emit_c_code()")
        module_name, source, source_extension, kwds = self._assigned_source
        if source is not None:
            raise TypeError("emit_python_code() is only for dlopen()-style "
                            "pure Python modules, not for C extension modules")
        recompile(self, module_name, source,
                  c_file=filename, call_c_compiler=False, **kwds)

    def compile(self, tmpdir='.', verbose=0, target=None, debug=None):
        """The 'target' argument gives the final file name of the
        compiled DLL.  Use '*' to force distutils' choice, suitable for
        regular CPython C API modules.  Use a file name ending in '.*'
        to ask for the system's default extension for dynamic libraries
        (.so/.dll/.dylib).

        The default is '*' when building a non-embedded C API extension,
        and (module_name + '.*') when building an embedded library.
        """
        from .recompiler import recompile
        #
        if not hasattr(self, '_assigned_source'):
            raise ValueError("set_source() must be called before compile()")
        module_name, source, source_extension, kwds = self._assigned_source
        return recompile(self, module_name, source, tmpdir=tmpdir,
                         target=target, source_extension=source_extension,
                         compiler_verbose=verbose, debug=debug, **kwds)

    def init_once(self, func, tag):
        # Read _init_once_cache[tag], which is either (False, lock) if
        # we're calling the function now in some thread, or (True, result).
        # Don't call setdefault() in most cases, to avoid allocating and
        # immediately freeing a lock; but still use setdefaut() to avoid
        # races.
        try:
            x = self._init_once_cache[tag]
        except KeyError:
            x = self._init_once_cache.setdefault(tag, (False, allocate_lock()))
        # Common case: we got (True, result), so we return the result.
        if x[0]:
            return x[1]
        # Else, it's a lock.  Acquire it to serialize the following tests.
        with x[1]:
            # Read again from _init_once_cache the current status.
            x = self._init_once_cache[tag]
            if x[0]:
                return x[1]
            # Call the function and store the result back.
            result = func()
            self._init_once_cache[tag] = (True, result)
        return result

    def embedding_init_code(self, pysource):
        if self._embedding:
            raise ValueError("embedding_init_code() can only be called once")
        # fix 'pysource' before it gets dumped into the C file:
        # - remove empty lines at the beginning, so it starts at "line 1"
        # - dedent, if all non-empty lines are indented
        # - check for SyntaxErrors
        import re
        match = re.match(r'\s*\n', pysource)
        if match:
            pysource = pysource[match.end():]
        lines = pysource.splitlines() or ['']
        prefix = re.match(r'\s*', lines[0]).group()
        for i in range(1, len(lines)):
            line = lines[i]
            if line.rstrip():
                while not line.startswith(prefix):
                    prefix = prefix[:-1]
        i = len(prefix)
        lines = [line[i:]+'\n' for line in lines]
        pysource = ''.join(lines)
        #
        compile(pysource, "cffi_init", "exec")
        #
        self._embedding = pysource

    def def_extern(self, *args, **kwds):
        raise ValueError("ffi.def_extern() is only available on API-mode FFI "
                         "objects")

    def list_types(self):
        """Returns the user type names known to this FFI instance.
        This returns a tuple containing three lists of names:
        (typedef_names, names_of_structs, names_of_unions)
        """
        typedefs = []
        structs = []
        unions = []
        for key in self._parser._declarations:
            if key.startswith('typedef '):
                typedefs.append(key[8:])
            elif key.startswith('struct '):
                structs.append(key[7:])
            elif key.startswith('union '):
                unions.append(key[6:])
        typedefs.sort()
        structs.sort()
        unions.sort()
        return (typedefs, structs, unions)


def _load_backend_lib(backend, name, flags):
    import os
    if not isinstance(name, basestring):
        if sys.platform != "win32" or name is not None:
            return backend.load_library(name, flags)
        name = "c"    # Windows: load_library(None) fails, but this works
                      # on Python 2 (backward compatibility hack only)
    first_error = None
    if '.' in name or '/' in name or os.sep in name:
        try:
            return backend.load_library(name, flags)
        except OSError as e:
            first_error = e
    import ctypes.util
    path = ctypes.util.find_library(name)
    if path is None:
        if name == "c" and sys.platform == "win32" and sys.version_info >= (3,):
            raise OSError("dlopen(None) cannot work on Windows for Python 3 "
                          "(see http://bugs.python.org/issue23606)")
        msg = ("ctypes.util.find_library() did not manage "
               "to locate a library called %r" % (name,))
        if first_error is not None:
            msg = "%s.  Additionally, %s" % (first_error, msg)
        raise OSError(msg)
    return backend.load_library(path, flags)

def _make_ffi_library(ffi, libname, flags):
    backend = ffi._backend
    backendlib = _load_backend_lib(backend, libname, flags)
    #
    def accessor_function(name):
        key = 'function ' + name
        tp, _ = ffi._parser._declarations[key]
        BType = ffi._get_cached_btype(tp)
        value = backendlib.load_function(BType, name)
        library.__dict__[name] = value
    #
    def accessor_variable(name):
        key = 'variable ' + name
        tp, _ = ffi._parser._declarations[key]
        BType = ffi._get_cached_btype(tp)
        read_variable = backendlib.read_variable
        write_variable = backendlib.write_variable
        setattr(FFILibrary, name, property(
            lambda self: read_variable(BType, name),
            lambda self, value: write_variable(BType, name, value)))
    #
    def addressof_var(name):
        try:
            return addr_variables[name]
        except KeyError:
            with ffi._lock:
                if name not in addr_variables:
                    key = 'variable ' + name
                    tp, _ = ffi._parser._declarations[key]
                    BType = ffi._get_cached_btype(tp)
                    if BType.kind != 'array':
                        BType = model.pointer_cache(ffi, BType)
                    p = backendlib.load_function(BType, name)
                    addr_variables[name] = p
            return addr_variables[name]
    #
    def accessor_constant(name):
        raise NotImplementedError("non-integer constant '%s' cannot be "
                                  "accessed from a dlopen() library" % (name,))
    #
    def accessor_int_constant(name):
        library.__dict__[name] = ffi._parser._int_constants[name]
    #
    accessors = {}
    accessors_version = [False]
    addr_variables = {}
    #
    def update_accessors():
        if accessors_version[0] is ffi._cdef_version:
            return
        #
        for key, (tp, _) in ffi._parser._declarations.items():
            if not isinstance(tp, model.EnumType):
                tag, name = key.split(' ', 1)
                if tag == 'function':
                    accessors[name] = accessor_function
                elif tag == 'variable':
                    accessors[name] = accessor_variable
                elif tag == 'constant':
                    accessors[name] = accessor_constant
            else:
                for i, enumname in enumerate(tp.enumerators):
                    def accessor_enum(name, tp=tp, i=i):
                        tp.check_not_partial()
                        library.__dict__[name] = tp.enumvalues[i]
                    accessors[enumname] = accessor_enum
        for name in ffi._parser._int_constants:
            accessors.setdefault(name, accessor_int_constant)
        accessors_version[0] = ffi._cdef_version
    #
    def make_accessor(name):
        with ffi._lock:
            if name in library.__dict__ or name in FFILibrary.__dict__:
                return    # added by another thread while waiting for the lock
            if name not in accessors:
                update_accessors()
                if name not in accessors:
                    raise AttributeError(name)
            accessors[name](name)
    #
    class FFILibrary(object):
        def __getattr__(self, name):
            make_accessor(name)
            return getattr(self, name)
        def __setattr__(self, name, value):
            try:
                property = getattr(self.__class__, name)
            except AttributeError:
                make_accessor(name)
                setattr(self, name, value)
            else:
                property.__set__(self, value)
        def __dir__(self):
            with ffi._lock:
                update_accessors()
                return accessors.keys()
        def __addressof__(self, name):
            if name in library.__dict__:
                return library.__dict__[name]
            if name in FFILibrary.__dict__:
                return addressof_var(name)
            make_accessor(name)
            if name in library.__dict__:
                return library.__dict__[name]
            if name in FFILibrary.__dict__:
                return addressof_var(name)
            raise AttributeError("cffi library has no function or "
                                 "global variable named '%s'" % (name,))
        def __cffi_close__(self):
            backendlib.close_lib()
            self.__dict__.clear()
    #
    if isinstance(libname, basestring):
        try:
            if not isinstance(libname, str):    # unicode, on Python 2
                libname = libname.encode('utf-8')
            FFILibrary.__name__ = 'FFILibrary_%s' % libname
        except UnicodeError:
            pass
    library = FFILibrary()
    return library, library.__dict__

def _builtin_function_type(func):
    # a hack to make at least ffi.typeof(builtin_function) work,
    # if the builtin function was obtained by 'vengine_cpy'.
    import sys
    try:
        module = sys.modules[func.__module__]
        ffi = module._cffi_original_ffi
        types_of_builtin_funcs = module._cffi_types_of_builtin_funcs
        tp = types_of_builtin_funcs[func]
    except (KeyError, AttributeError, TypeError):
        return None
    else:
        with ffi._lock:
            return ffi._get_cached_btype(tp)

src/cffi/api.py
python-cffi/cffi
import sys, os
from .error import VerificationError


LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
                      'extra_objects', 'depends']

def get_extension(srcfilename, modname, sources=(), **kwds):
    from cffi._shimmed_dist_utils import Extension
    allsources = [srcfilename]
    for src in sources:
        allsources.append(os.path.normpath(src))
    return Extension(name=modname, sources=allsources, **kwds)

def compile(tmpdir, ext, compiler_verbose=0, debug=None):
    """Compile a C extension module using distutils."""

    saved_environ = os.environ.copy()
    try:
        outputfilename = _build(tmpdir, ext, compiler_verbose, debug)
        outputfilename = os.path.abspath(outputfilename)
    finally:
        # workaround for a distutils bugs where some env vars can
        # become longer and longer every time it is used
        for key, value in saved_environ.items():
            if os.environ.get(key) != value:
                os.environ[key] = value
    return outputfilename

def _build(tmpdir, ext, compiler_verbose=0, debug=None):
    # XXX compact but horrible :-(
    from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity

    dist = Distribution({'ext_modules': [ext]})
    dist.parse_config_files()
    options = dist.get_option_dict('build_ext')
    if debug is None:
        debug = sys.flags.debug
    options['debug'] = ('ffiplatform', debug)
    options['force'] = ('ffiplatform', True)
    options['build_lib'] = ('ffiplatform', tmpdir)
    options['build_temp'] = ('ffiplatform', tmpdir)
    #
    try:
        old_level = set_threshold(0) or 0
        try:
            set_verbosity(compiler_verbose)
            dist.run_command('build_ext')
            cmd_obj = dist.get_command_obj('build_ext')
            [soname] = cmd_obj.get_outputs()
        finally:
            set_threshold(old_level)
    except (CompileError, LinkError) as e:
        raise VerificationError('%s: %s' % (e.__class__.__name__, e))
    #
    return soname

try:
    from os.path import samefile
except ImportError:
    def samefile(f1, f2):
        return os.path.abspath(f1) == os.path.abspath(f2)

def maybe_relative_path(path):
    if not os.path.isabs(path):
        return path      # already relative
    dir = path
    names = []
    while True:
        prevdir = dir
        dir, name = os.path.split(prevdir)
        if dir == prevdir or not dir:
            return path     # failed to make it relative
        names.append(name)
        try:
            if samefile(dir, os.curdir):
                names.reverse()
                return os.path.join(*names)
        except OSError:
            pass

# ____________________________________________________________

try:
    int_or_long = (int, long)
    import cStringIO
except NameError:
    int_or_long = int      # Python 3
    import io as cStringIO

def _flatten(x, f):
    if isinstance(x, str):
        f.write('%ds%s' % (len(x), x))
    elif isinstance(x, dict):
        keys = sorted(x.keys())
        f.write('%dd' % len(keys))
        for key in keys:
            _flatten(key, f)
            _flatten(x[key], f)
    elif isinstance(x, (list, tuple)):
        f.write('%dl' % len(x))
        for value in x:
            _flatten(value, f)
    elif isinstance(x, int_or_long):
        f.write('%di' % (x,))
    else:
        raise TypeError(
            "the keywords to verify() contains unsupported object %r" % (x,))

def flatten(x):
    f = cStringIO.StringIO()
    _flatten(x, f)
    return f.getvalue()

src/cffi/ffiplatform.py
python-cffi/cffi
import types
import weakref

from .lock import allocate_lock
from .error import CDefError, VerificationError, VerificationMissing

# type qualifiers
Q_CONST    = 0x01
Q_RESTRICT = 0x02
Q_VOLATILE = 0x04

def qualify(quals, replace_with):
    if quals & Q_CONST:
        replace_with = ' const ' + replace_with.lstrip()
    if quals & Q_VOLATILE:
        replace_with = ' volatile ' + replace_with.lstrip()
    if quals & Q_RESTRICT:
        # It seems that __restrict is supported by gcc and msvc.
        # If you hit some different compiler, add a #define in
        # _cffi_include.h for it (and in its copies, documented there)
        replace_with = ' __restrict ' + replace_with.lstrip()
    return replace_with


class BaseTypeByIdentity(object):
    is_array_type = False
    is_raw_function = False

    def get_c_name(self, replace_with='', context='a C file', quals=0):
        result = self.c_name_with_marker
        assert result.count('&') == 1
        # some logic duplication with ffi.getctype()... :-(
        replace_with = replace_with.strip()
        if replace_with:
            if replace_with.startswith('*') and '&[' in result:
                replace_with = '(%s)' % replace_with
            elif not replace_with[0] in '[(':
                replace_with = ' ' + replace_with
        replace_with = qualify(quals, replace_with)
        result = result.replace('&', replace_with)
        if '$' in result:
            raise VerificationError(
                "cannot generate '%s' in %s: unknown type name"
                % (self._get_c_name(), context))
        return result

    def _get_c_name(self):
        return self.c_name_with_marker.replace('&', '')

    def has_c_name(self):
        return '$' not in self._get_c_name()

    def is_integer_type(self):
        return False

    def get_cached_btype(self, ffi, finishlist, can_delay=False):
        try:
            BType = ffi._cached_btypes[self]
        except KeyError:
            BType = self.build_backend_type(ffi, finishlist)
            BType2 = ffi._cached_btypes.setdefault(self, BType)
            assert BType2 is BType
        return BType

    def __repr__(self):
        return '<%s>' % (self._get_c_name(),)

    def _get_items(self):
        return [(name, getattr(self, name)) for name in self._attrs_]


class BaseType(BaseTypeByIdentity):

    def __eq__(self, other):
        return (self.__class__ == other.__class__ and
                self._get_items() == other._get_items())

    def __ne__(self, other):
        return not self == other

    def __hash__(self):
        return hash((self.__class__, tuple(self._get_items())))


class VoidType(BaseType):
    _attrs_ = ()

    def __init__(self):
        self.c_name_with_marker = 'void&'

    def build_backend_type(self, ffi, finishlist):
        return global_cache(self, ffi, 'new_void_type')

void_type = VoidType()


class BasePrimitiveType(BaseType):
    def is_complex_type(self):
        return False


class PrimitiveType(BasePrimitiveType):
    _attrs_ = ('name',)

    ALL_PRIMITIVE_TYPES = {
        'char':               'c',
        'short':              'i',
        'int':                'i',
        'long':               'i',
        'long long':          'i',
        'signed char':        'i',
        'unsigned char':      'i',
        'unsigned short':     'i',
        'unsigned int':       'i',
        'unsigned long':      'i',
        'unsigned long long': 'i',
        'float':              'f',
        'double':             'f',
        'long double':        'f',
        'float _Complex':     'j',
        'double _Complex':    'j',
        '_Bool':              'i',
        # the following types are not primitive in the C sense
        'wchar_t':            'c',
        'char16_t':           'c',
        'char32_t':           'c',
        'int8_t':             'i',
        'uint8_t':            'i',
        'int16_t':            'i',
        'uint16_t':           'i',
        'int32_t':            'i',
        'uint32_t':           'i',
        'int64_t':            'i',
        'uint64_t':           'i',
        'int_least8_t':       'i',
        'uint_least8_t':      'i',
        'int_least16_t':      'i',
        'uint_least16_t':     'i',
        'int_least32_t':      'i',
        'uint_least32_t':     'i',
        'int_least64_t':      'i',
        'uint_least64_t':     'i',
        'int_fast8_t':        'i',
        'uint_fast8_t':       'i',
        'int_fast16_t':       'i',
        'uint_fast16_t':      'i',
        'int_fast32_t':       'i',
        'uint_fast32_t':      'i',
        'int_fast64_t':       'i',
        'uint_fast64_t':      'i',
        'intptr_t':           'i',
        'uintptr_t':          'i',
        'intmax_t':           'i',
        'uintmax_t':          'i',
        'ptrdiff_t':          'i',
        'size_t':             'i',
        'ssize_t':            'i',
        }

    def __init__(self, name):
        assert name in self.ALL_PRIMITIVE_TYPES
        self.name = name
        self.c_name_with_marker = name + '&'

    def is_char_type(self):
        return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
    def is_integer_type(self):
        return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
    def is_float_type(self):
        return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
    def is_complex_type(self):
        return self.ALL_PRIMITIVE_TYPES[self.name] == 'j'

    def build_backend_type(self, ffi, finishlist):
        return global_cache(self, ffi, 'new_primitive_type', self.name)


class UnknownIntegerType(BasePrimitiveType):
    _attrs_ = ('name',)

    def __init__(self, name):
        self.name = name
        self.c_name_with_marker = name + '&'

    def is_integer_type(self):
        return True

    def build_backend_type(self, ffi, finishlist):
        raise NotImplementedError("integer type '%s' can only be used after "
                                  "compilation" % self.name)

class UnknownFloatType(BasePrimitiveType):
    _attrs_ = ('name', )

    def __init__(self, name):
        self.name = name
        self.c_name_with_marker = name + '&'

    def build_backend_type(self, ffi, finishlist):
        raise NotImplementedError("float type '%s' can only be used after "
                                  "compilation" % self.name)


class BaseFunctionType(BaseType):
    _attrs_ = ('args', 'result', 'ellipsis', 'abi')

    def __init__(self, args, result, ellipsis, abi=None):
        self.args = args
        self.result = result
        self.ellipsis = ellipsis
        self.abi = abi
        #
        reprargs = [arg._get_c_name() for arg in self.args]
        if self.ellipsis:
            reprargs.append('...')
        reprargs = reprargs or ['void']
        replace_with = self._base_pattern % (', '.join(reprargs),)
        if abi is not None:
            replace_with = replace_with[:1] + abi + ' ' + replace_with[1:]
        self.c_name_with_marker = (
            self.result.c_name_with_marker.replace('&', replace_with))


class RawFunctionType(BaseFunctionType):
    # Corresponds to a C type like 'int(int)', which is the C type of
    # a function, but not a pointer-to-function.  The backend has no
    # notion of such a type; it's used temporarily by parsing.
    _base_pattern = '(&)(%s)'
    is_raw_function = True

    def build_backend_type(self, ffi, finishlist):
        raise CDefError("cannot render the type %r: it is a function "
                        "type, not a pointer-to-function type" % (self,))

    def as_function_pointer(self):
        return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi)


class FunctionPtrType(BaseFunctionType):
    _base_pattern = '(*&)(%s)'

    def build_backend_type(self, ffi, finishlist):
        result = self.result.get_cached_btype(ffi, finishlist)
        args = []
        for tp in self.args:
            args.append(tp.get_cached_btype(ffi, finishlist))
        abi_args = ()
        if self.abi == "__stdcall":
            if not self.ellipsis:    # __stdcall ignored for variadic funcs
                try:
                    abi_args = (ffi._backend.FFI_STDCALL,)
                except AttributeError:
                    pass
        return global_cache(self, ffi, 'new_function_type',
                            tuple(args), result, self.ellipsis, *abi_args)

    def as_raw_function(self):
        return RawFunctionType(self.args, self.result, self.ellipsis, self.abi)


class PointerType(BaseType):
    _attrs_ = ('totype', 'quals')

    def __init__(self, totype, quals=0):
        self.totype = totype
        self.quals = quals
        extra = " *&"
        if totype.is_array_type:
            extra = "(%s)" % (extra.lstrip(),)
        extra = qualify(quals, extra)
        self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)

    def build_backend_type(self, ffi, finishlist):
        BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
        return global_cache(self, ffi, 'new_pointer_type', BItem)

voidp_type = PointerType(void_type)

def ConstPointerType(totype):
    return PointerType(totype, Q_CONST)

const_voidp_type = ConstPointerType(void_type)


class NamedPointerType(PointerType):
    _attrs_ = ('totype', 'name')

    def __init__(self, totype, name, quals=0):
        PointerType.__init__(self, totype, quals)
        self.name = name
        self.c_name_with_marker = name + '&'


class ArrayType(BaseType):
    _attrs_ = ('item', 'length')
    is_array_type = True

    def __init__(self, item, length):
        self.item = item
        self.length = length
        #
        if length is None:
            brackets = '&[]'
        elif length == '...':
            brackets = '&[/*...*/]'
        else:
            brackets = '&[%s]' % length
        self.c_name_with_marker = (
            self.item.c_name_with_marker.replace('&', brackets))

    def length_is_unknown(self):
        return isinstance(self.length, str)

    def resolve_length(self, newlength):
        return ArrayType(self.item, newlength)

    def build_backend_type(self, ffi, finishlist):
        if self.length_is_unknown():
            raise CDefError("cannot render the type %r: unknown length" %
                            (self,))
        self.item.get_cached_btype(ffi, finishlist)   # force the item BType
        BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist)
        return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length)

char_array_type = ArrayType(PrimitiveType('char'), None)


class StructOrUnionOrEnum(BaseTypeByIdentity):
    _attrs_ = ('name',)
    forcename = None

    def build_c_name_with_marker(self):
        name = self.forcename or '%s %s' % (self.kind, self.name)
        self.c_name_with_marker = name + '&'

    def force_the_name(self, forcename):
        self.forcename = forcename
        self.build_c_name_with_marker()

    def get_official_name(self):
        assert self.c_name_with_marker.endswith('&')
        return self.c_name_with_marker[:-1]


class StructOrUnion(StructOrUnionOrEnum):
    fixedlayout = None
    completed = 0
    partial = False
    packed = 0

    def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None):
        self.name = name
        self.fldnames = fldnames
        self.fldtypes = fldtypes
        self.fldbitsize = fldbitsize
        self.fldquals = fldquals
        self.build_c_name_with_marker()

    def anonymous_struct_fields(self):
        if self.fldtypes is not None:
            for name, type in zip(self.fldnames, self.fldtypes):
                if name == '' and isinstance(type, StructOrUnion):
                    yield type

    def enumfields(self, expand_anonymous_struct_union=True):
        fldquals = self.fldquals
        if fldquals is None:
            fldquals = (0,) * len(self.fldnames)
        for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes,
                                              self.fldbitsize, fldquals):
            if (name == '' and isinstance(type, StructOrUnion)
                    and expand_anonymous_struct_union):
                # nested anonymous struct/union
                for result in type.enumfields():
                    yield result
            else:
                yield (name, type, bitsize, quals)

    def force_flatten(self):
        # force the struct or union to have a declaration that lists
        # directly all fields returned by enumfields(), flattening
        # nested anonymous structs/unions.
        names = []
        types = []
        bitsizes = []
        fldquals = []
        for name, type, bitsize, quals in self.enumfields():
            names.append(name)
            types.append(type)
            bitsizes.append(bitsize)
            fldquals.append(quals)
        self.fldnames = tuple(names)
        self.fldtypes = tuple(types)
        self.fldbitsize = tuple(bitsizes)
        self.fldquals = tuple(fldquals)

    def get_cached_btype(self, ffi, finishlist, can_delay=False):
        BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist,
                                                     can_delay)
        if not can_delay:
            self.finish_backend_type(ffi, finishlist)
        return BType

    def finish_backend_type(self, ffi, finishlist):
        if self.completed:
            if self.completed != 2:
                raise NotImplementedError("recursive structure declaration "
                                          "for '%s'" % (self.name,))
            return
        BType = ffi._cached_btypes[self]
        #
        self.completed = 1
        #
        if self.fldtypes is None:
            pass    # not completing it: it's an opaque struct
            #
        elif self.fixedlayout is None:
            fldtypes = [tp.get_cached_btype(ffi, finishlist)
                        for tp in self.fldtypes]
            lst = list(zip(self.fldnames, fldtypes, self.fldbitsize))
            extra_flags = ()
            if self.packed:
                if self.packed == 1:
                    extra_flags = (8,)    # SF_PACKED
                else:
                    extra_flags = (0, self.packed)
            ffi._backend.complete_struct_or_union(BType, lst, self,
                                                  -1, -1, *extra_flags)
            #
        else:
            fldtypes = []
            fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout
            for i in range(len(self.fldnames)):
                fsize = fieldsize[i]
                ftype = self.fldtypes[i]
                #
                if isinstance(ftype, ArrayType) and ftype.length_is_unknown():
                    # fix the length to match the total size
                    BItemType = ftype.item.get_cached_btype(ffi, finishlist)
                    nlen, nrest = divmod(fsize, ffi.sizeof(BItemType))
                    if nrest != 0:
                        self._verification_error(
                            "field '%s.%s' has a bogus size?" % (
                            self.name, self.fldnames[i] or '{}'))
                    ftype = ftype.resolve_length(nlen)
                    self.fldtypes = (self.fldtypes[:i] + (ftype,) +
                                     self.fldtypes[i+1:])
                #
                BFieldType = ftype.get_cached_btype(ffi, finishlist)
                if isinstance(ftype, ArrayType) and ftype.length is None:
                    assert fsize == 0
                else:
                    bitemsize = ffi.sizeof(BFieldType)
                    if bitemsize != fsize:
                        self._verification_error(
                            "field '%s.%s' is declared as %d bytes, but is "
                            "really %d bytes" % (self.name,
                                                 self.fldnames[i] or '{}',
                                                 bitemsize, fsize))
                fldtypes.append(BFieldType)
            #
            lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs))
            ffi._backend.complete_struct_or_union(BType, lst, self,
                                                  totalsize, totalalignment)
        self.completed = 2

    def _verification_error(self, msg):
        raise VerificationError(msg)

    def check_not_partial(self):
        if self.partial and self.fixedlayout is None:
            raise VerificationMissing(self._get_c_name())

    def build_backend_type(self, ffi, finishlist):
        self.check_not_partial()
        finishlist.append(self)
        #
        return global_cache(self, ffi, 'new_%s_type' % self.kind,
                            self.get_official_name(), key=self)


class StructType(StructOrUnion):
    kind = 'struct'


class UnionType(StructOrUnion):
    kind = 'union'


class EnumType(StructOrUnionOrEnum):
    kind = 'enum'
    partial = False
    partial_resolved = False

    def __init__(self, name, enumerators, enumvalues, baseinttype=None):
        self.name = name
        self.enumerators = enumerators
        self.enumvalues = enumvalues
        self.baseinttype = baseinttype
        self.build_c_name_with_marker()

    def force_the_name(self, forcename):
        StructOrUnionOrEnum.force_the_name(self, forcename)
        if self.forcename is None:
            name = self.get_official_name()
            self.forcename = '$' + name.replace(' ', '_')

    def check_not_partial(self):
        if self.partial and not self.partial_resolved:
            raise VerificationMissing(self._get_c_name())

    def build_backend_type(self, ffi, finishlist):
        self.check_not_partial()
        base_btype = self.build_baseinttype(ffi, finishlist)
        return global_cache(self, ffi, 'new_enum_type',
                            self.get_official_name(),
                            self.enumerators, self.enumvalues,
                            base_btype, key=self)

    def build_baseinttype(self, ffi, finishlist):
        if self.baseinttype is not None:
            return self.baseinttype.get_cached_btype(ffi, finishlist)
        #
        if self.enumvalues:
            smallest_value = min(self.enumvalues)
            largest_value = max(self.enumvalues)
        else:
            import warnings
            try:
                # XXX!  The goal is to ensure that the warnings.warn()
                # will not suppress the warning.  We want to get it
                # several times if we reach this point several times.
                __warningregistry__.clear()
            except NameError:
                pass
            warnings.warn("%r has no values explicitly defined; "
                          "guessing that it is equivalent to 'unsigned int'"
                          % self._get_c_name())
            smallest_value = largest_value = 0
        if smallest_value < 0:   # needs a signed type
            sign = 1
            candidate1 = PrimitiveType("int")
            candidate2 = PrimitiveType("long")
        else:
            sign = 0
            candidate1 = PrimitiveType("unsigned int")
            candidate2 = PrimitiveType("unsigned long")
        btype1 = candidate1.get_cached_btype(ffi, finishlist)
        btype2 = candidate2.get_cached_btype(ffi, finishlist)
        size1 = ffi.sizeof(btype1)
        size2 = ffi.sizeof(btype2)
        if (smallest_value >= ((-1) << (8*size1-1)) and
            largest_value < (1 << (8*size1-sign))):
            return btype1
        if (smallest_value >= ((-1) << (8*size2-1)) and
            largest_value < (1 << (8*size2-sign))):
            return btype2
        raise CDefError("%s values don't all fit into either 'long' "
                        "or 'unsigned long'" % self._get_c_name())

def unknown_type(name, structname=None):
    if structname is None:
        structname = '$%s' % name
    tp = StructType(structname, None, None, None)
    tp.force_the_name(name)
    tp.origin = "unknown_type"
    return tp

def unknown_ptr_type(name, structname=None):
    if structname is None:
        structname = '$$%s' % name
    tp = StructType(structname, None, None, None)
    return NamedPointerType(tp, name)


global_lock = allocate_lock()
_typecache_cffi_backend = weakref.WeakValueDictionary()

def get_typecache(backend):
    # returns _typecache_cffi_backend if backend is the _cffi_backend
    # module, or type(backend).__typecache if backend is an instance of
    # CTypesBackend (or some FakeBackend class during tests)
    if isinstance(backend, types.ModuleType):
        return _typecache_cffi_backend
    with global_lock:
        if not hasattr(type(backend), '__typecache'):
            type(backend).__typecache = weakref.WeakValueDictionary()
        return type(backend).__typecache

def global_cache(srctype, ffi, funcname, *args, **kwds):
    key = kwds.pop('key', (funcname, args))
    assert not kwds
    try:
        return ffi._typecache[key]
    except KeyError:
        pass
    try:
        res = getattr(ffi._backend, funcname)(*args)
    except NotImplementedError as e:
        raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e))
    # note that setdefault() on WeakValueDictionary is not atomic
    # and contains a rare bug (http://bugs.python.org/issue19542);
    # we have to use a lock and do it ourselves
    cache = ffi._typecache
    with global_lock:
        res1 = cache.get(key)
        if res1 is None:
            cache[key] = res
            return res
        else:
            return res1

def pointer_cache(ffi, BType):
    return global_cache('?', ffi, 'new_pointer_type', BType)

def attach_exception_info(e, name):
    if e.args and type(e.args[0]) is str:
        e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:]

src/cffi/model.py
python-cffi/cffi
import os, sys, io
from . import ffiplatform, model
from .error import VerificationError
from .cffi_opcode import *

VERSION_BASE = 0x2601
VERSION_EMBEDDED = 0x2701
VERSION_CHAR16CHAR32 = 0x2801

USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or
                   sys.version_info >= (3, 5))


class GlobalExpr:
    def __init__(self, name, address, type_op, size=0, check_value=0):
        self.name = name
        self.address = address
        self.type_op = type_op
        self.size = size
        self.check_value = check_value

    def as_c_expr(self):
        return '  { "%s", (void *)%s, %s, (void *)%s },' % (
            self.name, self.address, self.type_op.as_c_expr(), self.size)

    def as_python_expr(self):
        return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name,
                               self.check_value)

class FieldExpr:
    def __init__(self, name, field_offset, field_size, fbitsize, field_type_op):
        self.name = name
        self.field_offset = field_offset
        self.field_size = field_size
        self.fbitsize = fbitsize
        self.field_type_op = field_type_op

    def as_c_expr(self):
        spaces = " " * len(self.name)
        return ('  { "%s", %s,\n' % (self.name, self.field_offset) +
                '     %s   %s,\n' % (spaces, self.field_size) +
                '     %s   %s },' % (spaces, self.field_type_op.as_c_expr()))

    def as_python_expr(self):
        raise NotImplementedError

    def as_field_python_expr(self):
        if self.field_type_op.op == OP_NOOP:
            size_expr = ''
        elif self.field_type_op.op == OP_BITFIELD:
            size_expr = format_four_bytes(self.fbitsize)
        else:
            raise NotImplementedError
        return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(),
                              size_expr,
                              self.name)

class StructUnionExpr:
    def __init__(self, name, type_index, flags, size, alignment, comment,
                 first_field_index, c_fields):
        self.name = name
        self.type_index = type_index
        self.flags = flags
        self.size = size
        self.alignment = alignment
        self.comment = comment
        self.first_field_index = first_field_index
        self.c_fields = c_fields

    def as_c_expr(self):
        return ('  { "%s", %d, %s,' % (self.name, self.type_index, self.flags)
                + '\n    %s, %s, ' % (self.size, self.alignment)
                + '%d, %d ' % (self.first_field_index, len(self.c_fields))
                + ('/* %s */ ' % self.comment if self.comment else '')
                + '},')

    def as_python_expr(self):
        flags = eval(self.flags, G_FLAGS)
        fields_expr = [c_field.as_field_python_expr()
                       for c_field in self.c_fields]
        return "(b'%s%s%s',%s)" % (
            format_four_bytes(self.type_index),
            format_four_bytes(flags),
            self.name,
            ','.join(fields_expr))

class EnumExpr:
    def __init__(self, name, type_index, size, signed, allenums):
        self.name = name
        self.type_index = type_index
        self.size = size
        self.signed = signed
        self.allenums = allenums

    def as_c_expr(self):
        return ('  { "%s", %d, _cffi_prim_int(%s, %s),\n'
                '    "%s" },' % (self.name, self.type_index,
                                 self.size, self.signed, self.allenums))

    def as_python_expr(self):
        prim_index = {
            (1, 0): PRIM_UINT8,  (1, 1):  PRIM_INT8,
            (2, 0): PRIM_UINT16, (2, 1):  PRIM_INT16,
            (4, 0): PRIM_UINT32, (4, 1):  PRIM_INT32,
            (8, 0): PRIM_UINT64, (8, 1):  PRIM_INT64,
            }[self.size, self.signed]
        return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index),
                                     format_four_bytes(prim_index),
                                     self.name, self.allenums)

class TypenameExpr:
    def __init__(self, name, type_index):
        self.name = name
        self.type_index = type_index

    def as_c_expr(self):
        return '  { "%s", %d },' % (self.name, self.type_index)

    def as_python_expr(self):
        return "b'%s%s'" % (format_four_bytes(self.type_index), self.name)


# ____________________________________________________________


class Recompiler:
    _num_externpy = 0

    def __init__(self, ffi, module_name, target_is_python=False):
        self.ffi = ffi
        self.module_name = module_name
        self.target_is_python = target_is_python
        self._version = VERSION_BASE

    def needs_version(self, ver):
        self._version = max(self._version, ver)

    def collect_type_table(self):
        self._typesdict = {}
        self._generate("collecttype")
        #
        all_decls = sorted(self._typesdict, key=str)
        #
        # prepare all FUNCTION bytecode sequences first
        self.cffi_types = []
        for tp in all_decls:
            if tp.is_raw_function:
                assert self._typesdict[tp] is None
                self._typesdict[tp] = len(self.cffi_types)
                self.cffi_types.append(tp)     # placeholder
                for tp1 in tp.args:
                    assert isinstance(tp1, (model.VoidType,
                                            model.BasePrimitiveType,
                                            model.PointerType,
                                            model.StructOrUnionOrEnum,
                                            model.FunctionPtrType))
                    if self._typesdict[tp1] is None:
                        self._typesdict[tp1] = len(self.cffi_types)
                    self.cffi_types.append(tp1)   # placeholder
                self.cffi_types.append('END')     # placeholder
        #
        # prepare all OTHER bytecode sequences
        for tp in all_decls:
            if not tp.is_raw_function and self._typesdict[tp] is None:
                self._typesdict[tp] = len(self.cffi_types)
                self.cffi_types.append(tp)        # placeholder
                if tp.is_array_type and tp.length is not None:
                    self.cffi_types.append('LEN') # placeholder
        assert None not in self._typesdict.values()
        #
        # collect all structs and unions and enums
        self._struct_unions = {}
        self._enums = {}
        for tp in all_decls:
            if isinstance(tp, model.StructOrUnion):
                self._struct_unions[tp] = None
            elif isinstance(tp, model.EnumType):
                self._enums[tp] = None
        for i, tp in enumerate(sorted(self._struct_unions,
                                      key=lambda tp: tp.name)):
            self._struct_unions[tp] = i
        for i, tp in enumerate(sorted(self._enums,
                                      key=lambda tp: tp.name)):
            self._enums[tp] = i
        #
        # emit all bytecode sequences now
        for tp in all_decls:
            method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__)
            method(tp, self._typesdict[tp])
        #
        # consistency check
        for op in self.cffi_types:
            assert isinstance(op, CffiOp)
        self.cffi_types = tuple(self.cffi_types)    # don't change any more

    def _enum_fields(self, tp):
        # When producing C, expand all anonymous struct/union fields.
        # That's necessary to have C code checking the offsets of the
        # individual fields contained in them.  When producing Python,
        # don't do it and instead write it like it is, with the
        # corresponding fields having an empty name.  Empty names are
        # recognized at runtime when we import the generated Python
        # file.
        expand_anonymous_struct_union = not self.target_is_python
        return tp.enumfields(expand_anonymous_struct_union)

    def _do_collect_type(self, tp):
        if not isinstance(tp, model.BaseTypeByIdentity):
            if isinstance(tp, tuple):
                for x in tp:
                    self._do_collect_type(x)
            return
        if tp not in self._typesdict:
            self._typesdict[tp] = None
            if isinstance(tp, model.FunctionPtrType):
                self._do_collect_type(tp.as_raw_function())
            elif isinstance(tp, model.StructOrUnion):
                if tp.fldtypes is not None and (
                        tp not in self.ffi._parser._included_declarations):
                    for name1, tp1, _, _ in self._enum_fields(tp):
                        self._do_collect_type(self._field_type(tp, name1, tp1))
            else:
                for _, x in tp._get_items():
                    self._do_collect_type(x)

    def _generate(self, step_name):
        lst = self.ffi._parser._declarations.items()
        for name, (tp, quals) in sorted(lst):
            kind, realname = name.split(' ', 1)
            try:
                method = getattr(self, '_generate_cpy_%s_%s' % (kind,
                                                                step_name))
            except AttributeError:
                raise VerificationError(
                    "not implemented in recompile(): %r" % name)
            try:
                self._current_quals = quals
                method(tp, realname)
            except Exception as e:
                model.attach_exception_info(e, name)
                raise

    # ----------

    ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"]

    def collect_step_tables(self):
        # collect the declarations for '_cffi_globals', '_cffi_typenames', etc.
        self._lsts = {}
        for step_name in self.ALL_STEPS:
            self._lsts[step_name] = []
        self._seen_struct_unions = set()
        self._generate("ctx")
        self._add_missing_struct_unions()
        #
        for step_name in self.ALL_STEPS:
            lst = self._lsts[step_name]
            if step_name != "field":
                lst.sort(key=lambda entry: entry.name)
            self._lsts[step_name] = tuple(lst)    # don't change any more
        #
        # check for a possible internal inconsistency: _cffi_struct_unions
        # should have been generated with exactly self._struct_unions
        lst = self._lsts["struct_union"]
        for tp, i in self._struct_unions.items():
            assert i < len(lst)
            assert lst[i].name == tp.name
        assert len(lst) == len(self._struct_unions)
        # same with enums
        lst = self._lsts["enum"]
        for tp, i in self._enums.items():
            assert i < len(lst)
            assert lst[i].name == tp.name
        assert len(lst) == len(self._enums)

    # ----------

    def _prnt(self, what=''):
        self._f.write(what + '\n')

    def write_source_to_f(self, f, preamble):
        if self.target_is_python:
            assert preamble is None
            self.write_py_source_to_f(f)
        else:
            assert preamble is not None
            self.write_c_source_to_f(f, preamble)

    def _rel_readlines(self, filename):
        g = open(os.path.join(os.path.dirname(__file__), filename), 'r')
        lines = g.readlines()
        g.close()
        return lines

    def write_c_source_to_f(self, f, preamble):
        self._f = f
        prnt = self._prnt
        if self.ffi._embedding is not None:
            prnt('#define _CFFI_USE_EMBEDDING')
        if not USE_LIMITED_API:
            prnt('#define _CFFI_NO_LIMITED_API')
        #
        # first the '#include' (actually done by inlining the file's content)
        lines = self._rel_readlines('_cffi_include.h')
        i = lines.index('#include "parse_c_type.h"\n')
        lines[i:i+1] = self._rel_readlines('parse_c_type.h')
        prnt(''.join(lines))
        #
        # if we have ffi._embedding != None, we give it here as a macro
        # and include an extra file
        base_module_name = self.module_name.split('.')[-1]
        if self.ffi._embedding is not None:
            prnt('#define _CFFI_MODULE_NAME  "%s"' % (self.module_name,))
            prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {')
            self._print_string_literal_in_array(self.ffi._embedding)
            prnt('0 };')
            prnt('#ifdef PYPY_VERSION')
            prnt('# define _CFFI_PYTHON_STARTUP_FUNC  _cffi_pypyinit_%s' % (
                base_module_name,))
            prnt('#elif PY_MAJOR_VERSION >= 3')
            prnt('# define _CFFI_PYTHON_STARTUP_FUNC  PyInit_%s' % (
                base_module_name,))
            prnt('#else')
            prnt('# define _CFFI_PYTHON_STARTUP_FUNC  init%s' % (
                base_module_name,))
            prnt('#endif')
            lines = self._rel_readlines('_embedding.h')
            i = lines.index('#include "_cffi_errors.h"\n')
            lines[i:i+1] = self._rel_readlines('_cffi_errors.h')
            prnt(''.join(lines))
            self.needs_version(VERSION_EMBEDDED)
        #
        # then paste the C source given by the user, verbatim.
        prnt('/************************************************************/')
        prnt()
        prnt(preamble)
        prnt()
        prnt('/************************************************************/')
        prnt()
        #
        # the declaration of '_cffi_types'
        prnt('static void *_cffi_types[] = {')
        typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
        for i, op in enumerate(self.cffi_types):
            comment = ''
            if i in typeindex2type:
                comment = ' // ' + typeindex2type[i]._get_c_name()
            prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment))
        if not self.cffi_types:
            prnt('  0')
        prnt('};')
        prnt()
        #
        # call generate_cpy_xxx_decl(), for every xxx found from
        # ffi._parser._declarations.  This generates all the functions.
        self._seen_constants = set()
        self._generate("decl")
        #
        # the declaration of '_cffi_globals' and '_cffi_typenames'
        nums = {}
        for step_name in self.ALL_STEPS:
            lst = self._lsts[step_name]
            nums[step_name] = len(lst)
            if nums[step_name] > 0:
                prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
                    step_name, step_name))
                for entry in lst:
                    prnt(entry.as_c_expr())
                prnt('};')
                prnt()
        #
        # the declaration of '_cffi_includes'
        if self.ffi._included_ffis:
            prnt('static const char * const _cffi_includes[] = {')
            for ffi_to_include in self.ffi._included_ffis:
                try:
                    included_module_name, included_source = (
                        ffi_to_include._assigned_source[:2])
                except AttributeError:
                    raise VerificationError(
                        "ffi object %r includes %r, but the latter has not "
                        "been prepared with set_source()" % (
                            self.ffi, ffi_to_include,))
                if included_source is None:
                    raise VerificationError(
                        "not implemented yet: ffi.include() of a Python-based "
                        "ffi inside a C-based ffi")
                prnt('  "%s",' % (included_module_name,))
            prnt('  NULL')
            prnt('};')
            prnt()
        #
        # the declaration of '_cffi_type_context'
        prnt('static const struct _cffi_type_context_s _cffi_type_context = {')
        prnt('  _cffi_types,')
        for step_name in self.ALL_STEPS:
            if nums[step_name] > 0:
                prnt('  _cffi_%ss,' % step_name)
            else:
                prnt('  NULL,  /* no %ss */' % step_name)
        for step_name in self.ALL_STEPS:
            if step_name != "field":
                prnt('  %d,  /* num_%ss */' % (nums[step_name], step_name))
        if self.ffi._included_ffis:
            prnt('  _cffi_includes,')
        else:
            prnt('  NULL,  /* no includes */')
        prnt('  %d,  /* num_types */' % (len(self.cffi_types),))
        flags = 0
        if self._num_externpy > 0 or self.ffi._embedding is not None:
            flags |= 1     # set to mean that we use extern "Python"
        prnt('  %d,  /* flags */' % flags)
        prnt('};')
        prnt()
        #
        # the init function
        prnt('#ifdef __GNUC__')
        prnt('#  pragma GCC visibility push(default)  /* for -fvisibility= */')
        prnt('#endif')
        prnt()
        prnt('#ifdef PYPY_VERSION')
        prnt('PyMODINIT_FUNC')
        prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,))
        prnt('{')
        if flags & 1:
            prnt('    if (((intptr_t)p[0]) >= 0x0A03) {')
            prnt('        _cffi_call_python_org = '
                 '(void(*)(struct _cffi_externpy_s *, char *))p[1];')
            prnt('    }')
        prnt('    p[0] = (const void *)0x%x;' % self._version)
        prnt('    p[1] = &_cffi_type_context;')
        prnt('#if PY_MAJOR_VERSION >= 3')
        prnt('    return NULL;')
        prnt('#endif')
        prnt('}')
        # on Windows, distutils insists on putting init_cffi_xyz in
        # 'export_symbols', so instead of fighting it, just give up and
        # give it one
        prnt('#  ifdef _MSC_VER')
        prnt('     PyMODINIT_FUNC')
        prnt('#  if PY_MAJOR_VERSION >= 3')
        prnt('     PyInit_%s(void) { return NULL; }' % (base_module_name,))
        prnt('#  else')
        prnt('     init%s(void) { }' % (base_module_name,))
        prnt('#  endif')
        prnt('#  endif')
        prnt('#elif PY_MAJOR_VERSION >= 3')
        prnt('PyMODINIT_FUNC')
        prnt('PyInit_%s(void)' % (base_module_name,))
        prnt('{')
        prnt('  return _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
            self.module_name, self._version))
        prnt('}')
        prnt('#else')
        prnt('PyMODINIT_FUNC')
        prnt('init%s(void)' % (base_module_name,))
        prnt('{')
        prnt('  _cffi_init("%s", 0x%x, &_cffi_type_context);' % (
            self.module_name, self._version))
        prnt('}')
        prnt('#endif')
        prnt()
        prnt('#ifdef __GNUC__')
        prnt('#  pragma GCC visibility pop')
        prnt('#endif')
        self._version = None

    def _to_py(self, x):
        if isinstance(x, str):
            return "b'%s'" % (x,)
        if isinstance(x, (list, tuple)):
            rep = [self._to_py(item) for item in x]
            if len(rep) == 1:
                rep.append('')
            return "(%s)" % (','.join(rep),)
        return x.as_python_expr()  # Py2: unicode unexpected; Py3: bytes unexp.

    def write_py_source_to_f(self, f):
        self._f = f
        prnt = self._prnt
        #
        # header
        prnt("# auto-generated file")
        prnt("import _cffi_backend")
        #
        # the 'import' of the included ffis
        num_includes = len(self.ffi._included_ffis or ())
        for i in range(num_includes):
            ffi_to_include = self.ffi._included_ffis[i]
            try:
                included_module_name, included_source = (
                    ffi_to_include._assigned_source[:2])
            except AttributeError:
                raise VerificationError(
                    "ffi object %r includes %r, but the latter has not "
                    "been prepared with set_source()" % (
                        self.ffi, ffi_to_include,))
            if included_source is not None:
                raise VerificationError(
                    "not implemented yet: ffi.include() of a C-based "
                    "ffi inside a Python-based ffi")
            prnt('from %s import ffi as _ffi%d' % (included_module_name, i))
        prnt()
        prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,))
        prnt("    _version = 0x%x," % (self._version,))
        self._version = None
        #
        # the '_types' keyword argument
        self.cffi_types = tuple(self.cffi_types)    # don't change any more
        types_lst = [op.as_python_bytes() for op in self.cffi_types]
        prnt('    _types = %s,' % (self._to_py(''.join(types_lst)),))
        typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()])
        #
        # the keyword arguments from ALL_STEPS
        for step_name in self.ALL_STEPS:
            lst = self._lsts[step_name]
            if len(lst) > 0 and step_name != "field":
                prnt('    _%ss = %s,' % (step_name, self._to_py(lst)))
        #
        # the '_includes' keyword argument
        if num_includes > 0:
            prnt('    _includes = (%s,),' % (
                ', '.join(['_ffi%d' % i for i in range(num_includes)]),))
        #
        # the footer
        prnt(')')

    # ----------

    def _gettypenum(self, type):
        # a KeyError here is a bug.  please report it! :-)
        return self._typesdict[type]

    def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
        extraarg = ''
        if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type():
            if tp.is_integer_type() and tp.name != '_Bool':
                converter = '_cffi_to_c_int'
                extraarg = ', %s' % tp.name
            elif isinstance(tp, model.UnknownFloatType):
                # don't check with is_float_type(): it may be a 'long
                # double' here, and _cffi_to_c_double would loose precision
                converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),)
            else:
                cname = tp.get_c_name('')
                converter = '(%s)_cffi_to_c_%s' % (cname,
                                                   tp.name.replace(' ', '_'))
                if cname in ('char16_t', 'char32_t'):
                    self.needs_version(VERSION_CHAR16CHAR32)
            errvalue = '-1'
        #
        elif isinstance(tp, model.PointerType):
            self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
                                                    tovar, errcode)
            return
        #
        elif (isinstance(tp, model.StructOrUnionOrEnum) or
              isinstance(tp, model.BasePrimitiveType)):
            # a struct (not a struct pointer) as a function argument;
            # or, a complex (the same code works)
            self._prnt('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
                      % (tovar, self._gettypenum(tp), fromvar))
            self._prnt('    %s;' % errcode)
            return
        #
        elif isinstance(tp, model.FunctionPtrType):
            converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
            extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
            errvalue = 'NULL'
        #
        else:
            raise NotImplementedError(tp)
        #
        self._prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
        self._prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
            tovar, tp.get_c_name(''), errvalue))
        self._prnt('    %s;' % errcode)

    def _extra_local_variables(self, tp, localvars, freelines):
        if isinstance(tp, model.PointerType):
            localvars.add('Py_ssize_t datasize')
            localvars.add('struct _cffi_freeme_s *large_args_free = NULL')
            freelines.add('if (large_args_free != NULL)'
                          ' _cffi_free_array_arguments(large_args_free);')

    def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
        self._prnt('  datasize = _cffi_prepare_pointer_call_argument(')
        self._prnt('      _cffi_type(%d), %s, (char **)&%s);' % (
            self._gettypenum(tp), fromvar, tovar))
        self._prnt('  if (datasize != 0) {')
        self._prnt('    %s = ((size_t)datasize) <= 640 ? '
                   '(%s)alloca((size_t)datasize) : NULL;' % (
            tovar, tp.get_c_name('')))
        self._prnt('    if (_cffi_convert_array_argument(_cffi_type(%d), %s, '
                   '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar))
        self._prnt('            datasize, &large_args_free) < 0)')
        self._prnt('      %s;' % errcode)
        self._prnt('  }')

    def _convert_expr_from_c(self, tp, var, context):
        if isinstance(tp, model.BasePrimitiveType):
            if tp.is_integer_type() and tp.name != '_Bool':
                return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
            elif isinstance(tp, model.UnknownFloatType):
                return '_cffi_from_c_double(%s)' % (var,)
            elif tp.name != 'long double' and not tp.is_complex_type():
                cname = tp.name.replace(' ', '_')
                if cname in ('char16_t', 'char32_t'):
                    self.needs_version(VERSION_CHAR16CHAR32)
                return '_cffi_from_c_%s(%s)' % (cname, var)
            else:
                return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
                    var, self._gettypenum(tp))
        elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
                var, self._gettypenum(tp))
        elif isinstance(tp, model.ArrayType):
            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
                var, self._gettypenum(model.PointerType(tp.item)))
        elif isinstance(tp, model.StructOrUnion):
            if tp.fldnames is None:
                raise TypeError("'%s' is used as %s, but is opaque" % (
                    tp._get_c_name(), context))
            return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
                var, self._gettypenum(tp))
        elif isinstance(tp, model.EnumType):
            return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
                var, self._gettypenum(tp))
        else:
            raise NotImplementedError(tp)

    # ----------
    # typedefs

    def _typedef_type(self, tp, name):
        return self._global_type(tp, "(*(%s *)0)" % (name,))

    def _generate_cpy_typedef_collecttype(self, tp, name):
        self._do_collect_type(self._typedef_type(tp, name))

    def _generate_cpy_typedef_decl(self, tp, name):
        pass

    def _typedef_ctx(self, tp, name):
        type_index = self._typesdict[tp]
        self._lsts["typename"].append(TypenameExpr(name, type_index))

    def _generate_cpy_typedef_ctx(self, tp, name):
        tp = self._typedef_type(tp, name)
        self._typedef_ctx(tp, name)
        if getattr(tp, "origin", None) == "unknown_type":
            self._struct_ctx(tp, tp.name, approxname=None)
        elif isinstance(tp, model.NamedPointerType):
            self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name,
                             named_ptr=tp)

    # ----------
    # function declarations

    def _generate_cpy_function_collecttype(self, tp, name):
        self._do_collect_type(tp.as_raw_function())
        if tp.ellipsis and not self.target_is_python:
            self._do_collect_type(tp)

    def _generate_cpy_function_decl(self, tp, name):
        assert not self.target_is_python
        assert isinstance(tp, model.FunctionPtrType)
        if tp.ellipsis:
            # cannot support vararg functions better than this: check for its
            # exact type (including the fixed arguments), and build it as a
            # constant function pointer (no CPython wrapper)
            self._generate_cpy_constant_decl(tp, name)
            return
        prnt = self._prnt
        numargs = len(tp.args)
        if numargs == 0:
            argname = 'noarg'
        elif numargs == 1:
            argname = 'arg0'
        else:
            argname = 'args'
        #
        # ------------------------------
        # the 'd' version of the function, only for addressof(lib, 'func')
        arguments = []
        call_arguments = []
        context = 'argument of %s' % name
        for i, type in enumerate(tp.args):
            arguments.append(type.get_c_name(' x%d' % i, context))
            call_arguments.append('x%d' % i)
        repr_arguments = ', '.join(arguments)
        repr_arguments = repr_arguments or 'void'
        if tp.abi:
            abi = tp.abi + ' '
        else:
            abi = ''
        name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments)
        prnt('static %s' % (tp.result.get_c_name(name_and_arguments),))
        prnt('{')
        call_arguments = ', '.join(call_arguments)
        result_code = 'return '
        if isinstance(tp.result, model.VoidType):
            result_code = ''
        prnt('  %s%s(%s);' % (result_code, name, call_arguments))
        prnt('}')
        #
        prnt('#ifndef PYPY_VERSION')        # ------------------------------
        #
        prnt('static PyObject *')
        prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
        prnt('{')
        #
        context = 'argument of %s' % name
        for i, type in enumerate(tp.args):
            arg = type.get_c_name(' x%d' % i, context)
            prnt('  %s;' % arg)
        #
        localvars = set()
        freelines = set()
        for type in tp.args:
            self._extra_local_variables(type, localvars, freelines)
        for decl in sorted(localvars):
            prnt('  %s;' % (decl,))
        #
        if not isinstance(tp.result, model.VoidType):
            result_code = 'result = '
            context = 'result of %s' % name
            result_decl = '  %s;' % tp.result.get_c_name(' result', context)
            prnt(result_decl)
            prnt('  PyObject *pyresult;')
        else:
            result_decl = None
            result_code = ''
        #
        if len(tp.args) > 1:
            rng = range(len(tp.args))
            for i in rng:
                prnt('  PyObject *arg%d;' % i)
            prnt()
            prnt('  if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % (
                name, len(rng), len(rng),
                ', '.join(['&arg%d' % i for i in rng])))
            prnt('    return NULL;')
        prnt()
        #
        for i, type in enumerate(tp.args):
            self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
                                       'return NULL')
            prnt()
        #
        prnt('  Py_BEGIN_ALLOW_THREADS')
        prnt('  _cffi_restore_errno();')
        call_arguments = ['x%d' % i for i in range(len(tp.args))]
        call_arguments = ', '.join(call_arguments)
        prnt('  { %s%s(%s); }' % (result_code, name, call_arguments))
        prnt('  _cffi_save_errno();')
        prnt('  Py_END_ALLOW_THREADS')
        prnt()
        #
        prnt('  (void)self; /* unused */')
        if numargs == 0:
            prnt('  (void)noarg; /* unused */')
        if result_code:
            prnt('  pyresult = %s;' %
                 self._convert_expr_from_c(tp.result, 'result', 'result type'))
            for freeline in freelines:
                prnt('  ' + freeline)
            prnt('  return pyresult;')
        else:
            for freeline in freelines:
                prnt('  ' + freeline)
            prnt('  Py_INCREF(Py_None);')
            prnt('  return Py_None;')
        prnt('}')
        #
        prnt('#else')        # ------------------------------
        #
        # the PyPy version: need to replace struct/union arguments with
        # pointers, and if the result is a struct/union, insert a first
        # arg that is a pointer to the result.  We also do that for
        # complex args and return type.
        def need_indirection(type):
            return (isinstance(type, model.StructOrUnion) or
                    (isinstance(type, model.PrimitiveType) and
                     type.is_complex_type()))
        difference = False
        arguments = []
        call_arguments = []
        context = 'argument of %s' % name
        for i, type in enumerate(tp.args):
            indirection = ''
            if need_indirection(type):
                indirection = '*'
                difference = True
            arg = type.get_c_name(' %sx%d' % (indirection, i), context)
            arguments.append(arg)
            call_arguments.append('%sx%d' % (indirection, i))
        tp_result = tp.result
        if need_indirection(tp_result):
            context = 'result of %s' % name
            arg = tp_result.get_c_name(' *result', context)
            arguments.insert(0, arg)
            tp_result = model.void_type
            result_decl = None
            result_code = '*result = '
            difference = True
        if difference:
            repr_arguments = ', '.join(arguments)
            repr_arguments = repr_arguments or 'void'
            name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name,
                                                       repr_arguments)
            prnt('static %s' % (tp_result.get_c_name(name_and_arguments),))
            prnt('{')
            if result_decl:
                prnt(result_decl)
            call_arguments = ', '.join(call_arguments)
            prnt('  { %s%s(%s); }' % (result_code, name, call_arguments))
            if result_decl:
                prnt('  return result;')
            prnt('}')
        else:
            prnt('#  define _cffi_f_%s _cffi_d_%s' % (name, name))
        #
        prnt('#endif')        # ------------------------------
        prnt()

    def _generate_cpy_function_ctx(self, tp, name):
        if tp.ellipsis and not self.target_is_python:
            self._generate_cpy_constant_ctx(tp, name)
            return
        type_index = self._typesdict[tp.as_raw_function()]
        numargs = len(tp.args)
        if self.target_is_python:
            meth_kind = OP_DLOPEN_FUNC
        elif numargs == 0:
            meth_kind = OP_CPYTHON_BLTN_N   # 'METH_NOARGS'
        elif numargs == 1:
            meth_kind = OP_CPYTHON_BLTN_O   # 'METH_O'
        else:
            meth_kind = OP_CPYTHON_BLTN_V   # 'METH_VARARGS'
        self._lsts["global"].append(
            GlobalExpr(name, '_cffi_f_%s' % name,
                       CffiOp(meth_kind, type_index),
                       size='_cffi_d_%s' % name))

    # ----------
    # named structs or unions

    def _field_type(self, tp_struct, field_name, tp_field):
        if isinstance(tp_field, model.ArrayType):
            actual_length = tp_field.length
            if actual_length == '...':
                ptr_struct_name = tp_struct.get_c_name('*')
                actual_length = '_cffi_array_len(((%s)0)->%s)' % (
                    ptr_struct_name, field_name)
            tp_item = self._field_type(tp_struct, '%s[0]' % field_name,
                                       tp_field.item)
            tp_field = model.ArrayType(tp_item, actual_length)
        return tp_field

    def _struct_collecttype(self, tp):
        self._do_collect_type(tp)
        if self.target_is_python:
            # also requires nested anon struct/unions in ABI mode, recursively
            for fldtype in tp.anonymous_struct_fields():
                self._struct_collecttype(fldtype)

    def _struct_decl(self, tp, cname, approxname):
        if tp.fldtypes is None:
            return
        prnt = self._prnt
        checkfuncname = '_cffi_checkfld_%s' % (approxname,)
        prnt('_CFFI_UNUSED_FN')
        prnt('static void %s(%s *p)' % (checkfuncname, cname))
        prnt('{')
        prnt('  /* only to generate compile-time warnings or errors */')
        prnt('  (void)p;')
        for fname, ftype, fbitsize, fqual in self._enum_fields(tp):
            try:
                if ftype.is_integer_type() or fbitsize >= 0:
                    # accept all integers, but complain on float or double
                    if fname != '':
                        prnt("  (void)((p->%s) | 0);  /* check that '%s.%s' is "
                             "an integer */" % (fname, cname, fname))
                    continue
                # only accept exactly the type declared, except that '[]'
                # is interpreted as a '*' and so will match any array length.
                # (It would also match '*', but that's harder to detect...)
                while (isinstance(ftype, model.ArrayType)
                       and (ftype.length is None or ftype.length == '...')):
                    ftype = ftype.item
                    fname = fname + '[0]'
                prnt('  { %s = &p->%s; (void)tmp; }' % (
                    ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
                    fname))
            except VerificationError as e:
                prnt('  /* %s */' % str(e))   # cannot verify it, ignore
        prnt('}')
        prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname))
        prnt()

    def _struct_ctx(self, tp, cname, approxname, named_ptr=None):
        type_index = self._typesdict[tp]
        reason_for_not_expanding = None
        flags = []
        if isinstance(tp, model.UnionType):
            flags.append("_CFFI_F_UNION")
        if tp.fldtypes is None:
            flags.append("_CFFI_F_OPAQUE")
            reason_for_not_expanding = "opaque"
        if (tp not in self.ffi._parser._included_declarations and
                (named_ptr is None or
                 named_ptr not in self.ffi._parser._included_declarations)):
            if tp.fldtypes is None:
                pass    # opaque
            elif tp.partial or any(tp.anonymous_struct_fields()):
                pass    # field layout obtained silently from the C compiler
            else:
                flags.append("_CFFI_F_CHECK_FIELDS")
            if tp.packed:
                if tp.packed > 1:
                    raise NotImplementedError(
                        "%r is declared with 'pack=%r'; only 0 or 1 are "
                        "supported in API mode (try to use \"...;\", which "
                        "does not require a 'pack' declaration)" %
                        (tp, tp.packed))
                flags.append("_CFFI_F_PACKED")
        else:
            flags.append("_CFFI_F_EXTERNAL")
            reason_for_not_expanding = "external"
        flags = '|'.join(flags) or '0'
        c_fields = []
        if reason_for_not_expanding is None:
            enumfields = list(self._enum_fields(tp))
            for fldname, fldtype, fbitsize, fqual in enumfields:
                fldtype = self._field_type(tp, fldname, fldtype)
                self._check_not_opaque(fldtype,
                                       "field '%s.%s'" % (tp.name, fldname))
                # cname is None for _add_missing_struct_unions() only
                op = OP_NOOP
                if fbitsize >= 0:
                    op = OP_BITFIELD
                    size = '%d /* bits */' % fbitsize
                elif cname is None or (
                        isinstance(fldtype, model.ArrayType) and
                        fldtype.length is None):
                    size = '(size_t)-1'
                else:
                    size = 'sizeof(((%s)0)->%s)' % (
                        tp.get_c_name('*') if named_ptr is None
                                           else named_ptr.name,
                        fldname)
                if cname is None or fbitsize >= 0:
                    offset = '(size_t)-1'
                elif named_ptr is not None:
                    offset = '((char *)&((%s)0)->%s) - (char *)0' % (
                        named_ptr.name, fldname)
                else:
                    offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname)
                c_fields.append(
                    FieldExpr(fldname, offset, size, fbitsize,
                              CffiOp(op, self._typesdict[fldtype])))
            first_field_index = len(self._lsts["field"])
            self._lsts["field"].extend(c_fields)
            #
            if cname is None:  # unknown name, for _add_missing_struct_unions
                size = '(size_t)-2'
                align = -2
                comment = "unnamed"
            else:
                if named_ptr is not None:
                    size = 'sizeof(*(%s)0)' % (named_ptr.name,)
                    align = '-1 /* unknown alignment */'
                else:
                    size = 'sizeof(%s)' % (cname,)
                    align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,)
                comment = None
        else:
            size = '(size_t)-1'
            align = -1
            first_field_index = -1
            comment = reason_for_not_expanding
        self._lsts["struct_union"].append(
            StructUnionExpr(tp.name, type_index, flags, size, align, comment,
                            first_field_index, c_fields))
        self._seen_struct_unions.add(tp)

    def _check_not_opaque(self, tp, location):
        while isinstance(tp, model.ArrayType):
            tp = tp.item
        if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None:
            raise TypeError(
                "%s is of an opaque type (not declared in cdef())" % location)

    def _add_missing_struct_unions(self):
        # not very nice, but some struct declarations might be missing
        # because they don't have any known C name.  Check that they are
        # not partial (we can't complete or verify them!) and emit them
        # anonymously.
        lst = list(self._struct_unions.items())
        lst.sort(key=lambda tp_order: tp_order[1])
        for tp, order in lst:
            if tp not in self._seen_struct_unions:
                if tp.partial:
                    raise NotImplementedError("internal inconsistency: %r is "
                                              "partial but was not seen at "
                                              "this point" % (tp,))
                if tp.name.startswith('$') and tp.name[1:].isdigit():
                    approxname = tp.name[1:]
                elif tp.name == '_IO_FILE' and tp.forcename == 'FILE':
                    approxname = 'FILE'
                    self._typedef_ctx(tp, 'FILE')
                else:
                    raise NotImplementedError("internal inconsistency: %r" %
                                              (tp,))
                self._struct_ctx(tp, None, approxname)

    def _generate_cpy_struct_collecttype(self, tp, name):
        self._struct_collecttype(tp)
    _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype

    def _struct_names(self, tp):
        cname = tp.get_c_name('')
        if ' ' in cname:
            return cname, cname.replace(' ', '_')
        else:
            return cname, '_' + cname

    def _generate_cpy_struct_decl(self, tp, name):
        self._struct_decl(tp, *self._struct_names(tp))
    _generate_cpy_union_decl = _generate_cpy_struct_decl

    def _generate_cpy_struct_ctx(self, tp, name):
        self._struct_ctx(tp, *self._struct_names(tp))
    _generate_cpy_union_ctx = _generate_cpy_struct_ctx

    # ----------
    # 'anonymous' declarations.  These are produced for anonymous structs
    # or unions; the 'name' is obtained by a typedef.

    def _generate_cpy_anonymous_collecttype(self, tp, name):
        if isinstance(tp, model.EnumType):
            self._generate_cpy_enum_collecttype(tp, name)
        else:
            self._struct_collecttype(tp)

    def _generate_cpy_anonymous_decl(self, tp, name):
        if isinstance(tp, model.EnumType):
            self._generate_cpy_enum_decl(tp)
        else:
            self._struct_decl(tp, name, 'typedef_' + name)

    def _generate_cpy_anonymous_ctx(self, tp, name):
        if isinstance(tp, model.EnumType):
            self._enum_ctx(tp, name)
        else:
            self._struct_ctx(tp, name, 'typedef_' + name)

    # ----------
    # constants, declared with "static const ..."

    def _generate_cpy_const(self, is_int, name, tp=None, category='const',
                            check_value=None):
        if (category, name) in self._seen_constants:
            raise VerificationError(
                "duplicate declaration of %s '%s'" % (category, name))
        self._seen_constants.add((category, name))
        #
        prnt = self._prnt
        funcname = '_cffi_%s_%s' % (category, name)
        if is_int:
            prnt('static int %s(unsigned long long *o)' % funcname)
            prnt('{')
            prnt('  int n = (%s) <= 0;' % (name,))
            prnt('  *o = (unsigned long long)((%s) | 0);'
                 '  /* check that %s is an integer */' % (name, name))
            if check_value is not None:
                if check_value > 0:
                    check_value = '%dU' % (check_value,)
                prnt('  if (!_cffi_check_int(*o, n, %s))' % (check_value,))
                prnt('    n |= 2;')
            prnt('  return n;')
            prnt('}')
        else:
            assert check_value is None
            prnt('static void %s(char *o)' % funcname)
            prnt('{')
            prnt('  *(%s)o = %s;' % (tp.get_c_name('*'), name))
            prnt('}')
        prnt()

    def _generate_cpy_constant_collecttype(self, tp, name):
        is_int = tp.is_integer_type()
        if not is_int or self.target_is_python:
            self._do_collect_type(tp)

    def _generate_cpy_constant_decl(self, tp, name):
        is_int = tp.is_integer_type()
        self._generate_cpy_const(is_int, name, tp)

    def _generate_cpy_constant_ctx(self, tp, name):
        if not self.target_is_python and tp.is_integer_type():
            type_op = CffiOp(OP_CONSTANT_INT, -1)
        else:
            if self.target_is_python:
                const_kind = OP_DLOPEN_CONST
            else:
                const_kind = OP_CONSTANT
            type_index = self._typesdict[tp]
            type_op = CffiOp(const_kind, type_index)
        self._lsts["global"].append(
            GlobalExpr(name, '_cffi_const_%s' % name, type_op))

    # ----------
    # enums

    def _generate_cpy_enum_collecttype(self, tp, name):
        self._do_collect_type(tp)

    def _generate_cpy_enum_decl(self, tp, name=None):
        for enumerator in tp.enumerators:
            self._generate_cpy_const(True, enumerator)

    def _enum_ctx(self, tp, cname):
        type_index = self._typesdict[tp]
        type_op = CffiOp(OP_ENUM, -1)
        if self.target_is_python:
            tp.check_not_partial()
        for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
            self._lsts["global"].append(
                GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op,
                           check_value=enumvalue))
        #
        if cname is not None and '$' not in cname and not self.target_is_python:
            size = "sizeof(%s)" % cname
            signed = "((%s)-1) <= 0" % cname
        else:
            basetp = tp.build_baseinttype(self.ffi, [])
            size = self.ffi.sizeof(basetp)
            signed = int(int(self.ffi.cast(basetp, -1)) < 0)
        allenums = ",".join(tp.enumerators)
        self._lsts["enum"].append(
            EnumExpr(tp.name, type_index, size, signed, allenums))

    def _generate_cpy_enum_ctx(self, tp, name):
        self._enum_ctx(tp, tp._get_c_name())

    # ----------
    # macros: for now only for integers

    def _generate_cpy_macro_collecttype(self, tp, name):
        pass

    def _generate_cpy_macro_decl(self, tp, name):
        if tp == '...':
            check_value = None
        else:
            check_value = tp     # an integer
        self._generate_cpy_const(True, name, check_value=check_value)

    def _generate_cpy_macro_ctx(self, tp, name):
        if tp == '...':
            if self.target_is_python:
                raise VerificationError(
                    "cannot use the syntax '...' in '#define %s ...' when "
                    "using the ABI mode" % (name,))
            check_value = None
        else:
            check_value = tp     # an integer
        type_op = CffiOp(OP_CONSTANT_INT, -1)
        self._lsts["global"].append(
            GlobalExpr(name, '_cffi_const_%s' % name, type_op,
                       check_value=check_value))

    # ----------
    # global variables

    def _global_type(self, tp, global_name):
        if isinstance(tp, model.ArrayType):
            actual_length = tp.length
            if actual_length == '...':
                actual_length = '_cffi_array_len(%s)' % (global_name,)
            tp_item = self._global_type(tp.item, '%s[0]' % global_name)
            tp = model.ArrayType(tp_item, actual_length)
        return tp

    def _generate_cpy_variable_collecttype(self, tp, name):
        self._do_collect_type(self._global_type(tp, name))

    def _generate_cpy_variable_decl(self, tp, name):
        prnt = self._prnt
        tp = self._global_type(tp, name)
        if isinstance(tp, model.ArrayType) and tp.length is None:
            tp = tp.item
            ampersand = ''
        else:
            ampersand = '&'
        # This code assumes that casts from "tp *" to "void *" is a
        # no-op, i.e. a function that returns a "tp *" can be called
        # as if it returned a "void *".  This should be generally true
        # on any modern machine.  The only exception to that rule (on
        # uncommon architectures, and as far as I can tell) might be
        # if 'tp' were a function type, but that is not possible here.
        # (If 'tp' is a function _pointer_ type, then casts from "fn_t
        # **" to "void *" are again no-ops, as far as I can tell.)
        decl = '*_cffi_var_%s(void)' % (name,)
        prnt('static ' + tp.get_c_name(decl, quals=self._current_quals))
        prnt('{')
        prnt('  return %s(%s);' % (ampersand, name))
        prnt('}')
        prnt()

    def _generate_cpy_variable_ctx(self, tp, name):
        tp = self._global_type(tp, name)
        type_index = self._typesdict[tp]
        if self.target_is_python:
            op = OP_GLOBAL_VAR
        else:
            op = OP_GLOBAL_VAR_F
        self._lsts["global"].append(
            GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))

    # ----------
    # extern "Python"

    def _generate_cpy_extern_python_collecttype(self, tp, name):
        assert isinstance(tp, model.FunctionPtrType)
        self._do_collect_type(tp)
    _generate_cpy_dllexport_python_collecttype = \
      _generate_cpy_extern_python_plus_c_collecttype = \
      _generate_cpy_extern_python_collecttype

    def _extern_python_decl(self, tp, name, tag_and_space):
        prnt = self._prnt
        if isinstance(tp.result, model.VoidType):
            size_of_result = '0'
        else:
            context = 'result of %s' % name
            size_of_result = '(int)sizeof(%s)' % (
                tp.result.get_c_name('', context),)
        prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name)
        prnt('  { "%s.%s", %s, 0, 0 };' % (
            self.module_name, name, size_of_result))
        prnt()
        #
        arguments = []
        context = 'argument of %s' % name
        for i, type in enumerate(tp.args):
            arg = type.get_c_name(' a%d' % i, context)
            arguments.append(arg)
        #
        repr_arguments = ', '.join(arguments)
        repr_arguments = repr_arguments or 'void'
        name_and_arguments = '%s(%s)' % (name, repr_arguments)
        if tp.abi == "__stdcall":
            name_and_arguments = '_cffi_stdcall ' + name_and_arguments
        #
        def may_need_128_bits(tp):
            return (isinstance(tp, model.PrimitiveType) and
                    tp.name == 'long double')
        #
        size_of_a = max(len(tp.args)*8, 8)
        if may_need_128_bits(tp.result):
            size_of_a = max(size_of_a, 16)
        if isinstance(tp.result, model.StructOrUnion):
            size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % (
                tp.result.get_c_name(''), size_of_a,
                tp.result.get_c_name(''), size_of_a)
        prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments)))
        prnt('{')
        prnt('  char a[%s];' % size_of_a)
        prnt('  char *p = a;')
        for i, type in enumerate(tp.args):
            arg = 'a%d' % i
            if (isinstance(type, model.StructOrUnion) or
                    may_need_128_bits(type)):
                arg = '&' + arg
                type = model.PointerType(type)
            prnt('  *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg))
        prnt('  _cffi_call_python(&_cffi_externpy__%s, p);' % name)
        if not isinstance(tp.result, model.VoidType):
            prnt('  return *(%s)p;' % (tp.result.get_c_name('*'),))
        prnt('}')
        prnt()
        self._num_externpy += 1

    def _generate_cpy_extern_python_decl(self, tp, name):
        self._extern_python_decl(tp, name, 'static ')

    def _generate_cpy_dllexport_python_decl(self, tp, name):
        self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ')

    def _generate_cpy_extern_python_plus_c_decl(self, tp, name):
        self._extern_python_decl(tp, name, '')

    def _generate_cpy_extern_python_ctx(self, tp, name):
        if self.target_is_python:
            raise VerificationError(
                "cannot use 'extern \"Python\"' in the ABI mode")
        if tp.ellipsis:
            raise NotImplementedError("a vararg function is extern \"Python\"")
        type_index = self._typesdict[tp]
        type_op = CffiOp(OP_EXTERN_PYTHON, type_index)
        self._lsts["global"].append(
            GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name))

    _generate_cpy_dllexport_python_ctx = \
      _generate_cpy_extern_python_plus_c_ctx = \
      _generate_cpy_extern_python_ctx

    def _print_string_literal_in_array(self, s):
        prnt = self._prnt
        prnt('// # NB. this is not a string because of a size limit in MSVC')
        if not isinstance(s, bytes):    # unicode
            s = s.encode('utf-8')       # -> bytes
        else:
            s.decode('utf-8')           # got bytes, check for valid utf-8
        try:
            s.decode('ascii')
        except UnicodeDecodeError:
            s = b'# -*- encoding: utf8 -*-\n' + s
        for line in s.splitlines(True):
            comment = line
            if type('//') is bytes:     # python2
                line = map(ord, line)   #     make a list of integers
            else:                       # python3
                # type(line) is bytes, which enumerates like a list of integers
                comment = ascii(comment)[1:-1]
            prnt(('// ' + comment).rstrip())
            printed_line = ''
            for c in line:
                if len(printed_line) >= 76:
                    prnt(printed_line)
                    printed_line = ''
                printed_line += '%d,' % (c,)
            prnt(printed_line)

    # ----------
    # emitting the opcodes for individual types

    def _emit_bytecode_VoidType(self, tp, index):
        self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID)

    def _emit_bytecode_PrimitiveType(self, tp, index):
        prim_index = PRIMITIVE_TO_INDEX[tp.name]
        self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index)

    def _emit_bytecode_UnknownIntegerType(self, tp, index):
        s = ('_cffi_prim_int(sizeof(%s), (\n'
             '           ((%s)-1) | 0 /* check that %s is an integer type */\n'
             '         ) <= 0)' % (tp.name, tp.name, tp.name))
        self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)

    def _emit_bytecode_UnknownFloatType(self, tp, index):
        s = ('_cffi_prim_float(sizeof(%s) *\n'
             '           (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n'
             '         )' % (tp.name, tp.name))
        self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s)

    def _emit_bytecode_RawFunctionType(self, tp, index):
        self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result])
        index += 1
        for tp1 in tp.args:
            realindex = self._typesdict[tp1]
            if index != realindex:
                if isinstance(tp1, model.PrimitiveType):
                    self._emit_bytecode_PrimitiveType(tp1, index)
                else:
                    self.cffi_types[index] = CffiOp(OP_NOOP, realindex)
            index += 1
        flags = int(tp.ellipsis)
        if tp.abi is not None:
            if tp.abi == '__stdcall':
                flags |= 2
            else:
                raise NotImplementedError("abi=%r" % (tp.abi,))
        self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags)

    def _emit_bytecode_PointerType(self, tp, index):
        self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype])

    _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType
    _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType

    def _emit_bytecode_FunctionPtrType(self, tp, index):
        raw = tp.as_raw_function()
        self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw])

    def _emit_bytecode_ArrayType(self, tp, index):
        item_index = self._typesdict[tp.item]
        if tp.length is None:
            self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index)
        elif tp.length == '...':
            raise VerificationError(
                "type %s badly placed: the '...' array length can only be "
                "used on global arrays or on fields of structures" % (
                    str(tp).replace('/*...*/', '...'),))
        else:
            assert self.cffi_types[index + 1] == 'LEN'
            self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
            self.cffi_types[index + 1] = CffiOp(None, str(tp.length))

    def _emit_bytecode_StructType(self, tp, index):
        struct_index = self._struct_unions[tp]
        self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index)
    _emit_bytecode_UnionType = _emit_bytecode_StructType

    def _emit_bytecode_EnumType(self, tp, index):
        enum_index = self._enums[tp]
        self.cffi_types[index] = CffiOp(OP_ENUM, enum_index)


if sys.version_info >= (3,):
    NativeIO = io.StringIO
else:
    class NativeIO(io.BytesIO):
        def write(self, s):
            if isinstance(s, unicode):
                s = s.encode('ascii')
            super(NativeIO, self).write(s)

def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose):
    if verbose:
        print("generating %s" % (target_file,))
    recompiler = Recompiler(ffi, module_name,
                            target_is_python=(preamble is None))
    recompiler.collect_type_table()
    recompiler.collect_step_tables()
    f = NativeIO()
    recompiler.write_source_to_f(f, preamble)
    output = f.getvalue()
    try:
        with open(target_file, 'r') as f1:
            if f1.read(len(output) + 1) != output:
                raise IOError
        if verbose:
            print("(already up-to-date)")
        return False     # already up-to-date
    except IOError:
        tmp_file = '%s.~%d' % (target_file, os.getpid())
        with open(tmp_file, 'w') as f1:
            f1.write(output)
        try:
            os.rename(tmp_file, target_file)
        except OSError:
            os.unlink(target_file)
            os.rename(tmp_file, target_file)
        return True

def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False):
    assert preamble is not None
    return _make_c_or_py_source(ffi, module_name, preamble, target_c_file,
                                verbose)

def make_py_source(ffi, module_name, target_py_file, verbose=False):
    return _make_c_or_py_source(ffi, module_name, None, target_py_file,
                                verbose)

def _modname_to_file(outputdir, modname, extension):
    parts = modname.split('.')
    try:
        os.makedirs(os.path.join(outputdir, *parts[:-1]))
    except OSError:
        pass
    parts[-1] += extension
    return os.path.join(outputdir, *parts), parts


# Aaargh.  Distutils is not tested at all for the purpose of compiling
# DLLs that are not extension modules.  Here are some hacks to work
# around that, in the _patch_for_*() functions...

def _patch_meth(patchlist, cls, name, new_meth):
    old = getattr(cls, name)
    patchlist.append((cls, name, old))
    setattr(cls, name, new_meth)
    return old

def _unpatch_meths(patchlist):
    for cls, name, old_meth in reversed(patchlist):
        setattr(cls, name, old_meth)

def _patch_for_embedding(patchlist):
    if sys.platform == 'win32':
        # we must not remove the manifest when building for embedding!
        from cffi._shimmed_dist_utils import MSVCCompiler
        _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref',
                    lambda self, manifest_file: manifest_file)

    if sys.platform == 'darwin':
        # we must not make a '-bundle', but a '-dynamiclib' instead
        from cffi._shimmed_dist_utils import CCompiler
        def my_link_shared_object(self, *args, **kwds):
            if '-bundle' in self.linker_so:
                self.linker_so = list(self.linker_so)
                i = self.linker_so.index('-bundle')
                self.linker_so[i] = '-dynamiclib'
            return old_link_shared_object(self, *args, **kwds)
        old_link_shared_object = _patch_meth(patchlist, CCompiler,
                                             'link_shared_object',
                                             my_link_shared_object)

def _patch_for_target(patchlist, target):
    from cffi._shimmed_dist_utils import build_ext
    # if 'target' is different from '*', we need to patch some internal
    # method to just return this 'target' value, instead of having it
    # built from module_name
    if target.endswith('.*'):
        target = target[:-2]
        if sys.platform == 'win32':
            target += '.dll'
        elif sys.platform == 'darwin':
            target += '.dylib'
        else:
            target += '.so'
    _patch_meth(patchlist, build_ext, 'get_ext_filename',
                lambda self, ext_name: target)


def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True,
              c_file=None, source_extension='.c', extradir=None,
              compiler_verbose=1, target=None, debug=None, **kwds):
    if not isinstance(module_name, str):
        module_name = module_name.encode('ascii')
    if ffi._windows_unicode:
        ffi._apply_windows_unicode(kwds)
    if preamble is not None:
        embedding = (ffi._embedding is not None)
        if embedding:
            ffi._apply_embedding_fix(kwds)
        if c_file is None:
            c_file, parts = _modname_to_file(tmpdir, module_name,
                                             source_extension)
            if extradir:
                parts = [extradir] + parts
            ext_c_file = os.path.join(*parts)
        else:
            ext_c_file = c_file
        #
        if target is None:
            if embedding:
                target = '%s.*' % module_name
            else:
                target = '*'
        #
        ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds)
        updated = make_c_source(ffi, module_name, preamble, c_file,
                                verbose=compiler_verbose)
        if call_c_compiler:
            patchlist = []
            cwd = os.getcwd()
            try:
                if embedding:
                    _patch_for_embedding(patchlist)
                if target != '*':
                    _patch_for_target(patchlist, target)
                if compiler_verbose:
                    if tmpdir == '.':
                        msg = 'the current directory is'
                    else:
                        msg = 'setting the current directory to'
                    print('%s %r' % (msg, os.path.abspath(tmpdir)))
                os.chdir(tmpdir)
                outputfilename = ffiplatform.compile('.', ext,
                                                     compiler_verbose, debug)
            finally:
                os.chdir(cwd)
                _unpatch_meths(patchlist)
            return outputfilename
        else:
            return ext, updated
    else:
        if c_file is None:
            c_file, _ = _modname_to_file(tmpdir, module_name, '.py')
        updated = make_py_source(ffi, module_name, c_file,
                                 verbose=compiler_verbose)
        if call_c_compiler:
            return c_file
        else:
            return None, updated


src/cffi/recompiler.py
python-cffi/cffi
import os
import sys

try:
    basestring
except NameError:
    # Python 3.x
    basestring = str

def error(msg):
    from cffi._shimmed_dist_utils import DistutilsSetupError
    raise DistutilsSetupError(msg)


def execfile(filename, glob):
    # We use execfile() (here rewritten for Python 3) instead of
    # __import__() to load the build script.  The problem with
    # a normal import is that in some packages, the intermediate
    # __init__.py files may already try to import the file that
    # we are generating.
    with open(filename) as f:
        src = f.read()
    src += '\n'      # Python 2.6 compatibility
    code = compile(src, filename, 'exec')
    exec(code, glob, glob)


def add_cffi_module(dist, mod_spec):
    from cffi.api import FFI

    if not isinstance(mod_spec, basestring):
        error("argument to 'cffi_modules=...' must be a str or a list of str,"
              " not %r" % (type(mod_spec).__name__,))
    mod_spec = str(mod_spec)
    try:
        build_file_name, ffi_var_name = mod_spec.split(':')
    except ValueError:
        error("%r must be of the form 'path/build.py:ffi_variable'" %
              (mod_spec,))
    if not os.path.exists(build_file_name):
        ext = ''
        rewritten = build_file_name.replace('.', '/') + '.py'
        if os.path.exists(rewritten):
            ext = ' (rewrite cffi_modules to [%r])' % (
                rewritten + ':' + ffi_var_name,)
        error("%r does not name an existing file%s" % (build_file_name, ext))

    mod_vars = {'__name__': '__cffi__', '__file__': build_file_name}
    execfile(build_file_name, mod_vars)

    try:
        ffi = mod_vars[ffi_var_name]
    except KeyError:
        error("%r: object %r not found in module" % (mod_spec,
                                                     ffi_var_name))
    if not isinstance(ffi, FFI):
        ffi = ffi()      # maybe it's a function instead of directly an ffi
    if not isinstance(ffi, FFI):
        error("%r is not an FFI instance (got %r)" % (mod_spec,
                                                      type(ffi).__name__))
    if not hasattr(ffi, '_assigned_source'):
        error("%r: the set_source() method was not called" % (mod_spec,))
    module_name, source, source_extension, kwds = ffi._assigned_source
    if ffi._windows_unicode:
        kwds = kwds.copy()
        ffi._apply_windows_unicode(kwds)

    if source is None:
        _add_py_module(dist, ffi, module_name)
    else:
        _add_c_module(dist, ffi, module_name, source, source_extension, kwds)

def _set_py_limited_api(Extension, kwds):
    """
    Add py_limited_api to kwds if setuptools >= 26 is in use.
    Do not alter the setting if it already exists.
    Setuptools takes care of ignoring the flag on Python 2 and PyPy.

    CPython itself should ignore the flag in a debugging version
    (by not listing .abi3.so in the extensions it supports), but
    it doesn't so far, creating troubles.  That's why we check
    for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent
    of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401)

    On Windows, with CPython <= 3.4, it's better not to use py_limited_api
    because virtualenv *still* doesn't copy PYTHON3.DLL on these versions.
    Recently (2020) we started shipping only >= 3.5 wheels, though.  So
    we'll give it another try and set py_limited_api on Windows >= 3.5.
    """
    from cffi import recompiler

    if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount')
            and recompiler.USE_LIMITED_API):
        import setuptools
        try:
            setuptools_major_version = int(setuptools.__version__.partition('.')[0])
            if setuptools_major_version >= 26:
                kwds['py_limited_api'] = True
        except ValueError:  # certain development versions of setuptools
            # If we don't know the version number of setuptools, we
            # try to set 'py_limited_api' anyway.  At worst, we get a
            # warning.
            kwds['py_limited_api'] = True
    return kwds

def _add_c_module(dist, ffi, module_name, source, source_extension, kwds):
    # We are a setuptools extension. Need this build_ext for py_limited_api.
    from setuptools.command.build_ext import build_ext
    from cffi._shimmed_dist_utils import Extension, log, mkpath
    from cffi import recompiler

    allsources = ['$PLACEHOLDER']
    allsources.extend(kwds.pop('sources', []))
    kwds = _set_py_limited_api(Extension, kwds)
    ext = Extension(name=module_name, sources=allsources, **kwds)

    def make_mod(tmpdir, pre_run=None):
        c_file = os.path.join(tmpdir, module_name + source_extension)
        log.info("generating cffi module %r" % c_file)
        mkpath(tmpdir)
        # a setuptools-only, API-only hook: called with the "ext" and "ffi"
        # arguments just before we turn the ffi into C code.  To use it,
        # subclass the 'distutils.command.build_ext.build_ext' class and
        # add a method 'def pre_run(self, ext, ffi)'.
        if pre_run is not None:
            pre_run(ext, ffi)
        updated = recompiler.make_c_source(ffi, module_name, source, c_file)
        if not updated:
            log.info("already up-to-date")
        return c_file

    if dist.ext_modules is None:
        dist.ext_modules = []
    dist.ext_modules.append(ext)

    base_class = dist.cmdclass.get('build_ext', build_ext)
    class build_ext_make_mod(base_class):
        def run(self):
            if ext.sources[0] == '$PLACEHOLDER':
                pre_run = getattr(self, 'pre_run', None)
                ext.sources[0] = make_mod(self.build_temp, pre_run)
            base_class.run(self)
    dist.cmdclass['build_ext'] = build_ext_make_mod
    # NB. multiple runs here will create multiple 'build_ext_make_mod'
    # classes.  Even in this case the 'build_ext' command should be
    # run once; but just in case, the logic above does nothing if
    # called again.


def _add_py_module(dist, ffi, module_name):
    from setuptools.command.build_py import build_py
    from setuptools.command.build_ext import build_ext
    from cffi._shimmed_dist_utils import log, mkpath
    from cffi import recompiler

    def generate_mod(py_file):
        log.info("generating cffi module %r" % py_file)
        mkpath(os.path.dirname(py_file))
        updated = recompiler.make_py_source(ffi, module_name, py_file)
        if not updated:
            log.info("already up-to-date")

    base_class = dist.cmdclass.get('build_py', build_py)
    class build_py_make_mod(base_class):
        def run(self):
            base_class.run(self)
            module_path = module_name.split('.')
            module_path[-1] += '.py'
            generate_mod(os.path.join(self.build_lib, *module_path))
        def get_source_files(self):
            # This is called from 'setup.py sdist' only.  Exclude
            # the generate .py module in this case.
            saved_py_modules = self.py_modules
            try:
                if saved_py_modules:
                    self.py_modules = [m for m in saved_py_modules
                                         if m != module_name]
                return base_class.get_source_files(self)
            finally:
                self.py_modules = saved_py_modules
    dist.cmdclass['build_py'] = build_py_make_mod

    # distutils and setuptools have no notion I could find of a
    # generated python module.  If we don't add module_name to
    # dist.py_modules, then things mostly work but there are some
    # combination of options (--root and --record) that will miss
    # the module.  So we add it here, which gives a few apparently
    # harmless warnings about not finding the file outside the
    # build directory.
    # Then we need to hack more in get_source_files(); see above.
    if dist.py_modules is None:
        dist.py_modules = []
    dist.py_modules.append(module_name)

    # the following is only for "build_ext -i"
    base_class_2 = dist.cmdclass.get('build_ext', build_ext)
    class build_ext_make_mod(base_class_2):
        def run(self):
            base_class_2.run(self)
            if self.inplace:
                # from get_ext_fullpath() in distutils/command/build_ext.py
                module_path = module_name.split('.')
                package = '.'.join(module_path[:-1])
                build_py = self.get_finalized_command('build_py')
                package_dir = build_py.get_package_dir(package)
                file_name = module_path[-1] + '.py'
                generate_mod(os.path.join(package_dir, file_name))
    dist.cmdclass['build_ext'] = build_ext_make_mod

def cffi_modules(dist, attr, value):
    assert attr == 'cffi_modules'
    if isinstance(value, basestring):
        value = [value]

    for cffi_module in value:
        add_cffi_module(dist, cffi_module)

src/cffi/setuptools_ext.py
python-cffi/cffi
#
# DEPRECATED: implementation for ffi.verify()
#
import sys
from . import model
from .error import VerificationError
from . import _imp_emulation as imp


class VCPythonEngine(object):
    _class_key = 'x'
    _gen_python_module = True

    def __init__(self, verifier):
        self.verifier = verifier
        self.ffi = verifier.ffi
        self._struct_pending_verification = {}
        self._types_of_builtin_functions = {}

    def patch_extension_kwds(self, kwds):
        pass

    def find_module(self, module_name, path, so_suffixes):
        try:
            f, filename, descr = imp.find_module(module_name, path)
        except ImportError:
            return None
        if f is not None:
            f.close()
        # Note that after a setuptools installation, there are both .py
        # and .so files with the same basename.  The code here relies on
        # imp.find_module() locating the .so in priority.
        if descr[0] not in so_suffixes:
            return None
        return filename

    def collect_types(self):
        self._typesdict = {}
        self._generate("collecttype")

    def _prnt(self, what=''):
        self._f.write(what + '\n')

    def _gettypenum(self, type):
        # a KeyError here is a bug.  please report it! :-)
        return self._typesdict[type]

    def _do_collect_type(self, tp):
        if ((not isinstance(tp, model.PrimitiveType)
             or tp.name == 'long double')
                and tp not in self._typesdict):
            num = len(self._typesdict)
            self._typesdict[tp] = num

    def write_source_to_f(self):
        self.collect_types()
        #
        # The new module will have a _cffi_setup() function that receives
        # objects from the ffi world, and that calls some setup code in
        # the module.  This setup code is split in several independent
        # functions, e.g. one per constant.  The functions are "chained"
        # by ending in a tail call to each other.
        #
        # This is further split in two chained lists, depending on if we
        # can do it at import-time or if we must wait for _cffi_setup() to
        # provide us with the <ctype> objects.  This is needed because we
        # need the values of the enum constants in order to build the
        # <ctype 'enum'> that we may have to pass to _cffi_setup().
        #
        # The following two 'chained_list_constants' items contains
        # the head of these two chained lists, as a string that gives the
        # call to do, if any.
        self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)']
        #
        prnt = self._prnt
        # first paste some standard set of lines that are mostly '#define'
        prnt(cffimod_header)
        prnt()
        # then paste the C source given by the user, verbatim.
        prnt(self.verifier.preamble)
        prnt()
        #
        # call generate_cpy_xxx_decl(), for every xxx found from
        # ffi._parser._declarations.  This generates all the functions.
        self._generate("decl")
        #
        # implement the function _cffi_setup_custom() as calling the
        # head of the chained list.
        self._generate_setup_custom()
        prnt()
        #
        # produce the method table, including the entries for the
        # generated Python->C function wrappers, which are done
        # by generate_cpy_function_method().
        prnt('static PyMethodDef _cffi_methods[] = {')
        self._generate("method")
        prnt('  {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},')
        prnt('  {NULL, NULL, 0, NULL}    /* Sentinel */')
        prnt('};')
        prnt()
        #
        # standard init.
        modname = self.verifier.get_module_name()
        constants = self._chained_list_constants[False]
        prnt('#if PY_MAJOR_VERSION >= 3')
        prnt()
        prnt('static struct PyModuleDef _cffi_module_def = {')
        prnt('  PyModuleDef_HEAD_INIT,')
        prnt('  "%s",' % modname)
        prnt('  NULL,')
        prnt('  -1,')
        prnt('  _cffi_methods,')
        prnt('  NULL, NULL, NULL, NULL')
        prnt('};')
        prnt()
        prnt('PyMODINIT_FUNC')
        prnt('PyInit_%s(void)' % modname)
        prnt('{')
        prnt('  PyObject *lib;')
        prnt('  lib = PyModule_Create(&_cffi_module_def);')
        prnt('  if (lib == NULL)')
        prnt('    return NULL;')
        prnt('  if (%s < 0 || _cffi_init() < 0) {' % (constants,))
        prnt('    Py_DECREF(lib);')
        prnt('    return NULL;')
        prnt('  }')
        prnt('  return lib;')
        prnt('}')
        prnt()
        prnt('#else')
        prnt()
        prnt('PyMODINIT_FUNC')
        prnt('init%s(void)' % modname)
        prnt('{')
        prnt('  PyObject *lib;')
        prnt('  lib = Py_InitModule("%s", _cffi_methods);' % modname)
        prnt('  if (lib == NULL)')
        prnt('    return;')
        prnt('  if (%s < 0 || _cffi_init() < 0)' % (constants,))
        prnt('    return;')
        prnt('  return;')
        prnt('}')
        prnt()
        prnt('#endif')

    def load_library(self, flags=None):
        # XXX review all usages of 'self' here!
        # import it as a new extension module
        imp.acquire_lock()
        try:
            if hasattr(sys, "getdlopenflags"):
                previous_flags = sys.getdlopenflags()
            try:
                if hasattr(sys, "setdlopenflags") and flags is not None:
                    sys.setdlopenflags(flags)
                module = imp.load_dynamic(self.verifier.get_module_name(),
                                          self.verifier.modulefilename)
            except ImportError as e:
                error = "importing %r: %s" % (self.verifier.modulefilename, e)
                raise VerificationError(error)
            finally:
                if hasattr(sys, "setdlopenflags"):
                    sys.setdlopenflags(previous_flags)
        finally:
            imp.release_lock()
        #
        # call loading_cpy_struct() to get the struct layout inferred by
        # the C compiler
        self._load(module, 'loading')
        #
        # the C code will need the <ctype> objects.  Collect them in
        # order in a list.
        revmapping = dict([(value, key)
                           for (key, value) in self._typesdict.items()])
        lst = [revmapping[i] for i in range(len(revmapping))]
        lst = list(map(self.ffi._get_cached_btype, lst))
        #
        # build the FFILibrary class and instance and call _cffi_setup().
        # this will set up some fields like '_cffi_types', and only then
        # it will invoke the chained list of functions that will really
        # build (notably) the constant objects, as <cdata> if they are
        # pointers, and store them as attributes on the 'library' object.
        class FFILibrary(object):
            _cffi_python_module = module
            _cffi_ffi = self.ffi
            _cffi_dir = []
            def __dir__(self):
                return FFILibrary._cffi_dir + list(self.__dict__)
        library = FFILibrary()
        if module._cffi_setup(lst, VerificationError, library):
            import warnings
            warnings.warn("reimporting %r might overwrite older definitions"
                          % (self.verifier.get_module_name()))
        #
        # finally, call the loaded_cpy_xxx() functions.  This will perform
        # the final adjustments, like copying the Python->C wrapper
        # functions from the module to the 'library' object, and setting
        # up the FFILibrary class with properties for the global C variables.
        self._load(module, 'loaded', library=library)
        module._cffi_original_ffi = self.ffi
        module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions
        return library

    def _get_declarations(self):
        lst = [(key, tp) for (key, (tp, qual)) in
                                self.ffi._parser._declarations.items()]
        lst.sort()
        return lst

    def _generate(self, step_name):
        for name, tp in self._get_declarations():
            kind, realname = name.split(' ', 1)
            try:
                method = getattr(self, '_generate_cpy_%s_%s' % (kind,
                                                                step_name))
            except AttributeError:
                raise VerificationError(
                    "not implemented in verify(): %r" % name)
            try:
                method(tp, realname)
            except Exception as e:
                model.attach_exception_info(e, name)
                raise

    def _load(self, module, step_name, **kwds):
        for name, tp in self._get_declarations():
            kind, realname = name.split(' ', 1)
            method = getattr(self, '_%s_cpy_%s' % (step_name, kind))
            try:
                method(tp, realname, module, **kwds)
            except Exception as e:
                model.attach_exception_info(e, name)
                raise

    def _generate_nothing(self, tp, name):
        pass

    def _loaded_noop(self, tp, name, module, **kwds):
        pass

    # ----------

    def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
        extraarg = ''
        if isinstance(tp, model.PrimitiveType):
            if tp.is_integer_type() and tp.name != '_Bool':
                converter = '_cffi_to_c_int'
                extraarg = ', %s' % tp.name
            else:
                converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''),
                                                   tp.name.replace(' ', '_'))
            errvalue = '-1'
        #
        elif isinstance(tp, model.PointerType):
            self._convert_funcarg_to_c_ptr_or_array(tp, fromvar,
                                                    tovar, errcode)
            return
        #
        elif isinstance(tp, (model.StructOrUnion, model.EnumType)):
            # a struct (not a struct pointer) as a function argument
            self._prnt('  if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)'
                      % (tovar, self._gettypenum(tp), fromvar))
            self._prnt('    %s;' % errcode)
            return
        #
        elif isinstance(tp, model.FunctionPtrType):
            converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')
            extraarg = ', _cffi_type(%d)' % self._gettypenum(tp)
            errvalue = 'NULL'
        #
        else:
            raise NotImplementedError(tp)
        #
        self._prnt('  %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg))
        self._prnt('  if (%s == (%s)%s && PyErr_Occurred())' % (
            tovar, tp.get_c_name(''), errvalue))
        self._prnt('    %s;' % errcode)

    def _extra_local_variables(self, tp, localvars, freelines):
        if isinstance(tp, model.PointerType):
            localvars.add('Py_ssize_t datasize')
            localvars.add('struct _cffi_freeme_s *large_args_free = NULL')
            freelines.add('if (large_args_free != NULL)'
                          ' _cffi_free_array_arguments(large_args_free);')

    def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode):
        self._prnt('  datasize = _cffi_prepare_pointer_call_argument(')
        self._prnt('      _cffi_type(%d), %s, (char **)&%s);' % (
            self._gettypenum(tp), fromvar, tovar))
        self._prnt('  if (datasize != 0) {')
        self._prnt('    %s = ((size_t)datasize) <= 640 ? '
                   'alloca((size_t)datasize) : NULL;' % (tovar,))
        self._prnt('    if (_cffi_convert_array_argument(_cffi_type(%d), %s, '
                   '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar))
        self._prnt('            datasize, &large_args_free) < 0)')
        self._prnt('      %s;' % errcode)
        self._prnt('  }')

    def _convert_expr_from_c(self, tp, var, context):
        if isinstance(tp, model.PrimitiveType):
            if tp.is_integer_type() and tp.name != '_Bool':
                return '_cffi_from_c_int(%s, %s)' % (var, tp.name)
            elif tp.name != 'long double':
                return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
            else:
                return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
                    var, self._gettypenum(tp))
        elif isinstance(tp, (model.PointerType, model.FunctionPtrType)):
            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
                var, self._gettypenum(tp))
        elif isinstance(tp, model.ArrayType):
            return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % (
                var, self._gettypenum(model.PointerType(tp.item)))
        elif isinstance(tp, model.StructOrUnion):
            if tp.fldnames is None:
                raise TypeError("'%s' is used as %s, but is opaque" % (
                    tp._get_c_name(), context))
            return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % (
                var, self._gettypenum(tp))
        elif isinstance(tp, model.EnumType):
            return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
                var, self._gettypenum(tp))
        else:
            raise NotImplementedError(tp)

    # ----------
    # typedefs: generates no code so far

    _generate_cpy_typedef_collecttype = _generate_nothing
    _generate_cpy_typedef_decl   = _generate_nothing
    _generate_cpy_typedef_method = _generate_nothing
    _loading_cpy_typedef         = _loaded_noop
    _loaded_cpy_typedef          = _loaded_noop

    # ----------
    # function declarations

    def _generate_cpy_function_collecttype(self, tp, name):
        assert isinstance(tp, model.FunctionPtrType)
        if tp.ellipsis:
            self._do_collect_type(tp)
        else:
            # don't call _do_collect_type(tp) in this common case,
            # otherwise test_autofilled_struct_as_argument fails
            for type in tp.args:
                self._do_collect_type(type)
            self._do_collect_type(tp.result)

    def _generate_cpy_function_decl(self, tp, name):
        assert isinstance(tp, model.FunctionPtrType)
        if tp.ellipsis:
            # cannot support vararg functions better than this: check for its
            # exact type (including the fixed arguments), and build it as a
            # constant function pointer (no CPython wrapper)
            self._generate_cpy_const(False, name, tp)
            return
        prnt = self._prnt
        numargs = len(tp.args)
        if numargs == 0:
            argname = 'noarg'
        elif numargs == 1:
            argname = 'arg0'
        else:
            argname = 'args'
        prnt('static PyObject *')
        prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname))
        prnt('{')
        #
        context = 'argument of %s' % name
        for i, type in enumerate(tp.args):
            prnt('  %s;' % type.get_c_name(' x%d' % i, context))
        #
        localvars = set()
        freelines = set()
        for type in tp.args:
            self._extra_local_variables(type, localvars, freelines)
        for decl in sorted(localvars):
            prnt('  %s;' % (decl,))
        #
        if not isinstance(tp.result, model.VoidType):
            result_code = 'result = '
            context = 'result of %s' % name
            prnt('  %s;' % tp.result.get_c_name(' result', context))
            prnt('  PyObject *pyresult;')
        else:
            result_code = ''
        #
        if len(tp.args) > 1:
            rng = range(len(tp.args))
            for i in rng:
                prnt('  PyObject *arg%d;' % i)
            prnt()
            prnt('  if (!PyArg_ParseTuple(args, "%s:%s", %s))' % (
                'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng])))
            prnt('    return NULL;')
        prnt()
        #
        for i, type in enumerate(tp.args):
            self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i,
                                       'return NULL')
            prnt()
        #
        prnt('  Py_BEGIN_ALLOW_THREADS')
        prnt('  _cffi_restore_errno();')
        prnt('  { %s%s(%s); }' % (
            result_code, name,
            ', '.join(['x%d' % i for i in range(len(tp.args))])))
        prnt('  _cffi_save_errno();')
        prnt('  Py_END_ALLOW_THREADS')
        prnt()
        #
        prnt('  (void)self; /* unused */')
        if numargs == 0:
            prnt('  (void)noarg; /* unused */')
        if result_code:
            prnt('  pyresult = %s;' %
                 self._convert_expr_from_c(tp.result, 'result', 'result type'))
            for freeline in freelines:
                prnt('  ' + freeline)
            prnt('  return pyresult;')
        else:
            for freeline in freelines:
                prnt('  ' + freeline)
            prnt('  Py_INCREF(Py_None);')
            prnt('  return Py_None;')
        prnt('}')
        prnt()

    def _generate_cpy_function_method(self, tp, name):
        if tp.ellipsis:
            return
        numargs = len(tp.args)
        if numargs == 0:
            meth = 'METH_NOARGS'
        elif numargs == 1:
            meth = 'METH_O'
        else:
            meth = 'METH_VARARGS'
        self._prnt('  {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth))

    _loading_cpy_function = _loaded_noop

    def _loaded_cpy_function(self, tp, name, module, library):
        if tp.ellipsis:
            return
        func = getattr(module, name)
        setattr(library, name, func)
        self._types_of_builtin_functions[func] = tp

    # ----------
    # named structs

    _generate_cpy_struct_collecttype = _generate_nothing
    def _generate_cpy_struct_decl(self, tp, name):
        assert name == tp.name
        self._generate_struct_or_union_decl(tp, 'struct', name)
    def _generate_cpy_struct_method(self, tp, name):
        self._generate_struct_or_union_method(tp, 'struct', name)
    def _loading_cpy_struct(self, tp, name, module):
        self._loading_struct_or_union(tp, 'struct', name, module)
    def _loaded_cpy_struct(self, tp, name, module, **kwds):
        self._loaded_struct_or_union(tp)

    _generate_cpy_union_collecttype = _generate_nothing
    def _generate_cpy_union_decl(self, tp, name):
        assert name == tp.name
        self._generate_struct_or_union_decl(tp, 'union', name)
    def _generate_cpy_union_method(self, tp, name):
        self._generate_struct_or_union_method(tp, 'union', name)
    def _loading_cpy_union(self, tp, name, module):
        self._loading_struct_or_union(tp, 'union', name, module)
    def _loaded_cpy_union(self, tp, name, module, **kwds):
        self._loaded_struct_or_union(tp)

    def _generate_struct_or_union_decl(self, tp, prefix, name):
        if tp.fldnames is None:
            return     # nothing to do with opaque structs
        checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
        cname = ('%s %s' % (prefix, name)).strip()
        #
        prnt = self._prnt
        prnt('static void %s(%s *p)' % (checkfuncname, cname))
        prnt('{')
        prnt('  /* only to generate compile-time warnings or errors */')
        prnt('  (void)p;')
        for fname, ftype, fbitsize, fqual in tp.enumfields():
            if (isinstance(ftype, model.PrimitiveType)
                and ftype.is_integer_type()) or fbitsize >= 0:
                # accept all integers, but complain on float or double
                prnt('  (void)((p->%s) << 1);' % fname)
            else:
                # only accept exactly the type declared.
                try:
                    prnt('  { %s = &p->%s; (void)tmp; }' % (
                        ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
                        fname))
                except VerificationError as e:
                    prnt('  /* %s */' % str(e))   # cannot verify it, ignore
        prnt('}')
        prnt('static PyObject *')
        prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,))
        prnt('{')
        prnt('  struct _cffi_aligncheck { char x; %s y; };' % cname)
        prnt('  static Py_ssize_t nums[] = {')
        prnt('    sizeof(%s),' % cname)
        prnt('    offsetof(struct _cffi_aligncheck, y),')
        for fname, ftype, fbitsize, fqual in tp.enumfields():
            if fbitsize >= 0:
                continue      # xxx ignore fbitsize for now
            prnt('    offsetof(%s, %s),' % (cname, fname))
            if isinstance(ftype, model.ArrayType) and ftype.length is None:
                prnt('    0,  /* %s */' % ftype._get_c_name())
            else:
                prnt('    sizeof(((%s *)0)->%s),' % (cname, fname))
        prnt('    -1')
        prnt('  };')
        prnt('  (void)self; /* unused */')
        prnt('  (void)noarg; /* unused */')
        prnt('  return _cffi_get_struct_layout(nums);')
        prnt('  /* the next line is not executed, but compiled */')
        prnt('  %s(0);' % (checkfuncname,))
        prnt('}')
        prnt()

    def _generate_struct_or_union_method(self, tp, prefix, name):
        if tp.fldnames is None:
            return     # nothing to do with opaque structs
        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
        self._prnt('  {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname,
                                                         layoutfuncname))

    def _loading_struct_or_union(self, tp, prefix, name, module):
        if tp.fldnames is None:
            return     # nothing to do with opaque structs
        layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
        #
        function = getattr(module, layoutfuncname)
        layout = function()
        if isinstance(tp, model.StructOrUnion) and tp.partial:
            # use the function()'s sizes and offsets to guide the
            # layout of the struct
            totalsize = layout[0]
            totalalignment = layout[1]
            fieldofs = layout[2::2]
            fieldsize = layout[3::2]
            tp.force_flatten()
            assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
            tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
        else:
            cname = ('%s %s' % (prefix, name)).strip()
            self._struct_pending_verification[tp] = layout, cname

    def _loaded_struct_or_union(self, tp):
        if tp.fldnames is None:
            return     # nothing to do with opaque structs
        self.ffi._get_cached_btype(tp)   # force 'fixedlayout' to be considered

        if tp in self._struct_pending_verification:
            # check that the layout sizes and offsets match the real ones
            def check(realvalue, expectedvalue, msg):
                if realvalue != expectedvalue:
                    raise VerificationError(
                        "%s (we have %d, but C compiler says %d)"
                        % (msg, expectedvalue, realvalue))
            ffi = self.ffi
            BStruct = ffi._get_cached_btype(tp)
            layout, cname = self._struct_pending_verification.pop(tp)
            check(layout[0], ffi.sizeof(BStruct), "wrong total size")
            check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
            i = 2
            for fname, ftype, fbitsize, fqual in tp.enumfields():
                if fbitsize >= 0:
                    continue        # xxx ignore fbitsize for now
                check(layout[i], ffi.offsetof(BStruct, fname),
                      "wrong offset for field %r" % (fname,))
                if layout[i+1] != 0:
                    BField = ffi._get_cached_btype(ftype)
                    check(layout[i+1], ffi.sizeof(BField),
                          "wrong size for field %r" % (fname,))
                i += 2
            assert i == len(layout)

    # ----------
    # 'anonymous' declarations.  These are produced for anonymous structs
    # or unions; the 'name' is obtained by a typedef.

    _generate_cpy_anonymous_collecttype = _generate_nothing

    def _generate_cpy_anonymous_decl(self, tp, name):
        if isinstance(tp, model.EnumType):
            self._generate_cpy_enum_decl(tp, name, '')
        else:
            self._generate_struct_or_union_decl(tp, '', name)

    def _generate_cpy_anonymous_method(self, tp, name):
        if not isinstance(tp, model.EnumType):
            self._generate_struct_or_union_method(tp, '', name)

    def _loading_cpy_anonymous(self, tp, name, module):
        if isinstance(tp, model.EnumType):
            self._loading_cpy_enum(tp, name, module)
        else:
            self._loading_struct_or_union(tp, '', name, module)

    def _loaded_cpy_anonymous(self, tp, name, module, **kwds):
        if isinstance(tp, model.EnumType):
            self._loaded_cpy_enum(tp, name, module, **kwds)
        else:
            self._loaded_struct_or_union(tp)

    # ----------
    # constants, likely declared with '#define'

    def _generate_cpy_const(self, is_int, name, tp=None, category='const',
                            vartp=None, delayed=True, size_too=False,
                            check_value=None):
        prnt = self._prnt
        funcname = '_cffi_%s_%s' % (category, name)
        prnt('static int %s(PyObject *lib)' % funcname)
        prnt('{')
        prnt('  PyObject *o;')
        prnt('  int res;')
        if not is_int:
            prnt('  %s;' % (vartp or tp).get_c_name(' i', name))
        else:
            assert category == 'const'
        #
        if check_value is not None:
            self._check_int_constant_value(name, check_value)
        #
        if not is_int:
            if category == 'var':
                realexpr = '&' + name
            else:
                realexpr = name
            prnt('  i = (%s);' % (realexpr,))
            prnt('  o = %s;' % (self._convert_expr_from_c(tp, 'i',
                                                          'variable type'),))
            assert delayed
        else:
            prnt('  o = _cffi_from_c_int_const(%s);' % name)
        prnt('  if (o == NULL)')
        prnt('    return -1;')
        if size_too:
            prnt('  {')
            prnt('    PyObject *o1 = o;')
            prnt('    o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));'
                 % (name,))
            prnt('    Py_DECREF(o1);')
            prnt('    if (o == NULL)')
            prnt('      return -1;')
            prnt('  }')
        prnt('  res = PyObject_SetAttrString(lib, "%s", o);' % name)
        prnt('  Py_DECREF(o);')
        prnt('  if (res < 0)')
        prnt('    return -1;')
        prnt('  return %s;' % self._chained_list_constants[delayed])
        self._chained_list_constants[delayed] = funcname + '(lib)'
        prnt('}')
        prnt()

    def _generate_cpy_constant_collecttype(self, tp, name):
        is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
        if not is_int:
            self._do_collect_type(tp)

    def _generate_cpy_constant_decl(self, tp, name):
        is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
        self._generate_cpy_const(is_int, name, tp)

    _generate_cpy_constant_method = _generate_nothing
    _loading_cpy_constant = _loaded_noop
    _loaded_cpy_constant  = _loaded_noop

    # ----------
    # enums

    def _check_int_constant_value(self, name, value, err_prefix=''):
        prnt = self._prnt
        if value <= 0:
            prnt('  if ((%s) > 0 || (long)(%s) != %dL) {' % (
                name, name, value))
        else:
            prnt('  if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
                name, name, value))
        prnt('    char buf[64];')
        prnt('    if ((%s) <= 0)' % name)
        prnt('        snprintf(buf, 63, "%%ld", (long)(%s));' % name)
        prnt('    else')
        prnt('        snprintf(buf, 63, "%%lu", (unsigned long)(%s));' %
             name)
        prnt('    PyErr_Format(_cffi_VerificationError,')
        prnt('                 "%s%s has the real value %s, not %s",')
        prnt('                 "%s", "%s", buf, "%d");' % (
            err_prefix, name, value))
        prnt('    return -1;')
        prnt('  }')

    def _enum_funcname(self, prefix, name):
        # "$enum_$1" => "___D_enum____D_1"
        name = name.replace('$', '___D_')
        return '_cffi_e_%s_%s' % (prefix, name)

    def _generate_cpy_enum_decl(self, tp, name, prefix='enum'):
        if tp.partial:
            for enumerator in tp.enumerators:
                self._generate_cpy_const(True, enumerator, delayed=False)
            return
        #
        funcname = self._enum_funcname(prefix, name)
        prnt = self._prnt
        prnt('static int %s(PyObject *lib)' % funcname)
        prnt('{')
        for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
            self._check_int_constant_value(enumerator, enumvalue,
                                           "enum %s: " % name)
        prnt('  return %s;' % self._chained_list_constants[True])
        self._chained_list_constants[True] = funcname + '(lib)'
        prnt('}')
        prnt()

    _generate_cpy_enum_collecttype = _generate_nothing
    _generate_cpy_enum_method = _generate_nothing

    def _loading_cpy_enum(self, tp, name, module):
        if tp.partial:
            enumvalues = [getattr(module, enumerator)
                          for enumerator in tp.enumerators]
            tp.enumvalues = tuple(enumvalues)
            tp.partial_resolved = True

    def _loaded_cpy_enum(self, tp, name, module, library):
        for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
            setattr(library, enumerator, enumvalue)

    # ----------
    # macros: for now only for integers

    def _generate_cpy_macro_decl(self, tp, name):
        if tp == '...':
            check_value = None
        else:
            check_value = tp     # an integer
        self._generate_cpy_const(True, name, check_value=check_value)

    _generate_cpy_macro_collecttype = _generate_nothing
    _generate_cpy_macro_method = _generate_nothing
    _loading_cpy_macro = _loaded_noop
    _loaded_cpy_macro  = _loaded_noop

    # ----------
    # global variables

    def _generate_cpy_variable_collecttype(self, tp, name):
        if isinstance(tp, model.ArrayType):
            tp_ptr = model.PointerType(tp.item)
        else:
            tp_ptr = model.PointerType(tp)
        self._do_collect_type(tp_ptr)

    def _generate_cpy_variable_decl(self, tp, name):
        if isinstance(tp, model.ArrayType):
            tp_ptr = model.PointerType(tp.item)
            self._generate_cpy_const(False, name, tp, vartp=tp_ptr,
                                     size_too = tp.length_is_unknown())
        else:
            tp_ptr = model.PointerType(tp)
            self._generate_cpy_const(False, name, tp_ptr, category='var')

    _generate_cpy_variable_method = _generate_nothing
    _loading_cpy_variable = _loaded_noop

    def _loaded_cpy_variable(self, tp, name, module, library):
        value = getattr(library, name)
        if isinstance(tp, model.ArrayType):   # int a[5] is "constant" in the
                                              # sense that "a=..." is forbidden
            if tp.length_is_unknown():
                assert isinstance(value, tuple)
                (value, size) = value
                BItemType = self.ffi._get_cached_btype(tp.item)
                length, rest = divmod(size, self.ffi.sizeof(BItemType))
                if rest != 0:
                    raise VerificationError(
                        "bad size: %r does not seem to be an array of %s" %
                        (name, tp.item))
                tp = tp.resolve_length(length)
            # 'value' is a <cdata 'type *'> which we have to replace with
            # a <cdata 'type[N]'> if the N is actually known
            if tp.length is not None:
                BArray = self.ffi._get_cached_btype(tp)
                value = self.ffi.cast(BArray, value)
                setattr(library, name, value)
            return
        # remove ptr=<cdata 'int *'> from the library instance, and replace
        # it by a property on the class, which reads/writes into ptr[0].
        ptr = value
        delattr(library, name)
        def getter(library):
            return ptr[0]
        def setter(library, value):
            ptr[0] = value
        setattr(type(library), name, property(getter, setter))
        type(library)._cffi_dir.append(name)

    # ----------

    def _generate_setup_custom(self):
        prnt = self._prnt
        prnt('static int _cffi_setup_custom(PyObject *lib)')
        prnt('{')
        prnt('  return %s;' % self._chained_list_constants[True])
        prnt('}')

cffimod_header = r'''
#include <Python.h>
#include <stddef.h>

/* this block of #ifs should be kept exactly identical between
   c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
   and cffi/_cffi_include.h */
#if defined(_MSC_VER)
# include <malloc.h>   /* for alloca() */
# if _MSC_VER < 1600   /* MSVC < 2010 */
   typedef __int8 int8_t;
   typedef __int16 int16_t;
   typedef __int32 int32_t;
   typedef __int64 int64_t;
   typedef unsigned __int8 uint8_t;
   typedef unsigned __int16 uint16_t;
   typedef unsigned __int32 uint32_t;
   typedef unsigned __int64 uint64_t;
   typedef __int8 int_least8_t;
   typedef __int16 int_least16_t;
   typedef __int32 int_least32_t;
   typedef __int64 int_least64_t;
   typedef unsigned __int8 uint_least8_t;
   typedef unsigned __int16 uint_least16_t;
   typedef unsigned __int32 uint_least32_t;
   typedef unsigned __int64 uint_least64_t;
   typedef __int8 int_fast8_t;
   typedef __int16 int_fast16_t;
   typedef __int32 int_fast32_t;
   typedef __int64 int_fast64_t;
   typedef unsigned __int8 uint_fast8_t;
   typedef unsigned __int16 uint_fast16_t;
   typedef unsigned __int32 uint_fast32_t;
   typedef unsigned __int64 uint_fast64_t;
   typedef __int64 intmax_t;
   typedef unsigned __int64 uintmax_t;
# else
#  include <stdint.h>
# endif
# if _MSC_VER < 1800   /* MSVC < 2013 */
#  ifndef __cplusplus
    typedef unsigned char _Bool;
#  endif
# endif
#else
# include <stdint.h>
# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
#  include <alloca.h>
# endif
#endif

#if PY_MAJOR_VERSION < 3
# undef PyCapsule_CheckExact
# undef PyCapsule_GetPointer
# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule))
# define PyCapsule_GetPointer(capsule, name) \
    (PyCObject_AsVoidPtr(capsule))
#endif

#if PY_MAJOR_VERSION >= 3
# define PyInt_FromLong PyLong_FromLong
#endif

#define _cffi_from_c_double PyFloat_FromDouble
#define _cffi_from_c_float PyFloat_FromDouble
#define _cffi_from_c_long PyInt_FromLong
#define _cffi_from_c_ulong PyLong_FromUnsignedLong
#define _cffi_from_c_longlong PyLong_FromLongLong
#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
#define _cffi_from_c__Bool PyBool_FromLong

#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble

#define _cffi_from_c_int_const(x)                                        \
    (((x) > 0) ?                                                         \
        ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ?      \
            PyInt_FromLong((long)(x)) :                                  \
            PyLong_FromUnsignedLongLong((unsigned long long)(x)) :       \
        ((long long)(x) >= (long long)LONG_MIN) ?                        \
            PyInt_FromLong((long)(x)) :                                  \
            PyLong_FromLongLong((long long)(x)))

#define _cffi_from_c_int(x, type)                                        \
    (((type)-1) > 0 ? /* unsigned */                                     \
        (sizeof(type) < sizeof(long) ?                                   \
            PyInt_FromLong((long)x) :                                    \
         sizeof(type) == sizeof(long) ?                                  \
            PyLong_FromUnsignedLong((unsigned long)x) :                  \
            PyLong_FromUnsignedLongLong((unsigned long long)x)) :        \
        (sizeof(type) <= sizeof(long) ?                                  \
            PyInt_FromLong((long)x) :                                    \
            PyLong_FromLongLong((long long)x)))

#define _cffi_to_c_int(o, type)                                          \
    ((type)(                                                             \
     sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o)        \
                                         : (type)_cffi_to_c_i8(o)) :     \
     sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o)       \
                                         : (type)_cffi_to_c_i16(o)) :    \
     sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o)       \
                                         : (type)_cffi_to_c_i32(o)) :    \
     sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o)       \
                                         : (type)_cffi_to_c_i64(o)) :    \
     (Py_FatalError("unsupported size for type " #type), (type)0)))

#define _cffi_to_c_i8                                                    \
                 ((int(*)(PyObject *))_cffi_exports[1])
#define _cffi_to_c_u8                                                    \
                 ((int(*)(PyObject *))_cffi_exports[2])
#define _cffi_to_c_i16                                                   \
                 ((int(*)(PyObject *))_cffi_exports[3])
#define _cffi_to_c_u16                                                   \
                 ((int(*)(PyObject *))_cffi_exports[4])
#define _cffi_to_c_i32                                                   \
                 ((int(*)(PyObject *))_cffi_exports[5])
#define _cffi_to_c_u32                                                   \
                 ((unsigned int(*)(PyObject *))_cffi_exports[6])
#define _cffi_to_c_i64                                                   \
                 ((long long(*)(PyObject *))_cffi_exports[7])
#define _cffi_to_c_u64                                                   \
                 ((unsigned long long(*)(PyObject *))_cffi_exports[8])
#define _cffi_to_c_char                                                  \
                 ((int(*)(PyObject *))_cffi_exports[9])
#define _cffi_from_c_pointer                                             \
    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10])
#define _cffi_to_c_pointer                                               \
    ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11])
#define _cffi_get_struct_layout                                          \
    ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12])
#define _cffi_restore_errno                                              \
    ((void(*)(void))_cffi_exports[13])
#define _cffi_save_errno                                                 \
    ((void(*)(void))_cffi_exports[14])
#define _cffi_from_c_char                                                \
    ((PyObject *(*)(char))_cffi_exports[15])
#define _cffi_from_c_deref                                               \
    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16])
#define _cffi_to_c                                                       \
    ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17])
#define _cffi_from_c_struct                                              \
    ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18])
#define _cffi_to_c_wchar_t                                               \
    ((wchar_t(*)(PyObject *))_cffi_exports[19])
#define _cffi_from_c_wchar_t                                             \
    ((PyObject *(*)(wchar_t))_cffi_exports[20])
#define _cffi_to_c_long_double                                           \
    ((long double(*)(PyObject *))_cffi_exports[21])
#define _cffi_to_c__Bool                                                 \
    ((_Bool(*)(PyObject *))_cffi_exports[22])
#define _cffi_prepare_pointer_call_argument                              \
    ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23])
#define _cffi_convert_array_from_object                                  \
    ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24])
#define _CFFI_NUM_EXPORTS 25

typedef struct _ctypedescr CTypeDescrObject;

static void *_cffi_exports[_CFFI_NUM_EXPORTS];
static PyObject *_cffi_types, *_cffi_VerificationError;

static int _cffi_setup_custom(PyObject *lib);   /* forward */

static PyObject *_cffi_setup(PyObject *self, PyObject *args)
{
    PyObject *library;
    int was_alive = (_cffi_types != NULL);
    (void)self; /* unused */
    if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError,
                                       &library))
        return NULL;
    Py_INCREF(_cffi_types);
    Py_INCREF(_cffi_VerificationError);
    if (_cffi_setup_custom(library) < 0)
        return NULL;
    return PyBool_FromLong(was_alive);
}

union _cffi_union_alignment_u {
    unsigned char m_char;
    unsigned short m_short;
    unsigned int m_int;
    unsigned long m_long;
    unsigned long long m_longlong;
    float m_float;
    double m_double;
    long double m_longdouble;
};

struct _cffi_freeme_s {
    struct _cffi_freeme_s *next;
    union _cffi_union_alignment_u alignment;
};

#ifdef __GNUC__
  __attribute__((unused))
#endif
static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg,
                                        char **output_data, Py_ssize_t datasize,
                                        struct _cffi_freeme_s **freeme)
{
    char *p;
    if (datasize < 0)
        return -1;

    p = *output_data;
    if (p == NULL) {
        struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc(
            offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize);
        if (fp == NULL)
            return -1;
        fp->next = *freeme;
        *freeme = fp;
        p = *output_data = (char *)&fp->alignment;
    }
    memset((void *)p, 0, (size_t)datasize);
    return _cffi_convert_array_from_object(p, ctptr, arg);
}

#ifdef __GNUC__
  __attribute__((unused))
#endif
static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme)
{
    do {
        void *p = (void *)freeme;
        freeme = freeme->next;
        PyObject_Free(p);
    } while (freeme != NULL);
}

static int _cffi_init(void)
{
    PyObject *module, *c_api_object = NULL;

    module = PyImport_ImportModule("_cffi_backend");
    if (module == NULL)
        goto failure;

    c_api_object = PyObject_GetAttrString(module, "_C_API");
    if (c_api_object == NULL)
        goto failure;
    if (!PyCapsule_CheckExact(c_api_object)) {
        PyErr_SetNone(PyExc_ImportError);
        goto failure;
    }
    memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"),
           _CFFI_NUM_EXPORTS * sizeof(void *));

    Py_DECREF(module);
    Py_DECREF(c_api_object);
    return 0;

  failure:
    Py_XDECREF(module);
    Py_XDECREF(c_api_object);
    return -1;
}

#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num))

/**********/
'''

src/cffi/vengine_cpy.py
python-cffi/cffi
#
# DEPRECATED: implementation for ffi.verify()
#
import sys, os, binascii, shutil, io
from . import __version_verifier_modules__
from . import ffiplatform
from .error import VerificationError

if sys.version_info >= (3, 3):
    import importlib.machinery
    def _extension_suffixes():
        return importlib.machinery.EXTENSION_SUFFIXES[:]
else:
    import imp
    def _extension_suffixes():
        return [suffix for suffix, _, type in imp.get_suffixes()
                if type == imp.C_EXTENSION]


if sys.version_info >= (3,):
    NativeIO = io.StringIO
else:
    class NativeIO(io.BytesIO):
        def write(self, s):
            if isinstance(s, unicode):
                s = s.encode('ascii')
            super(NativeIO, self).write(s)


class Verifier(object):

    def __init__(self, ffi, preamble, tmpdir=None, modulename=None,
                 ext_package=None, tag='', force_generic_engine=False,
                 source_extension='.c', flags=None, relative_to=None, **kwds):
        if ffi._parser._uses_new_feature:
            raise VerificationError(
                "feature not supported with ffi.verify(), but only "
                "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,))
        self.ffi = ffi
        self.preamble = preamble
        if not modulename:
            flattened_kwds = ffiplatform.flatten(kwds)
        vengine_class = _locate_engine_class(ffi, force_generic_engine)
        self._vengine = vengine_class(self)
        self._vengine.patch_extension_kwds(kwds)
        self.flags = flags
        self.kwds = self.make_relative_to(kwds, relative_to)
        #
        if modulename:
            if tag:
                raise TypeError("can't specify both 'modulename' and 'tag'")
        else:
            key = '\x00'.join(['%d.%d' % sys.version_info[:2],
                               __version_verifier_modules__,
                               preamble, flattened_kwds] +
                              ffi._cdefsources)
            if sys.version_info >= (3,):
                key = key.encode('utf-8')
            k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff)
            k1 = k1.lstrip('0x').rstrip('L')
            k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff)
            k2 = k2.lstrip('0').rstrip('L')
            modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key,
                                              k1, k2)
        suffix = _get_so_suffixes()[0]
        self.tmpdir = tmpdir or _caller_dir_pycache()
        self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension)
        self.modulefilename = os.path.join(self.tmpdir, modulename + suffix)
        self.ext_package = ext_package
        self._has_source = False
        self._has_module = False

    def write_source(self, file=None):
        """Write the C source code.  It is produced in 'self.sourcefilename',
        which can be tweaked beforehand."""
        with self.ffi._lock:
            if self._has_source and file is None:
                raise VerificationError(
                    "source code already written")
            self._write_source(file)

    def compile_module(self):
        """Write the C source code (if not done already) and compile it.
        This produces a dynamic link library in 'self.modulefilename'."""
        with self.ffi._lock:
            if self._has_module:
                raise VerificationError("module already compiled")
            if not self._has_source:
                self._write_source()
            self._compile_module()

    def load_library(self):
        """Get a C module from this Verifier instance.
        Returns an instance of a FFILibrary class that behaves like the
        objects returned by ffi.dlopen(), but that delegates all
        operations to the C module.  If necessary, the C code is written
        and compiled first.
        """
        with self.ffi._lock:
            if not self._has_module:
                self._locate_module()
                if not self._has_module:
                    if not self._has_source:
                        self._write_source()
                    self._compile_module()
            return self._load_library()

    def get_module_name(self):
        basename = os.path.basename(self.modulefilename)
        # kill both the .so extension and the other .'s, as introduced
        # by Python 3: 'basename.cpython-33m.so'
        basename = basename.split('.', 1)[0]
        # and the _d added in Python 2 debug builds --- but try to be
        # conservative and not kill a legitimate _d
        if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'):
            basename = basename[:-2]
        return basename

    def get_extension(self):
        if not self._has_source:
            with self.ffi._lock:
                if not self._has_source:
                    self._write_source()
        sourcename = ffiplatform.maybe_relative_path(self.sourcefilename)
        modname = self.get_module_name()
        return ffiplatform.get_extension(sourcename, modname, **self.kwds)

    def generates_python_module(self):
        return self._vengine._gen_python_module

    def make_relative_to(self, kwds, relative_to):
        if relative_to and os.path.dirname(relative_to):
            dirname = os.path.dirname(relative_to)
            kwds = kwds.copy()
            for key in ffiplatform.LIST_OF_FILE_NAMES:
                if key in kwds:
                    lst = kwds[key]
                    if not isinstance(lst, (list, tuple)):
                        raise TypeError("keyword '%s' should be a list or tuple"
                                        % (key,))
                    lst = [os.path.join(dirname, fn) for fn in lst]
                    kwds[key] = lst
        return kwds

    # ----------

    def _locate_module(self):
        if not os.path.isfile(self.modulefilename):
            if self.ext_package:
                try:
                    pkg = __import__(self.ext_package, None, None, ['__doc__'])
                except ImportError:
                    return      # cannot import the package itself, give up
                    # (e.g. it might be called differently before installation)
                path = pkg.__path__
            else:
                path = None
            filename = self._vengine.find_module(self.get_module_name(), path,
                                                 _get_so_suffixes())
            if filename is None:
                return
            self.modulefilename = filename
        self._vengine.collect_types()
        self._has_module = True

    def _write_source_to(self, file):
        self._vengine._f = file
        try:
            self._vengine.write_source_to_f()
        finally:
            del self._vengine._f

    def _write_source(self, file=None):
        if file is not None:
            self._write_source_to(file)
        else:
            # Write our source file to an in memory file.
            f = NativeIO()
            self._write_source_to(f)
            source_data = f.getvalue()

            # Determine if this matches the current file
            if os.path.exists(self.sourcefilename):
                with open(self.sourcefilename, "r") as fp:
                    needs_written = not (fp.read() == source_data)
            else:
                needs_written = True

            # Actually write the file out if it doesn't match
            if needs_written:
                _ensure_dir(self.sourcefilename)
                with open(self.sourcefilename, "w") as fp:
                    fp.write(source_data)

            # Set this flag
            self._has_source = True

    def _compile_module(self):
        # compile this C source
        tmpdir = os.path.dirname(self.sourcefilename)
        outputfilename = ffiplatform.compile(tmpdir, self.get_extension())
        try:
            same = ffiplatform.samefile(outputfilename, self.modulefilename)
        except OSError:
            same = False
        if not same:
            _ensure_dir(self.modulefilename)
            shutil.move(outputfilename, self.modulefilename)
        self._has_module = True

    def _load_library(self):
        assert self._has_module
        if self.flags is not None:
            return self._vengine.load_library(self.flags)
        else:
            return self._vengine.load_library()

# ____________________________________________________________

_FORCE_GENERIC_ENGINE = False      # for tests

def _locate_engine_class(ffi, force_generic_engine):
    if _FORCE_GENERIC_ENGINE:
        force_generic_engine = True
    if not force_generic_engine:
        if '__pypy__' in sys.builtin_module_names:
            force_generic_engine = True
        else:
            try:
                import _cffi_backend
            except ImportError:
                _cffi_backend = '?'
            if ffi._backend is not _cffi_backend:
                force_generic_engine = True
    if force_generic_engine:
        from . import vengine_gen
        return vengine_gen.VGenericEngine
    else:
        from . import vengine_cpy
        return vengine_cpy.VCPythonEngine

# ____________________________________________________________

_TMPDIR = None

def _caller_dir_pycache():
    if _TMPDIR:
        return _TMPDIR
    result = os.environ.get('CFFI_TMPDIR')
    if result:
        return result
    filename = sys._getframe(2).f_code.co_filename
    return os.path.abspath(os.path.join(os.path.dirname(filename),
                           '__pycache__'))

def set_tmpdir(dirname):
    """Set the temporary directory to use instead of __pycache__."""
    global _TMPDIR
    _TMPDIR = dirname

def cleanup_tmpdir(tmpdir=None, keep_so=False):
    """Clean up the temporary directory by removing all files in it
    called `_cffi_*.{c,so}` as well as the `build` subdirectory."""
    tmpdir = tmpdir or _caller_dir_pycache()
    try:
        filelist = os.listdir(tmpdir)
    except OSError:
        return
    if keep_so:
        suffix = '.c'   # only remove .c files
    else:
        suffix = _get_so_suffixes()[0].lower()
    for fn in filelist:
        if fn.lower().startswith('_cffi_') and (
                fn.lower().endswith(suffix) or fn.lower().endswith('.c')):
            try:
                os.unlink(os.path.join(tmpdir, fn))
            except OSError:
                pass
    clean_dir = [os.path.join(tmpdir, 'build')]
    for dir in clean_dir:
        try:
            for fn in os.listdir(dir):
                fn = os.path.join(dir, fn)
                if os.path.isdir(fn):
                    clean_dir.append(fn)
                else:
                    os.unlink(fn)
        except OSError:
            pass

def _get_so_suffixes():
    suffixes = _extension_suffixes()
    if not suffixes:
        # bah, no C_EXTENSION available.  Occurs on pypy without cpyext
        if sys.platform == 'win32':
            suffixes = [".pyd"]
        else:
            suffixes = [".so"]

    return suffixes

def _ensure_dir(filename):
    dirname = os.path.dirname(filename)
    if dirname and not os.path.isdir(dirname):
        os.makedirs(dirname)

src/cffi/verifier.py
python-cffi/cffi
import pytest
import platform
import sys, ctypes, ctypes.util
from cffi import FFI, CDefError, FFIError, VerificationMissing
from testing.support import *

SIZE_OF_INT   = ctypes.sizeof(ctypes.c_int)
SIZE_OF_LONG  = ctypes.sizeof(ctypes.c_long)
SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
SIZE_OF_PTR   = ctypes.sizeof(ctypes.c_void_p)
SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)

def needs_dlopen_none():
    if sys.platform == 'win32' and not ctypes.util.find_library('c'):
        pytest.skip("dlopen(None) cannot work on Windows with this runtime")


class BackendTests:

    def test_integer_ranges(self):
        ffi = FFI(backend=self.Backend())
        for (c_type, size) in [('char', 1),
                               ('short', 2),
                               ('short int', 2),
                               ('', 4),
                               ('int', 4),
                               ('long', SIZE_OF_LONG),
                               ('long int', SIZE_OF_LONG),
                               ('long long', 8),
                               ('long long int', 8),
                               ]:
            for unsigned in [None, False, True]:
                c_decl = {None: '',
                          False: 'signed ',
                          True: 'unsigned '}[unsigned] + c_type
                if c_decl == 'char' or c_decl == '':
                    continue
                self._test_int_type(ffi, c_decl, size, unsigned)

    def test_fixedsize_int(self):
        ffi = FFI(backend=self.Backend())
        for size in [1, 2, 4, 8]:
            self._test_int_type(ffi, 'int%d_t' % (8*size), size, False)
            self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True)
        self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False)
        self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True)
        self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
        self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
        self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)

    def _test_int_type(self, ffi, c_decl, size, unsigned):
        if unsigned:
            min = 0
            max = (1 << (8*size)) - 1
        else:
            min = -(1 << (8*size-1))
            max = (1 << (8*size-1)) - 1
        min = int(min)
        max = int(max)
        p = ffi.cast(c_decl, min)
        assert p == min
        assert hash(p) == hash(min)
        assert bool(p) is bool(min)
        assert int(p) == min
        p = ffi.cast(c_decl, max)
        assert int(p) == max
        p = ffi.cast(c_decl, long(max))
        assert int(p) == max
        q = ffi.cast(c_decl, min - 1)
        assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
        q = ffi.cast(c_decl, long(min - 1))
        assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
        assert q == p
        assert int(q) == int(p)
        assert hash(q) == hash(p)
        c_decl_ptr = '%s *' % c_decl
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, min - 1)
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, max + 1)
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
        assert ffi.new(c_decl_ptr, min)[0] == min
        assert ffi.new(c_decl_ptr, max)[0] == max
        assert ffi.new(c_decl_ptr, long(min))[0] == min
        assert ffi.new(c_decl_ptr, long(max))[0] == max

    def test_new_unsupported_type(self):
        ffi = FFI(backend=self.Backend())
        e = pytest.raises(TypeError, ffi.new, "int")
        assert str(e.value) == "expected a pointer or array ctype, got 'int'"

    def test_new_single_integer(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *")     # similar to ffi.new("int[1]")
        assert p[0] == 0
        p[0] = -123
        assert p[0] == -123
        p = ffi.new("int *", -42)
        assert p[0] == -42
        assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT

    def test_new_array_no_arg(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[10]")
        # the object was zero-initialized:
        for i in range(10):
            assert p[i] == 0

    def test_array_indexing(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[10]")
        p[0] = 42
        p[9] = 43
        assert p[0] == 42
        assert p[9] == 43
        with pytest.raises(IndexError):
            p[10]
        with pytest.raises(IndexError):
            p[10] = 44
        with pytest.raises(IndexError):
            p[-1]
        with pytest.raises(IndexError):
            p[-1] = 44

    def test_new_array_args(self):
        ffi = FFI(backend=self.Backend())
        # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}"
        # then here we must enclose the items in a list
        p = ffi.new("int[5]", [10, 20, 30, 40, 50])
        assert p[0] == 10
        assert p[1] == 20
        assert p[2] == 30
        assert p[3] == 40
        assert p[4] == 50
        p = ffi.new("int[4]", [25])
        assert p[0] == 25
        assert p[1] == 0     # follow C convention rather than LuaJIT's
        assert p[2] == 0
        assert p[3] == 0
        p = ffi.new("int[4]", [ffi.cast("int", -5)])
        assert p[0] == -5
        assert repr(p) == "<cdata 'int[4]' owning %d bytes>" % (4*SIZE_OF_INT)

    def test_new_array_varsize(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[]", 10)     # a single integer is the length
        assert p[9] == 0
        with pytest.raises(IndexError):
            p[10]
        #
        pytest.raises(TypeError, ffi.new, "int[]")
        #
        p = ffi.new("int[]", [-6, -7])    # a list is all the items, like C
        assert p[0] == -6
        assert p[1] == -7
        with pytest.raises(IndexError):
            p[2]
        assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
        #
        p = ffi.new("int[]", 0)
        with pytest.raises(IndexError):
            p[0]
        pytest.raises(ValueError, ffi.new, "int[]", -1)
        assert repr(p) == "<cdata 'int[]' owning 0 bytes>"

    def test_pointer_init(self):
        ffi = FFI(backend=self.Backend())
        n = ffi.new("int *", 24)
        a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL])
        for i in range(10):
            if i not in (2, 3):
                assert a[i] == ffi.NULL
        assert a[2] == a[3] == n

    def test_cannot_cast(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("short int[10]")
        e = pytest.raises(TypeError, ffi.new, "long int **", a)
        msg = str(e.value)
        assert "'short[10]'" in msg and "'long *'" in msg

    def test_new_pointer_to_array(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("int[4]", [100, 102, 104, 106])
        p = ffi.new("int **", a)
        assert p[0] == ffi.cast("int *", a)
        assert p[0][2] == 104
        p = ffi.cast("int *", a)
        assert p[0] == 100
        assert p[1] == 102
        assert p[2] == 104
        assert p[3] == 106
        # keepalive: a

    def test_pointer_direct(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.cast("int*", 0)
        assert p is not None
        assert bool(p) is False
        assert p == ffi.cast("int*", 0)
        assert p != None
        assert repr(p) == "<cdata 'int *' NULL>"
        a = ffi.new("int[]", [123, 456])
        p = ffi.cast("int*", a)
        assert bool(p) is True
        assert p == ffi.cast("int*", a)
        assert p != ffi.cast("int*", 0)
        assert p[0] == 123
        assert p[1] == 456

    def test_repr(self):
        typerepr = self.TypeRepr
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { short a, b, c; };")
        p = ffi.cast("short unsigned int", 0)
        assert repr(p) == "<cdata 'unsigned short' 0>"
        assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
        p = ffi.cast("unsigned short int", 0)
        assert repr(p) == "<cdata 'unsigned short' 0>"
        assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
        p = ffi.cast("int*", 0)
        assert repr(p) == "<cdata 'int *' NULL>"
        assert repr(ffi.typeof(p)) == typerepr % "int *"
        #
        p = ffi.new("int*")
        assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
        assert repr(ffi.typeof(p)) == typerepr % "int *"
        p = ffi.new("int**")
        assert repr(p) == "<cdata 'int * *' owning %d bytes>" % SIZE_OF_PTR
        assert repr(ffi.typeof(p)) == typerepr % "int * *"
        p = ffi.new("int [2]")
        assert repr(p) == "<cdata 'int[2]' owning %d bytes>" % (2*SIZE_OF_INT)
        assert repr(ffi.typeof(p)) == typerepr % "int[2]"
        p = ffi.new("int*[2][3]")
        assert repr(p) == "<cdata 'int *[2][3]' owning %d bytes>" % (
            6*SIZE_OF_PTR)
        assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]"
        p = ffi.new("struct foo *")
        assert repr(p) == "<cdata 'struct foo *' owning %d bytes>" % (
            3*SIZE_OF_SHORT)
        assert repr(ffi.typeof(p)) == typerepr % "struct foo *"
        #
        q = ffi.cast("short", -123)
        assert repr(q) == "<cdata 'short' -123>"
        assert repr(ffi.typeof(q)) == typerepr % "short"
        p = ffi.new("int*")
        q = ffi.cast("short*", p)
        assert repr(q).startswith("<cdata 'short *' 0x")
        assert repr(ffi.typeof(q)) == typerepr % "short *"
        p = ffi.new("int [2]")
        q = ffi.cast("int*", p)
        assert repr(q).startswith("<cdata 'int *' 0x")
        assert repr(ffi.typeof(q)) == typerepr % "int *"
        p = ffi.new("struct foo*")
        q = ffi.cast("struct foo *", p)
        assert repr(q).startswith("<cdata 'struct foo *' 0x")
        assert repr(ffi.typeof(q)) == typerepr % "struct foo *"
        prevrepr = repr(q)
        q = q[0]
        assert repr(q) == prevrepr.replace(' *', ' &')
        assert repr(ffi.typeof(q)) == typerepr % "struct foo"

    def test_new_array_of_array(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[3][4]")
        p[0][0] = 10
        p[2][3] = 33
        assert p[0][0] == 10
        assert p[2][3] == 33
        with pytest.raises(IndexError):
            p[1][-1]

    def test_constructor_array_of_array(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[3][2]", [[10, 11], [12, 13], [14, 15]])
        assert p[2][1] == 15

    def test_new_array_of_pointer_1(self):
        ffi = FFI(backend=self.Backend())
        n = ffi.new("int*", 99)
        p = ffi.new("int*[4]")
        p[3] = n
        a = p[3]
        assert repr(a).startswith("<cdata 'int *' 0x")
        assert a[0] == 99

    def test_new_array_of_pointer_2(self):
        ffi = FFI(backend=self.Backend())
        n = ffi.new("int[1]", [99])
        p = ffi.new("int*[4]")
        p[3] = n
        a = p[3]
        assert repr(a).startswith("<cdata 'int *' 0x")
        assert a[0] == 99

    def test_char(self):
        ffi = FFI(backend=self.Backend())
        assert ffi.new("char*", b"\xff")[0] == b'\xff'
        assert ffi.new("char*")[0] == b'\x00'
        assert int(ffi.cast("char", 300)) == 300 - 256
        assert not bool(ffi.cast("char", 0))
        assert bool(ffi.cast("char", 1))
        assert bool(ffi.cast("char", 255))
        pytest.raises(TypeError, ffi.new, "char*", 32)
        pytest.raises(TypeError, ffi.new, "char*", u+"x")
        pytest.raises(TypeError, ffi.new, "char*", b"foo")
        #
        p = ffi.new("char[]", [b'a', b'b', b'\x9c'])
        assert len(p) == 3
        assert p[0] == b'a'
        assert p[1] == b'b'
        assert p[2] == b'\x9c'
        p[0] = b'\xff'
        assert p[0] == b'\xff'
        p = ffi.new("char[]", b"abcd")
        assert len(p) == 5
        assert p[4] == b'\x00'    # like in C, with:  char[] p = "abcd";
        #
        p = ffi.new("char[4]", b"ab")
        assert len(p) == 4
        assert [p[i] for i in range(4)] == [b'a', b'b', b'\x00', b'\x00']
        p = ffi.new("char[2]", b"ab")
        assert len(p) == 2
        assert [p[i] for i in range(2)] == [b'a', b'b']
        pytest.raises(IndexError, ffi.new, "char[2]", b"abc")

    def check_wchar_t(self, ffi):
        try:
            ffi.cast("wchar_t", 0)
        except NotImplementedError:
            pytest.skip("NotImplementedError: wchar_t")

    def test_wchar_t(self):
        ffi = FFI(backend=self.Backend())
        self.check_wchar_t(ffi)
        assert ffi.new("wchar_t*", u+'x')[0] == u+'x'
        assert ffi.new("wchar_t*", u+'\u1234')[0] == u+'\u1234'
        if SIZE_OF_WCHAR > 2:
            assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345'
        else:
            pytest.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345')
        assert ffi.new("wchar_t*")[0] == u+'\x00'
        assert int(ffi.cast("wchar_t", 300)) == 300
        assert not bool(ffi.cast("wchar_t", 0))
        assert bool(ffi.cast("wchar_t", 1))
        assert bool(ffi.cast("wchar_t", 65535))
        if SIZE_OF_WCHAR > 2:
            assert bool(ffi.cast("wchar_t", 65536))
        pytest.raises(TypeError, ffi.new, "wchar_t*", 32)
        pytest.raises(TypeError, ffi.new, "wchar_t*", "foo")
        #
        p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234'])
        assert len(p) == 3
        assert p[0] == u+'a'
        assert p[1] == u+'b' and type(p[1]) is unicode
        assert p[2] == u+'\u1234'
        p[0] = u+'x'
        assert p[0] == u+'x' and type(p[0]) is unicode
        p[1] = u+'\u1357'
        assert p[1] == u+'\u1357'
        p = ffi.new("wchar_t[]", u+"abcd")
        assert len(p) == 5
        assert p[4] == u+'\x00'
        p = ffi.new("wchar_t[]", u+"a\u1234b")
        assert len(p) == 4
        assert p[1] == u+'\u1234'
        #
        p = ffi.new("wchar_t[]", u+'\U00023456')
        if SIZE_OF_WCHAR == 2:
            assert len(p) == 3
            assert p[0] == u+'\ud84d'
            assert p[1] == u+'\udc56'
            assert p[2] == u+'\x00'
        else:
            assert len(p) == 2
            assert p[0] == u+'\U00023456'
            assert p[1] == u+'\x00'
        #
        p = ffi.new("wchar_t[4]", u+"ab")
        assert len(p) == 4
        assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00']
        p = ffi.new("wchar_t[2]", u+"ab")
        assert len(p) == 2
        assert [p[i] for i in range(2)] == [u+'a', u+'b']
        pytest.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc")

    def test_none_as_null_doesnt_work(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int*[1]")
        assert p[0] is not None
        assert p[0] != None
        assert p[0] == ffi.NULL
        assert repr(p[0]) == "<cdata 'int *' NULL>"
        #
        n = ffi.new("int*", 99)
        p = ffi.new("int*[]", [n])
        assert p[0][0] == 99
        with pytest.raises(TypeError):
            p[0] = None
        p[0] = ffi.NULL
        assert p[0] == ffi.NULL

    def test_float(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("float[]", [-2, -2.5])
        assert p[0] == -2.0
        assert p[1] == -2.5
        p[1] += 17.75
        assert p[1] == 15.25
        #
        p = ffi.new("float*", 15.75)
        assert p[0] == 15.75
        pytest.raises(TypeError, int, p)
        pytest.raises(TypeError, float, p)
        p[0] = 0.0
        assert bool(p) is True
        #
        p = ffi.new("float*", 1.1)
        f = p[0]
        assert f != 1.1      # because of rounding effect
        assert abs(f - 1.1) < 1E-7
        #
        INF = 1E200 * 1E200
        assert 1E200 != INF
        p[0] = 1E200
        assert p[0] == INF     # infinite, not enough precision

    def test_struct_simple(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a; short b, c; };")
        s = ffi.new("struct foo*")
        assert s.a == s.b == s.c == 0
        s.b = -23
        assert s.b == -23
        with pytest.raises(OverflowError):
            s.b = 32768
        #
        s = ffi.new("struct foo*", [-2, -3])
        assert s.a == -2
        assert s.b == -3
        assert s.c == 0
        with pytest.raises((AttributeError, TypeError)):
            del s.a
        assert repr(s) == "<cdata 'struct foo *' owning %d bytes>" % (
            SIZE_OF_INT + 2 * SIZE_OF_SHORT)
        #
        pytest.raises(ValueError, ffi.new, "struct foo*", [1, 2, 3, 4])

    def test_constructor_struct_from_dict(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a; short b, c; };")
        s = ffi.new("struct foo*", {'b': 123, 'c': 456})
        assert s.a == 0
        assert s.b == 123
        assert s.c == 456
        pytest.raises(KeyError, ffi.new, "struct foo*", {'d': 456})

    def test_struct_pointer(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a; short b, c; };")
        s = ffi.new("struct foo*")
        assert s[0].a == s[0].b == s[0].c == 0
        s[0].b = -23
        assert s[0].b == s.b == -23
        with pytest.raises(OverflowError):
            s[0].b = -32769
        with pytest.raises(IndexError):
            s[1]

    def test_struct_opaque(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(TypeError, ffi.new, "struct baz*")
        p = ffi.new("struct baz **")    # this works
        assert p[0] == ffi.NULL

    def test_pointer_to_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a; short b, c; };")
        s = ffi.new("struct foo *")
        s.a = -42
        assert s[0].a == -42
        p = ffi.new("struct foo **", s)
        assert p[0].a == -42
        assert p[0][0].a == -42
        p[0].a = -43
        assert s.a == -43
        assert s[0].a == -43
        p[0][0].a = -44
        assert s.a == -44
        assert s[0].a == -44
        s.a = -45
        assert p[0].a == -45
        assert p[0][0].a == -45
        s[0].a = -46
        assert p[0].a == -46
        assert p[0][0].a == -46

    def test_constructor_struct_of_array(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a[2]; char b[3]; };")
        s = ffi.new("struct foo *", [[10, 11], [b'a', b'b', b'c']])
        assert s.a[1] == 11
        assert s.b[2] == b'c'
        s.b[1] = b'X'
        assert s.b[0] == b'a'
        assert s.b[1] == b'X'
        assert s.b[2] == b'c'

    def test_recursive_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int value; struct foo *next; };")
        s = ffi.new("struct foo*")
        t = ffi.new("struct foo*")
        s.value = 123
        s.next = t
        t.value = 456
        assert s.value == 123
        assert s.next.value == 456

    def test_union_simple(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("union foo { int a; short b, c; };")
        u = ffi.new("union foo*")
        assert u.a == u.b == u.c == 0
        u.b = -23
        assert u.b == -23
        assert u.a != 0
        with pytest.raises(OverflowError):
            u.b = 32768
        #
        u = ffi.new("union foo*", [-2])
        assert u.a == -2
        with pytest.raises((AttributeError, TypeError)):
            del u.a
        assert repr(u) == "<cdata 'union foo *' owning %d bytes>" % SIZE_OF_INT

    def test_union_opaque(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(TypeError, ffi.new, "union baz *")
        u = ffi.new("union baz **")   # this works
        assert u[0] == ffi.NULL

    def test_union_initializer(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("union foo { char a; int b; };")
        pytest.raises(TypeError, ffi.new, "union foo*", b'A')
        pytest.raises(TypeError, ffi.new, "union foo*", 5)
        pytest.raises(ValueError, ffi.new, "union foo*", [b'A', 5])
        u = ffi.new("union foo*", [b'A'])
        assert u.a == b'A'
        pytest.raises(TypeError, ffi.new, "union foo*", [1005])
        u = ffi.new("union foo*", {'b': 12345})
        assert u.b == 12345
        u = ffi.new("union foo*", [])
        assert u.a == b'\x00'
        assert u.b == 0

    def test_sizeof_type(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo { int a; short b, c, d; };
            union foo { int a; short b, c, d; };
        """)
        for c_type, expected_size in [
            ('char', 1),
            ('unsigned int', 4),
            ('char *', SIZE_OF_PTR),
            ('int[5]', 20),
            ('struct foo', 12),
            ('union foo', 4),
            ]:
            size = ffi.sizeof(c_type)
            assert size == expected_size, (size, expected_size, ctype)

    def test_sizeof_cdata(self):
        ffi = FFI(backend=self.Backend())
        assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR
        assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT
        #
        a = ffi.new("int[]", [10, 11, 12, 13, 14])
        assert len(a) == 5
        assert ffi.sizeof(a) == 5 * SIZE_OF_INT

    def test_string_from_char_pointer(self):
        ffi = FFI(backend=self.Backend())
        x = ffi.new("char*", b"x")
        assert str(x) == repr(x)
        assert ffi.string(x) == b"x"
        assert ffi.string(ffi.new("char*", b"\x00")) == b""
        pytest.raises(TypeError, ffi.new, "char*", unicode("foo"))

    def test_unicode_from_wchar_pointer(self):
        ffi = FFI(backend=self.Backend())
        self.check_wchar_t(ffi)
        x = ffi.new("wchar_t*", u+"x")
        assert unicode(x) == unicode(repr(x))
        assert ffi.string(x) == u+"x"
        assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+""

    def test_string_from_char_array(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("char[]", b"hello.")
        p[5] = b'!'
        assert ffi.string(p) == b"hello!"
        p[6] = b'?'
        assert ffi.string(p) == b"hello!?"
        p[3] = b'\x00'
        assert ffi.string(p) == b"hel"
        assert ffi.string(p, 2) == b"he"
        with pytest.raises(IndexError):
            p[7] = b'X'
        #
        a = ffi.new("char[]", b"hello\x00world")
        assert len(a) == 12
        p = ffi.cast("char *", a)
        assert ffi.string(p) == b'hello'

    def test_string_from_wchar_array(self):
        ffi = FFI(backend=self.Backend())
        self.check_wchar_t(ffi)
        assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x"
        assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x"
        x = ffi.cast("wchar_t", "x")
        assert str(x) == repr(x)
        assert ffi.string(x) == u+"x"
        #
        p = ffi.new("wchar_t[]", u+"hello.")
        p[5] = u+'!'
        assert ffi.string(p) == u+"hello!"
        p[6] = u+'\u04d2'
        assert ffi.string(p) == u+"hello!\u04d2"
        p[3] = u+'\x00'
        assert ffi.string(p) == u+"hel"
        assert ffi.string(p, 123) == u+"hel"
        with pytest.raises(IndexError):
            p[7] = u+'X'
        #
        a = ffi.new("wchar_t[]", u+"hello\x00world")
        assert len(a) == 12
        p = ffi.cast("wchar_t *", a)
        assert ffi.string(p) == u+'hello'
        assert ffi.string(p, 123) == u+'hello'
        assert ffi.string(p, 5) == u+'hello'
        assert ffi.string(p, 2) == u+'he'

    def test_fetch_const_char_p_field(self):
        # 'const' is ignored so far
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { const char *name; };")
        t = ffi.new("const char[]", b"testing")
        s = ffi.new("struct foo*", [t])
        assert type(s.name) not in (bytes, str, unicode)
        assert ffi.string(s.name) == b"testing"
        with pytest.raises(TypeError):
            s.name = None
        s.name = ffi.NULL
        assert s.name == ffi.NULL

    def test_fetch_const_wchar_p_field(self):
        # 'const' is ignored so far
        ffi = FFI(backend=self.Backend())
        self.check_wchar_t(ffi)
        ffi.cdef("struct foo { const wchar_t *name; };")
        t = ffi.new("const wchar_t[]", u+"testing")
        s = ffi.new("struct foo*", [t])
        assert type(s.name) not in (bytes, str, unicode)
        assert ffi.string(s.name) == u+"testing"
        s.name = ffi.NULL
        assert s.name == ffi.NULL

    def test_voidp(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(TypeError, ffi.new, "void*")
        p = ffi.new("void **")
        assert p[0] == ffi.NULL
        a = ffi.new("int[]", [10, 11, 12])
        p = ffi.new("void **", a)
        vp = p[0]
        with pytest.raises(TypeError):
            vp[0]
        pytest.raises(TypeError, ffi.new, "short **", a)
        #
        ffi.cdef("struct foo { void *p; int *q; short *r; };")
        s = ffi.new("struct foo *")
        s.p = a    # works
        s.q = a    # works
        with pytest.raises(TypeError):
            s.r = a    # fails
        b = ffi.cast("int *", a)
        s.p = b    # works
        s.q = b    # works
        with pytest.raises(TypeError):
            s.r = b    # fails

    def test_functionptr_simple(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(TypeError, ffi.callback, "int(*)(int)", 0)
        def cb(n):
            return n + 1
        cb.__qualname__ = 'cb'
        p = ffi.callback("int(*)(int)", cb)
        res = p(41)     # calling an 'int(*)(int)', i.e. a function pointer
        assert res == 42 and type(res) is int
        res = p(ffi.cast("int", -41))
        assert res == -40 and type(res) is int
        assert repr(p).startswith(
            "<cdata 'int(*)(int)' calling <function cb at 0x")
        assert ffi.typeof(p) is ffi.typeof("int(*)(int)")
        q = ffi.new("int(**)(int)", p)
        assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % (
            SIZE_OF_PTR)
        with pytest.raises(TypeError):
            q(43)
        res = q[0](43)
        assert res == 44
        q = ffi.cast("int(*)(int)", p)
        assert repr(q).startswith("<cdata 'int(*)(int)' 0x")
        res = q(45)
        assert res == 46

    def test_functionptr_advanced(self):
        ffi = FFI(backend=self.Backend())
        t = ffi.typeof("int(*(*)(int))(int)")
        assert repr(t) == self.TypeRepr % "int(*(*)(int))(int)"

    def test_functionptr_voidptr_return(self):
        ffi = FFI(backend=self.Backend())
        def cb():
            return ffi.NULL
        p = ffi.callback("void*(*)()", cb)
        res = p()
        assert res is not None
        assert res == ffi.NULL
        int_ptr = ffi.new('int*')
        void_ptr = ffi.cast('void*', int_ptr)
        def cb():
            return void_ptr
        p = ffi.callback("void*(*)()", cb)
        res = p()
        assert res == void_ptr

    def test_functionptr_intptr_return(self):
        ffi = FFI(backend=self.Backend())
        def cb():
            return ffi.NULL
        p = ffi.callback("int*(*)()", cb)
        res = p()
        assert res == ffi.NULL
        int_ptr = ffi.new('int*')
        def cb():
            return int_ptr
        p = ffi.callback("int*(*)()", cb)
        res = p()
        assert repr(res).startswith("<cdata 'int *' 0x")
        assert res == int_ptr
        int_array_ptr = ffi.new('int[1]')
        def cb():
            return int_array_ptr
        p = ffi.callback("int*(*)()", cb)
        res = p()
        assert repr(res).startswith("<cdata 'int *' 0x")
        assert res == int_array_ptr

    def test_functionptr_void_return(self):
        ffi = FFI(backend=self.Backend())
        def foo():
            pass
        foo_cb = ffi.callback("void foo()", foo)
        result = foo_cb()
        assert result is None

    def test_char_cast(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.cast("int", b'\x01')
        assert ffi.typeof(p) is ffi.typeof("int")
        assert int(p) == 1
        p = ffi.cast("int", ffi.cast("char", b"a"))
        assert int(p) == ord("a")
        p = ffi.cast("int", ffi.cast("char", b"\x80"))
        assert int(p) == 0x80     # "char" is considered unsigned in this case
        p = ffi.cast("int", b"\x81")
        assert int(p) == 0x81

    def test_wchar_cast(self):
        ffi = FFI(backend=self.Backend())
        self.check_wchar_t(ffi)
        p = ffi.cast("int", ffi.cast("wchar_t", u+'\u1234'))
        assert int(p) == 0x1234
        p = ffi.cast("long long", ffi.cast("wchar_t", -1))
        if SIZE_OF_WCHAR == 2:      # 2 bytes, unsigned
            assert int(p) == 0xffff
        elif (sys.platform.startswith('linux') and
              platform.machine().startswith('x86')):   # known to be signed
            assert int(p) == -1
        else:                     # in general, it can be either signed or not
            assert int(p) in [-1, 0xffffffff]  # e.g. on arm, both cases occur
        p = ffi.cast("int", u+'\u1234')
        assert int(p) == 0x1234

    def test_cast_array_to_charp(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("short int[]", [0x1234, 0x5678])
        p = ffi.cast("char*", a)
        data = b''.join([p[i] for i in range(4)])
        if sys.byteorder == 'little':
            assert data == b'\x34\x12\x78\x56'
        else:
            assert data == b'\x12\x34\x56\x78'

    def test_cast_between_pointers(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("short int[]", [0x1234, 0x5678])
        p = ffi.cast("short*", a)
        p2 = ffi.cast("int*", p)
        q = ffi.cast("char*", p2)
        data = b''.join([q[i] for i in range(4)])
        if sys.byteorder == 'little':
            assert data == b'\x34\x12\x78\x56'
        else:
            assert data == b'\x12\x34\x56\x78'

    def test_cast_pointer_and_int(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("short int[]", [0x1234, 0x5678])
        l1 = ffi.cast("intptr_t", a)
        p = ffi.cast("short*", a)
        l2 = ffi.cast("intptr_t", p)
        assert int(l1) == int(l2) != 0
        q = ffi.cast("short*", l1)
        assert q == ffi.cast("short*", int(l1))
        assert q[0] == 0x1234
        assert int(ffi.cast("intptr_t", ffi.NULL)) == 0

    def test_cast_functionptr_and_int(self):
        ffi = FFI(backend=self.Backend())
        def cb(n):
            return n + 1
        a = ffi.callback("int(*)(int)", cb)
        p = ffi.cast("void *", a)
        assert p
        b = ffi.cast("int(*)(int)", p)
        assert b(41) == 42
        assert a == b
        assert hash(a) == hash(b)

    def test_callback_crash(self):
        ffi = FFI(backend=self.Backend())
        def cb(n):
            raise Exception
        a = ffi.callback("int(*)(int)", cb, error=42)
        res = a(1)    # and the error reported to stderr
        assert res == 42

    def test_structptr_argument(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int a, b; };")
        def cb(p):
            return p[0].a * 1000 + p[0].b * 100 + p[1].a * 10 + p[1].b
        a = ffi.callback("int(*)(struct foo_s[])", cb)
        res = a([[5, 6], {'a': 7, 'b': 8}])
        assert res == 5678
        res = a([[5], {'b': 8}])
        assert res == 5008

    def test_array_argument_as_list(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int a, b; };")
        seen = []
        def cb(argv):
            seen.append(ffi.string(argv[0]))
            seen.append(ffi.string(argv[1]))
        a = ffi.callback("void(*)(char *[])", cb)
        a([ffi.new("char[]", b"foobar"), ffi.new("char[]", b"baz")])
        assert seen == [b"foobar", b"baz"]

    def test_cast_float(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.cast("float", 12)
        assert float(a) == 12.0
        a = ffi.cast("float", 12.5)
        assert float(a) == 12.5
        a = ffi.cast("float", b"A")
        assert float(a) == ord("A")
        a = ffi.cast("int", 12.9)
        assert int(a) == 12
        a = ffi.cast("char", 66.9 + 256)
        assert ffi.string(a) == b"B"
        #
        a = ffi.cast("float", ffi.cast("int", 12))
        assert float(a) == 12.0
        a = ffi.cast("float", ffi.cast("double", 12.5))
        assert float(a) == 12.5
        a = ffi.cast("float", ffi.cast("char", b"A"))
        assert float(a) == ord("A")
        a = ffi.cast("int", ffi.cast("double", 12.9))
        assert int(a) == 12
        a = ffi.cast("char", ffi.cast("double", 66.9 + 256))
        assert ffi.string(a) == b"B"

    def test_enum(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("enum foo { A0, B0, CC0, D0 };")
        assert ffi.string(ffi.cast("enum foo", 0)) == "A0"
        assert ffi.string(ffi.cast("enum foo", 2)) == "CC0"
        assert ffi.string(ffi.cast("enum foo", 3)) == "D0"
        assert ffi.string(ffi.cast("enum foo", 4)) == "4"
        ffi.cdef("enum bar { A1, B1=-2, CC1, D1, E1 };")
        assert ffi.string(ffi.cast("enum bar", 0)) == "A1"
        assert ffi.string(ffi.cast("enum bar", -2)) == "B1"
        assert ffi.string(ffi.cast("enum bar", -1)) == "CC1"
        assert ffi.string(ffi.cast("enum bar", 1)) == "E1"
        assert ffi.cast("enum bar", -2) == ffi.cast("enum bar", -2)
        assert ffi.cast("enum foo", 0) == ffi.cast("enum bar", 0)
        assert ffi.cast("enum bar", 0) == ffi.cast("int", 0)
        assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC1>"
        assert repr(ffi.cast("enum foo", -1)) == (  # enums are unsigned, if
            "<cdata 'enum foo' 4294967295>")        # they contain no neg value
        ffi.cdef("enum baz { A2=0x1000, B2=0x2000 };")
        assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2"
        assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"

    def test_enum_in_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("enum foo { A, B, C, D }; struct bar { enum foo e; };")
        s = ffi.new("struct bar *")
        s.e = 0
        assert s.e == 0
        s.e = 3
        assert s.e == 3
        assert s[0].e == 3
        s[0].e = 2
        assert s.e == 2
        assert s[0].e == 2
        s.e = ffi.cast("enum foo", -1)
        assert s.e == 4294967295
        assert s[0].e == 4294967295
        s.e = s.e
        with pytest.raises(TypeError):
            s.e = 'B'
        with pytest.raises(TypeError):
            s.e = '2'
        with pytest.raises(TypeError):
            s.e = '#2'
        with pytest.raises(TypeError):
            s.e = '#7'

    def test_enum_non_contiguous(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("enum foo { A, B=42, C };")
        assert ffi.string(ffi.cast("enum foo", 0)) == "A"
        assert ffi.string(ffi.cast("enum foo", 42)) == "B"
        assert ffi.string(ffi.cast("enum foo", 43)) == "C"
        invalid_value = ffi.cast("enum foo", 2)
        assert int(invalid_value) == 2
        assert ffi.string(invalid_value) == "2"

    def test_enum_char_hex_oct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef(r"enum foo{A='!', B='\'', C=0x10, D=010, E=- 0x10, F=-010};")
        assert ffi.string(ffi.cast("enum foo", ord('!'))) == "A"
        assert ffi.string(ffi.cast("enum foo", ord("'"))) == "B"
        assert ffi.string(ffi.cast("enum foo", 16)) == "C"
        assert ffi.string(ffi.cast("enum foo", 8)) == "D"
        assert ffi.string(ffi.cast("enum foo", -16)) == "E"
        assert ffi.string(ffi.cast("enum foo", -8)) == "F"

    def test_enum_partial(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };")
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        assert lib.B == 0
        pytest.raises(VerificationMissing, getattr, lib, "A")
        assert lib.C == 1

    def test_array_of_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a, b; };")
        s = ffi.new("struct foo[1]")
        with pytest.raises(AttributeError):
            s.b
        with pytest.raises(AttributeError):
            s.b = 412
        s[0].b = 412
        assert s[0].b == 412
        with pytest.raises(IndexError):
            s[1]

    def test_pointer_to_array(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int(**)[5]")
        assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR

    def test_iterate_array(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("char[]", b"hello")
        assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
        assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
        #
        pytest.raises(TypeError, iter, ffi.cast("char *", a))
        pytest.raises(TypeError, list, ffi.cast("char *", a))
        pytest.raises(TypeError, iter, ffi.new("int *"))
        pytest.raises(TypeError, list, ffi.new("int *"))

    def test_offsetof(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a, b, c; };")
        assert ffi.offsetof("struct foo", "a") == 0
        assert ffi.offsetof("struct foo", "b") == 4
        assert ffi.offsetof("struct foo", "c") == 8

    def test_offsetof_nested(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a, b, c; };"
                 "struct bar { struct foo d, e; };")
        assert ffi.offsetof("struct bar", "e") == 12
        pytest.raises(KeyError, ffi.offsetof, "struct bar", "e.a")
        assert ffi.offsetof("struct bar", "e", "a") == 12
        assert ffi.offsetof("struct bar", "e", "b") == 16
        assert ffi.offsetof("struct bar", "e", "c") == 20

    def test_offsetof_array(self):
        ffi = FFI(backend=self.Backend())
        assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int")
        assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int")
        ffi.cdef("struct bar { int a, b; int c[99]; };")
        assert ffi.offsetof("struct bar", "c") == 2 * ffi.sizeof("int")
        assert ffi.offsetof("struct bar", "c", 0) == 2 * ffi.sizeof("int")
        assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int")

    def test_alignof(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { char a; short b; char c; };")
        assert ffi.alignof("int") == 4
        assert ffi.alignof("double") in (4, 8)
        assert ffi.alignof("struct foo") == 2

    def test_bitfield(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo { int a:10, b:20, c:3; };")
        assert ffi.sizeof("struct foo") == 8
        s = ffi.new("struct foo *")
        s.a = 511
        with pytest.raises(OverflowError):
            s.a = 512
        with pytest.raises(OverflowError):
            s[0].a = 512
        assert s.a == 511
        s.a = -512
        with pytest.raises(OverflowError):
            s.a = -513
        with pytest.raises(OverflowError):
            s[0].a = -513
        assert s.a == -512
        s.c = 3
        assert s.c == 3
        with pytest.raises(OverflowError):
            s.c = 4
        with pytest.raises(OverflowError):
            s[0].c = 4
        s.c = -4
        assert s.c == -4

    def test_bitfield_enum(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef enum { AA, BB, CC } foo_e;
            typedef struct { foo_e f:2; } foo_s;
        """)
        s = ffi.new("foo_s *")
        s.f = 2
        assert s.f == 2

    def test_anonymous_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("typedef struct { int a; } foo_t;")
        ffi.cdef("typedef struct { char b, c; } bar_t;")
        f = ffi.new("foo_t *", [12345])
        b = ffi.new("bar_t *", [b"B", b"C"])
        assert f.a == 12345
        assert b.b == b"B"
        assert b.c == b"C"
        assert repr(b).startswith("<cdata 'bar_t *'")

    def test_struct_with_two_usages(self):
        for name in ['foo_s', '']:    # anonymous or not
            ffi = FFI(backend=self.Backend())
            ffi.cdef("typedef struct %s { int a; } foo_t, *foo_p;" % name)
            f = ffi.new("foo_t *", [12345])
            ps = ffi.new("foo_p[]", [f])

    def test_pointer_arithmetic(self):
        ffi = FFI(backend=self.Backend())
        s = ffi.new("short[]", list(range(100, 110)))
        p = ffi.cast("short *", s)
        assert p[2] == 102
        assert p+1 == p+1
        assert p+1 != p+0
        assert p == p+0 == p-0
        assert (p+1)[0] == 101
        assert (p+19)[-10] == 109
        assert (p+5) - (p+1) == 4
        assert p == s+0
        assert p+1 == s+1

    def test_pointer_comparison(self):
        ffi = FFI(backend=self.Backend())
        s = ffi.new("short[]", list(range(100)))
        p = ffi.cast("short *", s)
        assert (p <  s) is False
        assert (p <= s) is True
        assert (p == s) is True
        assert (p != s) is False
        assert (p >  s) is False
        assert (p >= s) is True
        assert (s <  p) is False
        assert (s <= p) is True
        assert (s == p) is True
        assert (s != p) is False
        assert (s >  p) is False
        assert (s >= p) is True
        q = p + 1
        assert (q <  s) is False
        assert (q <= s) is False
        assert (q == s) is False
        assert (q != s) is True
        assert (q >  s) is True
        assert (q >= s) is True
        assert (s <  q) is True
        assert (s <= q) is True
        assert (s == q) is False
        assert (s != q) is True
        assert (s >  q) is False
        assert (s >= q) is False
        assert (q <  p) is False
        assert (q <= p) is False
        assert (q == p) is False
        assert (q != p) is True
        assert (q >  p) is True
        assert (q >= p) is True
        assert (p <  q) is True
        assert (p <= q) is True
        assert (p == q) is False
        assert (p != q) is True
        assert (p >  q) is False
        assert (p >= q) is False
        #
        assert (None == s) is False
        assert (None != s) is True
        assert (s == None) is False
        assert (s != None) is True
        assert (None == q) is False
        assert (None != q) is True
        assert (q == None) is False
        assert (q != None) is True

    def test_integer_comparison(self):
        ffi = FFI(backend=self.Backend())
        x = ffi.cast("int", 123)
        y = ffi.cast("int", 456)
        assert x < y
        #
        z = ffi.cast("double", 78.9)
        assert x > z
        assert y > z

    def test_ffi_buffer_ptr(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("short *", 100)
        try:
            b = ffi.buffer(a)
        except NotImplementedError as e:
            pytest.skip(str(e))
        assert type(b) is ffi.buffer
        content = b[:]
        assert len(content) == len(b) == 2
        if sys.byteorder == 'little':
            assert content == b'\x64\x00'
            assert b[0] == b'\x64'
            b[0] = b'\x65'
        else:
            assert content == b'\x00\x64'
            assert b[1] == b'\x64'
            b[1] = b'\x65'
        assert a[0] == 101

    def test_ffi_buffer_array(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("int[]", list(range(100, 110)))
        try:
            b = ffi.buffer(a)
        except NotImplementedError as e:
            pytest.skip(str(e))
        content = b[:]
        if sys.byteorder == 'little':
            assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00')
            b[4] = b'\x45'
        else:
            assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65')
            b[7] = b'\x45'
        assert len(content) == 4 * 10
        assert a[1] == 0x45

    def test_ffi_buffer_ptr_size(self):
        ffi = FFI(backend=self.Backend())
        a = ffi.new("short *", 0x4243)
        try:
            b = ffi.buffer(a, 1)
        except NotImplementedError as e:
            pytest.skip(str(e))
        content = b[:]
        assert len(content) == 1
        if sys.byteorder == 'little':
            assert content == b'\x43'
            b[0] = b'\x62'
            assert a[0] == 0x4262
        else:
            assert content == b'\x42'
            b[0] = b'\x63'
            assert a[0] == 0x6343

    def test_ffi_buffer_array_size(self):
        ffi = FFI(backend=self.Backend())
        a1 = ffi.new("int[]", list(range(100, 110)))
        a2 = ffi.new("int[]", list(range(100, 115)))
        try:
            ffi.buffer(a1)
        except NotImplementedError as e:
            pytest.skip(str(e))
        assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]

    def test_ffi_buffer_with_file(self):
        ffi = FFI(backend=self.Backend())
        import tempfile, os, array
        fd, filename = tempfile.mkstemp()
        f = os.fdopen(fd, 'r+b')
        a = ffi.new("int[]", list(range(1005)))
        try:
            ffi.buffer(a, 512)
        except NotImplementedError as e:
            pytest.skip(str(e))
        f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
        f.seek(0)
        assert f.read() == arraytostring(array.array('i', range(1000)))
        f.seek(0)
        b = ffi.new("int[]", 1005)
        f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
        assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
        f.close()
        os.unlink(filename)

    def test_ffi_buffer_with_io(self):
        ffi = FFI(backend=self.Backend())
        import io, array
        f = io.BytesIO()
        a = ffi.new("int[]", list(range(1005)))
        try:
            ffi.buffer(a, 512)
        except NotImplementedError as e:
            pytest.skip(str(e))
        f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
        f.seek(0)
        assert f.read() == arraytostring(array.array('i', range(1000)))
        f.seek(0)
        b = ffi.new("int[]", 1005)
        f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
        assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
        f.close()

    def test_ffi_buffer_comparisons(self):
        ffi = FFI(backend=self.Backend())
        ba = bytearray(range(100, 110))
        if sys.version_info >= (2, 7):
            assert ba == memoryview(ba)    # justification for the following
        a = ffi.new("uint8_t[]", list(ba))
        c = ffi.new("uint8_t[]", [99] + list(ba))
        try:
            b_full = ffi.buffer(a)
            b_short = ffi.buffer(a, 3)
            b_mid = ffi.buffer(a, 6)
            b_other = ffi.buffer(c, 6)
        except NotImplementedError as e:
            pytest.skip(str(e))
        else:
            content = b_full[:]
            assert content == b_full == ba
            assert b_other < b_short < b_mid < b_full
            assert ba > b_mid > ba[0:2]
            assert b_short != ba[1:4]

    def test_array_in_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int len; short data[5]; };")
        p = ffi.new("struct foo_s *")
        p.data[3] = 5
        assert p.data[3] == 5
        assert repr(p.data).startswith("<cdata 'short[5]' 0x")

    def test_struct_containing_array_varsize_workaround(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int len; short data[0]; };")
        p = ffi.new("char[]", ffi.sizeof("struct foo_s") + 7 * SIZE_OF_SHORT)
        q = ffi.cast("struct foo_s *", p)
        assert q.len == 0
        # 'q.data' gets not a 'short[0]', but just a 'short *' instead
        assert repr(q.data).startswith("<cdata 'short *' 0x")
        assert q.data[6] == 0
        q.data[6] = 15
        assert q.data[6] == 15

    def test_new_struct_containing_array_varsize(self):
        pytest.skip("later?")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int len; short data[]; };")
        p = ffi.new("struct foo_s *", 10)     # a single integer is the length
        assert p.len == 0
        assert p.data[9] == 0
        with pytest.raises(IndexError):
            p.data[10]

    def test_ffi_typeof_getcname(self):
        ffi = FFI(backend=self.Backend())
        assert ffi.getctype("int") == "int"
        assert ffi.getctype("int", 'x') == "int x"
        assert ffi.getctype("int*") == "int *"
        assert ffi.getctype("int*", '') == "int *"
        assert ffi.getctype("int*", 'x') == "int * x"
        assert ffi.getctype("int", '*') == "int *"
        assert ffi.getctype("int", ' * x ') == "int * x"
        assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
        assert ffi.getctype("int", '[5]') == "int[5]"
        assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
        assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
        # special-case for convenience: automatically put '()' around '*'
        assert ffi.getctype("int[5]", '*') == "int(*)[5]"
        assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
        assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"

    def test_array_of_func_ptr(self):
        ffi = FFI(backend=self.Backend())
        f = ffi.cast("int(*)(int)", 42)
        assert f != ffi.NULL
        pytest.raises(CDefError, ffi.cast, "int(int)", 42)
        pytest.raises(CDefError, ffi.new, "int([5])(int)")
        a = ffi.new("int(*[5])(int)", [f])
        assert ffi.getctype(ffi.typeof(a)) == "int(*[5])(int)"
        assert len(a) == 5
        assert a[0] == f
        assert a[1] == ffi.NULL
        pytest.raises(TypeError, ffi.cast, "int(*)(int)[5]", 0)
        #
        def cb(n):
            return n + 1
        f = ffi.callback("int(*)(int)", cb)
        a = ffi.new("int(*[5])(int)", [f, f])
        assert a[1](42) == 43

    def test_callback_as_function_argument(self):
        # In C, function arguments can be declared with a function type,
        # which is automatically replaced with the ptr-to-function type.
        ffi = FFI(backend=self.Backend())
        def cb(a, b):
            return chr(ord(a) + ord(b)).encode()
        f = ffi.callback("char cb(char, char)", cb)
        assert f(b'A', b'\x01') == b'B'
        def g(callback):
            return callback(b'A', b'\x01')
        g = ffi.callback("char g(char cb(char, char))", g)
        assert g(f) == b'B'

    def test_vararg_callback(self):
        pytest.skip("callback with '...'")
        ffi = FFI(backend=self.Backend())
        def cb(i, va_list):
            j = ffi.va_arg(va_list, "int")
            k = ffi.va_arg(va_list, "long long")
            return i * 2 + j * 3 + k * 5
        f = ffi.callback("long long cb(long i, ...)", cb)
        res = f(10, ffi.cast("int", 100), ffi.cast("long long", 1000))
        assert res == 20 + 300 + 5000

    def test_callback_decorator(self):
        ffi = FFI(backend=self.Backend())
        #
        @ffi.callback("long(long, long)", error=42)
        def cb(a, b):
            return a - b
        #
        assert cb(-100, -10) == -90
        sz = ffi.sizeof("long")
        assert cb((1 << (sz*8-1)) - 1, -10) == 42

    def test_unique_types(self):
        ffi1 = FFI(backend=self.Backend())
        ffi2 = FFI(backend=self.Backend())
        assert ffi1.typeof("char") is ffi2.typeof("char ")
        assert ffi1.typeof("long") is ffi2.typeof("signed long int")
        assert ffi1.typeof("double *") is ffi2.typeof("double*")
        assert ffi1.typeof("int ***") is ffi2.typeof(" int * * *")
        assert ffi1.typeof("int[]") is ffi2.typeof("signed int[]")
        assert ffi1.typeof("signed int*[17]") is ffi2.typeof("int *[17]")
        assert ffi1.typeof("void") is ffi2.typeof("void")
        assert ffi1.typeof("int(*)(int,int)") is ffi2.typeof("int(*)(int,int)")
        #
        # these depend on user-defined data, so should not be shared
        assert ffi1.typeof("struct foo") is not ffi2.typeof("struct foo")
        assert ffi1.typeof("union foo *") is not ffi2.typeof("union foo*")
        # the following test is an opaque enum, which we no longer support
        #assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo")
        # sanity check: twice 'ffi1'
        assert ffi1.typeof("struct foo*") is ffi1.typeof("struct foo *")

    def test_anonymous_enum(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("typedef enum { Value0 = 0 } e, *pe;\n"
                 "typedef enum { Value1 = 1 } e1;")
        assert ffi.getctype("e*") == 'e *'
        assert ffi.getctype("pe") == 'e *'
        assert ffi.getctype("e1*") == 'e1 *'

    def test_opaque_enum(self):
        import warnings
        ffi = FFI(backend=self.Backend())
        ffi.cdef("enum foo;")
        with warnings.catch_warnings(record=True) as log:
            warnings.simplefilter("always")
            n = ffi.cast("enum foo", -1)
            assert int(n) == 0xffffffff
        assert str(log[0].message) == (
            "'enum foo' has no values explicitly defined; "
            "guessing that it is equivalent to 'unsigned int'")

    def test_new_ctype(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *")
        pytest.raises(TypeError, ffi.new, p)
        p = ffi.new(ffi.typeof("int *"), 42)
        assert p[0] == 42

    def test_enum_with_non_injective_mapping(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("enum e { AA=0, BB=0, CC=0, DD=0 };")
        e = ffi.cast("enum e", 0)
        assert ffi.string(e) == "AA"     # pick the first one arbitrarily

    def test_enum_refer_previous_enum_value(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("enum e { AA, BB=2, CC=4, DD=BB, EE, FF=CC, GG=FF };")
        assert ffi.string(ffi.cast("enum e", 2)) == "BB"
        assert ffi.string(ffi.cast("enum e", 3)) == "EE"
        assert ffi.sizeof("char[DD]") == 2
        assert ffi.sizeof("char[EE]") == 3
        assert ffi.sizeof("char[FF]") == 4
        assert ffi.sizeof("char[GG]") == 4

    def test_nested_anonymous_struct(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo_s {
                struct { int a, b; };
                union { int c, d; };
            };
        """)
        assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
        p = ffi.new("struct foo_s *", [1, 2, 3])
        assert p.a == 1
        assert p.b == 2
        assert p.c == 3
        assert p.d == 3
        p.d = 17
        assert p.c == 17
        p.b = 19
        assert p.a == 1
        assert p.b == 19
        assert p.c == 17
        assert p.d == 17
        p = ffi.new("struct foo_s *", {'b': 12, 'd': 14})
        assert p.a == 0
        assert p.b == 12
        assert p.c == 14
        assert p.d == 14
        pytest.raises(ValueError, ffi.new, "struct foo_s *", [0, 0, 0, 0])

    def test_nested_field_offset_align(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo_s {
                struct { int a; char b; };
                union { char c; };
            };
        """)
        assert ffi.offsetof("struct foo_s", "c") == 2 * SIZE_OF_INT
        assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT

    def test_nested_anonymous_union(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            union foo_u {
                struct { int a, b; };
                union { int c, d; };
            };
        """)
        assert ffi.sizeof("union foo_u") == 2 * SIZE_OF_INT
        p = ffi.new("union foo_u *", [5])
        assert p.a == 5
        assert p.b == 0
        assert p.c == 5
        assert p.d == 5
        p.d = 17
        assert p.c == 17
        assert p.a == 17
        p.b = 19
        assert p.a == 17
        assert p.b == 19
        assert p.c == 17
        assert p.d == 17
        p = ffi.new("union foo_u *", {'d': 14})
        assert p.a == 14
        assert p.b == 0
        assert p.c == 14
        assert p.d == 14
        p = ffi.new("union foo_u *", {'a': -63, 'b': 12})
        assert p.a == -63
        assert p.b == 12
        assert p.c == -63
        assert p.d == -63
        p = ffi.new("union foo_u *", [123, 456])
        assert p.a == 123
        assert p.b == 456
        assert p.c == 123
        assert p.d == 123
        pytest.raises(ValueError, ffi.new, "union foo_u *", [0, 0, 0])

    def test_nested_anonymous_struct_2(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo_s {
                int a;
                union { int b; union { int c, d; }; };
                int e;
            };
        """)
        assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
        p = ffi.new("struct foo_s *", [11, 22, 33])
        assert p.a == 11
        assert p.b == p.c == p.d == 22
        assert p.e == 33
        pytest.raises(ValueError, ffi.new, "struct foo_s *", [11, 22, 33, 44])
        FOO = ffi.typeof("struct foo_s")
        fields = [(name, fld.offset, fld.flags) for (name, fld) in FOO.fields]
        assert fields == [
            ('a', 0 * SIZE_OF_INT, 0),
            ('b', 1 * SIZE_OF_INT, 0),
            ('c', 1 * SIZE_OF_INT, 1),
            ('d', 1 * SIZE_OF_INT, 1),
            ('e', 2 * SIZE_OF_INT, 0),
        ]

    def test_cast_to_array_type(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[4]", [-5])
        q = ffi.cast("int[3]", p)
        assert q[0] == -5
        assert repr(q).startswith("<cdata 'int[3]' 0x")

    def test_gc(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        seen = []
        def destructor(p1):
            assert p1 is p
            assert p1[0] == 123
            seen.append(1)
        q = ffi.gc(p, destructor)
        assert ffi.typeof(q) is ffi.typeof(p)
        import gc; gc.collect()
        assert seen == []
        del q
        import gc; gc.collect(); gc.collect(); gc.collect()
        assert seen == [1]

    def test_gc_2(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        seen = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        import gc; gc.collect()
        assert seen == []
        del q1, q2
        import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
        assert seen == [2, 1]

    def test_gc_3(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        r = ffi.new("int *", 123)
        seen = []
        seen_r = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        s1 = ffi.gc(r, lambda r: seen_r.append(4))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        s2 = ffi.gc(s1, lambda r: seen_r.append(5))
        q3 = ffi.gc(q2, lambda p: seen.append(3))
        import gc; gc.collect()
        assert seen == []
        assert seen_r == []
        del q1, q2, q3, s2, s1
        import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
        assert seen == [3, 2, 1]
        assert seen_r == [5, 4]

    def test_gc_4(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        seen = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        q3 = ffi.gc(q2, lambda p: seen.append(3))
        import gc; gc.collect()
        assert seen == []
        del q1, q3     # q2 remains, and has a hard ref to q1
        import gc; gc.collect(); gc.collect(); gc.collect()
        assert seen == [3]

    def test_gc_disable(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        pytest.raises(TypeError, ffi.gc, p, None)
        seen = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        import gc; gc.collect()
        assert seen == []
        assert ffi.gc(q1, None) is None
        del q1, q2
        import gc; gc.collect(); gc.collect(); gc.collect()
        assert seen == [2]

    def test_gc_finite_list(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        keepalive = []
        for i in range(10):
            keepalive.append(ffi.gc(p, lambda p: None))
        del keepalive[:]
        import gc; gc.collect(); gc.collect()
        for i in range(10):
            keepalive.append(ffi.gc(p, lambda p: None))

    def test_CData_CType(self):
        ffi = FFI(backend=self.Backend())
        assert isinstance(ffi.cast("int", 0), ffi.CData)
        assert isinstance(ffi.new("int *"), ffi.CData)
        assert not isinstance(ffi.typeof("int"), ffi.CData)
        assert not isinstance(ffi.cast("int", 0), ffi.CType)
        assert not isinstance(ffi.new("int *"), ffi.CType)

    def test_CData_CType_2(self):
        ffi = FFI(backend=self.Backend())
        assert isinstance(ffi.typeof("int"), ffi.CType)

    def test_bool(self):
        ffi = FFI(backend=self.Backend())
        assert int(ffi.cast("_Bool", 0.1)) == 1
        assert int(ffi.cast("_Bool", -0.0)) == 0
        assert int(ffi.cast("_Bool", b'\x02')) == 1
        assert int(ffi.cast("_Bool", b'\x00')) == 0
        assert int(ffi.cast("_Bool", b'\x80')) == 1
        assert ffi.new("_Bool *", False)[0] == 0
        assert ffi.new("_Bool *", 1)[0] == 1
        pytest.raises(OverflowError, ffi.new, "_Bool *", 2)
        pytest.raises(TypeError, ffi.string, ffi.cast("_Bool", 2))

    def test_use_own_bool(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""typedef int bool;""")

    def test_ordering_bug1(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo_s {
                struct bar_s *p;
            };
            struct bar_s {
                struct foo_s foo;
            };
        """)
        q = ffi.new("struct foo_s *")
        bar = ffi.new("struct bar_s *")
        q.p = bar
        assert q.p.foo.p == ffi.NULL

    def test_ordering_bug2(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct bar_s;

            struct foo_s {
                void (*foo)(struct bar_s[]);
            };

            struct bar_s {
                struct foo_s foo;
            };
        """)
        q = ffi.new("struct foo_s *")

    def test_addressof(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int x, y; };")
        p = ffi.new("struct foo_s *")
        a = ffi.addressof(p[0])
        assert repr(a).startswith("<cdata 'struct foo_s *' 0x")
        assert a == p
        pytest.raises(TypeError, ffi.addressof, p)
        pytest.raises((AttributeError, TypeError), ffi.addressof, 5)
        pytest.raises(TypeError, ffi.addressof, ffi.cast("int", 5))

    def test_addressof_field(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int x, y; };")
        p = ffi.new("struct foo_s *")
        a = ffi.addressof(p[0], 'y')
        assert repr(a).startswith("<cdata 'int *' 0x")
        assert int(ffi.cast("uintptr_t", a)) == (
            int(ffi.cast("uintptr_t", p)) + ffi.sizeof("int"))
        assert a == ffi.addressof(p, 'y')
        assert a != ffi.addressof(p, 'x')

    def test_addressof_field_nested(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int x, y; };"
                 "struct bar_s { struct foo_s a, b; };")
        p = ffi.new("struct bar_s *")
        pytest.raises(KeyError, ffi.addressof, p[0], 'b.y')
        a = ffi.addressof(p[0], 'b', 'y')
        assert int(ffi.cast("uintptr_t", a)) == (
            int(ffi.cast("uintptr_t", p)) +
            ffi.sizeof("struct foo_s") + ffi.sizeof("int"))

    def test_addressof_anonymous_struct(self):
        ffi = FFI()
        ffi.cdef("typedef struct { int x; } foo_t;")
        p = ffi.new("foo_t *")
        a = ffi.addressof(p[0])
        assert a == p

    def test_addressof_array(self):
        ffi = FFI()
        p = ffi.new("int[52]")
        p0 = ffi.addressof(p)
        assert p0 == p
        assert ffi.typeof(p0) is ffi.typeof("int(*)[52]")
        pytest.raises(TypeError, ffi.addressof, p0)
        #
        p1 = ffi.addressof(p, 25)
        assert ffi.typeof(p1) is ffi.typeof("int *")
        assert (p1 - p) == 25
        assert ffi.addressof(p, 0) == p

    def test_addressof_pointer(self):
        ffi = FFI()
        array = ffi.new("int[50]")
        p = ffi.cast("int *", array)
        pytest.raises(TypeError, ffi.addressof, p)
        assert ffi.addressof(p, 0) == p
        assert ffi.addressof(p, 25) == p + 25
        assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
        #
        ffi.cdef("struct foo { int a, b; };")
        array = ffi.new("struct foo[50]")
        p = ffi.cast("int *", array)
        pytest.raises(TypeError, ffi.addressof, p)
        assert ffi.addressof(p, 0) == p
        assert ffi.addressof(p, 25) == p + 25
        assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)

    def test_addressof_array_in_struct(self):
        ffi = FFI()
        ffi.cdef("struct foo { int a, b; int c[50]; };")
        p = ffi.new("struct foo *")
        p1 = ffi.addressof(p, "c", 25)
        assert ffi.typeof(p1) is ffi.typeof("int *")
        assert p1 == ffi.cast("int *", p) + 27
        assert ffi.addressof(p, "c") == ffi.cast("int *", p) + 2
        assert ffi.addressof(p, "c", 0) == ffi.cast("int *", p) + 2
        p2 = ffi.addressof(p, 1)
        assert ffi.typeof(p2) is ffi.typeof("struct foo *")
        assert p2 == p + 1

    def test_multiple_independent_structs(self):
        ffi1 = FFI(); ffi1.cdef("struct foo { int x; };")
        ffi2 = FFI(); ffi2.cdef("struct foo { int y, z; };")
        foo1 = ffi1.new("struct foo *", [10])
        foo2 = ffi2.new("struct foo *", [20, 30])
        assert foo1.x == 10
        assert foo2.y == 20
        assert foo2.z == 30

    def test_missing_include(self):
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi2 = FFI(backend=backend)
        ffi1.cdef("typedef signed char schar_t;")
        pytest.raises(CDefError, ffi2.cast, "schar_t", 142)

    def test_include_typedef(self):
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi2 = FFI(backend=backend)
        ffi1.cdef("typedef signed char schar_t;")
        ffi2.include(ffi1)
        p = ffi2.cast("schar_t", 142)
        assert int(p) == 142 - 256

    def test_include_struct(self):
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi2 = FFI(backend=backend)
        ffi1.cdef("struct foo { int x; };")
        ffi2.include(ffi1)
        p = ffi2.new("struct foo *", [142])
        assert p.x == 142

    def test_include_union(self):
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi2 = FFI(backend=backend)
        ffi1.cdef("union foo { int x; };")
        ffi2.include(ffi1)
        p = ffi2.new("union foo *", [142])
        assert p.x == 142

    def test_include_enum(self):
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi2 = FFI(backend=backend)
        ffi1.cdef("enum foo { FA, FB, FC };")
        ffi2.include(ffi1)
        p = ffi2.cast("enum foo", 1)
        assert ffi2.string(p) == "FB"
        assert ffi2.sizeof("char[FC]") == 2

    def test_include_typedef_2(self):
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi2 = FFI(backend=backend)
        ffi1.cdef("typedef struct { int x; } *foo_p;")
        ffi2.include(ffi1)
        p = ffi2.new("foo_p", [142])
        assert p.x == 142

    def test_ignore_multiple_declarations_of_constant(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("#define FOO 42")
        ffi.cdef("#define FOO 42")
        pytest.raises(FFIError, ffi.cdef, "#define FOO 43")

    def test_struct_packed(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct nonpacked { char a; int b; };")
        ffi.cdef("struct is_packed { char a; int b; };", packed=True)
        ffi.cdef("struct is_packed1 { char a; int b; };", pack=1)
        ffi.cdef("struct is_packed2 { char a; int b; };", pack=2)
        ffi.cdef("struct is_packed4 { char a; int b; };", pack=4)
        ffi.cdef("struct is_packed8 { char a; int b; };", pack=8)
        assert ffi.sizeof("struct nonpacked") == 8
        assert ffi.sizeof("struct is_packed") == 5
        assert ffi.sizeof("struct is_packed1") == 5
        assert ffi.sizeof("struct is_packed2") == 6
        assert ffi.sizeof("struct is_packed4") == 8
        assert ffi.sizeof("struct is_packed8") == 8
        assert ffi.alignof("struct nonpacked") == 4
        assert ffi.alignof("struct is_packed") == 1
        assert ffi.alignof("struct is_packed1") == 1
        assert ffi.alignof("struct is_packed2") == 2
        assert ffi.alignof("struct is_packed4") == 4
        assert ffi.alignof("struct is_packed8") == 4
        for name in ['is_packed', 'is_packed1', 'is_packed2',
                     'is_packed4', 'is_packed8']:
            s = ffi.new("struct %s[2]" % name)
            s[0].b = 42623381
            s[0].a = b'X'
            s[1].b = -4892220
            s[1].a = b'Y'
            assert s[0].b == 42623381
            assert s[0].a == b'X'
            assert s[1].b == -4892220
            assert s[1].a == b'Y'

    def test_pack_valueerror(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(ValueError, ffi.cdef, "", pack=3)
        pytest.raises(ValueError, ffi.cdef, "", packed=2)
        pytest.raises(ValueError, ffi.cdef, "", packed=True, pack=1)

    def test_define_integer_constant(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            #define DOT_0 0
            #define DOT 100
            #define DOT_OCT 0100l
            #define DOT_HEX 0x100u
            #define DOT_HEX2 0X10
            #define DOT_UL 1000UL
            enum foo {AA, BB=DOT, CC};
        """)
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        assert ffi.string(ffi.cast("enum foo", 100)) == "BB"
        assert lib.DOT_0 == 0
        assert lib.DOT == 100
        assert lib.DOT_OCT == 0o100
        assert lib.DOT_HEX == 0x100
        assert lib.DOT_HEX2 == 0x10
        assert lib.DOT_UL == 1000

    def test_opaque_struct_becomes_nonopaque(self):
        # Issue #193: if we use a struct between the first cdef() where it is
        # declared and another cdef() where its fields are defined, then the
        # definition was ignored.
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s;")
        pytest.raises(TypeError, ffi.new, "struct foo_s *")
        ffi.cdef("struct foo_s { int x; };")
        ffi.new("struct foo_s *")

    def test_ffi_self_include(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(ValueError, ffi.include, ffi)

    def test_anonymous_enum_include(self):
        ffi1 = FFI()
        ffi1.cdef("enum { EE1 };")
        ffi = FFI()
        ffi.include(ffi1)
        ffi.cdef("enum { EE2, EE3 };")
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        assert lib.EE1 == 0
        assert lib.EE2 == 0
        assert lib.EE3 == 1

    def test_init_once(self):
        def do_init():
            seen.append(1)
            return 42
        ffi = FFI()
        seen = []
        for i in range(3):
            res = ffi.init_once(do_init, "tag1")
            assert res == 42
            assert seen == [1]
        for i in range(3):
            res = ffi.init_once(do_init, "tag2")
            assert res == 42
            assert seen == [1, 1]

    def test_init_once_multithread(self):
        import sys, time
        if sys.version_info < (3,):
            import thread
        else:
            import _thread as thread
        #
        def do_init():
            seen.append('init!')
            time.sleep(1)
            seen.append('init done')
            return 7
        ffi = FFI()
        seen = []
        for i in range(6):
            def f():
                res = ffi.init_once(do_init, "tag")
                seen.append(res)
            thread.start_new_thread(f, ())
        time.sleep(1.5)
        assert seen == ['init!', 'init done'] + 6 * [7]

    def test_sizeof_struct_directly(self):
        # only works with the Python FFI instances
        ffi = FFI(backend=self.Backend())
        assert ffi.sizeof("struct{int a;}") == ffi.sizeof("int")

    def test_callback_large_struct(self):
        ffi = FFI(backend=self.Backend())
        # more than 8 bytes
        ffi.cdef("struct foo_s { unsigned long a, b, c; };")
        #
        @ffi.callback("void(struct foo_s)")
        def cb(s):
            seen.append(ffi.typeof(s))
            s.a += 1
            s.b += 2
            s.c += 3
            seen.append(s.a)
            seen.append(s.b)
            seen.append(s.c)
        #
        s1 = ffi.new("struct foo_s *", {'a': 100, 'b': 200, 'c': 300})
        seen = []
        cb(s1[0])
        assert len(seen) == 4
        assert s1.a == 100     # unmodified
        assert s1.b == 200
        assert s1.c == 300
        assert seen[0] == ffi.typeof("struct foo_s")
        assert seen[1] == 101
        assert seen[2] == 202
        assert seen[3] == 303

    def test_ffi_array_as_init(self):
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int[4]", [10, 20, 30, 400])
        q = ffi.new("int[4]", p)
        assert list(q) == [10, 20, 30, 400]
        pytest.raises(TypeError, ffi.new, "int[3]", p)
        pytest.raises(TypeError, ffi.new, "int[5]", p)
        pytest.raises(TypeError, ffi.new, "int16_t[4]", p)
        s = ffi.new("struct {int i[4];}*", {'i': p})
        assert list(s.i) == [10, 20, 30, 400]

    def test_too_many_initializers(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(IndexError, ffi.new, "int[4]", [10, 20, 30, 40, 50])

testing/cffi0/backend_tests.py
python-cffi/cffi
from cffi import FFI

class FakeBackend(object):

    def nonstandard_integer_types(self):
        return {}

    def sizeof(self, name):
        return 1

    def load_library(self, path):
        return "fake library"

    def new_primitive_type(self, name):
        return FakeType("primitive " + name)

    def new_void_type(self):
        return FakeType("void")
    def new_pointer_type(self, x):
        return FakeType('ptr-to-%r' % (x,))
    def new_array_type(self, x, y):
        return FakeType('array-from-%r-len-%r' % (x, y))
    def cast(self, x, y):
        return 'casted!'
    def _get_types(self):
        return "CData", "CType"

    buffer = "buffer type"


class FakeType(object):
    def __init__(self, cdecl):
        self.cdecl = cdecl


def test_typeof():
    ffi = FFI(backend=FakeBackend())
    clong = ffi.typeof("signed long int")
    assert isinstance(clong, FakeType)
    assert clong.cdecl == 'primitive long'

testing/cffi0/test_cdata.py
python-cffi/cffi
import sys
import pytest
from testing.cffi0 import backend_tests
from cffi.backend_ctypes import CTypesBackend


class TestCTypes(backend_tests.BackendTests):
    # for individual tests see
    # ====> backend_tests.py
    
    Backend = CTypesBackend
    TypeRepr = "<class 'ffi.CData<%s>'>"

    def test_array_of_func_ptr(self):
        pytest.skip("ctypes backend: not supported: "
                     "initializers for function pointers")

    def test_structptr_argument(self):
        pytest.skip("ctypes backend: not supported: passing a list "
                     "for a pointer argument")

    def test_array_argument_as_list(self):
        pytest.skip("ctypes backend: not supported: passing a list "
                     "for a pointer argument")

    def test_cast_to_array_type(self):
        pytest.skip("ctypes backend: not supported: casting to array")

    def test_nested_anonymous_struct(self):
        pytest.skip("ctypes backend: not supported: nested anonymous struct")

    def test_nested_field_offset_align(self):
        pytest.skip("ctypes backend: not supported: nested anonymous struct")

    def test_nested_anonymous_union(self):
        pytest.skip("ctypes backend: not supported: nested anonymous union")

    def test_nested_anonymous_struct_2(self):
        pytest.skip("ctypes backend: not supported: nested anonymous union")

    def test_CData_CType_2(self):
        if sys.version_info >= (3,):
            pytest.skip("ctypes backend: not supported in Python 3: CType")
        backend_tests.BackendTests.test_CData_CType_2(self)

testing/cffi0/test_ctypes.py
python-cffi/cffi
import sys, platform
import pytest
from testing.cffi0 import backend_tests, test_function, test_ownlib
from testing.support import u
from cffi import FFI
import _cffi_backend


class TestFFI(backend_tests.BackendTests,
              test_function.TestFunction,
              test_ownlib.TestOwnLib):
    TypeRepr = "<ctype '%s'>"

    @staticmethod
    def Backend():
        return _cffi_backend

    def test_not_supported_bitfield_in_result(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("struct foo_s { int a,b,c,d,e; int x:1; };")
        e = pytest.raises(NotImplementedError, ffi.callback,
                           "struct foo_s foo(void)", lambda: 42)
        assert str(e.value) == ("struct foo_s(*)(): "
            "callback with unsupported argument or return type or with '...'")

    def test_inspecttype(self):
        ffi = FFI(backend=self.Backend())
        assert ffi.typeof("long").kind == "primitive"
        assert ffi.typeof("long(*)(long, long**, ...)").cname == (
            "long(*)(long, long * *, ...)")
        assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True

    def test_new_handle(self):
        ffi = FFI(backend=self.Backend())
        o = [2, 3, 4]
        p = ffi.new_handle(o)
        assert ffi.typeof(p) == ffi.typeof("void *")
        assert ffi.from_handle(p) is o
        assert ffi.from_handle(ffi.cast("char *", p)) is o
        pytest.raises(RuntimeError, ffi.from_handle, ffi.NULL)

    def test_callback_onerror(self):
        ffi = FFI(backend=self.Backend())
        seen = []
        def oops(*args):
            seen.append(args)
        def otherfunc():
            raise LookupError
        def cb(n):
            otherfunc()
        a = ffi.callback("int(*)(int)", cb, error=42, onerror=oops)
        res = a(234)
        assert res == 42
        assert len(seen) == 1
        exc, val, tb = seen[0]
        assert exc is LookupError
        assert isinstance(val, LookupError)
        assert tb.tb_frame.f_code.co_name == 'cb'
        assert tb.tb_frame.f_locals['n'] == 234

    def test_ffi_new_allocator_2(self):
        ffi = FFI(backend=self.Backend())
        seen = []
        def myalloc(size):
            seen.append(size)
            return ffi.new("char[]", b"X" * size)
        def myfree(raw):
            seen.append(raw)
        alloc1 = ffi.new_allocator(myalloc, myfree)
        alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree,
                                   should_clear_after_alloc=False)
        p1 = alloc1("int[10]")
        p2 = alloc2("int[]", 10)
        assert seen == [40, 40]
        assert ffi.typeof(p1) == ffi.typeof("int[10]")
        assert ffi.sizeof(p1) == 40
        assert ffi.typeof(p2) == ffi.typeof("int[]")
        assert ffi.sizeof(p2) == 40
        assert p1[5] == 0
        assert p2[6] == ord('X') * 0x01010101
        raw1 = ffi.cast("char *", p1)
        raw2 = ffi.cast("char *", p2)
        del p1, p2
        retries = 0
        while len(seen) != 4:
            retries += 1
            assert retries <= 5
            import gc; gc.collect()
        assert seen == [40, 40, raw1, raw2]
        assert repr(seen[2]) == "<cdata 'char[]' owning 41 bytes>"
        assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>"

    def test_ffi_new_allocator_3(self):
        ffi = FFI(backend=self.Backend())
        seen = []
        def myalloc(size):
            seen.append(size)
            return ffi.new("char[]", b"X" * size)
        alloc1 = ffi.new_allocator(myalloc)    # no 'free'
        p1 = alloc1("int[10]")
        assert seen == [40]
        assert ffi.typeof(p1) == ffi.typeof("int[10]")
        assert ffi.sizeof(p1) == 40
        assert p1[5] == 0

    def test_ffi_new_allocator_4(self):
        ffi = FFI(backend=self.Backend())
        pytest.raises(TypeError, ffi.new_allocator, free=lambda x: None)
        #
        def myalloc2(size):
            raise LookupError
        alloc2 = ffi.new_allocator(myalloc2)
        pytest.raises(LookupError, alloc2, "int[5]")
        #
        def myalloc3(size):
            return 42
        alloc3 = ffi.new_allocator(myalloc3)
        e = pytest.raises(TypeError, alloc3, "int[5]")
        assert str(e.value) == "alloc() must return a cdata object (got int)"
        #
        def myalloc4(size):
            return ffi.cast("int", 42)
        alloc4 = ffi.new_allocator(myalloc4)
        e = pytest.raises(TypeError, alloc4, "int[5]")
        assert str(e.value) == "alloc() must return a cdata pointer, not 'int'"
        #
        def myalloc5(size):
            return ffi.NULL
        alloc5 = ffi.new_allocator(myalloc5)
        pytest.raises(MemoryError, alloc5, "int[5]")

    def test_new_struct_containing_struct_containing_array_varsize(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo_s { int len[100]; short data[]; };
            struct bar_s { int abc[100]; struct foo_s tail; };
        """)
        # loop to try to detect heap overwrites, if the size allocated
        # is too small
        for i in range(1, 501, 100):
            p = ffi.new("struct bar_s *", [[10], [[20], [3,4,5,6,7,8,9] * i]])
            assert p.abc[0] == 10
            assert p.tail.len[0] == 20
            assert p.tail.data[0] == 3
            assert p.tail.data[6] == 9
            assert p.tail.data[7 * i - 1] == 9

    def test_bogus_struct_containing_struct_containing_array_varsize(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct foo_s { signed char len; signed char data[]; };
            struct bar_s { struct foo_s foo; int bcd; };
        """)
        p = ffi.new("struct bar_s *", [[123, [45, 56, 67, 78]], 9999999])
        assert p.foo.len == 123
        assert p.foo.data[0] == 45
        assert p.foo.data[1] == 56
        assert p.foo.data[2] == 67
        assert p.bcd == 9999999
        assert p.foo.data[3] != 78   # has been overwritten with 9999999

    def test_issue553(self):
        import gc, warnings
        ffi = FFI(backend=self.Backend())
        p = ffi.new("int *", 123)
        with warnings.catch_warnings(record=True) as w:
            ffi.gc(p, lambda x: None)
            gc.collect()
        assert w == []

    def test_issue553_from_buffer(self):
        import gc, warnings
        ffi = FFI(backend=self.Backend())
        buf = b"123"
        with warnings.catch_warnings(record=True) as w:
            ffi.from_buffer(buf)
            gc.collect()
        assert w == []


class TestBitfield:
    def check(self, source, expected_ofs_y, expected_align, expected_size):
        # NOTE: 'expected_*' is the numbers expected from GCC.
        # The numbers expected from MSVC are not explicitly written
        # in this file, and will just be taken from the compiler.
        ffi = FFI()
        ffi.cdef("struct s1 { %s };" % source)
        ctype = ffi.typeof("struct s1")
        # verify the information with gcc
        ffi1 = FFI()
        ffi1.cdef("""
            static const int Gofs_y, Galign, Gsize;
            struct s1 *try_with_value(int fieldnum, long long value);
        """)
        fnames = [name for name, cfield in ctype.fields
                       if name and cfield.bitsize > 0]
        setters = ['case %d: s.%s = value; break;' % iname
                   for iname in enumerate(fnames)]
        lib = ffi1.verify("""
            #include <string.h>
            struct s1 { %s };
            struct sa { char a; struct s1 b; };
            #define Gofs_y  offsetof(struct s1, y)
            #define Galign  offsetof(struct sa, b)
            #define Gsize   sizeof(struct s1)
            struct s1 *try_with_value(int fieldnum, long long value)
            {
                static struct s1 s;
                memset(&s, 0, sizeof(s));
                switch (fieldnum) { %s }
                return &s;
            }
        """ % (source, ' '.join(setters)))
        if sys.platform == 'win32':
            expected_ofs_y = lib.Gofs_y
            expected_align = lib.Galign
            expected_size  = lib.Gsize
        else:
            assert (lib.Gofs_y, lib.Galign, lib.Gsize) == (
                expected_ofs_y, expected_align, expected_size)
        # the real test follows
        assert ffi.offsetof("struct s1", "y") == expected_ofs_y
        assert ffi.alignof("struct s1") == expected_align
        assert ffi.sizeof("struct s1") == expected_size
        # compare the actual storage of the two
        for name, cfield in ctype.fields:
            if cfield.bitsize < 0 or not name:
                continue
            if int(ffi.cast(cfield.type, -1)) == -1:   # signed
                min_value = -(1 << (cfield.bitsize-1))
                max_value = (1 << (cfield.bitsize-1)) - 1
            else:
                min_value = 0
                max_value = (1 << cfield.bitsize) - 1
            for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729,
                     -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]:
                if min_value <= t <= max_value:
                    self._fieldcheck(ffi, lib, fnames, name, t)

    def _fieldcheck(self, ffi, lib, fnames, name, value):
        s = ffi.new("struct s1 *")
        setattr(s, name, value)
        assert getattr(s, name) == value
        raw1 = ffi.buffer(s)[:]
        buff1 = ffi.buffer(s)
        t = lib.try_with_value(fnames.index(name), value)
        raw2 = ffi.buffer(t, len(raw1))[:]
        assert raw1 == raw2
        buff2 = ffi.buffer(t, len(buff1))
        assert buff1 == buff2

    def test_bitfield_basic(self):
        self.check("int a; int b:9; int c:20; int y;", 8, 4, 12)
        self.check("int a; short b:9; short c:7; int y;", 8, 4, 12)
        self.check("int a; short b:9; short c:9; int y;", 8, 4, 12)

    def test_bitfield_reuse_if_enough_space(self):
        self.check("int a:2; char y;", 1, 4, 4)
        self.check("int a:1; char b  ; int c:1; char y;", 3, 4, 4)
        self.check("int a:1; char b:8; int c:1; char y;", 3, 4, 4)
        self.check("char a; int b:9; char y;", 3, 4, 4)
        self.check("char a; short b:9; char y;", 4, 2, 6)
        self.check("int a:2; char b:6; char y;", 1, 4, 4)
        self.check("int a:2; char b:7; char y;", 2, 4, 4)
        self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8)
        self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4)

    @pytest.mark.skipif(
        "not (sys.platform == 'darwin' and platform.machine() == 'arm64')"
        " and "
        "platform.machine().startswith(('arm', 'aarch64'))")
    def test_bitfield_anonymous_no_align(self):
        L = FFI().alignof("long long")
        self.check("char y; int :1;", 0, 1, 2)
        self.check("char x; int z:1; char y;", 2, 4, 4)
        self.check("char x; int  :1; char y;", 2, 1, 3)
        self.check("char x; long long z:48; char y;", 7, L, 8)
        self.check("char x; long long  :48; char y;", 7, 1, 8)
        self.check("char x; long long z:56; char y;", 8, L, 8 + L)
        self.check("char x; long long  :56; char y;", 8, 1, 9)
        self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
        self.check("char x; long long  :57; char y;", L + 8, 1, L + 9)

    @pytest.mark.skipif(
        "(sys.platform == 'darwin' and platform.machine() == 'arm64')"
        " or "
        "not platform.machine().startswith(('arm', 'aarch64'))")
    def test_bitfield_anonymous_align_arm(self):
        L = FFI().alignof("long long")
        self.check("char y; int :1;", 0, 4, 4)
        self.check("char x; int z:1; char y;", 2, 4, 4)
        self.check("char x; int  :1; char y;", 2, 4, 4)
        self.check("char x; long long z:48; char y;", 7, L, 8)
        self.check("char x; long long  :48; char y;", 7, 8, 8)
        self.check("char x; long long z:56; char y;", 8, L, 8 + L)
        self.check("char x; long long  :56; char y;", 8, L, 8 + L)
        self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
        self.check("char x; long long  :57; char y;", L + 8, L, L + 8 + L)

    @pytest.mark.skipif(
        "not (sys.platform == 'darwin' and platform.machine() == 'arm64')"
        " and "
        "platform.machine().startswith(('arm', 'aarch64'))")
    def test_bitfield_zero(self):
        L = FFI().alignof("long long")
        self.check("char y; int :0;", 0, 1, 4)
        self.check("char x; int :0; char y;", 4, 1, 5)
        self.check("char x; int :0; int :0; char y;", 4, 1, 5)
        self.check("char x; long long :0; char y;", L, 1, L + 1)
        self.check("short x, y; int :0; int :0;", 2, 2, 4)
        self.check("char x; int :0; short b:1; char y;", 5, 2, 6)
        self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8)

    @pytest.mark.skipif(
        "(sys.platform == 'darwin' and platform.machine() == 'arm64')"
        " or "
        "not platform.machine().startswith(('arm', 'aarch64'))")
    def test_bitfield_zero_arm(self):
        L = FFI().alignof("long long")
        self.check("char y; int :0;", 0, 4, 4)
        self.check("char x; int :0; char y;", 4, 4, 8)
        self.check("char x; int :0; int :0; char y;", 4, 4, 8)
        self.check("char x; long long :0; char y;", L, 8, L + 8)
        self.check("short x, y; int :0; int :0;", 2, 4, 4)
        self.check("char x; int :0; short b:1; char y;", 5, 4, 8)
        self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8)

    def test_error_cases(self):
        ffi = FFI()
        ffi.cdef("struct s1 { float x:1; };")
        with pytest.raises(TypeError):
            ffi.new("struct s1 *")
        ffi.cdef("struct s2 { char x:0; };")
        with pytest.raises(TypeError):
            ffi.new("struct s2 *")
        ffi.cdef("struct s3 { char x:9; };")
        with pytest.raises(TypeError):
            ffi.new("struct s3 *")

    def test_struct_with_typedef(self):
        ffi = FFI()
        ffi.cdef("typedef struct { float x; } foo_t;")
        p = ffi.new("foo_t *", [5.2])
        assert repr(p).startswith("<cdata 'foo_t *' ")

    def test_struct_array_no_length(self):
        ffi = FFI()
        ffi.cdef("struct foo_s { int x; int a[]; };")
        p = ffi.new("struct foo_s *", [100, [200, 300, 400]])
        assert p.x == 100
        assert ffi.typeof(p.a) is ffi.typeof("int[]")
        assert len(p.a) == 3                            # length recorded
        assert p.a[0] == 200
        assert p.a[1] == 300
        assert p.a[2] == 400
        assert list(p.a) == [200, 300, 400]
        q = ffi.cast("struct foo_s *", p)
        assert q.x == 100
        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length recorded
        pytest.raises(TypeError, len, q.a)
        assert q.a[0] == 200
        assert q.a[1] == 300
        assert q.a[2] == 400
        pytest.raises(TypeError, list, q.a)

    @pytest.mark.skipif("sys.platform != 'win32'")
    def test_getwinerror(self):
        ffi = FFI()
        code, message = ffi.getwinerror(1155)
        assert code == 1155
        assert message == ("No application is associated with the "
                           "specified file for this operation")
        ffi.cdef("void SetLastError(int);")
        lib = ffi.dlopen("Kernel32.dll")
        lib.SetLastError(2)
        code, message = ffi.getwinerror()
        assert code == 2
        assert message == "The system cannot find the file specified"
        code, message = ffi.getwinerror(-1)
        assert code == 2
        assert message == "The system cannot find the file specified"

    def test_from_buffer(self):
        import array
        ffi = FFI()
        a = array.array('H', [10000, 20000, 30000])
        c = ffi.from_buffer(a)
        assert ffi.typeof(c) is ffi.typeof("char[]")
        assert len(c) == 6
        ffi.cast("unsigned short *", c)[1] += 500
        assert list(a) == [10000, 20500, 30000]
        assert c == ffi.from_buffer("char[]", a, True)
        assert c == ffi.from_buffer(a, require_writable=True)
        #
        c = ffi.from_buffer("unsigned short[]", a)
        assert len(c) == 3
        assert c[1] == 20500
        #
        p = ffi.from_buffer(b"abcd")
        assert p[2] == b"c"
        #
        assert p == ffi.from_buffer(b"abcd", require_writable=False)
        pytest.raises((TypeError, BufferError), ffi.from_buffer,
                                                 "char[]", b"abcd", True)
        pytest.raises((TypeError, BufferError), ffi.from_buffer, b"abcd",
                                                 require_writable=True)

    def test_release(self):
        ffi = FFI()
        p = ffi.new("int[]", 123)
        ffi.release(p)
        # here, reading p[0] might give garbage or segfault...
        ffi.release(p)   # no effect

    def test_memmove(self):
        ffi = FFI()
        p = ffi.new("short[]", [-1234, -2345, -3456, -4567, -5678])
        ffi.memmove(p, p + 1, 4)
        assert list(p) == [-2345, -3456, -3456, -4567, -5678]
        p[2] = 999
        ffi.memmove(p + 2, p, 6)
        assert list(p) == [-2345, -3456, -2345, -3456, 999]
        ffi.memmove(p + 4, ffi.new("char[]", b"\x71\x72"), 2)
        if sys.byteorder == 'little':
            assert list(p) == [-2345, -3456, -2345, -3456, 0x7271]
        else:
            assert list(p) == [-2345, -3456, -2345, -3456, 0x7172]

    def test_memmove_buffer(self):
        import array
        ffi = FFI()
        a = array.array('H', [10000, 20000, 30000])
        p = ffi.new("short[]", 5)
        ffi.memmove(p, a, 6)
        assert list(p) == [10000, 20000, 30000, 0, 0]
        ffi.memmove(p + 1, a, 6)
        assert list(p) == [10000, 10000, 20000, 30000, 0]
        b = array.array('h', [-1000, -2000, -3000])
        ffi.memmove(b, a, 4)
        assert b.tolist() == [10000, 20000, -3000]
        assert a.tolist() == [10000, 20000, 30000]
        p[0] = 999
        p[1] = 998
        p[2] = 997
        p[3] = 996
        p[4] = 995
        ffi.memmove(b, p, 2)
        assert b.tolist() == [999, 20000, -3000]
        ffi.memmove(b, p + 2, 4)
        assert b.tolist() == [997, 996, -3000]
        p[2] = -p[2]
        p[3] = -p[3]
        ffi.memmove(b, p + 2, 6)
        assert b.tolist() == [-997, -996, 995]

    def test_memmove_readonly_readwrite(self):
        ffi = FFI()
        p = ffi.new("signed char[]", 5)
        ffi.memmove(p, b"abcde", 3)
        assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0]
        ffi.memmove(p, bytearray(b"ABCDE"), 2)
        assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0]
        pytest.raises((TypeError, BufferError), ffi.memmove, b"abcde", p, 3)
        ba = bytearray(b"xxxxx")
        ffi.memmove(dest=ba, src=p, n=3)
        assert ba == bytearray(b"ABcxx")

    def test_all_primitives(self):
        ffi = FFI()
        for name in [
            "char",
            "short",
            "int",
            "long",
            "long long",
            "signed char",
            "unsigned char",
            "unsigned short",
            "unsigned int",
            "unsigned long",
            "unsigned long long",
            "float",
            "double",
            "long double",
            "wchar_t",
            "char16_t",
            "char32_t",
            "_Bool",
            "int8_t",
            "uint8_t",
            "int16_t",
            "uint16_t",
            "int32_t",
            "uint32_t",
            "int64_t",
            "uint64_t",
            "int_least8_t",
            "uint_least8_t",
            "int_least16_t",
            "uint_least16_t",
            "int_least32_t",
            "uint_least32_t",
            "int_least64_t",
            "uint_least64_t",
            "int_fast8_t",
            "uint_fast8_t",
            "int_fast16_t",
            "uint_fast16_t",
            "int_fast32_t",
            "uint_fast32_t",
            "int_fast64_t",
            "uint_fast64_t",
            "intptr_t",
            "uintptr_t",
            "intmax_t",
            "uintmax_t",
            "ptrdiff_t",
            "size_t",
            "ssize_t",
            ]:
            x = ffi.sizeof(name)
            assert 1 <= x <= 16

    def test_ffi_def_extern(self):
        ffi = FFI()
        pytest.raises(ValueError, ffi.def_extern)

    def test_introspect_typedef(self):
        ffi = FFI()
        ffi.cdef("typedef int foo_t;")
        assert ffi.list_types() == (['foo_t'], [], [])
        assert ffi.typeof('foo_t').kind == 'primitive'
        assert ffi.typeof('foo_t').cname == 'int'
        #
        ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;")
        assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'foo_t', 'g_t'],
                                    [], [])

    def test_introspect_struct(self):
        ffi = FFI()
        ffi.cdef("struct foo_s { int a; };")
        assert ffi.list_types() == ([], ['foo_s'], [])
        assert ffi.typeof('struct foo_s').kind == 'struct'
        assert ffi.typeof('struct foo_s').cname == 'struct foo_s'

    def test_introspect_union(self):
        ffi = FFI()
        ffi.cdef("union foo_s { int a; };")
        assert ffi.list_types() == ([], [], ['foo_s'])
        assert ffi.typeof('union foo_s').kind == 'union'
        assert ffi.typeof('union foo_s').cname == 'union foo_s'

    def test_introspect_struct_and_typedef(self):
        ffi = FFI()
        ffi.cdef("typedef struct { int a; } foo_t;")
        assert ffi.list_types() == (['foo_t'], [], [])
        assert ffi.typeof('foo_t').kind == 'struct'
        assert ffi.typeof('foo_t').cname == 'foo_t'

    def test_introspect_included_type(self):
        ffi1 = FFI()
        ffi2 = FFI()
        ffi1.cdef("typedef signed char schar_t; struct sint_t { int x; };")
        ffi2.include(ffi1)
        assert ffi1.list_types() == ffi2.list_types() == (
            ['schar_t'], ['sint_t'], [])

    def test_introspect_order(self):
        ffi = FFI()
        ffi.cdef("union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;")
        ffi.cdef("union CFFIg   { int a; }; typedef struct CFFIcc  { int a; } CFFIbbb;")
        ffi.cdef("union CFFIaa  { int a; }; typedef struct CFFIa   { int a; } CFFIbb;")
        assert ffi.list_types() == (['CFFIb', 'CFFIbb', 'CFFIbbb'],
                                    ['CFFIa', 'CFFIcc', 'CFFIccc'],
                                    ['CFFIaa', 'CFFIaaa', 'CFFIg'])

    def test_unpack(self):
        ffi = FFI()
        p = ffi.new("char[]", b"abc\x00def")
        assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
        p = ffi.new("int[]", [-123456789])
        assert ffi.unpack(p, 1) == [-123456789]

    def test_negative_array_size(self):
        ffi = FFI()
        pytest.raises(ValueError, ffi.cast, "int[-5]", 0)

    def test_cannot_instantiate_manually(self):
        ffi = FFI()
        ct = type(ffi.typeof("void *"))
        pytest.raises(TypeError, ct)
        pytest.raises(TypeError, ct, ffi.NULL)
        for cd in [type(ffi.cast("void *", 0)),
                   type(ffi.new("char[]", 3)),
                   type(ffi.gc(ffi.NULL, lambda x: None))]:
            pytest.raises(TypeError, cd)
            pytest.raises(TypeError, cd, ffi.NULL)
            pytest.raises(TypeError, cd, ffi.typeof("void *"))

    def test_explicitly_defined_char16_t(self):
        ffi = FFI()
        ffi.cdef("typedef uint16_t char16_t;")
        x = ffi.cast("char16_t", 1234)
        assert ffi.typeof(x) is ffi.typeof("uint16_t")

    def test_char16_t(self):
        ffi = FFI()
        x = ffi.new("char16_t[]", 5)
        assert len(x) == 5 and ffi.sizeof(x) == 10
        x[2] = u+'\u1324'
        assert x[2] == u+'\u1324'
        y = ffi.new("char16_t[]", u+'\u1234\u5678')
        assert len(y) == 3
        assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
        assert ffi.string(y) == u+'\u1234\u5678'
        z = ffi.new("char16_t[]", u+'\U00012345')
        assert len(z) == 3
        assert list(z) == [u+'\ud808', u+'\udf45', u+'\x00']
        assert ffi.string(z) == u+'\U00012345'

    def test_char32_t(self):
        ffi = FFI()
        x = ffi.new("char32_t[]", 5)
        assert len(x) == 5 and ffi.sizeof(x) == 20
        x[3] = u+'\U00013245'
        assert x[3] == u+'\U00013245'
        y = ffi.new("char32_t[]", u+'\u1234\u5678')
        assert len(y) == 3
        assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
        py_uni = u+'\U00012345'
        z = ffi.new("char32_t[]", py_uni)
        assert len(z) == 2
        assert list(z) == [py_uni, u+'\x00']    # maybe a 2-unichars string
        assert ffi.string(z) == py_uni
        if len(py_uni) == 1:    # 4-bytes unicodes in Python
            s = ffi.new("char32_t[]", u+'\ud808\udf00')
            assert len(s) == 3
            assert list(s) == [u+'\ud808', u+'\udf00', u+'\x00']

testing/cffi0/test_ffi_backend.py
python-cffi/cffi
import pytest
from cffi import FFI, CDefError
import math, os, sys
import ctypes.util
from cffi.backend_ctypes import CTypesBackend
from testing.udir import udir
from testing.support import FdWriteCapture, StdErrCapture, is_musl
from .backend_tests import needs_dlopen_none

try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

try:
    from packaging.tags import platform_tags
    _platform_tags_cached = set(platform_tags())
    _is_musl = any(t.startswith('musllinux') for t in _platform_tags_cached)
except ImportError:
    _is_musl = False

lib_m = 'm'
if sys.platform == 'win32':
    #there is a small chance this fails on Mingw via environ $CC
    import distutils.ccompiler
    if distutils.ccompiler.get_default_compiler() == 'msvc':
        lib_m = 'msvcrt'
elif is_musl:
    lib_m = 'c'

class TestFunction(object):
    Backend = CTypesBackend

    def test_sin(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            double sin(double x);
        """)
        m = ffi.dlopen(lib_m)
        x = m.sin(1.23)
        assert x == math.sin(1.23)

    def test_sinf(self):
        if sys.platform == 'win32':
            pytest.skip("no sinf found in the Windows stdlib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            float sinf(float x);
        """)
        m = ffi.dlopen(lib_m)
        x = m.sinf(1.23)
        assert type(x) is float
        assert x != math.sin(1.23)    # rounding effects
        assert abs(x - math.sin(1.23)) < 1E-6

    def test_getenv_no_return_value(self):
        # check that 'void'-returning functions work too
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            void getenv(char *);
        """)
        needs_dlopen_none()
        m = ffi.dlopen(None)
        x = m.getenv(b"FOO")
        assert x is None

    def test_dlopen_filename(self):
        path = ctypes.util.find_library(lib_m)
        if not path:
            pytest.skip("%s not found" % lib_m)
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            double cos(double x);
        """)
        m = ffi.dlopen(path)
        x = m.cos(1.23)
        assert x == math.cos(1.23)

        m = ffi.dlopen(os.path.basename(path))
        x = m.cos(1.23)
        assert x == math.cos(1.23)

    def test_dlopen_flags(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            double cos(double x);
        """)
        m = ffi.dlopen(lib_m, ffi.RTLD_LAZY | ffi.RTLD_LOCAL)
        x = m.cos(1.23)
        assert x == math.cos(1.23)

    def test_dlopen_constant(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            #define FOOBAR 42
            static const float baz = 42.5;   /* not visible */
            double sin(double x);
        """)
        m = ffi.dlopen(lib_m)
        assert m.FOOBAR == 42
        with pytest.raises(NotImplementedError):
            m.baz

    def test_tlsalloc(self):
        if sys.platform != 'win32':
            pytest.skip("win32 only")
        if self.Backend is CTypesBackend:
            pytest.skip("ctypes complains on wrong calling conv")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("long TlsAlloc(void); int TlsFree(long);")
        lib = ffi.dlopen('KERNEL32.DLL')
        x = lib.TlsAlloc()
        assert x != 0
        y = lib.TlsFree(x)
        assert y != 0

    def test_fputs(self):
        if not sys.platform.startswith('linux'):
            pytest.skip("probably no symbol 'stderr' in the lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int fputs(const char *, void *);
            extern void *stderr;
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        ffi.C.fputs   # fetch before capturing, for easier debugging
        with FdWriteCapture() as fd:
            ffi.C.fputs(b"hello\n", ffi.C.stderr)
            ffi.C.fputs(b"  world\n", ffi.C.stderr)
        res = fd.getvalue()
        assert res == b'hello\n  world\n'

    def test_fputs_without_const(self):
        if not sys.platform.startswith('linux'):
            pytest.skip("probably no symbol 'stderr' in the lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int fputs(char *, void *);
            extern void *stderr;
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        ffi.C.fputs   # fetch before capturing, for easier debugging
        with FdWriteCapture() as fd:
            ffi.C.fputs(b"hello\n", ffi.C.stderr)
            ffi.C.fputs(b"  world\n", ffi.C.stderr)
        res = fd.getvalue()
        assert res == b'hello\n  world\n'

    def test_vararg(self):
        if not sys.platform.startswith('linux'):
            pytest.skip("probably no symbol 'stderr' in the lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
           int fprintf(void *, const char *format, ...);
           extern void *stderr;
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        with FdWriteCapture() as fd:
            ffi.C.fprintf(ffi.C.stderr, b"hello with no arguments\n")
            ffi.C.fprintf(ffi.C.stderr,
                          b"hello, %s!\n", ffi.new("char[]", b"world"))
            ffi.C.fprintf(ffi.C.stderr,
                          ffi.new("char[]", b"hello, %s!\n"),
                          ffi.new("char[]", b"world2"))
            ffi.C.fprintf(ffi.C.stderr,
                          b"hello int %d long %ld long long %lld\n",
                          ffi.cast("int", 42),
                          ffi.cast("long", 84),
                          ffi.cast("long long", 168))
            ffi.C.fprintf(ffi.C.stderr, b"hello %p\n", ffi.NULL)
        res = fd.getvalue()
        if is_musl:
            nil_repr = b'0'
        else:
            nil_repr = b'(nil)'
        assert res == (b"hello with no arguments\n"
                       b"hello, world!\n"
                       b"hello, world2!\n"
                       b"hello int 42 long 84 long long 168\n"
                       b"hello " + nil_repr + b"\n")

    def test_must_specify_type_of_vararg(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
           int printf(const char *format, ...);
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        e = pytest.raises(TypeError, ffi.C.printf, b"hello %d\n", 42)
        assert str(e.value) == ("argument 2 passed in the variadic part "
                                "needs to be a cdata object (got int)")

    def test_function_has_a_c_type(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int puts(const char *);
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        fptr = ffi.C.puts
        assert ffi.typeof(fptr) == ffi.typeof("int(*)(const char*)")
        if self.Backend is CTypesBackend:
            assert repr(fptr).startswith("<cdata 'int puts(char *)' 0x")

    def test_function_pointer(self):
        ffi = FFI(backend=self.Backend())
        def cb(charp):
            assert repr(charp).startswith("<cdata 'char *' 0x")
            return 42
        fptr = ffi.callback("int(*)(const char *txt)", cb)
        assert fptr != ffi.callback("int(*)(const char *)", cb)
        assert repr(fptr) == "<cdata 'int(*)(char *)' calling %r>" % (cb,)
        res = fptr(b"Hello")
        assert res == 42
        #
        if not sys.platform.startswith('linux'):
            pytest.skip("probably no symbol 'stderr' in the lib")
        ffi.cdef("""
            int fputs(const char *, void *);
            extern void *stderr;
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        fptr = ffi.cast("int(*)(const char *txt, void *)", ffi.C.fputs)
        assert fptr == ffi.C.fputs
        assert repr(fptr).startswith("<cdata 'int(*)(char *, void *)' 0x")
        with FdWriteCapture() as fd:
            fptr(b"world\n", ffi.C.stderr)
        res = fd.getvalue()
        assert res == b'world\n'

    def test_callback_returning_void(self):
        ffi = FFI(backend=self.Backend())
        for returnvalue in [None, 42]:
            def cb():
                return returnvalue
            fptr = ffi.callback("void(*)(void)", cb)
            with StdErrCapture() as f:
                returned = fptr()
            printed = f.getvalue()
            assert returned is None
            if returnvalue is None:
                assert printed == ''
            else:
                assert "None" in printed

    def test_callback_returning_struct_three_bytes(self):
        if self.Backend is CTypesBackend:
            pytest.skip("not supported with the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef struct {
                unsigned char a, b, c;
            } THREEBYTES;
        """)
        def cb():
            return (12, 34, 56)
        fptr = ffi.callback("THREEBYTES(*)(void)", cb)
        tb = fptr()
        assert tb.a == 12
        assert tb.b == 34
        assert tb.c == 56

    def test_passing_array(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int strlen(char[]);
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        p = ffi.new("char[]", b"hello")
        res = ffi.C.strlen(p)
        assert res == 5

    def test_write_variable(self):
        if not sys.platform.startswith('linux') or _is_musl:
            pytest.skip("probably no symbol 'stdout' in the lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            extern void *stdout;
        """)
        needs_dlopen_none()
        C = ffi.dlopen(None)
        pout = C.stdout
        C.stdout = ffi.NULL
        assert C.stdout == ffi.NULL
        C.stdout = pout
        assert C.stdout == pout

    def test_strchr(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            char *strchr(const char *s, int c);
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        p = ffi.new("char[]", b"hello world!")
        q = ffi.C.strchr(p, ord('w'))
        assert ffi.string(q) == b"world!"

    def test_function_with_struct_argument(self):
        if sys.platform == 'win32':
            pytest.skip("no 'inet_ntoa'")
        if (self.Backend is CTypesBackend and
            '__pypy__' in sys.builtin_module_names):
            pytest.skip("ctypes limitation on pypy")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            struct in_addr { unsigned int s_addr; };
            char *inet_ntoa(struct in_addr in);
        """)
        needs_dlopen_none()
        ffi.C = ffi.dlopen(None)
        ina = ffi.new("struct in_addr *", [0x04040404])
        a = ffi.C.inet_ntoa(ina[0])
        assert ffi.string(a) == b'4.4.4.4'

    def test_function_typedef(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef double func_t(double);
            func_t sin;
        """)
        m = ffi.dlopen(lib_m)
        x = m.sin(1.23)
        assert x == math.sin(1.23)

    def test_fputs_custom_FILE(self):
        if self.Backend is CTypesBackend:
            pytest.skip("FILE not supported with the ctypes backend")
        filename = str(udir.join('fputs_custom_FILE'))
        ffi = FFI(backend=self.Backend())
        ffi.cdef("int fputs(const char *, FILE *);")
        needs_dlopen_none()
        C = ffi.dlopen(None)
        with open(filename, 'wb') as f:
            f.write(b'[')
            C.fputs(b"hello from custom file", f)
            f.write(b'][')
            C.fputs(b"some more output", f)
            f.write(b']')
        with open(filename, 'rb') as f:
            res = f.read()
        assert res == b'[hello from custom file][some more output]'

    def test_constants_on_lib(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""enum foo_e { AA, BB, CC=5, DD };
                    typedef enum { EE=-5, FF } some_enum_t;""")
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        assert lib.AA == 0
        assert lib.BB == 1
        assert lib.CC == 5
        assert lib.DD == 6
        assert lib.EE == -5
        assert lib.FF == -4

    def test_void_star_accepts_string(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""int strlen(const void *);""")
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        res = lib.strlen(b"hello")
        assert res == 5

    def test_signed_char_star_accepts_string(self):
        if self.Backend is CTypesBackend:
            pytest.skip("not supported by the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""int strlen(signed char *);""")
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        res = lib.strlen(b"hello")
        assert res == 5

    def test_unsigned_char_star_accepts_string(self):
        if self.Backend is CTypesBackend:
            pytest.skip("not supported by the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""int strlen(unsigned char *);""")
        needs_dlopen_none()
        lib = ffi.dlopen(None)
        res = lib.strlen(b"hello")
        assert res == 5

    def test_missing_function(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int nonexistent();
        """)
        m = ffi.dlopen(lib_m)
        assert not hasattr(m, 'nonexistent')

    def test_wraps_from_stdlib(self):
        import functools
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            double sin(double x);
        """)
        def my_decorator(f):
            @functools.wraps(f)
            def wrapper(*args):
                return f(*args) + 100
            return wrapper
        m = ffi.dlopen(lib_m)
        sin100 = my_decorator(m.sin)
        x = sin100(1.23)
        assert x == math.sin(1.23) + 100

    def test_free_callback_cycle(self):
        if self.Backend is CTypesBackend:
            pytest.skip("seems to fail with the ctypes backend on windows")
        import weakref
        def make_callback(data):
            container = [data]
            callback = ffi.callback('int()', lambda: len(container))
            container.append(callback)
            # Ref cycle: callback -> lambda (closure) -> container -> callback
            return callback

        class Data(object):
            pass
        ffi = FFI(backend=self.Backend())
        data = Data()
        callback = make_callback(data)
        wr = weakref.ref(data)
        del callback, data
        for i in range(3):
            if wr() is not None:
                import gc; gc.collect()
        assert wr() is None    # 'data' does not leak

    def test_windows_stdcall(self):
        if sys.platform != 'win32':
            pytest.skip("Windows-only test")
        if self.Backend is CTypesBackend:
            pytest.skip("not with the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
        """)
        m = ffi.dlopen("Kernel32.dll")
        p_freq = ffi.new("LONGLONG *")
        res = m.QueryPerformanceFrequency(p_freq)
        assert res != 0
        assert p_freq[0] != 0

    def test_explicit_cdecl_stdcall(self):
        if sys.platform != 'win32':
            pytest.skip("Windows-only test")
        if self.Backend is CTypesBackend:
            pytest.skip("not with the ctypes backend")
        win64 = (sys.maxsize > 2**32)
        #
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
        """)
        m = ffi.dlopen("Kernel32.dll")
        tp = ffi.typeof(m.QueryPerformanceFrequency)
        assert str(tp) == "<ctype 'int(*)(long long *)'>"
        #
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            BOOL __cdecl QueryPerformanceFrequency(LONGLONG *lpFrequency);
        """)
        m = ffi.dlopen("Kernel32.dll")
        tpc = ffi.typeof(m.QueryPerformanceFrequency)
        assert tpc is tp
        #
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            BOOL WINAPI QueryPerformanceFrequency(LONGLONG *lpFrequency);
        """)
        m = ffi.dlopen("Kernel32.dll")
        tps = ffi.typeof(m.QueryPerformanceFrequency)
        if win64:
            assert tps is tpc
        else:
            assert tps is not tpc
            assert str(tps) == "<ctype 'int(__stdcall *)(long long *)'>"
        #
        ffi = FFI(backend=self.Backend())
        ffi.cdef("typedef int (__cdecl *fnc_t)(int);")
        ffi.cdef("typedef int (__stdcall *fns_t)(int);")
        tpc = ffi.typeof("fnc_t")
        tps = ffi.typeof("fns_t")
        assert str(tpc) == "<ctype 'int(*)(int)'>"
        if win64:
            assert tps is tpc
        else:
            assert str(tps) == "<ctype 'int(__stdcall *)(int)'>"
        #
        fnc = ffi.cast("fnc_t", 0)
        fns = ffi.cast("fns_t", 0)
        ffi.new("fnc_t[]", [fnc])
        if not win64:
            pytest.raises(TypeError, ffi.new, "fnc_t[]", [fns])
            pytest.raises(TypeError, ffi.new, "fns_t[]", [fnc])
        ffi.new("fns_t[]", [fns])

    def test_stdcall_only_on_windows(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("double __stdcall sin(double x);")     # stdcall ignored
        m = ffi.dlopen(lib_m)
        if (sys.platform == 'win32' and sys.maxsize < 2**32 and
                self.Backend is not CTypesBackend):
            assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin))
        else:
            assert "double(*)(double)" in str(ffi.typeof(m.sin))
        x = m.sin(1.23)
        assert x == math.sin(1.23)

    def test_dir_on_dlopen_lib(self):
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef enum { MYE1, MYE2 } myenum_t;
            double myfunc(double);
            extern double myvar;
            const double myconst;
            #define MYFOO 42
        """)
        m = ffi.dlopen(lib_m)
        assert dir(m) == ['MYE1', 'MYE2', 'MYFOO', 'myconst', 'myfunc', 'myvar']

    def test_dlclose(self):
        if self.Backend is CTypesBackend:
            pytest.skip("not with the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("int foobar(void); extern int foobaz;")
        lib = ffi.dlopen(lib_m)
        ffi.dlclose(lib)
        e = pytest.raises(ValueError, getattr, lib, 'foobar')
        assert str(e.value).startswith("library '")
        assert str(e.value).endswith("' has already been closed")
        e = pytest.raises(ValueError, getattr, lib, 'foobaz')
        assert str(e.value).startswith("library '")
        assert str(e.value).endswith("' has already been closed")
        e = pytest.raises(ValueError, setattr, lib, 'foobaz', 42)
        assert str(e.value).startswith("library '")
        assert str(e.value).endswith("' has already been closed")
        ffi.dlclose(lib)    # does not raise

    def test_passing_large_list(self):
        if self.Backend is CTypesBackend:
            pytest.skip("the ctypes backend doesn't support this")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            void getenv(char *);
        """)
        needs_dlopen_none()
        m = ffi.dlopen(None)
        arg = [b"F", b"O", b"O"] + [b"\x00"] * 20000000
        x = m.getenv(arg)
        assert x is None

testing/cffi0/test_function.py
python-cffi/cffi
from cffi.model import *


def test_void_type():
    assert void_type.get_c_name() == "void"
    assert void_type.get_c_name("foo") == "void foo"
    assert void_type.get_c_name("*foo") == "void *foo"

def test_primitive_type():
    int_type = PrimitiveType("int")
    assert int_type.get_c_name() == "int"
    assert int_type.get_c_name("foo") == "int foo"
    assert int_type.get_c_name("*foo") == "int *foo"
    assert int_type.get_c_name("[5]") == "int[5]"

def test_raw_function_type():
    int_type = PrimitiveType("int")
    fn_type = RawFunctionType([], int_type, False)
    assert fn_type.get_c_name() == "int()(void)"
    assert fn_type.get_c_name("*") == "int( *)(void)"
    assert fn_type.get_c_name("*foo") == "int( *foo)(void)"
    fn_type = RawFunctionType([int_type], int_type, False)
    assert fn_type.get_c_name() == "int()(int)"
    fn_type = RawFunctionType([int_type] * 2, int_type, False)
    assert fn_type.get_c_name() == "int()(int, int)"
    #
    fn_type = RawFunctionType([int_type], int_type, True)
    assert fn_type.get_c_name() == "int()(int, ...)"
    assert fn_type.get_c_name("*foo") == "int( *foo)(int, ...)"
    #
    res_type = FunctionPtrType([int_type], int_type, True)
    fn_type = RawFunctionType([int_type], res_type, True)
    assert fn_type.get_c_name("x") == "int(*( x)(int, ...))(int, ...)"

def test_function_ptr_type():
    int_type = PrimitiveType("int")
    fn_type = FunctionPtrType([], int_type, False)
    assert fn_type.get_c_name() == "int(*)(void)"
    assert fn_type.get_c_name("*") == "int(* *)(void)"
    assert fn_type.get_c_name("*foo") == "int(* *foo)(void)"
    fn_type = FunctionPtrType([int_type], int_type, False)
    assert fn_type.get_c_name() == "int(*)(int)"
    fn_type = FunctionPtrType([int_type] * 2, int_type, False)
    assert fn_type.get_c_name() == "int(*)(int, int)"
    #
    fn_type = FunctionPtrType([int_type], int_type, True)
    assert fn_type.get_c_name() == "int(*)(int, ...)"

def test_pointer_type():
    ptr_type = PointerType(PrimitiveType("int"))
    assert ptr_type.get_c_name("x") == "int * x"

def test_const_pointer_type():
    ptr_type = ConstPointerType(PrimitiveType("int"))
    assert ptr_type.get_c_name("x") == "int const * x"
    ptr_type = ConstPointerType(ArrayType(PrimitiveType("int"), 5))
    assert ptr_type.get_c_name("") == "int const (*)[5]"
    assert ptr_type.get_c_name("*x") == "int const (* *x)[5]"
    ptr_type = ConstPointerType(ArrayType(
        ConstPointerType(PrimitiveType("int")), 5))
    assert ptr_type.get_c_name("x") == "int const * const (* x)[5]"
    ptr_type = PointerType(ArrayType(
        ConstPointerType(PrimitiveType("int")), 5))
    assert ptr_type.get_c_name("x") == "int const *(* x)[5]"
    ptr_type = ConstPointerType(ArrayType(
        PointerType(PrimitiveType("int")), 5))
    assert ptr_type.get_c_name("x") == "int * const (* x)[5]"

def test_qual_pointer_type():
    ptr_type = PointerType(PrimitiveType("long long"), Q_RESTRICT)
    assert ptr_type.get_c_name("") == "long long __restrict *"
    assert const_voidp_type.get_c_name("") == "void const *"

def test_unknown_pointer_type():
    ptr_type = unknown_ptr_type("foo_p")
    assert ptr_type.get_c_name("") == "foo_p"
    assert ptr_type.get_c_name("x") == "foo_p x"

def test_unknown_type():
    u_type = unknown_type("foo_t")
    assert u_type.get_c_name("") == "foo_t"
    assert u_type.get_c_name("x") == "foo_t x"

def test_array_type():
    a_type = ArrayType(PrimitiveType("int"), None)
    assert a_type.get_c_name("") == "int[]"
    assert a_type.get_c_name("x") == "int x[]"
    assert a_type.get_c_name("*x") == "int(*x)[]"
    assert a_type.get_c_name(" *x") == "int(*x)[]"
    assert a_type.get_c_name("[5]") == "int[5][]"
    a_type = ArrayType(unknown_type("foo_t"), 5)
    assert a_type.get_c_name("") == "foo_t[5]"
    assert a_type.get_c_name("x") == "foo_t x[5]"
    assert a_type.get_c_name("*x") == "foo_t(*x)[5]"
    a_type = ArrayType(unknown_ptr_type("foo_p"), None)
    assert a_type.get_c_name("") == "foo_p[]"
    assert a_type.get_c_name("x") == "foo_p x[]"
    assert a_type.get_c_name("*x") == "foo_p(*x)[]"
    a_type = ArrayType(ConstPointerType(PrimitiveType("int")), None)
    assert a_type.get_c_name("") == "int const *[]"
    assert a_type.get_c_name("x") == "int const * x[]"
    assert a_type.get_c_name("*x") == "int const *(*x)[]"
    fn_type = FunctionPtrType([], PrimitiveType("int"), False)
    a_type = ArrayType(fn_type, 5)
    assert a_type.get_c_name("") == "int(*[5])(void)"
    assert a_type.get_c_name("x") == "int(* x[5])(void)"
    assert a_type.get_c_name("*x") == "int(*(*x)[5])(void)"

def test_struct_type():
    struct_type = StructType("foo_s", None, None, None)
    assert struct_type.get_c_name() == "struct foo_s"
    assert struct_type.get_c_name("*x") == "struct foo_s *x"

def test_union_type():
    union_type = UnionType("foo_s", None, None, None)
    assert union_type.get_c_name() == "union foo_s"

def test_enum_type():
    enum_type = EnumType("foo_e", [], [])
    assert enum_type.get_c_name() == "enum foo_e"

testing/cffi0/test_model.py
python-cffi/cffi
import sys, os
import subprocess, weakref
import pytest
from cffi import FFI
from cffi.backend_ctypes import CTypesBackend
from testing.support import u, is_musl


SOURCE = """\
#include <errno.h>

#ifdef _WIN32
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif

EXPORT int test_getting_errno(void) {
    errno = 123;
    return -1;
}

EXPORT int test_setting_errno(void) {
    return errno;
};

typedef struct {
    long x;
    long y;
} POINT;

typedef struct {
    long left;
    long top;
    long right;
    long bottom;
} RECT;

typedef struct {
    unsigned char a, b, c;
} THREEBYTES;


EXPORT int PointInRect(RECT *prc, POINT pt)
{
    if (pt.x < prc->left)
        return 0;
    if (pt.x > prc->right)
        return 0;
    if (pt.y < prc->top)
        return 0;
    if (pt.y > prc->bottom)
        return 0;
    return 1;
};

EXPORT long left = 10;
EXPORT long top = 20;
EXPORT long right = 30;
EXPORT long bottom = 40;

EXPORT RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
                        RECT *er, POINT fp, RECT gr)
{
    /*Check input */
    if (ar.left + br->left + dr.left + er->left + gr.left != left * 5)
    {
        ar.left = 100;
        return ar;
    }
    if (ar.right + br->right + dr.right + er->right + gr.right != right * 5)
    {
        ar.right = 100;
        return ar;
    }
    if (cp.x != fp.x)
    {
        ar.left = -100;
    }
    if (cp.y != fp.y)
    {
        ar.left = -200;
    }
    switch(i)
    {
    case 0:
        return ar;
        break;
    case 1:
        return dr;
        break;
    case 2:
        return gr;
        break;

    }
    return ar;
}

EXPORT int my_array[7] = {0, 1, 2, 3, 4, 5, 6};

EXPORT unsigned short foo_2bytes(unsigned short a)
{
    return (unsigned short)(a + 42);
}
EXPORT unsigned int foo_4bytes(unsigned int a)
{
    return (unsigned int)(a + 42);
}

EXPORT void modify_struct_value(RECT r)
{
    r.left = r.right = r.top = r.bottom = 500;
}

EXPORT THREEBYTES return_three_bytes(void)
{
    THREEBYTES result;
    result.a = 12;
    result.b = 34;
    result.c = 56;
    return result;
}
"""

class TestOwnLib(object):
    Backend = CTypesBackend

    def setup_class(cls):
        cls.module = None
        from testing.udir import udir
        udir.join('testownlib.c').write(SOURCE)
        if sys.platform == 'win32':
            # did we already build it?
            if cls.Backend is CTypesBackend:
                dll_path = str(udir) + '\\testownlib1.dll'   # only ascii for the ctypes backend
            else:
                dll_path = str(udir) + '\\' + (u+'testownlib\u03be.dll')   # non-ascii char
            if os.path.exists(dll_path):
                cls.module = dll_path
                return
            # try (not too hard) to find the version used to compile this python
            # no mingw
            from distutils.msvc9compiler import get_build_version
            version = get_build_version()
            toolskey = "VS%0.f0COMNTOOLS" % version
            toolsdir = os.environ.get(toolskey, None)
            if toolsdir is None:
                return
            productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
            productdir = os.path.abspath(productdir)
            vcvarsall = os.path.join(productdir, "vcvarsall.bat")
            # 64?
            arch = 'x86'
            if sys.maxsize > 2**32:
                arch = 'amd64'
            if os.path.isfile(vcvarsall):
                cmd = '"%s" %s' % (vcvarsall, arch) + ' & cl.exe testownlib.c ' \
                        ' /LD /Fetestownlib.dll'
                subprocess.check_call(cmd, cwd = str(udir), shell=True)
                os.rename(str(udir) + '\\testownlib.dll', dll_path)
                cls.module = dll_path
        else:
            encoded = None
            if cls.Backend is not CTypesBackend:
                try:
                    unicode_name = u+'testownlibcaf\xe9'
                    encoded = unicode_name.encode(sys.getfilesystemencoding())
                    if sys.version_info >= (3,):
                        encoded = str(unicode_name)
                except UnicodeEncodeError:
                    pass
            if encoded is None:
                unicode_name = u+'testownlib'
                encoded = str(unicode_name)
            subprocess.check_call(
                "cc testownlib.c -shared -fPIC -o '%s.so'" % (encoded,),
                cwd=str(udir), shell=True)
            cls.module = os.path.join(str(udir), unicode_name + (u+'.so'))
        print(repr(cls.module))

    def test_getting_errno(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if sys.platform == 'win32':
            pytest.skip("fails, errno at multiple addresses")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int test_getting_errno(void);
        """)
        ownlib = ffi.dlopen(self.module)
        res = ownlib.test_getting_errno()
        assert res == -1
        assert ffi.errno == 123

    def test_setting_errno(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if sys.platform == 'win32':
            pytest.skip("fails, errno at multiple addresses")
        if self.Backend is CTypesBackend and '__pypy__' in sys.modules:
            pytest.skip("XXX errno issue with ctypes on pypy?")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int test_setting_errno(void);
        """)
        ownlib = ffi.dlopen(self.module)
        ffi.errno = 42
        res = ownlib.test_setting_errno()
        assert res == 42
        assert ffi.errno == 42

    def test_my_array_7(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            extern int my_array[7];
        """)
        ownlib = ffi.dlopen(self.module)
        for i in range(7):
            assert ownlib.my_array[i] == i
        assert len(ownlib.my_array) == 7
        if self.Backend is CTypesBackend:
            pytest.skip("not supported by the ctypes backend")
        ownlib.my_array = list(range(10, 17))
        for i in range(7):
            assert ownlib.my_array[i] == 10 + i
        ownlib.my_array = list(range(7))
        for i in range(7):
            assert ownlib.my_array[i] == i

    def test_my_array_no_length(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if self.Backend is CTypesBackend:
            pytest.skip("not supported by the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            extern int my_array[];
        """)
        ownlib = ffi.dlopen(self.module)
        for i in range(7):
            assert ownlib.my_array[i] == i
        pytest.raises(TypeError, len, ownlib.my_array)
        ownlib.my_array = list(range(10, 17))
        for i in range(7):
            assert ownlib.my_array[i] == 10 + i
        ownlib.my_array = list(range(7))
        for i in range(7):
            assert ownlib.my_array[i] == i

    def test_keepalive_lib(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int test_getting_errno(void);
        """)
        ownlib = ffi.dlopen(self.module)
        ffi_r = weakref.ref(ffi)
        ownlib_r = weakref.ref(ownlib)
        func = ownlib.test_getting_errno
        del ffi
        import gc; gc.collect()       # ownlib stays alive
        assert ownlib_r() is not None
        assert ffi_r() is not None    # kept alive by ownlib
        res = func()
        assert res == -1

    def test_keepalive_ffi(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            int test_getting_errno(void);
        """)
        ownlib = ffi.dlopen(self.module)
        ffi_r = weakref.ref(ffi)
        ownlib_r = weakref.ref(ownlib)
        func = ownlib.test_getting_errno
        del ownlib
        import gc; gc.collect()       # ffi stays alive
        assert ffi_r() is not None
        assert ownlib_r() is not None # kept alive by ffi
        res = func()
        assert res == -1
        if sys.platform != 'win32':  # else, errno at multiple addresses
            assert ffi.errno == 123

    def test_struct_by_value(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef struct {
                long x;
                long y;
            } POINT;

            typedef struct {
                long left;
                long top;
                long right;
                long bottom;
            } RECT;
            
            extern long left, top, right, bottom;

            RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
                        RECT *er, POINT fp, RECT gr);
        """)
        ownlib = ffi.dlopen(self.module)

        rect = ffi.new('RECT[1]')
        pt = ffi.new('POINT[1]')
        pt[0].x = 15
        pt[0].y = 25
        rect[0].left = ownlib.left
        rect[0].right = ownlib.right
        rect[0].top = ownlib.top
        rect[0].bottom = ownlib.bottom
        
        for i in range(4):
            ret = ownlib.ReturnRect(i, rect[0], rect, pt[0], rect[0],
                                    rect, pt[0], rect[0])
            assert ret.left == ownlib.left
            assert ret.right == ownlib.right
            assert ret.top == ownlib.top
            assert ret.bottom == ownlib.bottom

    def test_addressof_lib(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if self.Backend is CTypesBackend:
            pytest.skip("not implemented with the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("extern long left; int test_getting_errno(void);")
        lib = ffi.dlopen(self.module)
        lib.left = 123456
        p = ffi.addressof(lib, "left")
        assert ffi.typeof(p) == ffi.typeof("long *")
        assert p[0] == 123456
        p[0] += 1
        assert lib.left == 123457
        pfn = ffi.addressof(lib, "test_getting_errno")
        assert ffi.typeof(pfn) == ffi.typeof("int(*)(void)")
        assert pfn == lib.test_getting_errno

    def test_char16_char32_t(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if self.Backend is CTypesBackend:
            pytest.skip("not implemented with the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            char16_t foo_2bytes(char16_t);
            char32_t foo_4bytes(char32_t);
        """)
        lib = ffi.dlopen(self.module)
        assert lib.foo_2bytes(u+'\u1234') == u+'\u125e'
        assert lib.foo_4bytes(u+'\u1234') == u+'\u125e'
        assert lib.foo_4bytes(u+'\U00012345') == u+'\U0001236f'

    def test_modify_struct_value(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if self.Backend is CTypesBackend:
            pytest.skip("fails with the ctypes backend on some architectures")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef struct {
                long left;
                long top;
                long right;
                long bottom;
            } RECT;

            void modify_struct_value(RECT r);
        """)
        lib = ffi.dlopen(self.module)
        s = ffi.new("RECT *", [11, 22, 33, 44])
        lib.modify_struct_value(s[0])
        assert s.left == 11
        assert s.top == 22
        assert s.right == 33
        assert s.bottom == 44

    def test_dlopen_handle(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if sys.platform == 'win32' or is_musl:
            pytest.skip("uses 'dl' explicitly")
        if self.__class__.Backend is CTypesBackend:
            pytest.skip("not for the ctypes backend")
        backend = self.Backend()
        ffi1 = FFI(backend=backend)
        ffi1.cdef("""void *dlopen(const char *filename, int flags);
                     int dlclose(void *handle);""")
        lib1 = ffi1.dlopen('dl')
        handle = lib1.dlopen(self.module.encode(sys.getfilesystemencoding()),
                             backend.RTLD_LAZY)
        assert ffi1.typeof(handle) == ffi1.typeof("void *")
        assert handle

        ffi = FFI(backend=backend)
        ffi.cdef("""unsigned short foo_2bytes(unsigned short a);""")
        lib = ffi.dlopen(handle)
        x = lib.foo_2bytes(1000)
        assert x == 1042

        err = lib1.dlclose(handle)
        assert err == 0

    def test_return_three_bytes(self):
        if self.module is None:
            pytest.skip("fix the auto-generation of the tiny test lib")
        if self.__class__.Backend is CTypesBackend:
            pytest.skip("not working on win32 on the ctypes backend")
        ffi = FFI(backend=self.Backend())
        ffi.cdef("""
            typedef struct {
                unsigned char a, b, c;
            } THREEBYTES;

            THREEBYTES return_three_bytes(void);
        """)
        lib = ffi.dlopen(self.module)
        tb = lib.return_three_bytes()
        assert tb.a == 12
        assert tb.b == 34
        assert tb.c == 56

testing/cffi0/test_ownlib.py
python-cffi/cffi
import sys, re
import pytest
from cffi import FFI, FFIError, CDefError, VerificationError
from .backend_tests import needs_dlopen_none
from testing.support import is_musl


class FakeBackend(object):

    def nonstandard_integer_types(self):
        return {}

    def sizeof(self, name):
        return 1

    def load_library(self, name, flags):
        if sys.platform == 'win32':
            assert name is None or "msvcr" in name
        else:
            assert name is None or "libc" in name or "libm" in name
        return FakeLibrary()

    def new_function_type(self, args, result, has_varargs):
        args = [arg.cdecl for arg in args]
        result = result.cdecl
        return FakeType(
            '<func (%s), %s, %s>' % (', '.join(args), result, has_varargs))

    def new_primitive_type(self, name):
        assert name == name.lower()
        return FakeType('<%s>' % name)

    def new_pointer_type(self, itemtype):
        return FakeType('<pointer to %s>' % (itemtype,))

    def new_struct_type(self, name):
        return FakeStruct(name)

    def complete_struct_or_union(self, s, fields, tp=None,
                                 totalsize=-1, totalalignment=-1, sflags=0):
        assert isinstance(s, FakeStruct)
        s.fields = fields

    def new_array_type(self, ptrtype, length):
        return FakeType('<array %s x %s>' % (ptrtype, length))

    def new_void_type(self):
        return FakeType("<void>")
    def cast(self, x, y):
        return 'casted!'
    def _get_types(self):
        return "CData", "CType"

    buffer = "buffer type"

class FakeType(object):
    def __init__(self, cdecl):
        self.cdecl = cdecl
    def __str__(self):
        return self.cdecl

class FakeStruct(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return ', '.join([str(y) + str(x) for x, y, z in self.fields])

class FakeLibrary(object):

    def load_function(self, BType, name):
        return FakeFunction(BType, name)

class FakeFunction(object):

    def __init__(self, BType, name):
        self.BType = str(BType)
        self.name = name

lib_m = "m"
if sys.platform == 'win32':
    #there is a small chance this fails on Mingw via environ $CC
    import distutils.ccompiler
    if distutils.ccompiler.get_default_compiler() == 'msvc':
        lib_m = 'msvcrt'
elif is_musl:
    lib_m = 'c'


def test_simple():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("double sin(double x);")
    m = ffi.dlopen(lib_m)
    func = m.sin    # should be a callable on real backends
    assert func.name == 'sin'
    assert func.BType == '<func (<double>), <double>, False>'

def test_pipe():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("int pipe(int pipefd[2]);")
    needs_dlopen_none()
    C = ffi.dlopen(None)
    func = C.pipe
    assert func.name == 'pipe'
    assert func.BType == '<func (<pointer to <int>>), <int>, False>'

def test_vararg():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("short foo(int, ...);")
    needs_dlopen_none()
    C = ffi.dlopen(None)
    func = C.foo
    assert func.name == 'foo'
    assert func.BType == '<func (<int>), <short>, True>'

def test_no_args():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        int foo(void);
        """)
    needs_dlopen_none()
    C = ffi.dlopen(None)
    assert C.foo.BType == '<func (), <int>, False>'

def test_typedef():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        typedef unsigned int UInt;
        typedef UInt UIntReally;
        UInt foo(void);
        """)
    needs_dlopen_none()
    C = ffi.dlopen(None)
    assert str(ffi.typeof("UIntReally")) == '<unsigned int>'
    assert C.foo.BType == '<func (), <unsigned int>, False>'

def test_typedef_more_complex():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        typedef struct { int a, b; } foo_t, *foo_p;
        int foo(foo_p[]);
        """)
    needs_dlopen_none()
    C = ffi.dlopen(None)
    assert str(ffi.typeof("foo_t")) == '<int>a, <int>b'
    assert str(ffi.typeof("foo_p")) == '<pointer to <int>a, <int>b>'
    assert C.foo.BType == ('<func (<pointer to <pointer to '
                           '<int>a, <int>b>>), <int>, False>')

def test_typedef_array_convert_array_to_pointer():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        typedef int (*fn_t)(int[5]);
        """)
    with ffi._lock:
        type = ffi._parser.parse_type("fn_t")
        BType = ffi._get_cached_btype(type)
    assert str(BType) == '<func (<pointer to <int>>), <int>, False>'

def test_remove_comments():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        double /*comment here*/ sin   // blah blah
        /* multi-
           line-
           //comment */  (
        // foo
        double // bar      /* <- ignored, because it's in a comment itself
        x, double/*several*//*comment*/y) /*on the same line*/
        ;
    """)
    m = ffi.dlopen(lib_m)
    func = m.sin
    assert func.name == 'sin'
    assert func.BType == '<func (<double>, <double>), <double>, False>'

def test_remove_line_continuation_comments():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        double // blah \\
                  more comments
        x(void);
        double // blah // blah\\\\
        y(void);
        double // blah\\ \
                  etc
        z(void);
    """)
    m = ffi.dlopen(lib_m)
    m.x
    m.y
    m.z

def test_dont_remove_comment_in_line_directives():
    ffi = FFI(backend=FakeBackend())
    e = pytest.raises(CDefError, ffi.cdef, """
        \t # \t line \t 8 \t "baz.c" \t

        some syntax error here
    """)
    assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax"
    #
    e = pytest.raises(CDefError, ffi.cdef, """
        #line 7 "foo//bar.c"

        some syntax error here
    """)
    #
    assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax"
    ffi = FFI(backend=FakeBackend())
    e = pytest.raises(CDefError, ffi.cdef, """
        \t # \t 8 \t "baz.c" \t

        some syntax error here
    """)
    assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax"
    #
    e = pytest.raises(CDefError, ffi.cdef, """
        # 7 "foo//bar.c"

        some syntax error here
    """)
    assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax"

def test_multiple_line_directives():
    ffi = FFI(backend=FakeBackend())
    e = pytest.raises(CDefError, ffi.cdef,
    """ #line 5 "foo.c"
        extern int xx;
        #line 6 "bar.c"
        extern int yy;
        #line 7 "baz.c"
        some syntax error here
        #line 8 "yadda.c"
        extern int zz;
    """)
    assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax"
    #
    e = pytest.raises(CDefError, ffi.cdef,
    """ # 5 "foo.c"
        extern int xx;
        # 6 "bar.c"
        extern int yy;
        # 7 "baz.c"
        some syntax error here
        # 8 "yadda.c"
        extern int zz;
    """)
    assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax"

def test_commented_line_directive():
    ffi = FFI(backend=FakeBackend())
    e = pytest.raises(CDefError, ffi.cdef, """
        /*
        #line 5 "foo.c"
        */
        void xx(void);

        #line 6 "bar.c"
        /*
        #line 35 "foo.c"
        */
        some syntax error
    """)
    #
    assert str(e.value) == "parse error\nbar.c:9:14: before: syntax"
    e = pytest.raises(CDefError, ffi.cdef, """
        /*
        # 5 "foo.c"
        */
        void xx(void);

        # 6 "bar.c"
        /*
        # 35 "foo.c"
        */
        some syntax error
    """)
    assert str(e.value) == "parse error\nbar.c:9:14: before: syntax"

def test_line_continuation_in_defines():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("""
        #define ABC\\
            42
        #define BCD   \\
            43
    """)
    m = ffi.dlopen(lib_m)
    assert m.ABC == 42
    assert m.BCD == 43

def test_define_not_supported_for_now():
    ffi = FFI(backend=FakeBackend())
    e = pytest.raises(CDefError, ffi.cdef, '#define FOO "blah"')
    assert str(e.value) == (
        'only supports one of the following syntax:\n'
        '  #define FOO ...     (literally dot-dot-dot)\n'
        '  #define FOO NUMBER  (with NUMBER an integer'
                                    ' constant, decimal/hex/octal)\n'
        'got:\n'
        '  #define FOO "blah"')

def test_unnamed_struct():
    ffi = FFI(backend=FakeBackend())
    ffi.cdef("typedef struct { int x; } foo_t;\n"
             "typedef struct { int y; } *bar_p;\n")
    assert 'typedef foo_t' in ffi._parser._declarations
    assert 'typedef bar_p' in ffi._parser._declarations
    assert 'anonymous foo_t' in ffi._parser._declarations
    type_foo = ffi._parser.parse_type("foo_t")
    type_bar = ffi._parser.parse_type("bar_p").totype
    assert repr(type_foo) == "<foo_t>"
    assert repr(type_bar) == "<struct $1>"
    pytest.raises(VerificationError, type_bar.get_c_name)
    assert type_foo.get_c_name() == "foo_t"

def test_override():
    ffi = FFI(backend=FakeBackend())
    needs_dlopen_none()
    C = ffi.dlopen(None)
    ffi.cdef("int foo(void);")
    pytest.raises(FFIError, ffi.cdef, "long foo(void);")
    assert C.foo.BType == '<func (), <int>, False>'
    ffi.cdef("long foo(void);", override=True)
    assert C.foo.BType == '<func (), <long>, False>'

def test_cannot_have_only_variadic_part():
    # this checks that we get a sensible error if we try "int foo(...);"
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cdef, "int foo(...);")
    assert str(e.value) == (
           "<cdef source string>:1: foo: a function with only '(...)' "
           "as argument is not correct C")

def test_parse_error():
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cdef, " x y z ")
    assert str(e.value).startswith(
        'cannot parse "x y z"\n<cdef source string>:1:')
    e = pytest.raises(CDefError, ffi.cdef, "\n\n\n x y z ")
    assert str(e.value).startswith(
        'cannot parse "x y z"\n<cdef source string>:4:')

def test_error_custom_lineno():
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cdef, """
# 42 "foobar"

    a b c d
    """)
    assert str(e.value).startswith('parse error\nfoobar:43:')

def test_cannot_declare_enum_later():
    ffi = FFI()
    e = pytest.raises(NotImplementedError, ffi.cdef,
                       "typedef enum foo_e foo_t; enum foo_e { AA, BB };")
    assert str(e.value) == (
           "enum foo_e: the '{}' declaration should appear on the "
           "first time the enum is mentioned, not later")

def test_unknown_name():
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cast, "foobarbazunknown", 0)
    assert str(e.value) == "unknown identifier 'foobarbazunknown'"
    e = pytest.raises(CDefError, ffi.cast, "foobarbazunknown*", 0)
    assert str(e.value).startswith('cannot parse "foobarbazunknown*"')
    e = pytest.raises(CDefError, ffi.cast, "int(*)(foobarbazunknown)", 0)
    assert str(e.value).startswith('cannot parse "int(*)(foobarbazunknown)"')

def test_redefine_common_type():
    prefix = "" if sys.version_info < (3,) else "b"
    ffi = FFI()
    ffi.cdef("typedef char FILE;")
    assert repr(ffi.cast("FILE", 123)) == "<cdata 'char' %s'{'>" % prefix
    ffi.cdef("typedef char int32_t;")
    assert repr(ffi.cast("int32_t", 123)) == "<cdata 'char' %s'{'>" % prefix
    ffi = FFI()
    ffi.cdef("typedef int bool, *FILE;")
    assert repr(ffi.cast("bool", 123)) == "<cdata 'int' 123>"
    assert re.match(r"<cdata 'int [*]' 0[xX]?0*7[bB]>",
                    repr(ffi.cast("FILE", 123)))
    ffi = FFI()
    ffi.cdef("typedef bool (*fn_t)(bool, bool);")   # "bool," but within "( )"

def test_bool():
    ffi = FFI()
    ffi.cdef("void f(bool);")
    #
    ffi = FFI()
    ffi.cdef("typedef _Bool bool; void f(bool);")

def test_unknown_argument_type():
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cdef, "void f(foobarbazzz);")
    assert str(e.value) == ("<cdef source string>:1: f arg 1:"
                            " unknown type 'foobarbazzz' (if you meant"
                            " to use the old C syntax of giving untyped"
                            " arguments, it is not supported)")

def test_void_renamed_as_only_arg():
    ffi = FFI()
    ffi.cdef("typedef void void_t1;"
             "typedef void_t1 void_t;"
             "typedef int (*func_t)(void_t);")
    assert ffi.typeof("func_t").args == ()

def test_WPARAM_on_windows():
    if sys.platform != 'win32':
        pytest.skip("Only for Windows")
    ffi = FFI()
    ffi.cdef("void f(WPARAM);")
    #
    # WPARAM -> UINT_PTR -> unsigned 32/64-bit integer
    ffi = FFI()
    value = int(ffi.cast("WPARAM", -42))
    assert value == sys.maxsize * 2 - 40

def test__is_constant_globalvar():
    import warnings
    for input, expected_output in [
        ("int a;",          False),
        ("const int a;",    True),
        ("int *a;",         False),
        ("const int *a;",   False),
        ("int const *a;",   False),
        ("int *const a;",   True),
        ("int a[5];",       False),
        ("const int a[5];", False),
        ("int *a[5];",      False),
        ("const int *a[5];", False),
        ("int const *a[5];", False),
        ("int *const a[5];", False),
        ("int a[5][6];",       False),
        ("const int a[5][6];", False),
        ]:
        ffi = FFI()
        with warnings.catch_warnings(record=True) as log:
            warnings.simplefilter("always")
            ffi.cdef(input)
        declarations = ffi._parser._declarations
        assert ('constant a' in declarations) == expected_output
        assert ('variable a' in declarations) == (not expected_output)
        assert len(log) == (1 - expected_output)

def test_restrict():
    from cffi import model
    for input, expected_output in [
        ("int a;",             False),
        ("restrict int a;",    True),
        ("int *a;",            False),
        ]:
        ffi = FFI()
        ffi.cdef("extern " + input)
        tp, quals = ffi._parser._declarations['variable a']
        assert bool(quals & model.Q_RESTRICT) == expected_output

def test_different_const_funcptr_types():
    lst = []
    for input in [
        "int(*)(int *a)",
        "int(*)(int const *a)",
        "int(*)(int * const a)",
        "int(*)(int const a[])"]:
        ffi = FFI(backend=FakeBackend())
        lst.append(ffi._parser.parse_type(input))
    assert lst[0] != lst[1]
    assert lst[0] == lst[2]
    assert lst[1] == lst[3]

def test_const_pointer_to_pointer():
    from cffi import model
    ffi = FFI(backend=FakeBackend())
    #
    tp, qual = ffi._parser.parse_type_and_quals("char * * (* const)")
    assert (str(tp), qual) == ("<char * * *>", model.Q_CONST)
    tp, qual = ffi._parser.parse_type_and_quals("char * (* const (*))")
    assert (str(tp), qual) == ("<char * * const *>", 0)
    tp, qual = ffi._parser.parse_type_and_quals("char (* const (* (*)))")
    assert (str(tp), qual) == ("<char * const * *>", 0)
    tp, qual = ffi._parser.parse_type_and_quals("char const * * *")
    assert (str(tp), qual) == ("<char const * * *>", 0)
    tp, qual = ffi._parser.parse_type_and_quals("const char * * *")
    assert (str(tp), qual) == ("<char const * * *>", 0)
    #
    tp, qual = ffi._parser.parse_type_and_quals("char * * * const const")
    assert (str(tp), qual) == ("<char * * *>", model.Q_CONST)
    tp, qual = ffi._parser.parse_type_and_quals("char * * volatile *")
    assert (str(tp), qual) == ("<char * * volatile *>", 0)
    tp, qual = ffi._parser.parse_type_and_quals("char * volatile restrict * *")
    assert (str(tp), qual) == ("<char * __restrict volatile * *>", 0)
    tp, qual = ffi._parser.parse_type_and_quals("char const volatile * * *")
    assert (str(tp), qual) == ("<char volatile const * * *>", 0)
    tp, qual = ffi._parser.parse_type_and_quals("const char * * *")
    assert (str(tp), qual) == ("<char const * * *>", 0)
    #
    tp, qual = ffi._parser.parse_type_and_quals(
        "int(char*const*, short****const*)")
    assert (str(tp), qual) == (
        "<int()(char * const *, short * * * * const *)>", 0)
    tp, qual = ffi._parser.parse_type_and_quals(
        "char*const*(short*const****)")
    assert (str(tp), qual) == (
        "<char * const *()(short * const * * * *)>", 0)

def test_enum():
    ffi = FFI()
    ffi.cdef("""
        enum Enum {
            POS = +1,
            TWO = 2,
            NIL = 0,
            NEG = -1,
            ADDSUB = (POS+TWO)-1,
            DIVMULINT = (3 * 3) / 2,
            SHIFT = (1 << 3) >> 1,
            BINOPS = (0x7 & 0x1) | 0x8,
            XOR = 0xf ^ 0xa
        };
        """)
    needs_dlopen_none()
    C = ffi.dlopen(None)
    assert C.POS == 1
    assert C.TWO == 2
    assert C.NIL == 0
    assert C.NEG == -1
    assert C.ADDSUB == 2
    assert C.DIVMULINT == 4
    assert C.SHIFT == 4
    assert C.BINOPS == 0b1001
    assert C.XOR == 0b0101

def test_stdcall():
    ffi = FFI()
    tp = ffi.typeof("int(*)(int __stdcall x(int),"
                    "       long (__cdecl*y)(void),"
                    "       short(WINAPI *z)(short))")
    if sys.platform == 'win32' and sys.maxsize < 2**32:
        stdcall = '__stdcall '
    else:
        stdcall = ''
    assert str(tp) == (
        "<ctype 'int(*)(int(%s*)(int), "
                        "long(*)(), "
                        "short(%s*)(short))'>" % (stdcall, stdcall))

def test_extern_python():
    ffi = FFI()
    ffi.cdef("""
        int bok(int, int);
        extern "Python" int foobar(int, int);
        int baz(int, int);
    """)
    assert sorted(ffi._parser._declarations) == [
        'extern_python foobar', 'function baz', 'function bok']
    assert (ffi._parser._declarations['function bok'] ==
            ffi._parser._declarations['extern_python foobar'] ==
            ffi._parser._declarations['function baz'])

def test_extern_python_group():
    ffi = FFI()
    ffi.cdef("""
        int bok(int);
        extern "Python" {int foobar(int, int);int bzrrr(int);}
        int baz(int, int);
    """)
    assert sorted(ffi._parser._declarations) == [
        'extern_python bzrrr', 'extern_python foobar',
        'function baz', 'function bok']
    assert (ffi._parser._declarations['function baz'] ==
            ffi._parser._declarations['extern_python foobar'] !=
            ffi._parser._declarations['function bok'] ==
            ffi._parser._declarations['extern_python bzrrr'])

def test_error_invalid_syntax_for_cdef():
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cdef, 'void foo(void) {}')
    assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: '
                            'this construct is valid C but not valid in cdef()')

def test_unsigned_int_suffix_for_constant():
    ffi = FFI()
    ffi.cdef("""enum e {
                    bin_0=0b10,
                    bin_1=0b10u,
                    bin_2=0b10U,
                    bin_3=0b10l,
                    bin_4=0b10L,
                    bin_5=0b10ll,
                    bin_6=0b10LL,
                    oct_0=010,
                    oct_1=010u,
                    oct_2=010U,
                    oct_3=010l,
                    oct_4=010L,
                    oct_5=010ll,
                    oct_6=010LL,
                    dec_0=10,
                    dec_1=10u,
                    dec_2=10U,
                    dec_3=10l,
                    dec_4=10L,
                    dec_5=10ll,
                    dec_6=10LL,
                    hex_0=0x10,
                    hex_1=0x10u,
                    hex_2=0x10U,
                    hex_3=0x10l,
                    hex_4=0x10L,
                    hex_5=0x10ll,
                    hex_6=0x10LL,};""")
    needs_dlopen_none()
    C = ffi.dlopen(None)
    for base, expected_result in (('bin', 2), ('oct', 8), ('dec', 10), ('hex', 16)):
        for index in range(7):
            assert getattr(C, '{base}_{index}'.format(base=base, index=index)) == expected_result

testing/cffi0/test_parsing.py
python-cffi/cffi
import re
import pytest
import sys, os, math, weakref
from cffi import FFI, VerificationError, VerificationMissing, model, FFIError
from testing.support import *
from testing.support import extra_compile_args, is_musl

# eliminate warning noise from common test modules that are repeatedly re-imported
pytestmark = [
    pytest.mark.filterwarnings("ignore:reimporting:UserWarning"),
    #pytest.mark.filterwarnings("ignore:Deprecated:_DeprecatedConfig")
]

lib_m = ['m']
if sys.platform == 'win32':
    #there is a small chance this fails on Mingw via environ $CC
    import distutils.ccompiler
    if distutils.ccompiler.get_default_compiler() == 'msvc':
        lib_m = ['msvcrt']
    pass      # no obvious -Werror equivalent on MSVC
else:
    class FFI(FFI):
        def verify(self, *args, **kwds):
            return super(FFI, self).verify(
                *args, extra_compile_args=extra_compile_args, **kwds)

def setup_module():
    import cffi.verifier
    cffi.verifier.cleanup_tmpdir()
    #
    # check that no $ sign is produced in the C file; it used to be the
    # case that anonymous enums would produce '$enum_$1', which was
    # used as part of a function name.  GCC accepts such names, but it's
    # apparently non-standard.
    _r_comment = re.compile(r"/\*.*?\*/|//.*?$", re.DOTALL | re.MULTILINE)
    _r_string = re.compile(r'\".*?\"')
    def _write_source_and_check(self, file=None):
        base_write_source(self, file)
        if file is None:
            f = open(self.sourcefilename)
            data = f.read()
            f.close()
            data = _r_comment.sub(' ', data)
            data = _r_string.sub('"skipped"', data)
            assert '$' not in data
    base_write_source = cffi.verifier.Verifier._write_source
    cffi.verifier.Verifier._write_source = _write_source_and_check


def test_module_type():
    import cffi.verifier
    ffi = FFI()
    lib = ffi.verify()
    if hasattr(lib, '_cffi_python_module'):
        print('verify got a PYTHON module')
    if hasattr(lib, '_cffi_generic_module'):
        print('verify got a GENERIC module')
    expected_generic = (cffi.verifier._FORCE_GENERIC_ENGINE or
                        '__pypy__' in sys.builtin_module_names)
    assert hasattr(lib, '_cffi_python_module') == (not expected_generic)
    assert hasattr(lib, '_cffi_generic_module') == expected_generic

def test_missing_function(ffi=None):
    # uses the FFI hacked above with '-Werror'
    if ffi is None:
        ffi = FFI()
    ffi.cdef("void some_completely_unknown_function();")
    try:
        lib = ffi.verify()
    except (VerificationError, OSError):
        pass     # expected case: we get a VerificationError
    else:
        # but depending on compiler and loader details, maybe
        # 'lib' could actually be imported but will fail if we
        # actually try to call the unknown function...  Hard
        # to test anything more.
        pass

def test_missing_function_import_error():
    # uses the original FFI that just gives a warning during compilation
    import cffi
    test_missing_function(ffi=cffi.FFI())

def test_simple_case():
    ffi = FFI()
    ffi.cdef("double sin(double x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    assert lib.sin(1.23) == math.sin(1.23)

def _Wconversion(cdef, source, **kargs):
    if sys.platform in ('win32', 'darwin'):
        pytest.skip("needs GCC")
    if '-Wno-error=sign-conversion' in extra_compile_args:
        pytest.skip("gcc 9.2.0 compiler bug exposed by Python 3.12+ prevents compilation with sign-conversion warnings-as-errors")
    ffi = FFI()
    ffi.cdef(cdef)
    pytest.raises(VerificationError, ffi.verify, source, **kargs)
    extra_compile_args_orig = extra_compile_args[:]
    extra_compile_args.remove('-Wconversion')
    try:
        lib = ffi.verify(source, **kargs)
    finally:
        extra_compile_args[:] = extra_compile_args_orig
    return lib

def test_Wconversion_unsigned():
    _Wconversion("unsigned foo(void);",
                 "int foo(void) { return -1;}")

def test_Wconversion_integer():
    _Wconversion("short foo(void);",
                 "long long foo(void) { return 1<<sizeof(short);}")

def test_Wconversion_floating():
    lib = _Wconversion("float sin(double);",
                       "#include <math.h>", libraries=lib_m)
    res = lib.sin(1.23)
    assert res != math.sin(1.23)     # not exact, because of double->float
    assert abs(res - math.sin(1.23)) < 1E-5

def test_Wconversion_float2int():
    _Wconversion("int sinf(float);",
                 "#include <math.h>", libraries=lib_m)

def test_Wconversion_double2int():
    _Wconversion("int sin(double);",
                 "#include <math.h>", libraries=lib_m)

def test_rounding_1():
    ffi = FFI()
    ffi.cdef("double sinf(float x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    res = lib.sinf(1.23)
    assert res != math.sin(1.23)     # not exact, because of double->float
    assert abs(res - math.sin(1.23)) < 1E-5

def test_rounding_2():
    ffi = FFI()
    ffi.cdef("double sin(float x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    res = lib.sin(1.23)
    assert res != math.sin(1.23)     # not exact, because of double->float
    assert abs(res - math.sin(1.23)) < 1E-5

def test_strlen_exact():
    ffi = FFI()
    ffi.cdef("size_t strlen(const char *s);")
    lib = ffi.verify("#include <string.h>")
    assert lib.strlen(b"hi there!") == 9

def test_strlen_approximate():
    lib = _Wconversion("int strlen(char *s);",
                       "#include <string.h>")
    assert lib.strlen(b"hi there!") == 9

def test_return_approximate():
    for typename in ['short', 'int', 'long', 'long long']:
        ffi = FFI()
        ffi.cdef("%s foo(signed char x);" % typename)
        lib = ffi.verify("signed char foo(signed char x) { return x;}")
        assert lib.foo(-128) == -128
        assert lib.foo(+127) == +127

def test_strlen_array_of_char():
    ffi = FFI()
    ffi.cdef("size_t strlen(char[]);")
    lib = ffi.verify("#include <string.h>")
    assert lib.strlen(b"hello") == 5

def test_longdouble():
    ffi = FFI()
    ffi.cdef("long double sinl(long double x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    for input in [1.23,
                  ffi.cast("double", 1.23),
                  ffi.cast("long double", 1.23)]:
        x = lib.sinl(input)
        assert repr(x).startswith("<cdata 'long double'")
        assert (float(x) - math.sin(1.23)) < 1E-10

def test_longdouble_precision():
    # Test that we don't loose any precision of 'long double' when
    # passing through Python and CFFI.
    ffi = FFI()
    ffi.cdef("long double step1(long double x);")
    SAME_SIZE = ffi.sizeof("long double") == ffi.sizeof("double")
    lib = ffi.verify("""
        long double step1(long double x)
        {
            return 4*x-x*x;
        }
    """)
    def do(cast_to_double):
        x = 0.9789
        for i in range(10000):
            x = lib.step1(x)
            if cast_to_double:
                x = float(x)
        return float(x)

    more_precise = do(False)
    less_precise = do(True)
    if SAME_SIZE:
        assert more_precise == less_precise
    else:
        assert abs(more_precise - less_precise) > 0.1
        # Check the particular results on Intel
        import platform
        if (platform.machine().startswith('i386') or
            platform.machine().startswith('i486') or
            platform.machine().startswith('i586') or
            platform.machine().startswith('i686') or
            platform.machine().startswith('x86')):
            assert abs(more_precise - 0.656769) < 0.001
            assert abs(less_precise - 3.99091) < 0.001
        else:
            pytest.skip("don't know the very exact precision of 'long double'")


all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
if sys.platform == 'win32':
    all_primitive_types = all_primitive_types.copy()
    del all_primitive_types['ssize_t']
all_integer_types = sorted(tp for tp in all_primitive_types
                           if all_primitive_types[tp] == 'i')
all_float_types = sorted(tp for tp in all_primitive_types
                            if all_primitive_types[tp] == 'f')

def all_signed_integer_types(ffi):
    return [x for x in all_integer_types if int(ffi.cast(x, -1)) < 0]

def all_unsigned_integer_types(ffi):
    return [x for x in all_integer_types if int(ffi.cast(x, -1)) > 0]


def test_primitive_category():
    for typename in all_primitive_types:
        tp = model.PrimitiveType(typename)
        C = tp.is_char_type()
        F = tp.is_float_type()
        X = tp.is_complex_type()
        I = tp.is_integer_type()
        assert C == (typename in ('char', 'wchar_t', 'char16_t', 'char32_t'))
        assert F == (typename in ('float', 'double', 'long double'))
        assert X == (typename in ('float _Complex', 'double _Complex'))
        assert I + F + C + X == 1      # one and only one of them is true

def test_all_integer_and_float_types():
    typenames = []
    for typename in all_primitive_types:
        if (all_primitive_types[typename] == 'c' or
            all_primitive_types[typename] == 'j' or    # complex
            typename == '_Bool' or typename == 'long double'):
            pass
        else:
            typenames.append(typename)
    #
    ffi = FFI()
    ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                       for tp in typenames]))
    lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return (%s)(x+1); }" %
                                (tp, tp.replace(' ', '_'), tp, tp)
                                for tp in typenames]))
    for typename in typenames:
        foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_'))
        assert foo(42) == 43
        if sys.version < '3':
            assert foo(long(44)) == 45
        assert foo(ffi.cast(typename, 46)) == 47
        pytest.raises(TypeError, foo, ffi.NULL)
        #
        # check for overflow cases
        if all_primitive_types[typename] == 'f':
            continue
        for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1,
                      2**5, 2**10, 2**20, 2**40, 2**80]:
            overflows = int(ffi.cast(typename, value)) != value
            if overflows:
                pytest.raises(OverflowError, foo, value)
            else:
                assert foo(value) == value + 1

def test_var_signed_integer_types():
    ffi = FFI()
    lst = all_signed_integer_types(ffi)
    csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
                         for tp in lst])
    ffi.cdef(csource)
    lib = ffi.verify(csource)
    for tp in lst:
        varname = 'somevar_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        max = (1 << (8*sz-1)) - 1
        min = -(1 << (8*sz-1))
        setattr(lib, varname, max)
        assert getattr(lib, varname) == max
        setattr(lib, varname, min)
        assert getattr(lib, varname) == min
        pytest.raises(OverflowError, setattr, lib, varname, max+1)
        pytest.raises(OverflowError, setattr, lib, varname, min-1)

def test_var_unsigned_integer_types():
    ffi = FFI()
    lst = all_unsigned_integer_types(ffi)
    csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
                         for tp in lst])
    ffi.cdef(csource)
    lib = ffi.verify(csource)
    for tp in lst:
        varname = 'somevar_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        if tp != '_Bool':
            max = (1 << (8*sz)) - 1
        else:
            max = 1
        setattr(lib, varname, max)
        assert getattr(lib, varname) == max
        setattr(lib, varname, 0)
        assert getattr(lib, varname) == 0
        pytest.raises(OverflowError, setattr, lib, varname, max+1)
        pytest.raises(OverflowError, setattr, lib, varname, -1)

def test_fn_signed_integer_types():
    ffi = FFI()
    lst = all_signed_integer_types(ffi)
    cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                         for tp in lst])
    ffi.cdef(cdefsrc)
    verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
                           (tp, tp.replace(' ', '_'), tp) for tp in lst])
    lib = ffi.verify(verifysrc)
    for tp in lst:
        fnname = 'somefn_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        max = (1 << (8*sz-1)) - 1
        min = -(1 << (8*sz-1))
        fn = getattr(lib, fnname)
        assert fn(max) == max
        assert fn(min) == min
        pytest.raises(OverflowError, fn, max + 1)
        pytest.raises(OverflowError, fn, min - 1)

def test_fn_unsigned_integer_types():
    ffi = FFI()
    lst = all_unsigned_integer_types(ffi)
    cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                         for tp in lst])
    ffi.cdef(cdefsrc)
    verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
                           (tp, tp.replace(' ', '_'), tp) for tp in lst])
    lib = ffi.verify(verifysrc)
    for tp in lst:
        fnname = 'somefn_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        if tp != '_Bool':
            max = (1 << (8*sz)) - 1
        else:
            max = 1
        fn = getattr(lib, fnname)
        assert fn(max) == max
        assert fn(0) == 0
        pytest.raises(OverflowError, fn, max + 1)
        pytest.raises(OverflowError, fn, -1)

def test_char_type():
    ffi = FFI()
    ffi.cdef("char foo(char);")
    lib = ffi.verify("char foo(char x) { return ++x; }")
    assert lib.foo(b"A") == b"B"
    pytest.raises(TypeError, lib.foo, b"bar")
    pytest.raises(TypeError, lib.foo, "bar")

def test_wchar_type():
    ffi = FFI()
    if ffi.sizeof('wchar_t') == 2:
        uniexample1 = u+'\u1234'
        uniexample2 = u+'\u1235'
    else:
        uniexample1 = u+'\U00012345'
        uniexample2 = u+'\U00012346'
    #
    ffi.cdef("wchar_t foo(wchar_t);")
    lib = ffi.verify("wchar_t foo(wchar_t x) { return x+1; }")
    assert lib.foo(uniexample1) == uniexample2

def test_char16_char32_type():
    pytest.skip("XXX test or fully prevent char16_t and char32_t from "
                 "working in ffi.verify() mode")

def test_no_argument():
    ffi = FFI()
    ffi.cdef("int foo(void);")
    lib = ffi.verify("int foo(void) { return 42; }")
    assert lib.foo() == 42

def test_two_arguments():
    ffi = FFI()
    ffi.cdef("int foo(int, int);")
    lib = ffi.verify("int foo(int a, int b) { return a - b; }")
    assert lib.foo(40, -2) == 42

def test_macro():
    ffi = FFI()
    ffi.cdef("int foo(int, int);")
    lib = ffi.verify("#define foo(a, b) ((a) * (b))")
    assert lib.foo(-6, -7) == 42

def test_ptr():
    ffi = FFI()
    ffi.cdef("int *foo(int *);")
    lib = ffi.verify("int *foo(int *a) { return a; }")
    assert lib.foo(ffi.NULL) == ffi.NULL
    p = ffi.new("int *", 42)
    q = ffi.new("int *", 42)
    assert lib.foo(p) == p
    assert lib.foo(q) != p

def test_bogus_ptr():
    ffi = FFI()
    ffi.cdef("int *foo(int *);")
    lib = ffi.verify("int *foo(int *a) { return a; }")
    pytest.raises(TypeError, lib.foo, ffi.new("short *", 42))


def test_verify_typedefs():
    pytest.skip("ignored so far")
    types = ['signed char', 'unsigned char', 'int', 'long']
    for cdefed in types:
        for real in types:
            ffi = FFI()
            ffi.cdef("typedef %s foo_t;" % cdefed)
            if cdefed == real:
                ffi.verify("typedef %s foo_t;" % real)
            else:
                pytest.raises(VerificationError, ffi.verify,
                               "typedef %s foo_t;" % real)

def test_nondecl_struct():
    ffi = FFI()
    ffi.cdef("typedef struct foo_s foo_t; int bar(foo_t *);")
    lib = ffi.verify("typedef struct foo_s foo_t;\n"
                     "int bar(foo_t *f) { (void)f; return 42; }\n")
    assert lib.bar(ffi.NULL) == 42

def test_ffi_full_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { char x; int y; long *z; };")
    ffi.verify("struct foo_s { char x; int y; long *z; };")
    #
    if sys.platform != 'win32':  # XXX fixme: only gives warnings
        pytest.raises(VerificationError, ffi.verify,
            "struct foo_s { char x; int y; int *z; };")
    #
    pytest.raises(VerificationError, ffi.verify,
        "struct foo_s { int y; long *z; };")
    #
    e = pytest.raises(VerificationError, ffi.verify,
        "struct foo_s { int y; char x; long *z; };")
    assert str(e.value) == (
        "struct foo_s: wrong offset for field 'x'"
        " (we have 0, but C compiler says 4)")
    #
    e = pytest.raises(VerificationError, ffi.verify,
        "struct foo_s { char x; int y; long *z; char extra; };")
    assert str(e.value) == (
        "struct foo_s: wrong total size"
        " (we have %d, but C compiler says %d)" % (
            ffi.sizeof("struct foo_s"),
            ffi.sizeof("struct foo_s") + ffi.sizeof("long*")))
    #
    # a corner case that we cannot really detect, but where it has no
    # bad consequences: the size is the same, but there is an extra field
    # that replaces what is just padding in our declaration above
    ffi.verify("struct foo_s { char x, extra; int y; long *z; };")
    #
    e = pytest.raises(VerificationError, ffi.verify,
        "struct foo_s { char x; short pad; short y; long *z; };")
    assert str(e.value) == (
        "struct foo_s: wrong size for field 'y'"
        " (we have 4, but C compiler says 2)")

def test_ffi_nonfull_struct():
    ffi = FFI()
    ffi.cdef("""
    struct foo_s {
       int x;
       ...;
    };
    """)
    pytest.raises(VerificationMissing, ffi.sizeof, 'struct foo_s')
    pytest.raises(VerificationMissing, ffi.offsetof, 'struct foo_s', 'x')
    pytest.raises(VerificationMissing, ffi.new, 'struct foo_s *')
    ffi.verify("""
    struct foo_s {
       int a, b, x, c, d, e;
    };
    """)
    assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int')
    assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int')

def test_ffi_nonfull_alignment():
    ffi = FFI()
    ffi.cdef("struct foo_s { char x; ...; };")
    ffi.verify("struct foo_s { int a, b; char x; };")
    assert ffi.sizeof('struct foo_s') == 3 * ffi.sizeof('int')
    assert ffi.alignof('struct foo_s') == ffi.sizeof('int')

def _check_field_match(typename, real, expect_mismatch):
    ffi = FFI()
    testing_by_size = (expect_mismatch == 'by_size')
    if testing_by_size:
        expect_mismatch = ffi.sizeof(typename) != ffi.sizeof(real)
    ffi.cdef("struct foo_s { %s x; ...; };" % typename)
    try:
        ffi.verify("struct foo_s { %s x; };" % real)
    except VerificationError:
        if not expect_mismatch:
            if testing_by_size and typename != real:
                print("ignoring mismatch between %s* and %s* even though "
                      "they have the same size" % (typename, real))
                return
            raise AssertionError("unexpected mismatch: %s should be accepted "
                                 "as equal to %s" % (typename, real))
    else:
        if expect_mismatch:
            raise AssertionError("mismatch not detected: "
                                 "%s != %s" % (typename, real))

def test_struct_bad_sized_integer():
    for typename in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
        for real in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
            _check_field_match(typename, real, "by_size")

def test_struct_bad_sized_float():
    for typename in all_float_types:
        for real in all_float_types:
            _check_field_match(typename, real, "by_size")

def test_struct_signedness_ignored():
    _check_field_match("int", "unsigned int", expect_mismatch=False)
    _check_field_match("unsigned short", "signed short", expect_mismatch=False)

def test_struct_float_vs_int():
    if sys.platform == 'win32':
        pytest.skip("XXX fixme: only gives warnings")
    ffi = FFI()
    for typename in all_signed_integer_types(ffi):
        for real in all_float_types:
            _check_field_match(typename, real, expect_mismatch=True)
    for typename in all_float_types:
        for real in all_signed_integer_types(ffi):
            _check_field_match(typename, real, expect_mismatch=True)

def test_struct_array_field():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[17]; ...; };")
    ffi.verify("struct foo_s { int x; int a[17]; int y; };")
    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')

def test_struct_array_no_length():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[]; int y; ...; };\n"
             "int bar(struct foo_s *);\n")
    lib = ffi.verify("struct foo_s { int x; int a[17]; int y; };\n"
                     "int bar(struct foo_s *f) { return f->a[14]; }\n")
    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.typeof(s.a) is ffi.typeof('int[]')   # implicit max length
    assert len(s.a) == 18  # max length, computed from the size and start offset
    s.a[14] = 4242
    assert lib.bar(s) == 4242
    # with no declared length, out-of-bound accesses are not detected
    s.a[17] = -521
    assert s.y == s.a[17] == -521
    #
    s = ffi.new("struct foo_s *", {'a': list(range(17))})
    assert s.a[16] == 16
    # overflows at construction time not detected either
    s = ffi.new("struct foo_s *", {'a': list(range(18))})
    assert s.y == s.a[17] == 17

def test_struct_array_guess_length():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[...]; };")
    ffi.verify("struct foo_s { int x; int a[17]; int y; };")
    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
    with pytest.raises(IndexError):
        s.a[17]

def test_struct_array_c99_1():
    if sys.platform == 'win32':
        pytest.skip("requires C99")
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; int a[]; };")
    ffi.verify("struct foo_s { int x; int a[]; };")
    assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242, 4])
    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
    # ^^^ explanation: if you write in C: "char x[5];", then
    # "sizeof(x)" will evaluate to 5.  The behavior above is
    # a generalization of that to "struct foo_s[len(a)=5] x;"
    # if you could do that in C.
    assert s.a[3] == 0
    s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
    assert s.a[3] == -10
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242])
    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')

def test_struct_array_c99_2():
    if sys.platform == 'win32':
        pytest.skip("requires C99")
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; int a[]; ...; };")
    ffi.verify("struct foo_s { int x, y; int a[]; };")
    assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242, 4])
    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
    assert s.a[3] == 0
    s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
    assert s.a[3] == -10
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242])
    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')

def test_struct_ptr_to_array_field():
    ffi = FFI()
    ffi.cdef("struct foo_s { int (*a)[17]; ...; }; struct bar_s { ...; };")
    ffi.verify("struct foo_s { int x; int (*a)[17]; int y; };\n"
               "struct bar_s { int x; int *a; int y; };")
    assert ffi.sizeof('struct foo_s') == ffi.sizeof("struct bar_s")
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s.a) == ffi.sizeof('int(*)[17]') == ffi.sizeof("int *")

def test_struct_with_bitfield_exact():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a:2, b:3; };")
    ffi.verify("struct foo_s { int a:2, b:3; };")
    s = ffi.new("struct foo_s *")
    s.b = 3
    with pytest.raises(OverflowError):
        s.b = 4
    assert s.b == 3

def test_struct_with_bitfield_enum():
    ffi = FFI()
    code = """
        typedef enum { AA, BB, CC } foo_e;
        typedef struct { foo_e f:2; } foo_s;
    """
    ffi.cdef(code)
    ffi.verify(code)
    s = ffi.new("foo_s *")
    s.f = 2
    assert s.f == 2

def test_unsupported_struct_with_bitfield_ellipsis():
    ffi = FFI()
    pytest.raises(NotImplementedError, ffi.cdef,
                   "struct foo_s { int a:2, b:3; ...; };")

def test_global_constants():
    ffi = FFI()
    # use 'static const int', as generally documented, although in this
    # case the 'static' is completely ignored.
    ffi.cdef("static const int AA, BB, CC, DD;")
    lib = ffi.verify("#define AA 42\n"
                     "#define BB (-43)   // blah\n"
                     "#define CC (22*2)  /* foobar */\n"
                     "#define DD ((unsigned int)142)  /* foo\nbar */\n")
    assert lib.AA == 42
    assert lib.BB == -43
    assert lib.CC == 44
    assert lib.DD == 142

def test_global_const_int_size():
    # integer constants: ignore the declared type, always just use the value
    for value in [-2**63, -2**31, -2**15,
                  2**15-1, 2**15, 2**31-1, 2**31, 2**32-1, 2**32,
                  2**63-1, 2**63, 2**64-1]:
        ffi = FFI()
        if value == int(ffi.cast("long long", value)):
            if value < 0:
                vstr = '(-%dLL-1)' % (~value,)
            else:
                vstr = '%dLL' % value
        elif value == int(ffi.cast("unsigned long long", value)):
            vstr = '%dULL' % value
        else:
            raise AssertionError(value)
        ffi.cdef("static const unsigned short AA;")
        lib = ffi.verify("#define AA %s\n" % vstr)
        assert lib.AA == value
        assert type(lib.AA) is type(int(lib.AA))

def test_global_constants_non_int():
    ffi = FFI()
    ffi.cdef("static char *const PP;")
    lib = ffi.verify('static char *const PP = "testing!";\n')
    assert ffi.typeof(lib.PP) == ffi.typeof("char *")
    assert ffi.string(lib.PP) == b"testing!"

def test_nonfull_enum():
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2, EE3, ... \n \t };")
    pytest.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE2')
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
    assert ffi.string(ffi.cast('enum ee', -10)) == "EE3"
    #
    # try again
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
    #
    assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3': -10}
    assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'}

def test_full_enum():
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2, EE3 };")
    ffi.verify("enum ee { EE1, EE2, EE3 };")
    pytest.raises(VerificationError, ffi.verify, "enum ee { EE1, EE2 };")
    e = pytest.raises(VerificationError, ffi.verify,
                       "enum ee { EE1, EE3, EE2 };")
    assert str(e.value) == 'enum ee: EE2 has the real value 2, not 1'
    # extra items cannot be seen and have no bad consequence anyway
    lib = ffi.verify("enum ee { EE1, EE2, EE3, EE4 };")
    assert lib.EE3 == 2

def test_enum_usage():
    ffi = FFI()
    ffi.cdef("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
    lib = ffi.verify("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
    assert lib.EE2 == 1
    s = ffi.new("sp", [lib.EE2])
    assert s.x == 1
    s.x = 17
    assert s.x == 17

def test_anonymous_enum():
    ffi = FFI()
    ffi.cdef("enum { EE1 }; enum { EE2, EE3 };")
    lib = ffi.verify("enum { EE1 }; enum { EE2, EE3 };")
    assert lib.EE1 == 0
    assert lib.EE2 == 0
    assert lib.EE3 == 1

def test_nonfull_anonymous_enum():
    ffi = FFI()
    ffi.cdef("enum { EE1, ... }; enum { EE3, ... };")
    lib = ffi.verify("enum { EE2, EE1 }; enum { EE3 };")
    assert lib.EE1 == 1
    assert lib.EE3 == 0

def test_nonfull_enum_syntax2():
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2=\t..., EE3 };")
    pytest.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
    assert ffi.string(ffi.cast('enum ee', -10)) == 'EE3'
    #
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2=\t... };")
    pytest.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
    #
    ffi = FFI()
    ffi.cdef("enum ee2 { EE4=..., EE5=..., ... };")
    ffi.verify("enum ee2 { EE4=-1234-5, EE5 }; ")
    assert ffi.string(ffi.cast('enum ee2', -1239)) == 'EE4'
    assert ffi.string(ffi.cast('enum ee2', -1238)) == 'EE5'

def test_nonfull_enum_bug3():
    ffi = FFI()
    ffi.cdef("enum ee2 { EE4=..., EE5=... };")
    ffi.cdef("enum ee6 { EE7=10, EE8=..., EE9=... };")

def test_get_set_errno():
    ffi = FFI()
    ffi.cdef("int foo(int);")
    lib = ffi.verify("""
        static int foo(int x)
        {
            errno += 1;
            return x * 7;
        }
    """)
    ffi.errno = 15
    assert lib.foo(6) == 42
    assert ffi.errno == 16

def test_define_int():
    ffi = FFI()
    ffi.cdef("#define FOO ...\n"
             "\t#\tdefine\tBAR\t...\t\n"
             "#define BAZ ...\n")
    lib = ffi.verify("#define FOO 42\n"
                     "#define BAR (-44)\n"
                     "#define BAZ 0xffffffffffffffffULL\n")
    assert lib.FOO == 42
    assert lib.BAR == -44
    assert lib.BAZ == 0xffffffffffffffff

def test_access_variable():
    ffi = FFI()
    ffi.cdef("static int foo(void);\n"
             "static int somenumber;")
    lib = ffi.verify("""
        static int somenumber = 2;
        static int foo(void) {
            return somenumber * 7;
        }
    """)
    assert lib.somenumber == 2
    assert lib.foo() == 14
    lib.somenumber = -6
    assert lib.foo() == -42
    assert lib.somenumber == -6
    lib.somenumber = 2   # reset for the next run, if any

def test_access_address_of_variable():
    # access the address of 'somenumber': need a trick
    ffi = FFI()
    ffi.cdef("static int somenumber; static int *const somenumberptr;")
    lib = ffi.verify("""
        static int somenumber = 2;
        #define somenumberptr (&somenumber)
    """)
    assert lib.somenumber == 2
    lib.somenumberptr[0] = 42
    assert lib.somenumber == 42
    lib.somenumber = 2    # reset for the next run, if any

def test_access_array_variable(length=5):
    ffi = FFI()
    ffi.cdef("int foo(int);\n"
             "static int somenumber[%s];" % (length,))
    lib = ffi.verify("""
        static int somenumber[] = {2, 2, 3, 4, 5};
        static int foo(int i) {
            return somenumber[i] * 7;
        }
    """)
    if length == '':
        # a global variable of an unknown array length is implicitly
        # transformed into a global pointer variable, because we can only
        # work with array instances whose length we know.  using a pointer
        # instead of an array gives the correct effects.
        assert repr(lib.somenumber).startswith("<cdata 'int *' 0x")
        pytest.raises(TypeError, len, lib.somenumber)
    else:
        assert repr(lib.somenumber).startswith("<cdata 'int[%s]' 0x" % length)
        assert len(lib.somenumber) == 5
    assert lib.somenumber[3] == 4
    assert lib.foo(3) == 28
    lib.somenumber[3] = -6
    assert lib.foo(3) == -42
    assert lib.somenumber[3] == -6
    assert lib.somenumber[4] == 5
    lib.somenumber[3] = 4    # reset for the next run, if any

def test_access_array_variable_length_hidden():
    test_access_array_variable(length='')

def test_access_struct_variable():
    ffi = FFI()
    ffi.cdef("struct foo { int x; ...; };\n"
             "int foo(int);\n"
             "static struct foo stuff;")
    lib = ffi.verify("""
        struct foo { int x, y, z; };
        static struct foo stuff = {2, 5, 8};
        static int foo(int i) {
            switch (i) {
            case 0: return stuff.x * 7;
            case 1: return stuff.y * 7;
            case 2: return stuff.z * 7;
            }
            return -1;
        }
    """)
    assert lib.stuff.x == 2
    assert lib.foo(0) == 14
    assert lib.foo(1) == 35
    assert lib.foo(2) == 56
    lib.stuff.x = -6
    assert lib.foo(0) == -42
    assert lib.foo(1) == 35
    lib.stuff.x = 2      # reset for the next run, if any

def test_access_callback():
    ffi = FFI()
    ffi.cdef("static int (*cb)(int);\n"
             "static int foo(int);\n"
             "static void reset_cb(void);")
    lib = ffi.verify("""
        static int g(int x) { return x * 7; }
        static int (*cb)(int);
        static int foo(int i) { return cb(i) - 1; }
        static void reset_cb(void) { cb = g; }
    """)
    lib.reset_cb()
    assert lib.foo(6) == 41
    my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
    lib.cb = my_callback
    assert lib.foo(4) == 887

def test_access_callback_function_typedef():
    ffi = FFI()
    ffi.cdef("typedef int mycallback_t(int);\n"
             "static mycallback_t *cb;\n"
             "static int foo(int);\n"
             "static void reset_cb(void);")
    lib = ffi.verify("""
        static int g(int x) { return x * 7; }
        static int (*cb)(int);
        static int foo(int i) { return cb(i) - 1; }
        static void reset_cb(void) { cb = g; }
    """)
    lib.reset_cb()
    assert lib.foo(6) == 41
    my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
    lib.cb = my_callback
    assert lib.foo(4) == 887

def test_ctypes_backend_forces_generic_engine():
    from cffi.backend_ctypes import CTypesBackend
    ffi = FFI(backend=CTypesBackend())
    ffi.cdef("int func(int a);")
    lib = ffi.verify("int func(int a) { return a * 42; }")
    assert not hasattr(lib, '_cffi_python_module')
    assert hasattr(lib, '_cffi_generic_module')
    assert lib.func(100) == 4200

def test_call_with_struct_ptr():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);")
    lib = ffi.verify("""
        typedef struct { int y, x; } foo_t;
        static int foo(foo_t *f) { return f->x * 7; }
    """)
    f = ffi.new("foo_t *")
    f.x = 6
    assert lib.foo(f) == 42

def test_unknown_type():
    ffi = FFI()
    ffi.cdef("""
        typedef ... token_t;
        int foo(token_t *);
        #define TOKEN_SIZE ...
    """)
    lib = ffi.verify("""
        typedef float token_t;
        static int foo(token_t *tk) {
            if (!tk)
                return -42;
            *tk += 1.601f;
            return (int)*tk;
        }
        #define TOKEN_SIZE sizeof(token_t)
    """)
    # we cannot let ffi.new("token_t *") work, because we don't know ahead of
    # time if it's ok to ask 'sizeof(token_t)' in the C code or not.
    # See test_unknown_type_2.  Workaround.
    tkmem = ffi.new("char[]", lib.TOKEN_SIZE)    # zero-initialized
    tk = ffi.cast("token_t *", tkmem)
    results = [lib.foo(tk) for i in range(6)]
    assert results == [1, 3, 4, 6, 8, 9]
    assert lib.foo(ffi.NULL) == -42

def test_unknown_type_2():
    ffi = FFI()
    ffi.cdef("typedef ... token_t;")
    lib = ffi.verify("typedef struct token_s token_t;")
    # assert did not crash, even though 'sizeof(token_t)' is not valid in C.

def test_unknown_type_3():
    ffi = FFI()
    ffi.cdef("""
        typedef ... *token_p;
        token_p foo(token_p);
    """)
    lib = ffi.verify("""
        typedef struct _token_s *token_p;
        token_p foo(token_p arg) {
            if (arg)
                return (token_p)0x12347;
            else
                return (token_p)0x12345;
        }
    """)
    p = lib.foo(ffi.NULL)
    assert int(ffi.cast("intptr_t", p)) == 0x12345
    q = lib.foo(p)
    assert int(ffi.cast("intptr_t", q)) == 0x12347

def test_varargs():
    ffi = FFI()
    ffi.cdef("int foo(int x, ...);")
    lib = ffi.verify("""
        int foo(int x, ...) {
            va_list vargs;
            va_start(vargs, x);
            x -= va_arg(vargs, int);
            x -= va_arg(vargs, int);
            va_end(vargs);
            return x;
        }
    """)
    assert lib.foo(50, ffi.cast("int", 5), ffi.cast("int", 3)) == 42

def test_varargs_exact():
    if sys.platform == 'win32':
        pytest.skip("XXX fixme: only gives warnings")
    ffi = FFI()
    ffi.cdef("int foo(int x, ...);")
    pytest.raises(VerificationError, ffi.verify, """
        int foo(long long x, ...) {
            return x;
        }
    """)

def test_varargs_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { char a; int b; }; int foo(int x, ...);")
    lib = ffi.verify("""
        struct foo_s {
            char a; int b;
        };
        int foo(int x, ...) {
            va_list vargs;
            struct foo_s s;
            va_start(vargs, x);
            s = va_arg(vargs, struct foo_s);
            va_end(vargs);
            return s.a - s.b;
        }
    """)
    s = ffi.new("struct foo_s *", [b'B', 1])
    assert lib.foo(50, s[0]) == ord('A')

def test_autofilled_struct_as_argument():
    ffi = FFI()
    ffi.cdef("struct foo_s { long a; double b; ...; };\n"
             "int foo(struct foo_s);")
    lib = ffi.verify("""
        struct foo_s {
            double b;
            long a;
        };
        int foo(struct foo_s s) {
            return (int)s.a - (int)s.b;
        }
    """)
    s = ffi.new("struct foo_s *", [100, 1])
    assert lib.foo(s[0]) == 99
    assert lib.foo([100, 1]) == 99

def test_autofilled_struct_as_argument_dynamic():
    ffi = FFI()
    ffi.cdef("struct foo_s { long a; ...; };\n"
             "static int (*foo)(struct foo_s);")
    lib = ffi.verify("""
        struct foo_s {
            double b;
            long a;
        };
        int foo1(struct foo_s s) {
            return (int)s.a - (int)s.b;
        }
        static int (*foo)(struct foo_s s) = &foo1;
    """)
    e = pytest.raises(NotImplementedError, lib.foo, "?")
    msg = ("ctype 'struct foo_s' not supported as argument.  It is a struct "
           'declared with "...;", but the C calling convention may depend on '
           "the missing fields; or, it contains anonymous struct/unions.  "
           "Such structs are only supported as argument "
           "if the function is 'API mode' and non-variadic (i.e. declared "
           "inside ffibuilder.cdef()+ffibuilder.set_source() and not taking "
           "a final '...' argument)")
    assert str(e.value) == msg

def test_func_returns_struct():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { int aa, bb; };
        struct foo_s foo(int a, int b);
    """)
    lib = ffi.verify("""
        struct foo_s { int aa, bb; };
        struct foo_s foo(int a, int b) {
            struct foo_s r;
            r.aa = a*a;
            r.bb = b*b;
            return r;
        }
    """)
    s = lib.foo(6, 7)
    assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>"
    assert s.aa == 36
    assert s.bb == 49

def test_func_as_funcptr():
    ffi = FFI()
    ffi.cdef("int *(*const fooptr)(void);")
    lib = ffi.verify("""
        int *foo(void) {
            return (int*)"foobar";
        }
        int *(*fooptr)(void) = foo;
    """)
    foochar = ffi.cast("char *(*)(void)", lib.fooptr)
    s = foochar()
    assert ffi.string(s) == b"foobar"

def test_funcptr_as_argument():
    ffi = FFI()
    ffi.cdef("""
        void qsort(void *base, size_t nel, size_t width,
            int (*compar)(const void *, const void *));
    """)
    ffi.verify("#include <stdlib.h>")

def test_func_as_argument():
    ffi = FFI()
    ffi.cdef("""
        void qsort(void *base, size_t nel, size_t width,
            int compar(const void *, const void *));
    """)
    ffi.verify("#include <stdlib.h>")

def test_array_as_argument():
    ffi = FFI()
    ffi.cdef("""
        size_t strlen(char string[]);
    """)
    ffi.verify("#include <string.h>")

def test_enum_as_argument():
    ffi = FFI()
    ffi.cdef("""
        enum foo_e { AA, BB, ... };
        int foo_func(enum foo_e);
    """)
    lib = ffi.verify("""
        enum foo_e { AA, CC, BB };
        int foo_func(enum foo_e e) { return (int)e; }
    """)
    assert lib.foo_func(lib.BB) == 2
    pytest.raises(TypeError, lib.foo_func, "BB")

def test_enum_as_function_result():
    ffi = FFI()
    ffi.cdef("""
        enum foo_e { AA, BB, ... };
        enum foo_e foo_func(int x);
    """)
    lib = ffi.verify("""
        enum foo_e { AA, CC, BB };
        enum foo_e foo_func(int x) { return (enum foo_e)x; }
    """)
    assert lib.foo_func(lib.BB) == lib.BB == 2

def test_enum_values():
    ffi = FFI()
    ffi.cdef("enum enum1_e { AA, BB };")
    lib = ffi.verify("enum enum1_e { AA, BB };")
    assert lib.AA == 0
    assert lib.BB == 1
    assert ffi.string(ffi.cast("enum enum1_e", 1)) == 'BB'

def test_typedef_complete_enum():
    ffi = FFI()
    ffi.cdef("typedef enum { AA, BB } enum1_t;")
    lib = ffi.verify("typedef enum { AA, BB } enum1_t;")
    assert ffi.string(ffi.cast("enum1_t", 1)) == 'BB'
    assert lib.AA == 0
    assert lib.BB == 1

def test_typedef_broken_complete_enum():
    ffi = FFI()
    ffi.cdef("typedef enum { AA, BB } enum1_t;")
    pytest.raises(VerificationError, ffi.verify,
                   "typedef enum { AA, CC, BB } enum1_t;")

def test_typedef_incomplete_enum():
    ffi = FFI()
    ffi.cdef("typedef enum { AA, BB, ... } enum1_t;")
    lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
    assert ffi.string(ffi.cast("enum1_t", 1)) == '1'
    assert ffi.string(ffi.cast("enum1_t", 2)) == 'BB'
    assert lib.AA == 0
    assert lib.BB == 2

def test_typedef_enum_as_argument():
    ffi = FFI()
    ffi.cdef("""
        typedef enum { AA, BB, ... } foo_t;
        int foo_func(foo_t);
    """)
    lib = ffi.verify("""
        typedef enum { AA, CC, BB } foo_t;
        int foo_func(foo_t e) { return (int)e; }
    """)
    assert lib.foo_func(lib.BB) == lib.BB == 2
    pytest.raises(TypeError, lib.foo_func, "BB")

def test_typedef_enum_as_function_result():
    ffi = FFI()
    ffi.cdef("""
        typedef enum { AA, BB, ... } foo_t;
        foo_t foo_func(int x);
    """)
    lib = ffi.verify("""
        typedef enum { AA, CC, BB } foo_t;
        foo_t foo_func(int x) { return (foo_t)x; }
    """)
    assert lib.foo_func(lib.BB) == lib.BB == 2

def test_function_typedef():
    ffi = FFI()
    ffi.cdef("""
        typedef double func_t(double);
        func_t sin;
    """)
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    assert lib.sin(1.23) == math.sin(1.23)

def test_opaque_integer_as_function_result():
    #import platform
    #if platform.machine().startswith('sparc'):
    #    pytest.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
    #elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
    #    pytest.skip('Segfaults on mips64el')
    # XXX bad abuse of "struct { ...; }".  It only works a bit by chance
    # anyway.  XXX think about something better :-(
    ffi = FFI()
    ffi.cdef("""
        typedef struct { ...; } myhandle_t;
        myhandle_t foo(void);
    """)
    lib = ffi.verify("""
        typedef short myhandle_t;
        myhandle_t foo(void) { return 42; }
    """)
    h = lib.foo()
    assert ffi.sizeof(h) == ffi.sizeof("short")

def test_return_partial_struct():
    ffi = FFI()
    ffi.cdef("""
        typedef struct { int x; ...; } foo_t;
        foo_t foo(void);
    """)
    lib = ffi.verify("""
        typedef struct { int y, x; } foo_t;
        foo_t foo(void) { foo_t r = { 45, 81 }; return r; }
    """)
    h = lib.foo()
    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
    assert h.x == 81

def test_take_and_return_partial_structs():
    ffi = FFI()
    ffi.cdef("""
        typedef struct { int x; ...; } foo_t;
        foo_t foo(foo_t, foo_t);
    """)
    lib = ffi.verify("""
        typedef struct { int y, x; } foo_t;
        foo_t foo(foo_t a, foo_t b) {
            foo_t r = { 100, a.x * 5 + b.x * 7 };
            return r;
        }
    """)
    args = ffi.new("foo_t[3]")
    args[0].x = 1000
    args[2].x = -498
    h = lib.foo(args[0], args[2])
    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
    assert h.x == 1000 * 5 - 498 * 7

def test_cannot_name_struct_type():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; } **sp; void foo(sp);")
    e = pytest.raises(VerificationError, ffi.verify,
                       "typedef struct { int x; } **sp; void foo(sp x) { }")
    assert 'in argument of foo: unknown type name' in str(e.value)

def test_dont_check_unnamable_fields():
    ffi = FFI()
    ffi.cdef("struct foo_s { struct { int x; } someone; };")
    ffi.verify("struct foo_s { struct { int x; } someone; };")
    # assert did not crash

def test_nested_anonymous_struct_exact():
    if sys.platform == 'win32':
        pytest.skip("nested anonymous struct/union")
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { struct { int a; char b; }; union { char c, d; }; };
    """)
    ffi.verify("""
        struct foo_s { struct { int a; char b; }; union { char c, d; }; };
    """)
    p = ffi.new("struct foo_s *")
    assert ffi.sizeof(p[0]) == 3 * ffi.sizeof("int")    # with alignment
    p.a = 1234567
    p.b = b'X'
    p.c = b'Y'
    assert p.a == 1234567
    assert p.b == b'X'
    assert p.c == b'Y'
    assert p.d == b'Y'

def test_nested_anonymous_struct_exact_error():
    if sys.platform == 'win32':
        pytest.skip("nested anonymous struct/union")
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { struct { int a; char b; }; union { char c, d; }; };
    """)
    pytest.raises(VerificationError, ffi.verify, """
        struct foo_s { struct { int a; short b; }; union { char c, d; }; };
    """)
    pytest.raises(VerificationError, ffi.verify, """
        struct foo_s { struct { int a; char e, b; }; union { char c, d; }; };
    """)

def test_nested_anonymous_struct_inexact_1():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { struct { char b; ...; }; union { char c, d; }; };
    """)
    ffi.verify("""
        struct foo_s { int a, padding; char c, d, b; };
    """)
    assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")

def test_nested_anonymous_struct_inexact_2():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { union { char c, d; }; struct { int a; char b; }; ...; };
    """)
    ffi.verify("""
        struct foo_s { int a, padding; char c, d, b; };
    """)
    assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")

def test_ffi_union():
    ffi = FFI()
    ffi.cdef("union foo_u { char x; long *z; };")
    ffi.verify("union foo_u { char x; int y; long *z; };")

def test_ffi_union_partial():
    ffi = FFI()
    ffi.cdef("union foo_u { char x; ...; };")
    ffi.verify("union foo_u { char x; int y; };")
    assert ffi.sizeof("union foo_u") == 4

def test_ffi_union_with_partial_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; ...; }; union foo_u { struct foo_s s; };")
    ffi.verify("struct foo_s { int a; int x; }; "
               "union foo_u { char b[32]; struct foo_s s; };")
    assert ffi.sizeof("struct foo_s") == 8
    assert ffi.sizeof("union foo_u") == 32

def test_ffi_union_partial_2():
    ffi = FFI()
    ffi.cdef("typedef union { char x; ...; } u1;")
    ffi.verify("typedef union { char x; int y; } u1;")
    assert ffi.sizeof("u1") == 4

def test_ffi_union_with_partial_struct_2():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; ...; } s1;"
             "typedef union { s1 s; } u1;")
    ffi.verify("typedef struct { int a; int x; } s1; "
               "typedef union { char b[32]; s1 s; } u1;")
    assert ffi.sizeof("s1") == 8
    assert ffi.sizeof("u1") == 32
    assert ffi.offsetof("u1", "s") == 0

def test_ffi_struct_packed():
    if sys.platform == 'win32':
        pytest.skip("needs a GCC extension")
    ffi = FFI()
    ffi.cdef("struct foo_s { int b; ...; };")
    ffi.verify("""
        struct foo_s {
            char a;
            int b;
        } __attribute__((packed));
    """)

def test_tmpdir():
    import tempfile, os
    from testing.udir import udir
    tmpdir = tempfile.mkdtemp(dir=str(udir))
    ffi = FFI()
    ffi.cdef("int foo(int);")
    lib = ffi.verify("int foo(int a) { return a + 42; }", tmpdir=tmpdir)
    assert os.listdir(tmpdir)
    assert lib.foo(100) == 142

def test_relative_to():
    import tempfile, os
    from testing.udir import udir
    tmpdir = tempfile.mkdtemp(dir=str(udir))
    ffi = FFI()
    ffi.cdef("int foo(int);")
    f = open(os.path.join(tmpdir, 'foo.h'), 'w')
    f.write("int foo(int a) { return a + 42; }\n")
    f.close()
    lib = ffi.verify('#include "foo.h"',
                     include_dirs=['.'],
                     relative_to=os.path.join(tmpdir, 'x'))
    assert lib.foo(100) == 142

def test_bug1():
    ffi = FFI()
    ffi.cdef("""
        typedef struct tdlhandle_s { ...; } *tdl_handle_t;
        typedef struct my_error_code_ {
            tdl_handle_t *rh;
        } my_error_code_t;
    """)
    ffi.verify("""
        typedef struct tdlhandle_s { int foo; } *tdl_handle_t;
        typedef struct my_error_code_ {
            tdl_handle_t *rh;
        } my_error_code_t;
    """)

def test_bool():
    if sys.platform == 'win32':
        pytest.skip("_Bool not in MSVC")
    ffi = FFI()
    ffi.cdef("struct foo_s { _Bool x; };"
             "_Bool foo(_Bool); static _Bool (*foop)(_Bool);")
    lib = ffi.verify("""
        struct foo_s { _Bool x; };
        int foo(int arg) {
            return !arg;
        }
        _Bool _foofunc(_Bool x) {
            return !x;
        }
        static _Bool (*foop)(_Bool) = _foofunc;
    """)
    p = ffi.new("struct foo_s *")
    p.x = 1
    assert p.x is True
    with pytest.raises(OverflowError):
        p.x = -1
    with pytest.raises(TypeError):
        p.x = 0.0
    assert lib.foop(1) is False
    assert lib.foop(True) is False
    assert lib.foop(0) is True
    pytest.raises(OverflowError, lib.foop, 42)
    pytest.raises(TypeError, lib.foop, 0.0)
    assert lib.foo(1) is False
    assert lib.foo(True) is False
    assert lib.foo(0) is True
    pytest.raises(OverflowError, lib.foo, 42)
    pytest.raises(TypeError, lib.foo, 0.0)
    assert int(ffi.cast("_Bool", long(1))) == 1
    assert int(ffi.cast("_Bool", long(0))) == 0
    assert int(ffi.cast("_Bool", long(-1))) == 1
    assert int(ffi.cast("_Bool", 10**200)) == 1
    assert int(ffi.cast("_Bool", 10**40000)) == 1
    #
    class Foo(object):
        def __int__(self):
            self.seen = 1
            return result
    f = Foo()
    f.seen = 0
    result = 42
    assert int(ffi.cast("_Bool", f)) == 1
    assert f.seen
    f.seen = 0
    result = 0
    assert int(ffi.cast("_Bool", f)) == 0
    assert f.seen
    #
    pytest.raises(TypeError, ffi.cast, "_Bool", [])

def test_bool_on_long_double():
    if sys.platform == 'win32':
        pytest.skip("_Bool not in MSVC")
    f = 1E-250
    if f == 0.0 or f*f != 0.0:
        pytest.skip("unexpected precision")
    ffi = FFI()
    ffi.cdef("long double square(long double f); _Bool opposite(_Bool);")
    lib = ffi.verify("long double square(long double f) { return f*f; }\n"
                     "_Bool opposite(_Bool x) { return !x; }")
    f0 = lib.square(0.0)
    f2 = lib.square(f)
    f3 = lib.square(f * 2.0)
    if repr(f2) == repr(f3):
        pytest.skip("long double doesn't have enough precision")
    assert float(f0) == float(f2) == float(f3) == 0.0  # too tiny for 'double'
    assert int(ffi.cast("_Bool", f2)) == 1
    assert int(ffi.cast("_Bool", f3)) == 1
    assert int(ffi.cast("_Bool", f0)) == 0
    pytest.raises(TypeError, lib.opposite, f2)

def test_cannot_pass_float():
    for basetype in ['char', 'short', 'int', 'long', 'long long']:
        for sign in ['signed', 'unsigned']:
            type = '%s %s' % (sign, basetype)
            ffi = FFI()
            ffi.cdef("struct foo_s { %s x; };\n"
                     "int foo(%s);" % (type, type))
            lib = ffi.verify("""
                struct foo_s { %s x; };
                int foo(%s arg) {
                    return !arg;
                }
            """ % (type, type))
            p = ffi.new("struct foo_s *")
            with pytest.raises(TypeError):
                p.x = 0.0
            assert lib.foo(42) == 0
            assert lib.foo(0) == 1
            pytest.raises(TypeError, lib.foo, 0.0)

def test_cast_from_int_type_to_bool():
    ffi = FFI()
    for basetype in ['char', 'short', 'int', 'long', 'long long']:
        for sign in ['signed', 'unsigned']:
            type = '%s %s' % (sign, basetype)
            assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1
            assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1
            assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0

def test_addressof():
    ffi = FFI()
    ffi.cdef("""
        struct point_s { int x, y; };
        struct foo_s { int z; struct point_s point; };
        struct point_s sum_coord(struct point_s *);
    """)
    lib = ffi.verify("""
        struct point_s { int x, y; };
        struct foo_s { int z; struct point_s point; };
        struct point_s sum_coord(struct point_s *point) {
            struct point_s r;
            r.x = point->x + point->y;
            r.y = point->x - point->y;
            return r;
        }
    """)
    p = ffi.new("struct foo_s *")
    p.point.x = 16
    p.point.y = 9
    pytest.raises(TypeError, lib.sum_coord, p.point)
    res = lib.sum_coord(ffi.addressof(p.point))
    assert res.x == 25
    assert res.y == 7
    res2 = lib.sum_coord(ffi.addressof(res))
    assert res2.x == 32
    assert res2.y == 18
    pytest.raises(TypeError, lib.sum_coord, res2)

def test_callback_in_thread():
    if sys.platform == 'win32':
        pytest.skip("pthread only")
    import os, subprocess
    from cffi import _imp_emulation as imp
    arg = os.path.join(os.path.dirname(__file__), 'callback_in_thread.py')
    g = subprocess.Popen([sys.executable, arg,
                          os.path.dirname(imp.find_module('cffi')[1])])
    result = g.wait()
    assert result == 0

def test_keepalive_lib():
    ffi = FFI()
    ffi.cdef("int foobar(void);")
    lib = ffi.verify("int foobar(void) { return 42; }")
    func = lib.foobar
    ffi_r = weakref.ref(ffi)
    lib_r = weakref.ref(lib)
    del ffi
    import gc; gc.collect()       # lib stays alive
    assert lib_r() is not None
    assert ffi_r() is not None
    assert func() == 42

def test_keepalive_ffi():
    ffi = FFI()
    ffi.cdef("int foobar(void);")
    lib = ffi.verify("int foobar(void) { return 42; }")
    func = lib.foobar
    ffi_r = weakref.ref(ffi)
    lib_r = weakref.ref(lib)
    del lib
    import gc; gc.collect()       # ffi stays alive
    assert ffi_r() is not None
    assert lib_r() is not None
    assert func() == 42

def test_FILE_stored_in_stdout():
    if not sys.platform.startswith('linux') or is_musl:
        pytest.skip("likely, we cannot assign to stdout")
    ffi = FFI()
    ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
    lib = ffi.verify("""
        #include <stdio.h>
        FILE *setstdout(FILE *f) {
            FILE *result = stdout;
            stdout = f;
            return result;
        }
    """)
    import os
    fdr, fdw = os.pipe()
    fw1 = os.fdopen(fdw, 'wb', 256)
    old_stdout = lib.setstdout(fw1)
    try:
        #
        fw1.write(b"X")
        r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42))
        fw1.close()
        assert r == len("hello, 42!\n")
        #
    finally:
        lib.setstdout(old_stdout)
    #
    result = os.read(fdr, 256)
    os.close(fdr)
    # the 'X' might remain in the user-level buffer of 'fw1' and
    # end up showing up after the 'hello, 42!\n'
    assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"

def test_FILE_stored_explicitly():
    ffi = FFI()
    ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;")
    lib = ffi.verify("""
        #include <stdio.h>
        FILE *myfile;
        int myprintf11(const char *out, int value) {
            return fprintf(myfile, out, value);
        }
    """)
    import os
    fdr, fdw = os.pipe()
    fw1 = os.fdopen(fdw, 'wb', 256)
    lib.myfile = ffi.cast("FILE *", fw1)
    #
    fw1.write(b"X")
    r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
    fw1.close()
    assert r == len("hello, 42!\n")
    #
    result = os.read(fdr, 256)
    os.close(fdr)
    # the 'X' might remain in the user-level buffer of 'fw1' and
    # end up showing up after the 'hello, 42!\n'
    assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"

def test_global_array_with_missing_length():
    ffi = FFI()
    ffi.cdef("extern int fooarray[];")
    lib = ffi.verify("int fooarray[50];")
    assert repr(lib.fooarray).startswith("<cdata 'int *'")

def test_global_array_with_dotdotdot_length():
    ffi = FFI()
    ffi.cdef("extern int fooarray[...];")
    lib = ffi.verify("int fooarray[50];")
    assert repr(lib.fooarray).startswith("<cdata 'int[50]'")

def test_bad_global_array_with_dotdotdot_length():
    ffi = FFI()
    ffi.cdef("extern int fooarray[...];")
    pytest.raises(VerificationError, ffi.verify, "char fooarray[23];")

def test_struct_containing_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { ...; }; struct bar_s { struct foo_s f; ...; };")
    ffi.verify("struct foo_s { int x; }; struct bar_s { struct foo_s f; };")
    #
    ffi = FFI()
    ffi.cdef("struct foo_s { struct bar_s f; ...; }; struct bar_s { ...; };")
    ffi.verify("struct bar_s { int x; }; struct foo_s { struct bar_s f; };")

def test_struct_returned_by_func():
    ffi = FFI()
    ffi.cdef("typedef ... foo_t; foo_t myfunc(void);")
    e = pytest.raises(TypeError, ffi.verify,
                       "typedef struct { int x; } foo_t; "
                       "foo_t myfunc(void) { foo_t x = { 42 }; return x; }")
    assert str(e.value) == (
        "function myfunc: 'foo_t' is used as result type, but is opaque")

def test_include():
    ffi1 = FFI()
    ffi1.cdef("typedef struct { int x; ...; } foo_t;")
    ffi1.verify("typedef struct { int y, x; } foo_t;")
    ffi2 = FFI()
    ffi2.include(ffi1)
    ffi2.cdef("int myfunc(foo_t *);")
    lib = ffi2.verify("typedef struct { int y, x; } foo_t;"
                      "int myfunc(foo_t *p) { return 42 * p->x; }")
    res = lib.myfunc(ffi2.new("foo_t *", {'x': 10}))
    assert res == 420
    res = lib.myfunc(ffi1.new("foo_t *", {'x': -10}))
    assert res == -420

def test_include_enum():
    ffi1 = FFI()
    ffi1.cdef("enum foo_e { AA, ... };")
    lib1 = ffi1.verify("enum foo_e { CC, BB, AA };")
    ffi2 = FFI()
    ffi2.include(ffi1)
    ffi2.cdef("int myfunc(enum foo_e);")
    lib2 = ffi2.verify("enum foo_e { CC, BB, AA };"
                       "int myfunc(enum foo_e x) { return (int)x; }")
    res = lib2.myfunc(lib2.AA)
    assert res == 2

def test_named_pointer_as_argument():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; } *mystruct_p;\n"
             "mystruct_p ff5a(mystruct_p);")
    lib = ffi.verify("typedef struct { int x; } *mystruct_p;\n"
                     "mystruct_p ff5a(mystruct_p p) { p->x += 40; return p; }")
    p = ffi.new("mystruct_p", [-2])
    q = lib.ff5a(p)
    assert q == p
    assert p.x == 38

def test_enum_size():
    cases = [('123',           4, 4294967295),
             ('4294967295U',   4, 4294967295),
             ('-123',          4, -1),
             ('-2147483647-1', 4, -1),
             ]
    if FFI().sizeof("long") == 8:
        cases += [('4294967296L',        8, 2**64-1),
                  ('%dUL' % (2**64-1),   8, 2**64-1),
                  ('-2147483649L',       8, -1),
                  ('%dL-1L' % (1-2**63), 8, -1)]
    for hidden_value, expected_size, expected_minus1 in cases:
        if sys.platform == 'win32' and 'U' in hidden_value:
            continue   # skipped on Windows
        ffi = FFI()
        ffi.cdef("enum foo_e { AA, BB, ... };")
        lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
        assert lib.AA == 0
        assert lib.BB == eval(hidden_value.replace('U', '').replace('L', ''))
        assert ffi.sizeof("enum foo_e") == expected_size
        assert int(ffi.cast("enum foo_e", -1)) == expected_minus1
    # test with the large value hidden:
    # disabled so far, doesn't work
##    for hidden_value, expected_size, expected_minus1 in cases:
##        ffi = FFI()
##        ffi.cdef("enum foo_e { AA, BB, ... };")
##        lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
##        assert lib.AA == 0
##        assert ffi.sizeof("enum foo_e") == expected_size
##        assert int(ffi.cast("enum foo_e", -1)) == expected_minus1

def test_enum_bug118():
    maxulong = 256 ** FFI().sizeof("unsigned long") - 1
    for c1, c2, c2c in [(0xffffffff, -1, ''),
                        (maxulong, -1, ''),
                        (-1, 0xffffffff, 'U'),
                        (-1, maxulong, 'UL')]:
        if c2c and sys.platform == 'win32':
            continue     # enums may always be signed with MSVC
        ffi = FFI()
        ffi.cdef("enum foo_e { AA=%s };" % c1)
        e = pytest.raises(VerificationError, ffi.verify,
                           "enum foo_e { AA=%s%s };" % (c2, c2c))
        assert str(e.value) == ('enum foo_e: AA has the real value %d, not %d'
                                % (c2, c1))

def test_string_to_voidp_arg():
    ffi = FFI()
    ffi.cdef("int myfunc(void *);")
    lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }")
    res = lib.myfunc(b"hi!")
    assert res == ord(b"h")
    p = ffi.new("char[]", b"gah")
    res = lib.myfunc(p)
    assert res == ord(b"g")
    res = lib.myfunc(ffi.cast("void *", p))
    assert res == ord(b"g")
    res = lib.myfunc(ffi.cast("int *", p))
    assert res == ord(b"g")

def test_callback_indirection():
    ffi = FFI()
    ffi.cdef("""
        static int (*python_callback)(int how_many, int *values);
        int (*const c_callback)(int,...);   /* pass this ptr to C routines */
        int some_c_function(int(*cb)(int,...));
    """)
    lib = ffi.verify("""
        #include <stdarg.h>
        #ifdef _WIN32
        #include <malloc.h>
        #define alloca _alloca
        #else
        # ifdef __FreeBSD__
        #  include <stdlib.h>
        # else
        #  include <alloca.h>
        # endif
        #endif
        static int (*python_callback)(int how_many, int *values);
        static int c_callback(int how_many, ...) {
            va_list ap;
            /* collect the "..." arguments into the values[] array */
            int i, *values = alloca((size_t)how_many * sizeof(int));
            va_start(ap, how_many);
            for (i=0; i<how_many; i++)
                values[i] = va_arg(ap, int);
            va_end(ap);
            return python_callback(how_many, values);
        }
        int some_c_function(int(*cb)(int,...)) {
            int result = cb(2, 10, 20);
            result += cb(3, 30, 40, 50);
            return result;
        }
    """)
    seen = []
    @ffi.callback("int(int, int*)")
    def python_callback(how_many, values):
        seen.append([values[i] for i in range(how_many)])
        return 42
    lib.python_callback = python_callback

    res = lib.some_c_function(lib.c_callback)
    assert res == 84
    assert seen == [[10, 20], [30, 40, 50]]

def test_floatstar_argument():
    ffi = FFI()
    ffi.cdef("float sum3floats(float *);")
    lib = ffi.verify("""
        float sum3floats(float *f) {
            return f[0] + f[1] + f[2];
        }
    """)
    assert lib.sum3floats((1.5, 2.5, 3.5)) == 7.5
    p = ffi.new("float[]", (1.5, 2.5, 3.5))
    assert lib.sum3floats(p) == 7.5

def test_charstar_argument():
    ffi = FFI()
    ffi.cdef("char sum3chars(char *);")
    lib = ffi.verify("""
        char sum3chars(char *f) {
            return (char)(f[0] + f[1] + f[2]);
        }
    """)
    assert lib.sum3chars((b'\x10', b'\x20', b'\x30')) == b'\x60'
    p = ffi.new("char[]", b'\x10\x20\x30')
    assert lib.sum3chars(p) == b'\x60'

def test_passing_string_or_NULL():
    ffi = FFI()
    ffi.cdef("int seeme1(char *); int seeme2(int *);")
    lib = ffi.verify("""
        int seeme1(char *x) {
            return (x == NULL);
        }
        int seeme2(int *x) {
            return (x == NULL);
        }
    """)
    assert lib.seeme1(b"foo") == 0
    assert lib.seeme1(ffi.NULL) == 1
    assert lib.seeme2([42, 43]) == 0
    assert lib.seeme2(ffi.NULL) == 1
    pytest.raises(TypeError, lib.seeme1, None)
    pytest.raises(TypeError, lib.seeme2, None)
    pytest.raises(TypeError, lib.seeme1, 0.0)
    pytest.raises(TypeError, lib.seeme2, 0.0)
    pytest.raises(TypeError, lib.seeme1, 0)
    pytest.raises(TypeError, lib.seeme2, 0)
    zeroL  = 99999999999999999999
    zeroL -= 99999999999999999999
    pytest.raises(TypeError, lib.seeme2, zeroL)

def test_typeof_function():
    ffi = FFI()
    ffi.cdef("int foo(int, char);")
    lib = ffi.verify("int foo(int x, char y) { (void)x; (void)y; return 42; }")
    ctype = ffi.typeof(lib.foo)
    assert len(ctype.args) == 2
    assert ctype.result == ffi.typeof("int")

def test_call_with_voidstar_arg():
    ffi = FFI()
    ffi.cdef("int f(void *);")
    lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }")
    assert lib.f(b"foobar") == ord(b"f")

def test_dir():
    ffi = FFI()
    ffi.cdef("""void somefunc(void);
                extern int somevar, somearray[2];
                static char *const sv2;
                enum my_e { AA, BB, ... };
                #define FOO ...""")
    lib = ffi.verify("""void somefunc(void) { }
                        int somevar, somearray[2];
                        #define sv2 "text"
                        enum my_e { AA, BB };
                        #define FOO 42""")
    assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray',
                        'somefunc', 'somevar', 'sv2']

def test_typeof_func_with_struct_argument():
    ffi = FFI()
    ffi.cdef("""struct s { int a; }; int foo(struct s);""")
    lib = ffi.verify("""struct s { int a; };
                        int foo(struct s x) { return x.a; }""")
    s = ffi.new("struct s *", [-1234])
    m = lib.foo(s[0])
    assert m == -1234
    assert repr(ffi.typeof(lib.foo)) == "<ctype 'int(*)(struct s)'>"

def test_bug_const_char_ptr_array_1():
    ffi = FFI()
    ffi.cdef("""extern const char *a[...];""")
    lib = ffi.verify("""const char *a[5];""")
    assert repr(ffi.typeof(lib.a)) == "<ctype 'char *[5]'>"

def test_bug_const_char_ptr_array_2():
    from cffi import FFI     # ignore warnings
    ffi = FFI()
    ffi.cdef("""extern const int a[];""")
    lib = ffi.verify("""const int a[5];""")
    assert repr(ffi.typeof(lib.a)) == "<ctype 'int *'>"

def _test_various_calls(force_libffi):
    cdef_source = """
    extern int xvalue;
    extern long long ivalue, rvalue;
    extern float fvalue;
    extern double dvalue;
    extern long double Dvalue;
    signed char tf_bb(signed char x, signed char c);
    unsigned char tf_bB(signed char x, unsigned char c);
    short tf_bh(signed char x, short c);
    unsigned short tf_bH(signed char x, unsigned short c);
    int tf_bi(signed char x, int c);
    unsigned int tf_bI(signed char x, unsigned int c);
    long tf_bl(signed char x, long c);
    unsigned long tf_bL(signed char x, unsigned long c);
    long long tf_bq(signed char x, long long c);
    unsigned long long tf_bQ(signed char x, unsigned long long c);
    float tf_bf(signed char x, float c);
    double tf_bd(signed char x, double c);
    long double tf_bD(signed char x, long double c);
    """
    if force_libffi:
        cdef_source = (cdef_source
            .replace('tf_', '(*const tf_')
            .replace('(signed char x', ')(signed char x'))
    ffi = FFI()
    ffi.cdef(cdef_source)
    lib = ffi.verify("""
    int xvalue;
    long long ivalue, rvalue;
    float fvalue;
    double dvalue;
    long double Dvalue;

    typedef signed char b_t;
    typedef unsigned char B_t;
    typedef short h_t;
    typedef unsigned short H_t;
    typedef int i_t;
    typedef unsigned int I_t;
    typedef long l_t;
    typedef unsigned long L_t;
    typedef long long q_t;
    typedef unsigned long long Q_t;
    typedef float f_t;
    typedef double d_t;
    typedef long double D_t;
    #define S(letter)  xvalue = (int)x; letter##value = (letter##_t)c;
    #define R(letter)  return (letter##_t)rvalue;

    signed char tf_bb(signed char x, signed char c) { S(i) R(b) }
    unsigned char tf_bB(signed char x, unsigned char c) { S(i) R(B) }
    short tf_bh(signed char x, short c) { S(i) R(h) }
    unsigned short tf_bH(signed char x, unsigned short c) { S(i) R(H) }
    int tf_bi(signed char x, int c) { S(i) R(i) }
    unsigned int tf_bI(signed char x, unsigned int c) { S(i) R(I) }
    long tf_bl(signed char x, long c) { S(i) R(l) }
    unsigned long tf_bL(signed char x, unsigned long c) { S(i) R(L) }
    long long tf_bq(signed char x, long long c) { S(i) R(q) }
    unsigned long long tf_bQ(signed char x, unsigned long long c) { S(i) R(Q) }
    float tf_bf(signed char x, float c) { S(f) R(f) }
    double tf_bd(signed char x, double c) { S(d) R(d) }
    long double tf_bD(signed char x, long double c) { S(D) R(D) }
    """)
    lib.rvalue = 0x7182838485868788
    for kind, cname in [('b', 'signed char'),
                        ('B', 'unsigned char'),
                        ('h', 'short'),
                        ('H', 'unsigned short'),
                        ('i', 'int'),
                        ('I', 'unsigned int'),
                        ('l', 'long'),
                        ('L', 'unsigned long'),
                        ('q', 'long long'),
                        ('Q', 'unsigned long long'),
                        ('f', 'float'),
                        ('d', 'double'),
                        ('D', 'long double')]:
        sign = +1 if 'unsigned' in cname else -1
        lib.xvalue = 0
        lib.ivalue = 0
        lib.fvalue = 0
        lib.dvalue = 0
        lib.Dvalue = 0
        fun = getattr(lib, 'tf_b' + kind)
        res = fun(-42, sign * 99)
        if kind == 'D':
            res = float(res)
        assert res == int(ffi.cast(cname, 0x7182838485868788))
        assert lib.xvalue == -42
        if kind in 'fdD':
            assert float(getattr(lib, kind + 'value')) == -99.0
        else:
            assert lib.ivalue == sign * 99

def test_various_calls_direct():
    _test_various_calls(force_libffi=False)

def test_various_calls_libffi():
    _test_various_calls(force_libffi=True)

def test_ptr_to_opaque():
    ffi = FFI()
    ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
    lib = ffi.verify("""
        #include <stdlib.h>
        typedef struct { int x; } foo_t;
        int f1(foo_t* p) {
            int x = p->x;
            free(p);
            return x;
        }
        foo_t *f2(int x) {
            foo_t *p = malloc(sizeof(foo_t));
            p->x = x;
            return p;
        }
    """)
    p = lib.f2(42)
    x = lib.f1(p)
    assert x == 42

def _run_in_multiple_threads(test1):
    test1()
    import sys
    try:
        import thread
    except ImportError:
        import _thread as thread
    errors = []
    def wrapper(lock):
        try:
            test1()
        except:
            errors.append(sys.exc_info())
        lock.release()
    locks = []
    for i in range(10):
        _lock = thread.allocate_lock()
        _lock.acquire()
        thread.start_new_thread(wrapper, (_lock,))
        locks.append(_lock)
    for _lock in locks:
        _lock.acquire()
        if errors:
            raise errors[0][1]

def test_errno_working_even_with_pypys_jit():
    # NOTE: on some platforms, to work correctly, this test needs to be
    # compiled with -pthread.  Otherwise, the accesses to errno done from f()
    # are compiled by assuming this small library won't be used from multiple
    # threads, which is wrong.  If you see failures _and_ if you pass your
    # own CFLAGS environment variable, please make sure "-pthread" is in it.
    ffi = FFI()
    ffi.cdef("int f(int);")
    lib = ffi.verify("""
        #include <errno.h>
        int f(int x) { return (errno = errno + x); }
    """)
    @_run_in_multiple_threads
    def test1():
        ffi.errno = 0
        for i in range(10000):
            e = lib.f(1)
            assert e == i + 1
            assert ffi.errno == e
        for i in range(10000):
            ffi.errno = i
            e = lib.f(42)
            assert e == i + 42

def test_getlasterror_working_even_with_pypys_jit():
    if sys.platform != 'win32':
        pytest.skip("win32-only test")
    ffi = FFI()
    ffi.cdef("void SetLastError(DWORD);")
    lib = ffi.dlopen("Kernel32.dll")
    @_run_in_multiple_threads
    def test1():
        for i in range(10000):
            n = (1 << 29) + i
            lib.SetLastError(n)
            assert ffi.getwinerror()[0] == n

def test_verify_dlopen_flags():
    # Careful with RTLD_GLOBAL.  If by chance the FFI is not deleted
    # promptly, like on PyPy, then other tests may see the same
    # exported symbols as well.  So we must not export a simple name
    # like 'foo'!
    ffi1 = FFI()
    ffi1.cdef("extern int foo_verify_dlopen_flags;")

    lib1 = ffi1.verify("int foo_verify_dlopen_flags;",
                       flags=ffi1.RTLD_GLOBAL | ffi1.RTLD_LAZY)
    lib2 = get_second_lib()

    lib1.foo_verify_dlopen_flags = 42
    assert lib2.foo_verify_dlopen_flags == 42
    lib2.foo_verify_dlopen_flags += 1
    assert lib1.foo_verify_dlopen_flags == 43

def get_second_lib():
    # Hack, using modulename makes the test fail
    ffi2 = FFI()
    ffi2.cdef("extern int foo_verify_dlopen_flags;")
    lib2 = ffi2.verify("int foo_verify_dlopen_flags;",
                       flags=ffi2.RTLD_GLOBAL | ffi2.RTLD_LAZY)
    return lib2

def test_consider_not_implemented_function_type():
    ffi = FFI()
    ffi.cdef("typedef union { int a; float b; } Data;"
             "typedef struct { int a:2; } MyStr;"
             "typedef void (*foofunc_t)(Data);"
             "typedef Data (*bazfunc_t)(void);"
             "typedef MyStr (*barfunc_t)(void);")
    fooptr = ffi.cast("foofunc_t", 123)
    bazptr = ffi.cast("bazfunc_t", 123)
    barptr = ffi.cast("barfunc_t", 123)
    # assert did not crash so far
    e = pytest.raises(NotImplementedError, fooptr, ffi.new("Data *"))
    assert str(e.value) == (
        "ctype 'Data' not supported as argument by libffi.  Unions are only "
        "supported as argument if the function is 'API mode' and "
        "non-variadic (i.e. declared inside ffibuilder.cdef()+"
        "ffibuilder.set_source() and not taking a final '...' argument)")
    e = pytest.raises(NotImplementedError, bazptr)
    assert str(e.value) == (
        "ctype 'Data' not supported as return value by libffi.  Unions are "
        "only supported as return value if the function is 'API mode' and "
        "non-variadic (i.e. declared inside ffibuilder.cdef()+"
        "ffibuilder.set_source() and not taking a final '...' argument)")
    e = pytest.raises(NotImplementedError, barptr)
    assert str(e.value) == (
        "ctype 'MyStr' not supported as return value.  It is a struct with "
        "bit fields, which libffi does not support.  Such structs are only "
        "supported as return value if the function is 'API mode' and non-"
        "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
        "set_source() and not taking a final '...' argument)")

def test_verify_extra_arguments():
    ffi = FFI()
    ffi.cdef("#define ABA ...")
    lib = ffi.verify("", define_macros=[('ABA', '42')])
    assert lib.ABA == 42

def test_implicit_unicode_on_windows():
    if sys.platform != 'win32':
        pytest.skip("win32-only test")
    ffi = FFI()
    e = pytest.raises(FFIError, ffi.cdef, "int foo(LPTSTR);")
    assert str(e.value) == ("The Windows type 'LPTSTR' is only available after"
                            " you call ffi.set_unicode()")
    for with_unicode in [True, False]:
        ffi = FFI()
        ffi.set_unicode(with_unicode)
        ffi.cdef("""
            DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename,
                                    DWORD nSize);
        """)
        lib = ffi.verify("""
            #include <windows.h>
        """, libraries=['Kernel32'])
        outbuf = ffi.new("TCHAR[]", 200)
        n = lib.GetModuleFileName(ffi.NULL, outbuf, 500)
        assert 0 < n < 500
        for i in range(n):
            #print repr(outbuf[i])
            assert ord(outbuf[i]) != 0
        assert ord(outbuf[n]) == 0
        assert ord(outbuf[0]) < 128     # should be a letter, or '\'

def test_use_local_dir():
    ffi = FFI()
    lib = ffi.verify("", modulename="test_use_local_dir")
    this_dir = os.path.dirname(__file__)
    pycache_files = os.listdir(os.path.join(this_dir, '__pycache__'))
    assert any('test_use_local_dir' in s for s in pycache_files)

def test_define_known_value():
    ffi = FFI()
    ffi.cdef("#define FOO 0x123")
    lib = ffi.verify("#define FOO 0x123")
    assert lib.FOO == 0x123

def test_define_wrong_value():
    ffi = FFI()
    ffi.cdef("#define FOO 123")
    e = pytest.raises(VerificationError, ffi.verify, "#define FOO 124")
    assert str(e.value).endswith("FOO has the real value 124, not 123")

def test_static_const_int_known_value():
    ffi = FFI()
    ffi.cdef("static const int FOO = 0x123;")
    lib = ffi.verify("#define FOO 0x123")
    assert lib.FOO == 0x123

def test_static_const_int_wrong_value():
    ffi = FFI()
    ffi.cdef("static const int FOO = 123;")
    e = pytest.raises(VerificationError, ffi.verify, "#define FOO 124")
    assert str(e.value).endswith("FOO has the real value 124, not 123")

def test_const_struct_global():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; ...; } T; const T myglob;")
    lib = ffi.verify("typedef struct { double y; int x; } T;"
                     "const T myglob = { 0.1, 42 };")
    assert ffi.typeof(lib.myglob) == ffi.typeof("T")
    assert lib.myglob.x == 42

def test_dont_support_int_dotdotdot():
    ffi = FFI()
    ffi.cdef("typedef int... t1;")
    e = pytest.raises(VerificationError, ffi.verify, "")
    assert str(e.value) == ("feature not supported with ffi.verify(), but only "
                            "with ffi.set_source(): 'typedef int... t1'")
    ffi = FFI()
    ffi.cdef("typedef double ... t1;")
    e = pytest.raises(VerificationError, ffi.verify, "")
    assert str(e.value) == ("feature not supported with ffi.verify(), but only "
                         "with ffi.set_source(): 'typedef float... t1'")

def test_const_fields():
    ffi = FFI()
    ffi.cdef("""struct foo_s { const int a; void *const b; };""")
    ffi.verify("""struct foo_s { const int a; void *const b; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'a'
    assert foo_s.fields[0][1].type is ffi.typeof("int")
    assert foo_s.fields[1][0] == 'b'
    assert foo_s.fields[1][1].type is ffi.typeof("void *")

def test_win32_calling_convention_0():
    ffi = FFI()
    ffi.cdef("""
        int call1(int(__cdecl   *cb)(int));
        int (*const call2)(int(__stdcall *cb)(int));
    """)
    lib = ffi.verify(r"""
        #ifndef _MSC_VER
        #  define __stdcall  /* nothing */
        #endif
        int call1(int(*cb)(int)) {
            int i, result = 0;
            //printf("call1: cb = %p\n", cb);
            for (i = 0; i < 1000; i++)
                result += cb(i);
            //printf("result = %d\n", result);
            return result;
        }
        int call2(int(__stdcall *cb)(int)) {
            int i, result = 0;
            //printf("call2: cb = %p\n", cb);
            for (i = 0; i < 1000; i++)
                result += cb(-i);
            //printf("result = %d\n", result);
            return result;
        }
    """)
    @ffi.callback("int(int)")
    def cb1(x):
        return x * 2
    @ffi.callback("int __stdcall(int)")
    def cb2(x):
        return x * 3
    #print 'cb1 =', cb1
    res = lib.call1(cb1)
    assert res == 500*999*2
    #print 'cb2 =', cb2
    #print ffi.typeof(lib.call2)
    #print 'call2 =', lib.call2
    res = lib.call2(cb2)
    #print '...'
    assert res == -500*999*3
    #print 'done'
    if sys.platform == 'win32' and sys.maxsize < 2**32:
        assert '__stdcall' in str(ffi.typeof(cb2))
        assert '__stdcall' not in str(ffi.typeof(cb1))
        pytest.raises(TypeError, lib.call1, cb2)
        pytest.raises(TypeError, lib.call2, cb1)
    else:
        assert '__stdcall' not in str(ffi.typeof(cb2))
        assert ffi.typeof(cb2) is ffi.typeof(cb1)

def test_win32_calling_convention_1():
    ffi = FFI()
    ffi.cdef("""
        int __cdecl   call1(int(__cdecl   *cb)(int));
        int __stdcall call2(int(__stdcall *cb)(int));
        int (__cdecl   *const cb1)(int);
        int (__stdcall *const cb2)(int);
    """)
    lib = ffi.verify(r"""
        #ifndef _MSC_VER
        #  define __cdecl
        #  define __stdcall
        #endif
        int __cdecl   cb1(int x) { return x * 2; }
        int __stdcall cb2(int x) { return x * 3; }

        int __cdecl call1(int(__cdecl *cb)(int)) {
            int i, result = 0;
            //printf("here1\n");
            //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
            for (i = 0; i < 1000; i++)
                result += cb(i);
            //printf("result = %d\n", result);
            return result;
        }
        int __stdcall call2(int(__stdcall *cb)(int)) {
            int i, result = 0;
            //printf("here1\n");
            //printf("cb = %p, cb2 = %p\n", cb, (void *)cb2);
            for (i = 0; i < 1000; i++)
                result += cb(-i);
            //printf("result = %d\n", result);
            return result;
        }
    """)
    assert lib.call1(lib.cb1) == 500*999*2
    assert lib.call2(lib.cb2) == -500*999*3

def test_win32_calling_convention_2():
    # any mistake in the declaration of plain function (including the
    # precise argument types and, here, the calling convention) are
    # automatically corrected.  But this does not apply to the 'cb'
    # function pointer argument.
    ffi = FFI()
    ffi.cdef("""
        int __stdcall call1(int(__cdecl   *cb)(int));
        int __cdecl   call2(int(__stdcall *cb)(int));
        int (__cdecl   *const cb1)(int);
        int (__stdcall *const cb2)(int);
    """)
    lib = ffi.verify(r"""
        #ifndef _MSC_VER
        #  define __cdecl
        #  define __stdcall
        #endif
        int __cdecl call1(int(__cdecl *cb)(int)) {
            int i, result = 0;
            for (i = 0; i < 1000; i++)
                result += cb(i);
            return result;
        }
        int __stdcall call2(int(__stdcall *cb)(int)) {
            int i, result = 0;
            for (i = 0; i < 1000; i++)
                result += cb(-i);
            return result;
        }
        int __cdecl   cb1(int x) { return x * 2; }
        int __stdcall cb2(int x) { return x * 3; }
    """)
    assert lib.call1(lib.cb1) == 500*999*2
    assert lib.call2(lib.cb2) == -500*999*3

def test_win32_calling_convention_3():
    ffi = FFI()
    ffi.cdef("""
        struct point { int x, y; };

        int (*const cb1)(struct point);
        int (__stdcall *const cb2)(struct point);

        struct point __stdcall call1(int(*cb)(struct point));
        struct point call2(int(__stdcall *cb)(struct point));
    """)
    lib = ffi.verify(r"""
        #ifndef _MSC_VER
        #  define __cdecl
        #  define __stdcall
        #endif
        struct point { int x, y; };
        int           cb1(struct point pt) { return pt.x + 10 * pt.y; }
        int __stdcall cb2(struct point pt) { return pt.x + 100 * pt.y; }
        struct point __stdcall call1(int(__cdecl *cb)(struct point)) {
            int i;
            struct point result = { 0, 0 };
            //printf("here1\n");
            //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
            for (i = 0; i < 1000; i++) {
                struct point p = { i, -i };
                int r = cb(p);
                result.x += r;
                result.y -= r;
            }
            return result;
        }
        struct point __cdecl call2(int(__stdcall *cb)(struct point)) {
            int i;
            struct point result = { 0, 0 };
            for (i = 0; i < 1000; i++) {
                struct point p = { -i, i };
                int r = cb(p);
                result.x += r;
                result.y -= r;
            }
            return result;
        }
    """)
    if sys.platform == 'win32' and sys.maxsize < 2**32:
        pytest.raises(TypeError, lib.call1, lib.cb2)
        pytest.raises(TypeError, lib.call2, lib.cb1)
    pt = lib.call1(lib.cb1)
    assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
    pt = lib.call2(lib.cb2)
    assert (pt.x, pt.y) == (99*500*999, -99*500*999)

def _only_test_on_linux_intel():
    if not sys.platform.startswith('linux'):
        pytest.skip('only running the memory-intensive test on Linux')
    import platform
    machine = platform.machine()
    if 'x86' not in machine and 'x64' not in machine:
        pytest.skip('only running the memory-intensive test on x86/x64')

def test_ffi_gc_size_arg():
    # with PyPy's GC, these calls to ffi.gc() would rapidly consume
    # 40 GB of RAM without the third argument
    _only_test_on_linux_intel()
    ffi = FFI()
    ffi.cdef("void *malloc(size_t); void free(void *);")
    lib = ffi.verify(r"""
        #include <stdlib.h>
    """)
    for i in range(2000):
        p = lib.malloc(20*1024*1024)    # 20 MB
        p1 = ffi.cast("char *", p)
        for j in range(0, 20*1024*1024, 4096):
            p1[j] = b'!'
        p = ffi.gc(p, lib.free, 20*1024*1024)
        del p

def test_ffi_gc_size_arg_2():
    # a variant of the above: this "attack" works on cpython's cyclic gc too
    # and I found no obvious way to prevent that.  So for now, this test
    # is skipped on CPython, where it eats all the memory.
    if '__pypy__' not in sys.builtin_module_names:
        pytest.skip("find a way to tweak the cyclic GC of CPython")
    _only_test_on_linux_intel()
    ffi = FFI()
    ffi.cdef("void *malloc(size_t); void free(void *);")
    lib = ffi.verify(r"""
        #include <stdlib.h>
    """)
    class X(object):
        pass
    for i in range(2000):
        p = lib.malloc(50*1024*1024)    # 50 MB
        p1 = ffi.cast("char *", p)
        for j in range(0, 50*1024*1024, 4096):
            p1[j] = b'!'
        p = ffi.gc(p, lib.free, 50*1024*1024)
        x = X()
        x.p = p
        x.cyclic = x
        del p, x

def test_ffi_new_with_cycles():
    # still another variant, with ffi.new()
    if '__pypy__' not in sys.builtin_module_names:
        pytest.skip("find a way to tweak the cyclic GC of CPython")
    ffi = FFI()
    ffi.cdef("")
    lib = ffi.verify("")
    class X(object):
        pass
    for i in range(2000):
        p = ffi.new("char[]", 50*1024*1024)    # 50 MB
        for j in range(0, 50*1024*1024, 4096):
            p[j] = b'!'
        x = X()
        x.p = p
        x.cyclic = x
        del p, x

def test_arithmetic_in_cdef():
    for a in [0, 11, 15]:
        ffi = FFI()
        ffi.cdef("""
            enum FOO {
                DIVNN = ((-?) / (-3)),
                DIVNP = ((-?) / (+3)),
                DIVPN = ((+?) / (-3)),
                MODNN = ((-?) % (-3)),
                MODNP = ((-?) % (+3)),
                MODPN = ((+?) % (-3)),
                };
        """.replace('?', str(a)))
        lib = ffi.verify("""
            enum FOO {
                DIVNN = ((-?) / (-3)),
                DIVNP = ((-?) / (+3)),
                DIVPN = ((+?) / (-3)),
                MODNN = ((-?) % (-3)),
                MODNP = ((-?) % (+3)),
                MODPN = ((+?) % (-3)),
                };
        """.replace('?', str(a)))
        # the verify() crashes if the values in the enum are different from
        # the values we computed ourselves from the cdef()

def test_passing_large_list():
    ffi = FFI()
    ffi.cdef("""void passing_large_list(long[]);""")
    lib = ffi.verify("""
        static void passing_large_list(long a[]) { }
    """)
    arg = list(range(20000000))
    lib.passing_large_list(arg)
    # assert did not segfault

testing/cffi0/test_verify.py
python-cffi/cffi
import pytest
from .test_verify import *

# eliminate warning noise from common test modules that are repeatedly re-imported
pytestmark = pytest.mark.filterwarnings("ignore:reimporting:UserWarning")

# This test file runs normally after test_verify.  We only clean up the .c
# sources, to check that it also works when we have only the .so.  The
# tests should run much faster than test_verify.

def setup_module():
    import cffi.verifier
    cffi.verifier.cleanup_tmpdir(keep_so=True)

testing/cffi0/test_verify2.py
python-cffi/cffi
import os, sys
import pytest
import cffi, _cffi_backend
from pathlib import Path

def setup_module(mod):
    if '_cffi_backend' in sys.builtin_module_names:
        pytest.skip("this is embedded version")

#BACKEND_VERSIONS = {
#    '0.4.2': '0.4',     # did not change
#    '0.7.1': '0.7',     # did not change
#    '0.7.2': '0.7',     # did not change
#    '0.8.1': '0.8',     # did not change (essentially)
#    '0.8.4': '0.8.3',   # did not change
#    }

def test_version():
    v = cffi.__version__
    version_info = '.'.join(str(i) for i in cffi.__version_info__)
    version_info = version_info.replace('.beta.', 'b')
    version_info = version_info.replace('.plus', '+')
    version_info = version_info.replace('.rc', 'rc')
    assert v == version_info
    #v = BACKEND_VERSIONS.get(v, v)
    assert v == _cffi_backend.__version__

def test_doc_version():
    cffi_root = Path(os.path.dirname(__file__)).parent.parent
    p = cffi_root / 'doc/source/conf.py'
    content = open(p).read()
    #
    v = cffi.__version__
    assert ("version = '%s'\n" % v[:4]) in content
    assert ("release = '%s'\n" % v) in content

def test_setup_version():
    cffi_root = Path(os.path.dirname(__file__)).parent.parent
    p = cffi_root / 'setup.py'
    content = open(p).read()
    #
    v = cffi.__version__.replace('+', '')
    assert ("version='%s'" % v) in content

def test_c_version():
    cffi_root = Path(os.path.dirname(__file__)).parent.parent
    v = cffi.__version__
    p = cffi_root / 'src/c/test_c.py'
    content = open(p).read()
    #v = BACKEND_VERSIONS.get(v, v)
    assert (('assert __version__ == "%s"' % v) in content)

def test_embedding_h():
    cffi_root = Path(os.path.dirname(__file__)).parent.parent
    v = cffi.__version__
    p = cffi_root / 'src/cffi/_embedding.h'
    content = open(p).read()
    assert ('cffi version: %s"' % (v,)) in content

testing/cffi0/test_version.py
python-cffi/cffi
import sys, os, math, shutil
import pytest
from cffi import FFI, FFIError
from cffi.verifier import Verifier, _locate_engine_class, _get_so_suffixes
from cffi.ffiplatform import maybe_relative_path
from testing.udir import udir
from testing.support import load_dynamic


class DistUtilsTest(object):
    def setup_class(self):
        self.lib_m = "m"
        if sys.platform == 'win32':
            #there is a small chance this fails on Mingw via environ $CC
            import distutils.ccompiler
            if distutils.ccompiler.get_default_compiler() == 'msvc':
                self.lib_m = 'msvcrt'

    def teardown_class(self):
        if udir.isdir():
            udir.remove(ignore_errors=True)
        udir.ensure(dir=1)

    def test_locate_engine_class(self):
        cls = _locate_engine_class(FFI(), self.generic)
        if self.generic:
            # asked for the generic engine, which must not generate a
            # CPython extension module
            assert not cls._gen_python_module
        else:
            # asked for the CPython engine: check that we got it, unless
            # we are running on top of PyPy, where the generic engine is
            # always better
            if '__pypy__' not in sys.builtin_module_names:
                assert cls._gen_python_module

    def test_write_source(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        v.write_source()
        with open(v.sourcefilename, 'r') as f:
            data = f.read()
        assert csrc in data

    def test_write_source_explicit_filename(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        v.sourcefilename = filename = str(udir.join('write_source.c'))
        v.write_source()
        assert filename == v.sourcefilename
        with open(filename, 'r') as f:
            data = f.read()
        assert csrc in data

    def test_write_source_to_file_obj(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        try:
            from StringIO import StringIO
        except ImportError:
            from io import StringIO
        f = StringIO()
        v.write_source(file=f)
        assert csrc in f.getvalue()

    def test_compile_module(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        v.compile_module()
        assert v.get_module_name().startswith('_cffi_')
        if v.generates_python_module():
            mod = load_dynamic(v.get_module_name(), v.modulefilename)
            assert hasattr(mod, '_cffi_setup')

    def test_compile_module_explicit_filename(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!2*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        basename = self.__class__.__name__[:10] + '_test_compile_module'
        v.modulefilename = filename = str(udir.join(basename + '.so'))
        v.compile_module()
        assert filename == v.modulefilename
        assert v.get_module_name() == basename
        if v.generates_python_module():
            mod = load_dynamic(v.get_module_name(), v.modulefilename)
            assert hasattr(mod, '_cffi_setup')

    def test_name_from_checksum_of_cdef(self):
        names = []
        for csrc in ['double', 'double', 'float']:
            ffi = FFI()
            ffi.cdef("%s sin(double x);" % csrc)
            v = Verifier(ffi, "#include <math.h>",
                         force_generic_engine=self.generic,
                         libraries=[self.lib_m])
            names.append(v.get_module_name())
        assert names[0] == names[1] != names[2]

    def test_name_from_checksum_of_csrc(self):
        names = []
        for csrc in ['123', '123', '1234']:
            ffi = FFI()
            ffi.cdef("double sin(double x);")
            v = Verifier(ffi, csrc, force_generic_engine=self.generic)
            names.append(v.get_module_name())
        assert names[0] == names[1] != names[2]

    def test_load_library(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!3*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        library = v.load_library()
        assert library.sin(12.3) == math.sin(12.3)

    def test_verifier_args(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there %s!4*/#include "test_verifier_args.h"\n' % self
        udir.join('test_verifier_args.h').write('#include <math.h>\n')
        v = Verifier(ffi, csrc, include_dirs=[str(udir)],
                     force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        library = v.load_library()
        assert library.sin(12.3) == math.sin(12.3)

    def test_verifier_object_from_ffi(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = "/*6%s*/\n#include <math.h>" % self
        lib = ffi.verify(csrc, force_generic_engine=self.generic,
                         libraries=[self.lib_m])
        assert lib.sin(12.3) == math.sin(12.3)
        assert isinstance(ffi.verifier, Verifier)
        with open(ffi.verifier.sourcefilename, 'r') as f:
            data = f.read()
        assert csrc in data

    def test_extension_object(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*7%s*/' % self + '''
    #include <math.h>
    #ifndef TEST_EXTENSION_OBJECT
    # error "define_macros missing"
    #endif
    '''
        lib = ffi.verify(csrc, define_macros=[('TEST_EXTENSION_OBJECT', '1')],
                         force_generic_engine=self.generic,
                         libraries=[self.lib_m])
        assert lib.sin(12.3) == math.sin(12.3)
        v = ffi.verifier
        ext = v.get_extension()
        assert 'distutils.extension.Extension' in str(ext.__class__) or \
               'setuptools.extension.Extension' in str(ext.__class__)
        assert ext.sources == [maybe_relative_path(v.sourcefilename)]
        assert ext.name == v.get_module_name()
        assert ext.define_macros == [('TEST_EXTENSION_OBJECT', '1')]

    def test_extension_forces_write_source(self):
        ffi = FFI()
        ffi.cdef("double sin(double x);")
        csrc = '/*hi there9!%s*/\n#include <math.h>\n' % self
        v = Verifier(ffi, csrc, force_generic_engine=self.generic,
                     libraries=[self.lib_m])
        assert not os.path.exists(v.sourcefilename)
        v.get_extension()
        assert os.path.exists(v.sourcefilename)

    def test_extension_object_extra_sources(self):
        ffi = FFI()
        ffi.cdef("double test1eoes(double x);")
        extra_source = str(udir.join('extension_extra_sources.c'))
        with open(extra_source, 'w') as f:
            f.write('double test1eoes(double x) { return x * 6.0; }\n')
        csrc = '/*9%s*/' % self + '''
        double test1eoes(double x);   /* or #include "extra_sources.h" */
        '''
        lib = ffi.verify(csrc, sources=[extra_source],
                         force_generic_engine=self.generic)
        assert lib.test1eoes(7.0) == 42.0
        v = ffi.verifier
        ext = v.get_extension()
        assert 'distutils.extension.Extension' in str(ext.__class__) or \
               'setuptools.extension.Extension' in str(ext.__class__)
        assert ext.sources == [maybe_relative_path(v.sourcefilename),
                               extra_source]
        assert ext.name == v.get_module_name()

    def test_install_and_reload_module(self, targetpackage='', ext_package=''):
        KEY = repr(self)
        if not hasattr(os, 'fork'):
            pytest.skip("test requires os.fork()")

        if targetpackage:
            udir.ensure(targetpackage, dir=1).ensure('__init__.py')
        sys.path.insert(0, str(udir))

        def make_ffi(**verifier_args):
            ffi = FFI()
            ffi.cdef("/* %s, %s, %s */" % (KEY, targetpackage, ext_package))
            ffi.cdef("double test1iarm(double x);")
            csrc = "double test1iarm(double x) { return x * 42.0; }"
            lib = ffi.verify(csrc, force_generic_engine=self.generic,
                             ext_package=ext_package,
                             **verifier_args)
            return ffi, lib

        childpid = os.fork()
        if childpid == 0:
            # in the child
            ffi, lib = make_ffi()
            assert lib.test1iarm(1.5) == 63.0
            # "install" the module by moving it into udir (/targetpackage)
            if targetpackage:
                target = udir.join(targetpackage)
            else:
                target = udir
            shutil.move(ffi.verifier.modulefilename, str(target))
            os._exit(0)
        # in the parent
        _, status = os.waitpid(childpid, 0)
        if not (os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0):
            raise AssertionError   # see error above in subprocess

        from cffi import ffiplatform
        prev_compile = ffiplatform.compile
        try:
            if targetpackage == ext_package:
                ffiplatform.compile = lambda *args: dont_call_me_any_more
            # won't find it in tmpdir, but should find it correctly
            # installed in udir
            ffi, lib = make_ffi()
            assert lib.test1iarm(0.5) == 21.0
        finally:
            ffiplatform.compile = prev_compile

    def test_install_and_reload_module_package(self):
        self.test_install_and_reload_module(targetpackage='foo_iarmp',
                                            ext_package='foo_iarmp')

    def test_install_and_reload_module_ext_package_not_found(self):
        self.test_install_and_reload_module(targetpackage='foo_epnf',
                                            ext_package='not_found')

    def test_tag(self):
        ffi = FFI()
        ffi.cdef("/* %s test_tag */ double test1tag(double x);" % self)
        csrc = "double test1tag(double x) { return x - 42.0; }"
        lib = ffi.verify(csrc, force_generic_engine=self.generic,
                         tag='xxtest_tagxx')
        assert lib.test1tag(143) == 101.0
        assert '_cffi_xxtest_tagxx_' in ffi.verifier.modulefilename

    def test_modulename(self):
        ffi = FFI()
        ffi.cdef("/* %s test_modulename */ double test1foo(double x);" % self)
        csrc = "double test1foo(double x) { return x - 63.0; }"
        modname = 'xxtest_modulenamexx%d' % (self.generic,)
        lib = ffi.verify(csrc, force_generic_engine=self.generic,
                         modulename=modname)
        assert lib.test1foo(143) == 80.0
        suffix = _get_so_suffixes()[0]
        fn1 = os.path.join(ffi.verifier.tmpdir, modname + '.c')
        fn2 = os.path.join(ffi.verifier.tmpdir, modname + suffix)
        assert ffi.verifier.sourcefilename == fn1
        assert ffi.verifier.modulefilename == fn2


class TestDistUtilsCPython(DistUtilsTest):
    generic = False

class TestDistUtilsGeneric(DistUtilsTest):
    generic = True

testing/cffi0/test_zdistutils.py
python-cffi/cffi
import py, os, sys, shutil
import subprocess
import textwrap
from testing.udir import udir
import pytest

if sys.platform == 'win32':
    pytestmark = pytest.mark.skip('snippets do not run on win32')
if sys.version_info < (2, 7):
    pytestmark = pytest.mark.skip(
                 'fails e.g. on a Debian/Ubuntu which patches virtualenv'
                 ' in a non-2.6-friendly way')

def create_venv(name):
    tmpdir = udir.join(name)
    try:
        # FUTURE: we should probably update this to use venv for at least more modern Pythons, and
        # install setuptools/pip/etc explicitly for the tests that require them (as venv has stopped including
        # setuptools and wheel by default for newer versions).
        subprocess.check_call(['virtualenv', 
            #'--never-download', <= could be added, but causes failures
            # in random cases on random machines
                               '-p', os.path.abspath(sys.executable),
                               str(tmpdir)])

        # Python 3.12 venv/virtualenv no longer include setuptools and wheel by default, which
        # breaks a number of these tests; ensure it's always present for 3.12+
        if sys.version_info >= (3, 12):
            subprocess.check_call([
                os.path.join(tmpdir, 'bin/python'),
                '-m',
                'pip',
                'install',
                'setuptools',
                'wheel',
                '--upgrade'
            ])

    except OSError as e:
        pytest.skip("Cannot execute virtualenv: %s" % (e,))

    site_packages = None
    for dirpath, dirnames, filenames in os.walk(str(tmpdir)):
        if os.path.basename(dirpath) == 'site-packages':
            site_packages = dirpath
            break
    paths = ""
    if site_packages:
        try:
            from cffi import _pycparser
            modules = ('cffi', '_cffi_backend')
        except ImportError:
            modules = ('cffi', '_cffi_backend', 'pycparser')
            try:
                import ply
            except ImportError:
                pass
            else:
                modules += ('ply',)   # needed for older versions of pycparser
        paths = []
        for module in modules:
            target = __import__(module, None, None, [])
            if not hasattr(target, '__file__'):   # for _cffi_backend on pypy
                continue
            src = os.path.abspath(target.__file__)
            for end in ['__init__.pyc', '__init__.pyo', '__init__.py']:
                if src.lower().endswith(end):
                    src = src[:-len(end)-1]
                    break
            paths.append(os.path.dirname(src))
        paths = os.pathsep.join(paths)
    return tmpdir, paths

SNIPPET_DIR = py.path.local(__file__).join('..', 'snippets')

def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet):
    venv_dir, paths = venv_dir_and_paths
    def remove(dir):
        dir = str(SNIPPET_DIR.join(dirname, dir))
        shutil.rmtree(dir, ignore_errors=True)
    remove('build')
    remove('__pycache__')
    for basedir in os.listdir(str(SNIPPET_DIR.join(dirname))):
        remove(os.path.join(basedir, '__pycache__'))
    olddir = os.getcwd()
    python_f = udir.join('x.py')
    python_f.write(textwrap.dedent(python_snippet))
    try:
        os.chdir(str(SNIPPET_DIR.join(dirname)))
        if os.name == 'nt':
            bindir = 'Scripts'
        else:
            bindir = 'bin'
        vp = str(venv_dir.join(bindir).join('python'))
        env = os.environ.copy()
        env['PYTHONPATH'] = paths
        subprocess.check_call((vp, 'setup.py', 'clean'), env=env)
        # there's a setuptools/easy_install bug that causes this to fail when the build/install occur together and
        # we're in the same directory with the build (it tries to look up dependencies for itself on PyPI);
        # subsequent runs will succeed because this test doesn't properly clean up the build- use pip for now.
        subprocess.check_call((vp, '-m', 'pip', 'install', '.'), env=env)
        subprocess.check_call((vp, str(python_f)), env=env)
    finally:
        os.chdir(olddir)

def run_setup_and_program(dirname, python_snippet):
    venv_dir = create_venv(dirname + '-cpy')
    really_run_setup_and_program(dirname, venv_dir, python_snippet)
    #
    sys._force_generic_engine_ = True
    try:
        venv_dir = create_venv(dirname + '-gen')
        really_run_setup_and_program(dirname, venv_dir, python_snippet)
    finally:
        del sys._force_generic_engine_
    # the two files lextab.py and yacctab.py are created by not-correctly-
    # installed versions of pycparser.
    assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'lextab.py')))
    assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'yacctab.py')))

class TestZIntegration(object):
    def teardown_class(self):
        if udir.isdir():
            udir.remove(ignore_errors=True)
        udir.ensure(dir=1)

    def test_infrastructure(self):
        run_setup_and_program('infrastructure', '''
        import snip_infrastructure
        assert snip_infrastructure.func() == 42
        ''')

    def test_distutils_module(self):
        run_setup_and_program("distutils_module", '''
        import snip_basic_verify
        p = snip_basic_verify.C.getpwuid(0)
        assert snip_basic_verify.ffi.string(p.pw_name) == b"root"
        ''')

    def test_distutils_package_1(self):
        run_setup_and_program("distutils_package_1", '''
        import snip_basic_verify1
        p = snip_basic_verify1.C.getpwuid(0)
        assert snip_basic_verify1.ffi.string(p.pw_name) == b"root"
        ''')

    def test_distutils_package_2(self):
        run_setup_and_program("distutils_package_2", '''
        import snip_basic_verify2
        p = snip_basic_verify2.C.getpwuid(0)
        assert snip_basic_verify2.ffi.string(p.pw_name) == b"root"
        ''')

    def test_setuptools_module(self):
        run_setup_and_program("setuptools_module", '''
        import snip_setuptools_verify
        p = snip_setuptools_verify.C.getpwuid(0)
        assert snip_setuptools_verify.ffi.string(p.pw_name) == b"root"
        ''')

    def test_setuptools_package_1(self):
        run_setup_and_program("setuptools_package_1", '''
        import snip_setuptools_verify1
        p = snip_setuptools_verify1.C.getpwuid(0)
        assert snip_setuptools_verify1.ffi.string(p.pw_name) == b"root"
        ''')

    def test_setuptools_package_2(self):
        run_setup_and_program("setuptools_package_2", '''
        import snip_setuptools_verify2
        p = snip_setuptools_verify2.C.getpwuid(0)
        assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
        ''')

    def test_set_py_limited_api(self):
        from cffi.setuptools_ext import _set_py_limited_api
        try:
            import setuptools
        except ImportError as e:
            pytest.skip(str(e))
        orig_version = setuptools.__version__
        expecting_limited_api = not hasattr(sys, 'gettotalrefcount')
        try:
            setuptools.__version__ = '26.0.0'
            from setuptools import Extension

            kwds = _set_py_limited_api(Extension, {})
            assert kwds.get('py_limited_api', False) == expecting_limited_api

            setuptools.__version__ = '25.0'
            kwds = _set_py_limited_api(Extension, {})
            assert kwds.get('py_limited_api', False) == False

            setuptools.__version__ = 'development'
            kwds = _set_py_limited_api(Extension, {})
            assert kwds.get('py_limited_api', False) == expecting_limited_api

        finally:
            setuptools.__version__ = orig_version

testing/cffi0/test_zintegration.py
python-cffi/cffi
import sys, os
import pytest
import _cffi_backend
from testing.support import is_musl

def test_no_unknown_exported_symbols():
    if not hasattr(_cffi_backend, '__file__'):
        pytest.skip("_cffi_backend module is built-in")
    if not sys.platform.startswith('linux') or is_musl:
        pytest.skip("linux-only")
    g = os.popen("objdump -T '%s'" % _cffi_backend.__file__, 'r')
    for line in g:
        if not line.startswith('0'):
            continue
        if line[line.find(' ') + 1] == 'l':
            continue
        if '*UND*' in line:
            continue
        name = line.split()[-1]
        if name.startswith('_') or name.startswith('.'):
            continue
        # a statically-linked libffi will always appear here without header hackage, ignore it if it's internal
        if name.startswith('ffi_') and 'Base' in line:
            continue
        if name not in ('init_cffi_backend', 'PyInit__cffi_backend', 'cffistatic_ffi_call'):
            raise Exception("Unexpected exported name %r" % (name,))
    g.close()

testing/cffi1/test_cffi_binary.py
python-cffi/cffi
import os, cffi, re
import pytest
import _cffi_backend


def getlines():
    try:
        f = open(os.path.join(os.path.dirname(cffi.__file__),
                              '..', 'c', 'commontypes.c'))
    except IOError:
        pytest.skip("cannot find ../c/commontypes.c")
    lines = [line for line in f.readlines() if line.strip().startswith('EQ(')]
    f.close()
    return lines

def test_alphabetical_order():
    lines = getlines()
    assert lines == sorted(lines)

def test_dependencies():
    r = re.compile(r'EQ[(]"([^"]+)",(?:\s*"([A-Z0-9_]+)\s*[*]*"[)])?')
    lines = getlines()
    d = {}
    for line in lines:
        match = r.search(line)
        if match is not None:
            d[match.group(1)] = match.group(2)
    for value in d.values():
        if value:
            assert value in d

def test_get_common_types():
    d = {}
    _cffi_backend._get_common_types(d)
    assert d["bool"] == "_Bool"

testing/cffi1/test_commontypes.py
python-cffi/cffi
import pytest
from cffi import FFI, VerificationError, CDefError
from cffi.recompiler import make_py_source
from testing.udir import udir


def test_simple():
    ffi = FFI()
    ffi.cdef("int close(int); static const int BB = 42; extern int somevar;")
    target = udir.join('test_simple.py')
    make_py_source(ffi, 'test_simple', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_simple',
    _version = 0x2601,
    _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F',
    _globals = (b'\xFF\xFF\xFF\x1FBB',42,b'\x00\x00\x00\x23close',0,b'\x00\x00\x01\x21somevar',0),
)
"""

def test_global_constant():
    ffi = FFI()
    ffi.cdef("static const long BB; static const float BF = 12;")
    target = udir.join('test_valid_global_constant.py')
    make_py_source(ffi, 'test_valid_global_constant', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_valid_global_constant',
    _version = 0x2601,
    _types = b'\x00\x00\x0D\x01\x00\x00\x09\x01',
    _globals = (b'\x00\x00\x01\x25BB',0,b'\x00\x00\x00\x25BF',0),
)
"""

def test_invalid_global_constant_3():
    ffi = FFI()
    e = pytest.raises(CDefError, ffi.cdef, "#define BB 12.34")
    assert str(e.value).startswith(
        "only supports one of the following syntax:")

def test_invalid_dotdotdot_in_macro():
    ffi = FFI()
    ffi.cdef("#define FOO ...")
    target = udir.join('test_invalid_dotdotdot_in_macro.py')
    e = pytest.raises(VerificationError, make_py_source, ffi,
                       'test_invalid_dotdotdot_in_macro', str(target))
    assert str(e.value) == ("macro FOO: cannot use the syntax '...' in "
                            "'#define FOO ...' when using the ABI mode")

def test_typename():
    ffi = FFI()
    ffi.cdef("typedef int foobar_t;")
    target = udir.join('test_typename.py')
    make_py_source(ffi, 'test_typename', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_typename',
    _version = 0x2601,
    _types = b'\x00\x00\x07\x01',
    _typenames = (b'\x00\x00\x00\x00foobar_t',),
)
"""

def test_enum():
    ffi = FFI()
    ffi.cdef("enum myenum_e { AA, BB, CC=-42 };")
    target = udir.join('test_enum.py')
    make_py_source(ffi, 'test_enum', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_enum',
    _version = 0x2601,
    _types = b'\x00\x00\x00\x0B',
    _globals = (b'\xFF\xFF\xFF\x0BAA',0,b'\xFF\xFF\xFF\x0BBB',1,b'\xFF\xFF\xFF\x0BCC',-42),
    _enums = (b'\x00\x00\x00\x00\x00\x00\x00\x15myenum_e\x00AA,BB,CC',),
)
"""

def test_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a; signed char b[]; }; struct bar_s;")
    target = udir.join('test_struct.py')
    make_py_source(ffi, 'test_struct', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_struct',
    _version = 0x2601,
    _types = b'\x00\x00\x07\x01\x00\x00\x03\x01\x00\x00\x01\x07\x00\x00\x00\x09\x00\x00\x01\x09',
    _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x10bar_s',),(b'\x00\x00\x00\x04\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x11a',b'\x00\x00\x02\x11b')),
)
"""

def test_include():
    ffi = FFI()
    ffi.cdef("#define ABC 123")
    ffi.set_source('test_include', None)
    target = udir.join('test_include.py')
    make_py_source(ffi, 'test_include', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_include',
    _version = 0x2601,
    _types = b'',
    _globals = (b'\xFF\xFF\xFF\x1FABC',123,),
)
"""
    #
    ffi2 = FFI()
    ffi2.include(ffi)
    target2 = udir.join('test2_include.py')
    make_py_source(ffi2, 'test2_include', str(target2))
    assert target2.read() == r"""# auto-generated file
import _cffi_backend
from test_include import ffi as _ffi0

ffi = _cffi_backend.FFI('test2_include',
    _version = 0x2601,
    _types = b'',
    _includes = (_ffi0,),
)
"""

def test_negative_constant():
    ffi = FFI()
    ffi.cdef("static const int BB = -42;")
    target = udir.join('test_negative_constant.py')
    make_py_source(ffi, 'test_negative_constant', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_negative_constant',
    _version = 0x2601,
    _types = b'',
    _globals = (b'\xFF\xFF\xFF\x1FBB',-42,),
)
"""

def test_struct_included():
    baseffi = FFI()
    baseffi.cdef("struct foo_s { int x; };")
    baseffi.set_source('test_struct_included_base', None)
    #
    ffi = FFI()
    ffi.include(baseffi)
    target = udir.join('test_struct_included.py')
    make_py_source(ffi, 'test_struct_included', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend
from test_struct_included_base import ffi as _ffi0

ffi = _cffi_backend.FFI('test_struct_included',
    _version = 0x2601,
    _types = b'\x00\x00\x00\x09',
    _struct_unions = ((b'\x00\x00\x00\x00\x00\x00\x00\x08foo_s',),),
    _includes = (_ffi0,),
)
"""

def test_no_cross_include():
    baseffi = FFI()
    baseffi.set_source('test_no_cross_include_base', "..source..")
    #
    ffi = FFI()
    ffi.include(baseffi)
    target = udir.join('test_no_cross_include.py')
    pytest.raises(VerificationError, make_py_source,
                   ffi, 'test_no_cross_include', str(target))

def test_array():
    ffi = FFI()
    ffi.cdef("typedef int32_t my_array_t[42];")
    target = udir.join('test_array.py')
    make_py_source(ffi, 'test_array', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_array',
    _version = 0x2601,
    _types = b'\x00\x00\x15\x01\x00\x00\x00\x05\x00\x00\x00\x2A',
    _typenames = (b'\x00\x00\x00\x01my_array_t',),
)
"""

def test_array_overflow():
    ffi = FFI()
    ffi.cdef("typedef int32_t my_array_t[3000000000];")
    target = udir.join('test_array_overflow.py')
    pytest.raises(OverflowError, make_py_source,
                   ffi, 'test_array_overflow', str(target))

def test_global_var():
    ffi = FFI()
    ffi.cdef("extern int myglob;")
    target = udir.join('test_global_var.py')
    make_py_source(ffi, 'test_global_var', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_global_var',
    _version = 0x2601,
    _types = b'\x00\x00\x07\x01',
    _globals = (b'\x00\x00\x00\x21myglob',0,),
)
"""

def test_bitfield():
    ffi = FFI()
    ffi.cdef("struct foo_s { int y:10; short x:5; };")
    target = udir.join('test_bitfield.py')
    make_py_source(ffi, 'test_bitfield', str(target))
    assert target.read() == r"""# auto-generated file
import _cffi_backend

ffi = _cffi_backend.FFI('test_bitfield',
    _version = 0x2601,
    _types = b'\x00\x00\x07\x01\x00\x00\x05\x01\x00\x00\x00\x09',
    _struct_unions = ((b'\x00\x00\x00\x02\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x13\x00\x00\x00\x0Ay',b'\x00\x00\x01\x13\x00\x00\x00\x05x'),),
)
"""

testing/cffi1/test_dlopen.py
python-cffi/cffi
import os

s = """from __future__ import unicode_literals
"""

with open(os.path.join(os.path.dirname(__file__), 'test_dlopen.py')) as f:
    s += f.read()

exec(compile(s, filename='test_dlopen.py', mode='exec'))

testing/cffi1/test_dlopen_unicode_literals.py
python-cffi/cffi
import sys
import pytest
import _cffi_backend as _cffi1_backend


def test_ffi_new():
    ffi = _cffi1_backend.FFI()
    p = ffi.new("int *")
    p[0] = -42
    assert p[0] == -42
    assert type(ffi) is ffi.__class__ is _cffi1_backend.FFI

def test_ffi_subclass():
    class FOO(_cffi1_backend.FFI):
        def __init__(self, x):
            self.x = x
    foo = FOO(42)
    assert foo.x == 42
    p = foo.new("int *")
    assert p[0] == 0
    assert type(foo) is foo.__class__ is FOO

def test_ffi_no_argument():
    pytest.raises(TypeError, _cffi1_backend.FFI, 42)

def test_ffi_cache_type():
    ffi = _cffi1_backend.FFI()
    t1 = ffi.typeof("int **")
    t2 = ffi.typeof("int *")
    assert t2.item is t1.item.item
    assert t2 is t1.item
    assert ffi.typeof("int[][10]") is ffi.typeof("int[][10]")
    assert ffi.typeof("int(*)()") is ffi.typeof("int(*)()")

def test_ffi_type_not_immortal():
    import weakref, gc
    ffi = _cffi1_backend.FFI()
    t1 = ffi.typeof("int **")
    t2 = ffi.typeof("int *")
    w1 = weakref.ref(t1)
    w2 = weakref.ref(t2)
    del t1, ffi
    gc.collect()
    assert w1() is None
    assert w2() is t2
    ffi = _cffi1_backend.FFI()
    assert ffi.typeof(ffi.new("int **")[0]) is t2
    #
    ffi = _cffi1_backend.FFI()
    t1 = ffi.typeof("int ***")
    t2 = ffi.typeof("int **")
    w1 = weakref.ref(t1)
    w2 = weakref.ref(t2)
    del t2, ffi
    gc.collect()
    assert w1() is t1
    assert w2() is not None   # kept alive by t1
    ffi = _cffi1_backend.FFI()
    assert ffi.typeof("int * *") is t1.item

def test_ffi_cache_type_globally():
    ffi1 = _cffi1_backend.FFI()
    ffi2 = _cffi1_backend.FFI()
    t1 = ffi1.typeof("int *")
    t2 = ffi2.typeof("int *")
    assert t1 is t2

def test_ffi_invalid():
    ffi = _cffi1_backend.FFI()
    # array of 10 times an "int[]" is invalid
    pytest.raises(ValueError, ffi.typeof, "int[10][]")

def test_ffi_docstrings():
    # check that all methods of the FFI class have a docstring.
    check_type = type(_cffi1_backend.FFI.new)
    for methname in dir(_cffi1_backend.FFI):
        if not methname.startswith('_'):
            method = getattr(_cffi1_backend.FFI, methname)
            if isinstance(method, check_type):
                assert method.__doc__, "method FFI.%s() has no docstring" % (
                    methname,)

def test_ffi_NULL():
    NULL = _cffi1_backend.FFI.NULL
    assert _cffi1_backend.FFI().typeof(NULL).cname == "void *"

def test_ffi_no_attr():
    ffi = _cffi1_backend.FFI()
    with pytest.raises(AttributeError):
        ffi.no_such_name
    with pytest.raises(AttributeError):
        ffi.no_such_name = 42
    with pytest.raises(AttributeError):
        del ffi.no_such_name

def test_ffi_string():
    ffi = _cffi1_backend.FFI()
    p = ffi.new("char[]", init=b"foobar\x00baz")
    assert ffi.string(p) == b"foobar"
    assert ffi.string(cdata=p, maxlen=3) == b"foo"

def test_ffi_errno():
    # xxx not really checking errno, just checking that we can read/write it
    ffi = _cffi1_backend.FFI()
    ffi.errno = 42
    assert ffi.errno == 42

def test_ffi_alignof():
    ffi = _cffi1_backend.FFI()
    assert ffi.alignof("int") == 4
    assert ffi.alignof("int[]") == 4
    assert ffi.alignof("int[41]") == 4
    assert ffi.alignof("short[41]") == 2
    assert ffi.alignof(ffi.new("int[41]")) == 4
    assert ffi.alignof(ffi.new("int[]", 41)) == 4

def test_ffi_sizeof():
    ffi = _cffi1_backend.FFI()
    assert ffi.sizeof("int") == 4
    pytest.raises(ffi.error, ffi.sizeof, "int[]")
    assert ffi.sizeof("int[41]") == 41 * 4
    assert ffi.sizeof(ffi.new("int[41]")) == 41 * 4
    assert ffi.sizeof(ffi.new("int[]", 41)) == 41 * 4

def test_ffi_callback():
    ffi = _cffi1_backend.FFI()
    assert ffi.callback("int(int)", lambda x: x + 42)(10) == 52
    assert ffi.callback("int(*)(int)", lambda x: x + 42)(10) == 52
    assert ffi.callback("int(int)", lambda x: x + "", -66)(10) == -66
    assert ffi.callback("int(int)", lambda x: x + "", error=-66)(10) == -66

def test_ffi_callback_decorator():
    ffi = _cffi1_backend.FFI()
    assert ffi.callback(ffi.typeof("int(*)(int)"))(lambda x: x + 42)(10) == 52
    deco = ffi.callback("int(int)", error=-66)
    assert deco(lambda x: x + "")(10) == -66
    assert deco(lambda x: x + 42)(10) == 52

def test_ffi_callback_onerror():
    ffi = _cffi1_backend.FFI()
    seen = []
    def oops(*args):
        seen.append(args)

    @ffi.callback("int(int)", onerror=oops)
    def fn1(x):
        return x + ""
    assert fn1(10) == 0

    @ffi.callback("int(int)", onerror=oops, error=-66)
    def fn2(x):
        return x + ""
    assert fn2(10) == -66

    assert len(seen) == 2
    exc, val, tb = seen[0]
    assert exc is TypeError
    assert isinstance(val, TypeError)
    assert tb.tb_frame.f_code.co_name == "fn1"
    exc, val, tb = seen[1]
    assert exc is TypeError
    assert isinstance(val, TypeError)
    assert tb.tb_frame.f_code.co_name == "fn2"
    #
    pytest.raises(TypeError, ffi.callback, "int(int)",
                   lambda x: x, onerror=42)   # <- not callable

def test_ffi_getctype():
    ffi = _cffi1_backend.FFI()
    assert ffi.getctype("int") == "int"
    assert ffi.getctype("int", 'x') == "int x"
    assert ffi.getctype("int*") == "int *"
    assert ffi.getctype("int*", '') == "int *"
    assert ffi.getctype("int*", 'x') == "int * x"
    assert ffi.getctype("int", '*') == "int *"
    assert ffi.getctype("int", replace_with=' * x ') == "int * x"
    assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
    assert ffi.getctype("int", '[5]') == "int[5]"
    assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
    assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
    # special-case for convenience: automatically put '()' around '*'
    assert ffi.getctype("int[5]", '*') == "int(*)[5]"
    assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
    assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"

def test_addressof():
    ffi = _cffi1_backend.FFI()
    a = ffi.new("int[10]")
    b = ffi.addressof(a, 5)
    b[2] = -123
    assert a[7] == -123

def test_handle():
    ffi = _cffi1_backend.FFI()
    x = [2, 4, 6]
    xp = ffi.new_handle(x)
    assert ffi.typeof(xp) == ffi.typeof("void *")
    assert ffi.from_handle(xp) is x
    yp = ffi.new_handle([6, 4, 2])
    assert ffi.from_handle(yp) == [6, 4, 2]

def test_handle_unique():
    ffi = _cffi1_backend.FFI()
    assert ffi.new_handle(None) is not ffi.new_handle(None)
    assert ffi.new_handle(None) != ffi.new_handle(None)

def test_ffi_cast():
    ffi = _cffi1_backend.FFI()
    assert ffi.cast("int(*)(int)", 0) == ffi.NULL
    ffi.callback("int(int)")      # side-effect of registering this string
    pytest.raises(ffi.error, ffi.cast, "int(int)", 0)

def test_ffi_invalid_type():
    ffi = _cffi1_backend.FFI()
    e = pytest.raises(ffi.error, ffi.cast, "", 0)
    assert str(e.value) == ("identifier expected\n"
                            "\n"
                            "^")
    e = pytest.raises(ffi.error, ffi.cast, "struct struct", 0)
    assert str(e.value) == ("struct or union name expected\n"
                            "struct struct\n"
                            "       ^")
    e = pytest.raises(ffi.error, ffi.cast, "struct never_heard_of_s", 0)
    assert str(e.value) == ("undefined struct/union name\n"
                            "struct never_heard_of_s\n"
                            "       ^")
    e = pytest.raises(ffi.error, ffi.cast, "\t\n\x01\x1f~\x7f\x80\xff", 0)
    marks = "?" if sys.version_info < (3,) else "??"
    assert str(e.value) == ("identifier expected\n"
                            "  ??~?%s%s\n"
                            "  ^" % (marks, marks))
    e = pytest.raises(ffi.error, ffi.cast, "X" * 600, 0)
    assert str(e.value) == ("undefined type name")

def test_ffi_buffer():
    ffi = _cffi1_backend.FFI()
    a = ffi.new("signed char[]", [5, 6, 7])
    assert ffi.buffer(a)[:] == b'\x05\x06\x07'
    assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06'
    assert type(ffi.buffer(a)) is ffi.buffer

def test_ffi_from_buffer():
    import array
    ffi = _cffi1_backend.FFI()
    a = array.array('H', [10000, 20000, 30000, 40000])
    c = ffi.from_buffer(a)
    assert ffi.typeof(c) is ffi.typeof("char[]")
    assert len(c) == 8
    ffi.cast("unsigned short *", c)[1] += 500
    assert list(a) == [10000, 20500, 30000, 40000]
    pytest.raises(TypeError, ffi.from_buffer, a, True)
    assert c == ffi.from_buffer("char[]", a, True)
    assert c == ffi.from_buffer(a, require_writable=True)
    #
    c = ffi.from_buffer("unsigned short[]", a)
    assert len(c) == 4
    assert c[1] == 20500
    #
    c = ffi.from_buffer("unsigned short[2][2]", a)
    assert len(c) == 2
    assert len(c[0]) == 2
    assert c[0][1] == 20500
    #
    p = ffi.from_buffer(b"abcd")
    assert p[2] == b"c"
    #
    assert p == ffi.from_buffer(b"abcd", require_writable=False)
    pytest.raises((TypeError, BufferError), ffi.from_buffer,
                                             "char[]", b"abcd", True)
    pytest.raises((TypeError, BufferError), ffi.from_buffer, b"abcd",
                                             require_writable=True)

def test_memmove():
    ffi = _cffi1_backend.FFI()
    p = ffi.new("short[]", [-1234, -2345, -3456, -4567, -5678])
    ffi.memmove(p, p + 1, 4)
    assert list(p) == [-2345, -3456, -3456, -4567, -5678]
    p[2] = 999
    ffi.memmove(p + 2, p, 6)
    assert list(p) == [-2345, -3456, -2345, -3456, 999]
    ffi.memmove(p + 4, ffi.new("char[]", b"\x71\x72"), 2)
    if sys.byteorder == 'little':
        assert list(p) == [-2345, -3456, -2345, -3456, 0x7271]
    else:
        assert list(p) == [-2345, -3456, -2345, -3456, 0x7172]

def test_memmove_buffer():
    import array
    ffi = _cffi1_backend.FFI()
    a = array.array('H', [10000, 20000, 30000])
    p = ffi.new("short[]", 5)
    ffi.memmove(p, a, 6)
    assert list(p) == [10000, 20000, 30000, 0, 0]
    ffi.memmove(p + 1, a, 6)
    assert list(p) == [10000, 10000, 20000, 30000, 0]
    b = array.array('h', [-1000, -2000, -3000])
    ffi.memmove(b, a, 4)
    assert b.tolist() == [10000, 20000, -3000]
    assert a.tolist() == [10000, 20000, 30000]
    p[0] = 999
    p[1] = 998
    p[2] = 997
    p[3] = 996
    p[4] = 995
    ffi.memmove(b, p, 2)
    assert b.tolist() == [999, 20000, -3000]
    ffi.memmove(b, p + 2, 4)
    assert b.tolist() == [997, 996, -3000]
    p[2] = -p[2]
    p[3] = -p[3]
    ffi.memmove(b, p + 2, 6)
    assert b.tolist() == [-997, -996, 995]

def test_memmove_readonly_readwrite():
    ffi = _cffi1_backend.FFI()
    p = ffi.new("signed char[]", 5)
    ffi.memmove(p, b"abcde", 3)
    assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0]
    ffi.memmove(p, bytearray(b"ABCDE"), 2)
    assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0]
    pytest.raises((TypeError, BufferError), ffi.memmove, b"abcde", p, 3)
    ba = bytearray(b"xxxxx")
    ffi.memmove(dest=ba, src=p, n=3)
    assert ba == bytearray(b"ABcxx")

def test_ffi_types():
    CData = _cffi1_backend.FFI.CData
    CType = _cffi1_backend.FFI.CType
    ffi = _cffi1_backend.FFI()
    assert isinstance(ffi.cast("int", 42), CData)
    assert isinstance(ffi.typeof("int"), CType)

def test_ffi_getwinerror():
    if sys.platform != "win32":
        pytest.skip("for windows")
    ffi = _cffi1_backend.FFI()
    n = (1 << 29) + 42
    code, message = ffi.getwinerror(code=n)
    assert code == n

def test_ffi_new_allocator_1():
    ffi = _cffi1_backend.FFI()
    alloc1 = ffi.new_allocator()
    alloc2 = ffi.new_allocator(should_clear_after_alloc=False)
    for retry in range(400):
        p1 = alloc1("int[10]")
        p2 = alloc2("int[]", 10 + retry * 13)
        combination = 0
        for i in range(10):
            assert p1[i] == 0
            combination |= p2[i]
            p1[i] = -42
            p2[i] = -43
        if combination != 0:
            break
    else:
        raise AssertionError("cannot seem to get an int[10] not "
                             "completely cleared")

def test_ffi_new_allocator_2():
    ffi = _cffi1_backend.FFI()
    seen = []
    def myalloc(size):
        seen.append(size)
        return ffi.new("char[]", b"X" * size)
    def myfree(raw):
        seen.append(raw)
    alloc1 = ffi.new_allocator(myalloc, myfree)
    alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree,
                               should_clear_after_alloc=False)
    p1 = alloc1("int[10]")
    p2 = alloc2("int[]", 10)
    assert seen == [40, 40]
    assert ffi.typeof(p1) == ffi.typeof("int[10]")
    assert ffi.sizeof(p1) == 40
    assert ffi.typeof(p2) == ffi.typeof("int[]")
    assert ffi.sizeof(p2) == 40
    assert p1[5] == 0
    assert p2[6] == ord('X') * 0x01010101
    raw1 = ffi.cast("char *", p1)
    raw2 = ffi.cast("char *", p2)
    del p1, p2
    retries = 0
    while len(seen) != 4:
        retries += 1
        assert retries <= 5
        import gc; gc.collect()
    assert (seen == [40, 40, raw1, raw2] or
            seen == [40, 40, raw2, raw1])
    assert repr(seen[2]) == "<cdata 'char[]' owning 41 bytes>"
    assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>"

def test_ffi_new_allocator_3():
    ffi = _cffi1_backend.FFI()
    seen = []
    def myalloc(size):
        seen.append(size)
        return ffi.new("char[]", b"X" * size)
    alloc1 = ffi.new_allocator(myalloc)    # no 'free'
    p1 = alloc1("int[10]")
    assert seen == [40]
    assert ffi.typeof(p1) == ffi.typeof("int[10]")
    assert ffi.sizeof(p1) == 40
    assert p1[5] == 0

def test_ffi_new_allocator_4():
    ffi = _cffi1_backend.FFI()
    pytest.raises(TypeError, ffi.new_allocator, free=lambda x: None)
    #
    def myalloc2(size):
        raise LookupError
    alloc2 = ffi.new_allocator(myalloc2)
    pytest.raises(LookupError, alloc2, "int[5]")
    #
    def myalloc3(size):
        return 42
    alloc3 = ffi.new_allocator(myalloc3)
    e = pytest.raises(TypeError, alloc3, "int[5]")
    assert str(e.value) == "alloc() must return a cdata object (got int)"
    #
    def myalloc4(size):
        return ffi.cast("int", 42)
    alloc4 = ffi.new_allocator(myalloc4)
    e = pytest.raises(TypeError, alloc4, "int[5]")
    assert str(e.value) == "alloc() must return a cdata pointer, not 'int'"
    #
    def myalloc5(size):
        return ffi.NULL
    alloc5 = ffi.new_allocator(myalloc5)
    pytest.raises(MemoryError, alloc5, "int[5]")

def test_bool_issue228():
    ffi = _cffi1_backend.FFI()
    fntype = ffi.typeof("int(*callback)(bool is_valid)")
    assert repr(fntype.args[0]) == "<ctype '_Bool'>"

def test_FILE_issue228():
    fntype1 = _cffi1_backend.FFI().typeof("FILE *")
    fntype2 = _cffi1_backend.FFI().typeof("FILE *")
    assert repr(fntype1) == "<ctype 'FILE *'>"
    assert fntype1 is fntype2

def test_cast_from_int_type_to_bool():
    ffi = _cffi1_backend.FFI()
    for basetype in ['char', 'short', 'int', 'long', 'long long']:
        for sign in ['signed', 'unsigned']:
            type = '%s %s' % (sign, basetype)
            assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1
            assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1
            assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0

def test_init_once():
    def do_init():
        seen.append(1)
        return 42
    ffi = _cffi1_backend.FFI()
    seen = []
    for i in range(3):
        res = ffi.init_once(do_init, "tag1")
        assert res == 42
        assert seen == [1]
    for i in range(3):
        res = ffi.init_once(do_init, "tag2")
        assert res == 42
        assert seen == [1, 1]

def test_init_once_multithread():
    if sys.version_info < (3,):
        import thread
    else:
        import _thread as thread
    import time
    #
    def do_init():
        print('init!')
        seen.append('init!')
        time.sleep(1)
        seen.append('init done')
        print('init done')
        return 7
    ffi = _cffi1_backend.FFI()
    seen = []
    for i in range(6):
        def f():
            res = ffi.init_once(do_init, "tag")
            seen.append(res)
        thread.start_new_thread(f, ())
    time.sleep(1.5)
    assert seen == ['init!', 'init done'] + 6 * [7]

def test_init_once_failure():
    def do_init():
        seen.append(1)
        raise ValueError
    ffi = _cffi1_backend.FFI()
    seen = []
    for i in range(5):
        pytest.raises(ValueError, ffi.init_once, do_init, "tag")
        assert seen == [1] * (i + 1)

def test_init_once_multithread_failure():
    if sys.version_info < (3,):
        import thread
    else:
        import _thread as thread
    import time
    def do_init():
        seen.append('init!')
        time.sleep(1)
        seen.append('oops')
        raise ValueError
    ffi = _cffi1_backend.FFI()
    seen = []
    for i in range(3):
        def f():
            pytest.raises(ValueError, ffi.init_once, do_init, "tag")
        thread.start_new_thread(f, ())
    i = 0
    while len(seen) < 6:
        i += 1
        assert i < 20
        time.sleep(0.51)
    assert seen == ['init!', 'oops'] * 3

def test_unpack():
    ffi = _cffi1_backend.FFI()
    p = ffi.new("char[]", b"abc\x00def")
    assert ffi.unpack(p+1, 7) == b"bc\x00def\x00"
    p = ffi.new("int[]", [-123456789])
    assert ffi.unpack(p, 1) == [-123456789]

def test_negative_array_size():
    ffi = _cffi1_backend.FFI()
    pytest.raises(ffi.error, ffi.cast, "int[-5]", 0)

testing/cffi1/test_ffi_obj.py
python-cffi/cffi
import pytest
import platform
import sys, os, ctypes
import cffi
from testing.udir import udir
from testing.support import *
from cffi.recompiler import recompile
from cffi.cffi_opcode import PRIMITIVE_TO_INDEX

SIZE_OF_INT   = ctypes.sizeof(ctypes.c_int)
SIZE_OF_LONG  = ctypes.sizeof(ctypes.c_long)
SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
SIZE_OF_PTR   = ctypes.sizeof(ctypes.c_void_p)
SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)


def setup_module():
    global ffi, construction_params
    ffi1 = cffi.FFI()
    DEFS = r"""
        struct repr { short a, b, c; };
        struct simple { int a; short b, c; };
        struct array { int a[2]; char b[3]; };
        struct recursive { int value; struct recursive *next; };
        union simple_u { int a; short b, c; };
        union init_u { char a; int b; };
        struct four_s { int a; short b, c, d; };
        union four_u { int a; short b, c, d; };
        struct string { const char *name; };
        struct ustring { const wchar_t *name; };
        struct voidp { void *p; int *q; short *r; };
        struct ab { int a, b; };
        struct abc { int a, b, c; };

        /* don't use A0, B0, CC0, D0 because termios.h might be included
           and it has its own #defines for these names */
        enum foq { cffiA0, cffiB0, cffiCC0, cffiD0 };
        enum bar { A1, B1=-2, CC1, D1, E1 };
        enum baz { A2=0x1000, B2=0x2000 };
        enum foo2 { A3, B3, C3, D3 };
        struct bar_with_e { enum foo2 e; };
        enum noncont { A4, B4=42, C4 };
        enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010};
        typedef enum { Value0 = 0 } e_t, *pe_t;
        enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 };
        enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 };

        struct nesting { struct abc d, e; };
        struct array2 { int a, b; int c[99]; };
        struct align { char a; short b; char c; };
        struct bitfield { int a:10, b:20, c:3; };
        typedef enum { AA2, BB2, CC2 } foo_e_t;
        typedef struct { foo_e_t f:2; } bfenum_t;
        typedef struct { int a; } anon_foo_t;
        typedef struct { char b, c; } anon_bar_t;
        typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p;
        typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p;
        struct nonpacked { char a; int b; };
        struct array0 { int len; short data[0]; };
        struct array_no_length { int x; int a[]; };

        struct nested_anon {
            struct { int a, b; };
            union { int c, d; };
        };
        struct nested_field_ofs_s {
            struct { int a; char b; };
            union { char c; };
        };
        union nested_anon_u {
            struct { int a, b; };
            union { int c, d; };
        };
        struct abc50 { int a, b; int c[50]; };
        struct ints_and_bitfield { int a,b,c,d,e; int x:1; };
    """
    DEFS_PACKED = """
        struct is_packed { char a; int b; } /*here*/;
    """
    if sys.platform == "win32":
        DEFS = DEFS.replace('data[0]', 'data[1]')   # not supported
        CCODE = (DEFS + "\n#pragma pack(push,1)\n" + DEFS_PACKED +
                 "\n#pragma pack(pop)\n")
    else:
        CCODE = (DEFS +
                 DEFS_PACKED.replace('/*here*/', '__attribute__((packed))'))

    ffi1.cdef(DEFS)
    ffi1.cdef(DEFS_PACKED, packed=True)
    ffi1.set_source("test_new_ffi_1", CCODE)

    outputfilename = recompile(ffi1, "test_new_ffi_1", CCODE,
                               tmpdir=str(udir))
    module = load_dynamic("test_new_ffi_1", outputfilename)
    ffi = module.ffi
    construction_params = (ffi1, CCODE)


class TestNewFFI1:

    def test_integer_ranges(self):
        for (c_type, size) in [('char', 1),
                               ('short', 2),
                               ('short int', 2),
                               ('', 4),
                               ('int', 4),
                               ('long', SIZE_OF_LONG),
                               ('long int', SIZE_OF_LONG),
                               ('long long', 8),
                               ('long long int', 8),
                               ]:
            for unsigned in [None, False, True]:
                c_decl = {None: '',
                          False: 'signed ',
                          True: 'unsigned '}[unsigned] + c_type
                if c_decl == 'char' or c_decl == '':
                    continue
                self._test_int_type(ffi, c_decl, size, unsigned)

    def test_fixedsize_int(self):
        for size in [1, 2, 4, 8]:
            self._test_int_type(ffi, 'int%d_t' % (8*size), size, False)
            self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True)
        self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False)
        self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True)
        self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
        self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
        self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)

    def _test_int_type(self, ffi, c_decl, size, unsigned):
        if unsigned:
            min = 0
            max = (1 << (8*size)) - 1
        else:
            min = -(1 << (8*size-1))
            max = (1 << (8*size-1)) - 1
        min = int(min)
        max = int(max)
        p = ffi.cast(c_decl, min)
        assert p == min
        assert bool(p) is bool(min)
        assert int(p) == min
        p = ffi.cast(c_decl, max)
        assert int(p) == max
        p = ffi.cast(c_decl, long(max))
        assert int(p) == max
        q = ffi.cast(c_decl, min - 1)
        assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
        q = ffi.cast(c_decl, long(min - 1))
        assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
        assert q == p
        assert int(q) == int(p)
        assert hash(q) == hash(p)
        c_decl_ptr = '%s *' % c_decl
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, min - 1)
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, max + 1)
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
        pytest.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
        assert ffi.new(c_decl_ptr, min)[0] == min
        assert ffi.new(c_decl_ptr, max)[0] == max
        assert ffi.new(c_decl_ptr, long(min))[0] == min
        assert ffi.new(c_decl_ptr, long(max))[0] == max

    def test_new_unsupported_type(self):
        e = pytest.raises(TypeError, ffi.new, "int")
        assert str(e.value) == "expected a pointer or array ctype, got 'int'"

    def test_new_single_integer(self):
        p = ffi.new("int *")     # similar to ffi.new("int[1]")
        assert p[0] == 0
        p[0] = -123
        assert p[0] == -123
        p = ffi.new("int *", -42)
        assert p[0] == -42
        assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT

    def test_new_array_no_arg(self):
        p = ffi.new("int[10]")
        # the object was zero-initialized:
        for i in range(10):
            assert p[i] == 0

    def test_array_indexing(self):
        p = ffi.new("int[10]")
        p[0] = 42
        p[9] = 43
        assert p[0] == 42
        assert p[9] == 43
        with pytest.raises(IndexError):
            p[10]
        with pytest.raises(IndexError):
            p[10] = 44
        with pytest.raises(IndexError):
            p[-1]
        with pytest.raises(IndexError):
            p[-1] = 44

    def test_new_array_args(self):
        # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}"
        # then here we must enclose the items in a list
        p = ffi.new("int[5]", [10, 20, 30, 40, 50])
        assert p[0] == 10
        assert p[1] == 20
        assert p[2] == 30
        assert p[3] == 40
        assert p[4] == 50
        p = ffi.new("int[4]", [25])
        assert p[0] == 25
        assert p[1] == 0     # follow C convention rather than LuaJIT's
        assert p[2] == 0
        assert p[3] == 0
        p = ffi.new("int[4]", [ffi.cast("int", -5)])
        assert p[0] == -5
        assert repr(p) == "<cdata 'int[4]' owning %d bytes>" % (4*SIZE_OF_INT)

    def test_new_array_varsize(self):
        p = ffi.new("int[]", 10)     # a single integer is the length
        assert p[9] == 0
        with pytest.raises(IndexError):
            p[10]
        #
        pytest.raises(TypeError, ffi.new, "int[]")
        #
        p = ffi.new("int[]", [-6, -7])    # a list is all the items, like C
        assert p[0] == -6
        assert p[1] == -7
        with pytest.raises(IndexError):
            p[2]
        assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
        #
        p = ffi.new("int[]", 0)
        with pytest.raises(IndexError):
            p[0]
        pytest.raises(ValueError, ffi.new, "int[]", -1)
        assert repr(p) == "<cdata 'int[]' owning 0 bytes>"

    def test_pointer_init(self):
        n = ffi.new("int *", 24)
        a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL])
        for i in range(10):
            if i not in (2, 3):
                assert a[i] == ffi.NULL
        assert a[2] == a[3] == n

    def test_cannot_cast(self):
        a = ffi.new("short int[10]")
        e = pytest.raises(TypeError, ffi.new, "long int **", a)
        msg = str(e.value)
        assert "'short[10]'" in msg and "'long *'" in msg

    def test_new_pointer_to_array(self):
        a = ffi.new("int[4]", [100, 102, 104, 106])
        p = ffi.new("int **", a)
        assert p[0] == ffi.cast("int *", a)
        assert p[0][2] == 104
        p = ffi.cast("int *", a)
        assert p[0] == 100
        assert p[1] == 102
        assert p[2] == 104
        assert p[3] == 106
        # keepalive: a

    def test_pointer_direct(self):
        p = ffi.cast("int*", 0)
        assert p is not None
        assert bool(p) is False
        assert p == ffi.cast("int*", 0)
        assert p != None
        assert repr(p) == "<cdata 'int *' NULL>"
        a = ffi.new("int[]", [123, 456])
        p = ffi.cast("int*", a)
        assert bool(p) is True
        assert p == ffi.cast("int*", a)
        assert p != ffi.cast("int*", 0)
        assert p[0] == 123
        assert p[1] == 456

    def test_repr(self):
        typerepr = "<ctype '%s'>"
        p = ffi.cast("short unsigned int", 0)
        assert repr(p) == "<cdata 'unsigned short' 0>"
        assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
        p = ffi.cast("unsigned short int", 0)
        assert repr(p) == "<cdata 'unsigned short' 0>"
        assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
        p = ffi.cast("int*", 0)
        assert repr(p) == "<cdata 'int *' NULL>"
        assert repr(ffi.typeof(p)) == typerepr % "int *"
        #
        p = ffi.new("int*")
        assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
        assert repr(ffi.typeof(p)) == typerepr % "int *"
        p = ffi.new("int**")
        assert repr(p) == "<cdata 'int * *' owning %d bytes>" % SIZE_OF_PTR
        assert repr(ffi.typeof(p)) == typerepr % "int * *"
        p = ffi.new("int [2]")
        assert repr(p) == "<cdata 'int[2]' owning %d bytes>" % (2*SIZE_OF_INT)
        assert repr(ffi.typeof(p)) == typerepr % "int[2]"
        p = ffi.new("int*[2][3]")
        assert repr(p) == "<cdata 'int *[2][3]' owning %d bytes>" % (
            6*SIZE_OF_PTR)
        assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]"
        p = ffi.new("struct repr *")
        assert repr(p) == "<cdata 'struct repr *' owning %d bytes>" % (
            3*SIZE_OF_SHORT)
        assert repr(ffi.typeof(p)) == typerepr % "struct repr *"
        #
        q = ffi.cast("short", -123)
        assert repr(q) == "<cdata 'short' -123>"
        assert repr(ffi.typeof(q)) == typerepr % "short"
        p = ffi.new("int*")
        q = ffi.cast("short*", p)
        assert repr(q).startswith("<cdata 'short *' 0x")
        assert repr(ffi.typeof(q)) == typerepr % "short *"
        p = ffi.new("int [2]")
        q = ffi.cast("int*", p)
        assert repr(q).startswith("<cdata 'int *' 0x")
        assert repr(ffi.typeof(q)) == typerepr % "int *"
        p = ffi.new("struct repr*")
        q = ffi.cast("struct repr *", p)
        assert repr(q).startswith("<cdata 'struct repr *' 0x")
        assert repr(ffi.typeof(q)) == typerepr % "struct repr *"
        prevrepr = repr(q)
        q = q[0]
        assert repr(q) == prevrepr.replace(' *', ' &')
        assert repr(ffi.typeof(q)) == typerepr % "struct repr"

    def test_new_array_of_array(self):
        p = ffi.new("int[3][4]")
        p[0][0] = 10
        p[2][3] = 33
        assert p[0][0] == 10
        assert p[2][3] == 33
        with pytest.raises(IndexError):
            p[1][-1]

    def test_constructor_array_of_array(self):
        p = ffi.new("int[3][2]", [[10, 11], [12, 13], [14, 15]])
        assert p[2][1] == 15

    def test_new_array_of_pointer_1(self):
        n = ffi.new("int*", 99)
        p = ffi.new("int*[4]")
        p[3] = n
        a = p[3]
        assert repr(a).startswith("<cdata 'int *' 0x")
        assert a[0] == 99

    def test_new_array_of_pointer_2(self):
        n = ffi.new("int[1]", [99])
        p = ffi.new("int*[4]")
        p[3] = n
        a = p[3]
        assert repr(a).startswith("<cdata 'int *' 0x")
        assert a[0] == 99

    def test_char(self):
        assert ffi.new("char*", b"\xff")[0] == b'\xff'
        assert ffi.new("char*")[0] == b'\x00'
        assert int(ffi.cast("char", 300)) == 300 - 256
        assert not bool(ffi.cast("char", 0))
        assert bool(ffi.cast("char", 1))
        assert bool(ffi.cast("char", 255))
        pytest.raises(TypeError, ffi.new, "char*", 32)
        pytest.raises(TypeError, ffi.new, "char*", u+"x")
        pytest.raises(TypeError, ffi.new, "char*", b"foo")
        #
        p = ffi.new("char[]", [b'a', b'b', b'\x9c'])
        assert len(p) == 3
        assert p[0] == b'a'
        assert p[1] == b'b'
        assert p[2] == b'\x9c'
        p[0] = b'\xff'
        assert p[0] == b'\xff'
        p = ffi.new("char[]", b"abcd")
        assert len(p) == 5
        assert p[4] == b'\x00'    # like in C, with:  char[] p = "abcd";
        #
        p = ffi.new("char[4]", b"ab")
        assert len(p) == 4
        assert [p[i] for i in range(4)] == [b'a', b'b', b'\x00', b'\x00']
        p = ffi.new("char[2]", b"ab")
        assert len(p) == 2
        assert [p[i] for i in range(2)] == [b'a', b'b']
        pytest.raises(IndexError, ffi.new, "char[2]", b"abc")

    def check_wchar_t(self, ffi):
        try:
            ffi.cast("wchar_t", 0)
        except NotImplementedError:
            pytest.skip("NotImplementedError: wchar_t")

    def test_wchar_t(self):
        self.check_wchar_t(ffi)
        assert ffi.new("wchar_t*", u+'x')[0] == u+'x'
        assert ffi.new("wchar_t*", u+'\u1234')[0] == u+'\u1234'
        if SIZE_OF_WCHAR > 2:
            assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345'
        else:
            pytest.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345')
        assert ffi.new("wchar_t*")[0] == u+'\x00'
        assert int(ffi.cast("wchar_t", 300)) == 300
        assert not bool(ffi.cast("wchar_t", 0))
        assert bool(ffi.cast("wchar_t", 1))
        assert bool(ffi.cast("wchar_t", 65535))
        if SIZE_OF_WCHAR > 2:
            assert bool(ffi.cast("wchar_t", 65536))
        pytest.raises(TypeError, ffi.new, "wchar_t*", 32)
        pytest.raises(TypeError, ffi.new, "wchar_t*", "foo")
        #
        p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234'])
        assert len(p) == 3
        assert p[0] == u+'a'
        assert p[1] == u+'b' and type(p[1]) is unicode
        assert p[2] == u+'\u1234'
        p[0] = u+'x'
        assert p[0] == u+'x' and type(p[0]) is unicode
        p[1] = u+'\u1357'
        assert p[1] == u+'\u1357'
        p = ffi.new("wchar_t[]", u+"abcd")
        assert len(p) == 5
        assert p[4] == u+'\x00'
        p = ffi.new("wchar_t[]", u+"a\u1234b")
        assert len(p) == 4
        assert p[1] == u+'\u1234'
        #
        p = ffi.new("wchar_t[]", u+'\U00023456')
        if SIZE_OF_WCHAR == 2:
            assert len(p) == 3
            assert p[0] == u+'\ud84d'
            assert p[1] == u+'\udc56'
            assert p[2] == u+'\x00'
        else:
            assert len(p) == 2
            assert p[0] == u+'\U00023456'
            assert p[1] == u+'\x00'
        #
        p = ffi.new("wchar_t[4]", u+"ab")
        assert len(p) == 4
        assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00']
        p = ffi.new("wchar_t[2]", u+"ab")
        assert len(p) == 2
        assert [p[i] for i in range(2)] == [u+'a', u+'b']
        pytest.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc")

    def test_none_as_null_doesnt_work(self):
        p = ffi.new("int*[1]")
        assert p[0] is not None
        assert p[0] != None
        assert p[0] == ffi.NULL
        assert repr(p[0]) == "<cdata 'int *' NULL>"
        #
        n = ffi.new("int*", 99)
        p = ffi.new("int*[]", [n])
        assert p[0][0] == 99
        with pytest.raises(TypeError):
            p[0] = None
        p[0] = ffi.NULL
        assert p[0] == ffi.NULL

    def test_float(self):
        p = ffi.new("float[]", [-2, -2.5])
        assert p[0] == -2.0
        assert p[1] == -2.5
        p[1] += 17.75
        assert p[1] == 15.25
        #
        p = ffi.new("float*", 15.75)
        assert p[0] == 15.75
        pytest.raises(TypeError, int, p)
        pytest.raises(TypeError, float, p)
        p[0] = 0.0
        assert bool(p) is True
        #
        p = ffi.new("float*", 1.1)
        f = p[0]
        assert f != 1.1      # because of rounding effect
        assert abs(f - 1.1) < 1E-7
        #
        INF = 1E200 * 1E200
        assert 1E200 != INF
        p[0] = 1E200
        assert p[0] == INF     # infinite, not enough precision

    def test_struct_simple(self):
        s = ffi.new("struct simple*")
        assert s.a == s.b == s.c == 0
        s.b = -23
        assert s.b == -23
        with pytest.raises(OverflowError):
            s.b = 32768
        #
        s = ffi.new("struct simple*", [-2, -3])
        assert s.a == -2
        assert s.b == -3
        assert s.c == 0
        with pytest.raises((AttributeError, TypeError)):
            del s.a
        assert repr(s) == "<cdata 'struct simple *' owning %d bytes>" % (
            SIZE_OF_INT + 2 * SIZE_OF_SHORT)
        #
        pytest.raises(ValueError, ffi.new, "struct simple*", [1, 2, 3, 4])

    def test_constructor_struct_from_dict(self):
        s = ffi.new("struct simple*", {'b': 123, 'c': 456})
        assert s.a == 0
        assert s.b == 123
        assert s.c == 456
        pytest.raises(KeyError, ffi.new, "struct simple*", {'d': 456})

    def test_struct_pointer(self):
        s = ffi.new("struct simple*")
        assert s[0].a == s[0].b == s[0].c == 0
        s[0].b = -23
        assert s[0].b == s.b == -23
        with pytest.raises(OverflowError):
            s[0].b = -32769
        with pytest.raises(IndexError):
            s[1]

    def test_struct_opaque(self):
        pytest.raises(ffi.error, ffi.new, "struct baz*")
        # should 'ffi.new("struct baz **") work?  it used to, but it was
        # not particularly useful...
        pytest.raises(ffi.error, ffi.new, "struct baz**")

    def test_pointer_to_struct(self):
        s = ffi.new("struct simple *")
        s.a = -42
        assert s[0].a == -42
        p = ffi.new("struct simple **", s)
        assert p[0].a == -42
        assert p[0][0].a == -42
        p[0].a = -43
        assert s.a == -43
        assert s[0].a == -43
        p[0][0].a = -44
        assert s.a == -44
        assert s[0].a == -44
        s.a = -45
        assert p[0].a == -45
        assert p[0][0].a == -45
        s[0].a = -46
        assert p[0].a == -46
        assert p[0][0].a == -46

    def test_constructor_struct_of_array(self):
        s = ffi.new("struct array *", [[10, 11], [b'a', b'b', b'c']])
        assert s.a[1] == 11
        assert s.b[2] == b'c'
        s.b[1] = b'X'
        assert s.b[0] == b'a'
        assert s.b[1] == b'X'
        assert s.b[2] == b'c'

    def test_recursive_struct(self):
        s = ffi.new("struct recursive*")
        t = ffi.new("struct recursive*")
        s.value = 123
        s.next = t
        t.value = 456
        assert s.value == 123
        assert s.next.value == 456

    def test_union_simple(self):
        u = ffi.new("union simple_u*")
        assert u.a == u.b == u.c == 0
        u.b = -23
        assert u.b == -23
        assert u.a != 0
        with pytest.raises(OverflowError):
            u.b = 32768
        #
        u = ffi.new("union simple_u*", [-2])
        assert u.a == -2
        with pytest.raises((AttributeError, TypeError)):
            del u.a
        assert repr(u) == "<cdata 'union simple_u *' owning %d bytes>" % (
            SIZE_OF_INT,)

    def test_union_opaque(self):
        pytest.raises(ffi.error, ffi.new, "union baz*")
        # should 'ffi.new("union baz **") work?  it used to, but it was
        # not particularly useful...
        pytest.raises(ffi.error, ffi.new, "union baz**")

    def test_union_initializer(self):
        pytest.raises(TypeError, ffi.new, "union init_u*", b'A')
        pytest.raises(TypeError, ffi.new, "union init_u*", 5)
        pytest.raises(ValueError, ffi.new, "union init_u*", [b'A', 5])
        u = ffi.new("union init_u*", [b'A'])
        assert u.a == b'A'
        pytest.raises(TypeError, ffi.new, "union init_u*", [1005])
        u = ffi.new("union init_u*", {'b': 12345})
        assert u.b == 12345
        u = ffi.new("union init_u*", [])
        assert u.a == b'\x00'
        assert u.b == 0

    def test_sizeof_type(self):
        for c_type, expected_size in [
            ('char', 1),
            ('unsigned int', 4),
            ('char *', SIZE_OF_PTR),
            ('int[5]', 20),
            ('struct four_s', 12),
            ('union four_u', 4),
            ]:
            size = ffi.sizeof(c_type)
            assert size == expected_size, (size, expected_size, ctype)

    def test_sizeof_cdata(self):
        assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR
        assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT
        #
        a = ffi.new("int[]", [10, 11, 12, 13, 14])
        assert len(a) == 5
        assert ffi.sizeof(a) == 5 * SIZE_OF_INT

    def test_string_from_char_pointer(self):
        x = ffi.new("char*", b"x")
        assert str(x) == repr(x)
        assert ffi.string(x) == b"x"
        assert ffi.string(ffi.new("char*", b"\x00")) == b""
        pytest.raises(TypeError, ffi.new, "char*", unicode("foo"))

    def test_unicode_from_wchar_pointer(self):
        self.check_wchar_t(ffi)
        x = ffi.new("wchar_t*", u+"x")
        assert unicode(x) == unicode(repr(x))
        assert ffi.string(x) == u+"x"
        assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+""

    def test_string_from_char_array(self):
        p = ffi.new("char[]", b"hello.")
        p[5] = b'!'
        assert ffi.string(p) == b"hello!"
        p[6] = b'?'
        assert ffi.string(p) == b"hello!?"
        p[3] = b'\x00'
        assert ffi.string(p) == b"hel"
        assert ffi.string(p, 2) == b"he"
        with pytest.raises(IndexError):
            p[7] = b'X'
        #
        a = ffi.new("char[]", b"hello\x00world")
        assert len(a) == 12
        p = ffi.cast("char *", a)
        assert ffi.string(p) == b'hello'

    def test_string_from_wchar_array(self):
        self.check_wchar_t(ffi)
        assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x"
        assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x"
        x = ffi.cast("wchar_t", "x")
        assert str(x) == repr(x)
        assert ffi.string(x) == u+"x"
        #
        p = ffi.new("wchar_t[]", u+"hello.")
        p[5] = u+'!'
        assert ffi.string(p) == u+"hello!"
        p[6] = u+'\u04d2'
        assert ffi.string(p) == u+"hello!\u04d2"
        p[3] = u+'\x00'
        assert ffi.string(p) == u+"hel"
        assert ffi.string(p, 123) == u+"hel"
        with pytest.raises(IndexError):
            p[7] = u+'X'
        #
        a = ffi.new("wchar_t[]", u+"hello\x00world")
        assert len(a) == 12
        p = ffi.cast("wchar_t *", a)
        assert ffi.string(p) == u+'hello'
        assert ffi.string(p, 123) == u+'hello'
        assert ffi.string(p, 5) == u+'hello'
        assert ffi.string(p, 2) == u+'he'

    def test_fetch_const_char_p_field(self):
        # 'const' is ignored so far, in the declaration of 'struct string'
        t = ffi.new("const char[]", b"testing")
        s = ffi.new("struct string*", [t])
        assert type(s.name) not in (bytes, str, unicode)
        assert ffi.string(s.name) == b"testing"
        with pytest.raises(TypeError):
            s.name = None
        s.name = ffi.NULL
        assert s.name == ffi.NULL

    def test_fetch_const_wchar_p_field(self):
        # 'const' is ignored so far
        self.check_wchar_t(ffi)
        t = ffi.new("const wchar_t[]", u+"testing")
        s = ffi.new("struct ustring*", [t])
        assert type(s.name) not in (bytes, str, unicode)
        assert ffi.string(s.name) == u+"testing"
        s.name = ffi.NULL
        assert s.name == ffi.NULL

    def test_voidp(self):
        pytest.raises(TypeError, ffi.new, "void*")
        p = ffi.new("void **")
        assert p[0] == ffi.NULL
        a = ffi.new("int[]", [10, 11, 12])
        p = ffi.new("void **", a)
        vp = p[0]
        with pytest.raises(TypeError):
            vp[0]
        pytest.raises(TypeError, ffi.new, "short **", a)
        #
        s = ffi.new("struct voidp *")
        s.p = a    # works
        s.q = a    # works
        with pytest.raises(TypeError):
            s.r = a    # fails
        b = ffi.cast("int *", a)
        s.p = b    # works
        s.q = b    # works
        with pytest.raises(TypeError):
            s.r = b    # fails

    def test_functionptr_simple(self):
        pytest.raises(TypeError, ffi.callback, "int(*)(int)", 0)
        def cb(n):
            return n + 1
        cb.__qualname__ = 'cb'
        p = ffi.callback("int(*)(int)", cb)
        res = p(41)     # calling an 'int(*)(int)', i.e. a function pointer
        assert res == 42 and type(res) is int
        res = p(ffi.cast("int", -41))
        assert res == -40 and type(res) is int
        assert repr(p).startswith(
            "<cdata 'int(*)(int)' calling <function cb at 0x")
        assert ffi.typeof(p) is ffi.typeof("int(*)(int)")
        q = ffi.new("int(**)(int)", p)
        assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % (
            SIZE_OF_PTR)
        with pytest.raises(TypeError):
            q(43)
        res = q[0](43)
        assert res == 44
        q = ffi.cast("int(*)(int)", p)
        assert repr(q).startswith("<cdata 'int(*)(int)' 0x")
        res = q(45)
        assert res == 46

    def test_functionptr_advanced(self):
        t = ffi.typeof("int(*(*)(int))(int)")
        assert repr(t) == "<ctype '%s'>" % "int(*(*)(int))(int)"

    def test_functionptr_voidptr_return(self):
        def cb():
            return ffi.NULL
        p = ffi.callback("void*(*)()", cb)
        res = p()
        assert res is not None
        assert res == ffi.NULL
        int_ptr = ffi.new('int*')
        void_ptr = ffi.cast('void*', int_ptr)
        def cb():
            return void_ptr
        p = ffi.callback("void*(*)()", cb)
        res = p()
        assert res == void_ptr

    def test_functionptr_intptr_return(self):
        def cb():
            return ffi.NULL
        p = ffi.callback("int*(*)()", cb)
        res = p()
        assert res == ffi.NULL
        int_ptr = ffi.new('int*')
        def cb():
            return int_ptr
        p = ffi.callback("int*(*)()", cb)
        res = p()
        assert repr(res).startswith("<cdata 'int *' 0x")
        assert res == int_ptr
        int_array_ptr = ffi.new('int[1]')
        def cb():
            return int_array_ptr
        p = ffi.callback("int*(*)()", cb)
        res = p()
        assert repr(res).startswith("<cdata 'int *' 0x")
        assert res == int_array_ptr

    def test_functionptr_void_return(self):
        def foo():
            pass
        foo_cb = ffi.callback("void foo()", foo)
        result = foo_cb()
        assert result is None

    def test_char_cast(self):
        p = ffi.cast("int", b'\x01')
        assert ffi.typeof(p) is ffi.typeof("int")
        assert int(p) == 1
        p = ffi.cast("int", ffi.cast("char", b"a"))
        assert int(p) == ord("a")
        p = ffi.cast("int", ffi.cast("char", b"\x80"))
        assert int(p) == 0x80     # "char" is considered unsigned in this case
        p = ffi.cast("int", b"\x81")
        assert int(p) == 0x81

    def test_wchar_cast(self):
        self.check_wchar_t(ffi)
        p = ffi.cast("int", ffi.cast("wchar_t", u+'\u1234'))
        assert int(p) == 0x1234
        p = ffi.cast("long long", ffi.cast("wchar_t", -1))
        if SIZE_OF_WCHAR == 2:      # 2 bytes, unsigned
            assert int(p) == 0xffff
        elif (sys.platform.startswith('linux') and
              platform.machine().startswith('x86')):   # known to be signed
            assert int(p) == -1
        else:                     # in general, it can be either signed or not
            assert int(p) in [-1, 0xffffffff]  # e.g. on arm, both cases occur
        p = ffi.cast("int", u+'\u1234')
        assert int(p) == 0x1234

    def test_cast_array_to_charp(self):
        a = ffi.new("short int[]", [0x1234, 0x5678])
        p = ffi.cast("char*", a)
        data = b''.join([p[i] for i in range(4)])
        if sys.byteorder == 'little':
            assert data == b'\x34\x12\x78\x56'
        else:
            assert data == b'\x12\x34\x56\x78'

    def test_cast_between_pointers(self):
        a = ffi.new("short int[]", [0x1234, 0x5678])
        p = ffi.cast("short*", a)
        p2 = ffi.cast("int*", p)
        q = ffi.cast("char*", p2)
        data = b''.join([q[i] for i in range(4)])
        if sys.byteorder == 'little':
            assert data == b'\x34\x12\x78\x56'
        else:
            assert data == b'\x12\x34\x56\x78'

    def test_cast_pointer_and_int(self):
        a = ffi.new("short int[]", [0x1234, 0x5678])
        l1 = ffi.cast("intptr_t", a)
        p = ffi.cast("short*", a)
        l2 = ffi.cast("intptr_t", p)
        assert int(l1) == int(l2) != 0
        q = ffi.cast("short*", l1)
        assert q == ffi.cast("short*", int(l1))
        assert q[0] == 0x1234
        assert int(ffi.cast("intptr_t", ffi.NULL)) == 0

    def test_cast_functionptr_and_int(self):
        def cb(n):
            return n + 1
        a = ffi.callback("int(*)(int)", cb)
        p = ffi.cast("void *", a)
        assert p
        b = ffi.cast("int(*)(int)", p)
        assert b(41) == 42
        assert a == b
        assert hash(a) == hash(b)

    def test_callback_crash(self):
        def cb(n):
            raise Exception
        a = ffi.callback("int(*)(int)", cb, error=42)
        res = a(1)    # and the error reported to stderr
        assert res == 42

    def test_structptr_argument(self):
        def cb(p):
            return p[0].a * 1000 + p[0].b * 100 + p[1].a * 10 + p[1].b
        a = ffi.callback("int(*)(struct ab[])", cb)
        res = a([[5, 6], {'a': 7, 'b': 8}])
        assert res == 5678
        res = a([[5], {'b': 8}])
        assert res == 5008

    def test_array_argument_as_list(self):
        seen = []
        def cb(argv):
            seen.append(ffi.string(argv[0]))
            seen.append(ffi.string(argv[1]))
        a = ffi.callback("void(*)(char *[])", cb)
        a([ffi.new("char[]", b"foobar"), ffi.new("char[]", b"baz")])
        assert seen == [b"foobar", b"baz"]

    def test_cast_float(self):
        a = ffi.cast("float", 12)
        assert float(a) == 12.0
        a = ffi.cast("float", 12.5)
        assert float(a) == 12.5
        a = ffi.cast("float", b"A")
        assert float(a) == ord("A")
        a = ffi.cast("int", 12.9)
        assert int(a) == 12
        a = ffi.cast("char", 66.9 + 256)
        assert ffi.string(a) == b"B"
        #
        a = ffi.cast("float", ffi.cast("int", 12))
        assert float(a) == 12.0
        a = ffi.cast("float", ffi.cast("double", 12.5))
        assert float(a) == 12.5
        a = ffi.cast("float", ffi.cast("char", b"A"))
        assert float(a) == ord("A")
        a = ffi.cast("int", ffi.cast("double", 12.9))
        assert int(a) == 12
        a = ffi.cast("char", ffi.cast("double", 66.9 + 256))
        assert ffi.string(a) == b"B"

    def test_enum(self):
        # enum foq { A0, B0, CC0, D0 };
        assert ffi.string(ffi.cast("enum foq", 0)) == "cffiA0"
        assert ffi.string(ffi.cast("enum foq", 2)) == "cffiCC0"
        assert ffi.string(ffi.cast("enum foq", 3)) == "cffiD0"
        assert ffi.string(ffi.cast("enum foq", 4)) == "4"
        # enum bar { A1, B1=-2, CC1, D1, E1 };
        assert ffi.string(ffi.cast("enum bar", 0)) == "A1"
        assert ffi.string(ffi.cast("enum bar", -2)) == "B1"
        assert ffi.string(ffi.cast("enum bar", -1)) == "CC1"
        assert ffi.string(ffi.cast("enum bar", 1)) == "E1"
        assert ffi.cast("enum bar", -2) == ffi.cast("enum bar", -2)
        assert ffi.cast("enum foq", 0) == ffi.cast("enum bar", 0)
        assert ffi.cast("enum bar", 0) == ffi.cast("int", 0)
        assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC1>"
        assert repr(ffi.cast("enum foq", -1)) == (  # enums are unsigned, if
            "<cdata 'enum foq' 4294967295>") or (   # they contain no neg value
                sys.platform == "win32")            # (but not on msvc)
        # enum baz { A2=0x1000, B2=0x2000 };
        assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2"
        assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"

    def test_enum_in_struct(self):
        # enum foo2 { A3, B3, C3, D3 };
        # struct bar_with_e { enum foo2 e; };
        s = ffi.new("struct bar_with_e *")
        s.e = 0
        assert s.e == 0
        s.e = 3
        assert s.e == 3
        assert s[0].e == 3
        s[0].e = 2
        assert s.e == 2
        assert s[0].e == 2
        s.e = ffi.cast("enum foo2", -1)
        assert s.e in (4294967295, -1)     # two choices
        assert s[0].e in (4294967295, -1)
        s.e = s.e
        with pytest.raises(TypeError):
            s.e = 'B3'
        with pytest.raises(TypeError):
            s.e = '2'
        with pytest.raises(TypeError):
            s.e = '#2'
        with pytest.raises(TypeError):
            s.e = '#7'

    def test_enum_non_contiguous(self):
        # enum noncont { A4, B4=42, C4 };
        assert ffi.string(ffi.cast("enum noncont", 0)) == "A4"
        assert ffi.string(ffi.cast("enum noncont", 42)) == "B4"
        assert ffi.string(ffi.cast("enum noncont", 43)) == "C4"
        invalid_value = ffi.cast("enum noncont", 2)
        assert int(invalid_value) == 2
        assert ffi.string(invalid_value) == "2"

    def test_enum_char_hex_oct(self):
        # enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010};
        assert ffi.string(ffi.cast("enum etypes", ord('!'))) == "A5"
        assert ffi.string(ffi.cast("enum etypes", ord("'"))) == "B5"
        assert ffi.string(ffi.cast("enum etypes", 16)) == "C5"
        assert ffi.string(ffi.cast("enum etypes", 8)) == "D5"
        assert ffi.string(ffi.cast("enum etypes", -16)) == "E5"
        assert ffi.string(ffi.cast("enum etypes", -8)) == "F5"

    def test_array_of_struct(self):
        s = ffi.new("struct ab[1]")
        with pytest.raises(AttributeError):
            s.b
        with pytest.raises(AttributeError):
            s.b = 412
        s[0].b = 412
        assert s[0].b == 412
        with pytest.raises(IndexError):
            s[1]

    def test_pointer_to_array(self):
        p = ffi.new("int(**)[5]")
        assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR

    def test_iterate_array(self):
        a = ffi.new("char[]", b"hello")
        assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
        assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
        #
        pytest.raises(TypeError, iter, ffi.cast("char *", a))
        pytest.raises(TypeError, list, ffi.cast("char *", a))
        pytest.raises(TypeError, iter, ffi.new("int *"))
        pytest.raises(TypeError, list, ffi.new("int *"))

    def test_offsetof(self):
        # struct abc { int a, b, c; };
        assert ffi.offsetof("struct abc", "a") == 0
        assert ffi.offsetof("struct abc", "b") == 4
        assert ffi.offsetof("struct abc", "c") == 8

    def test_offsetof_nested(self):
        # struct nesting { struct abc d, e; };
        assert ffi.offsetof("struct nesting", "e") == 12
        pytest.raises(KeyError, ffi.offsetof, "struct nesting", "e.a")
        assert ffi.offsetof("struct nesting", "e", "a") == 12
        assert ffi.offsetof("struct nesting", "e", "b") == 16
        assert ffi.offsetof("struct nesting", "e", "c") == 20

    def test_offsetof_array(self):
        assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int")
        assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int")
        # struct array2 { int a, b; int c[99]; };
        assert ffi.offsetof("struct array2", "c") == 2 * ffi.sizeof("int")
        assert ffi.offsetof("struct array2", "c", 0) == 2 * ffi.sizeof("int")
        assert ffi.offsetof("struct array2", "c", 51) == 53 * ffi.sizeof("int")

    def test_alignof(self):
        # struct align { char a; short b; char c; };
        assert ffi.alignof("int") == 4
        assert ffi.alignof("double") in (4, 8)
        assert ffi.alignof("struct align") == 2

    def test_bitfield(self):
        # struct bitfield { int a:10, b:20, c:3; };
        assert ffi.sizeof("struct bitfield") == 8
        s = ffi.new("struct bitfield *")
        s.a = 511
        with pytest.raises(OverflowError):
            s.a = 512
        with pytest.raises(OverflowError):
            s[0].a = 512
        assert s.a == 511
        s.a = -512
        with pytest.raises(OverflowError):
            s.a = -513
        with pytest.raises(OverflowError):
            s[0].a = -513
        assert s.a == -512
        s.c = 3
        assert s.c == 3
        with pytest.raises(OverflowError):
            s.c = 4
        with pytest.raises(OverflowError):
            s[0].c = 4
        s.c = -4
        assert s.c == -4

    def test_bitfield_enum(self):
        # typedef enum { AA1, BB1, CC1 } foo_e_t;
        # typedef struct { foo_e_t f:2; } bfenum_t;
        if sys.platform == "win32":
            pytest.skip("enums are not unsigned")
        s = ffi.new("bfenum_t *")
        s.f = 2
        assert s.f == 2

    def test_anonymous_struct(self):
        # typedef struct { int a; } anon_foo_t;
        # typedef struct { char b, c; } anon_bar_t;
        f = ffi.new("anon_foo_t *", [12345])
        b = ffi.new("anon_bar_t *", [b"B", b"C"])
        assert f.a == 12345
        assert b.b == b"B"
        assert b.c == b"C"
        assert repr(b).startswith("<cdata 'anon_bar_t *'")

    def test_struct_with_two_usages(self):
        # typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p;
        # typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p;
        f = ffi.new("named_foo_t *", [12345])
        ps = ffi.new("named_foo_p[]", [f])
        f = ffi.new("unnamed_foo_t *", [12345])
        ps = ffi.new("unnamed_foo_p[]", [f])

    def test_pointer_arithmetic(self):
        s = ffi.new("short[]", list(range(100, 110)))
        p = ffi.cast("short *", s)
        assert p[2] == 102
        assert p+1 == p+1
        assert p+1 != p+0
        assert p == p+0 == p-0
        assert (p+1)[0] == 101
        assert (p+19)[-10] == 109
        assert (p+5) - (p+1) == 4
        assert p == s+0
        assert p+1 == s+1

    def test_pointer_comparison(self):
        s = ffi.new("short[]", list(range(100)))
        p = ffi.cast("short *", s)
        assert (p <  s) is False
        assert (p <= s) is True
        assert (p == s) is True
        assert (p != s) is False
        assert (p >  s) is False
        assert (p >= s) is True
        assert (s <  p) is False
        assert (s <= p) is True
        assert (s == p) is True
        assert (s != p) is False
        assert (s >  p) is False
        assert (s >= p) is True
        q = p + 1
        assert (q <  s) is False
        assert (q <= s) is False
        assert (q == s) is False
        assert (q != s) is True
        assert (q >  s) is True
        assert (q >= s) is True
        assert (s <  q) is True
        assert (s <= q) is True
        assert (s == q) is False
        assert (s != q) is True
        assert (s >  q) is False
        assert (s >= q) is False
        assert (q <  p) is False
        assert (q <= p) is False
        assert (q == p) is False
        assert (q != p) is True
        assert (q >  p) is True
        assert (q >= p) is True
        assert (p <  q) is True
        assert (p <= q) is True
        assert (p == q) is False
        assert (p != q) is True
        assert (p >  q) is False
        assert (p >= q) is False
        #
        assert (None == s) is False
        assert (None != s) is True
        assert (s == None) is False
        assert (s != None) is True
        assert (None == q) is False
        assert (None != q) is True
        assert (q == None) is False
        assert (q != None) is True

    def test_integer_comparison(self):
        x = ffi.cast("int", 123)
        y = ffi.cast("int", 456)
        assert x < y
        #
        z = ffi.cast("double", 78.9)
        assert x > z
        assert y > z

    def test_ffi_buffer_ptr(self):
        a = ffi.new("short *", 100)
        try:
            b = ffi.buffer(a)
        except NotImplementedError as e:
            pytest.skip(str(e))
        content = b[:]
        assert len(content) == len(b) == 2
        if sys.byteorder == 'little':
            assert content == b'\x64\x00'
            assert b[0] == b'\x64'
            b[0] = b'\x65'
        else:
            assert content == b'\x00\x64'
            assert b[1] == b'\x64'
            b[1] = b'\x65'
        assert a[0] == 101

    def test_ffi_buffer_array(self):
        a = ffi.new("int[]", list(range(100, 110)))
        try:
            b = ffi.buffer(a)
        except NotImplementedError as e:
            pytest.skip(str(e))
        content = b[:]
        if sys.byteorder == 'little':
            assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00')
            b[4] = b'\x45'
        else:
            assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65')
            b[7] = b'\x45'
        assert len(content) == 4 * 10
        assert a[1] == 0x45

    def test_ffi_buffer_ptr_size(self):
        a = ffi.new("short *", 0x4243)
        try:
            b = ffi.buffer(a, 1)
        except NotImplementedError as e:
            pytest.skip(str(e))
        content = b[:]
        assert len(content) == 1
        if sys.byteorder == 'little':
            assert content == b'\x43'
            b[0] = b'\x62'
            assert a[0] == 0x4262
        else:
            assert content == b'\x42'
            b[0] = b'\x63'
            assert a[0] == 0x6343

    def test_ffi_buffer_array_size(self):
        a1 = ffi.new("int[]", list(range(100, 110)))
        a2 = ffi.new("int[]", list(range(100, 115)))
        try:
            ffi.buffer(a1)
        except NotImplementedError as e:
            pytest.skip(str(e))
        assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]

    def test_ffi_buffer_with_file(self):
        import tempfile, os, array
        fd, filename = tempfile.mkstemp()
        f = os.fdopen(fd, 'r+b')
        a = ffi.new("int[]", list(range(1005)))
        try:
            ffi.buffer(a, 512)
        except NotImplementedError as e:
            pytest.skip(str(e))
        f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
        f.seek(0)
        assert f.read() == arraytostring(array.array('i', range(1000)))
        f.seek(0)
        b = ffi.new("int[]", 1005)
        f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
        assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
        f.close()
        os.unlink(filename)

    def test_ffi_buffer_with_io(self):
        import io, array
        f = io.BytesIO()
        a = ffi.new("int[]", list(range(1005)))
        try:
            ffi.buffer(a, 512)
        except NotImplementedError as e:
            pytest.skip(str(e))
        f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
        f.seek(0)
        assert f.read() == arraytostring(array.array('i', range(1000)))
        f.seek(0)
        b = ffi.new("int[]", 1005)
        f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
        assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
        f.close()

    def test_array_in_struct(self):
        # struct array { int a[2]; char b[3]; };
        p = ffi.new("struct array *")
        p.a[1] = 5
        assert p.a[1] == 5
        assert repr(p.a).startswith("<cdata 'int[2]' 0x")

    def test_struct_containing_array_varsize_workaround(self):
        if sys.platform == "win32":
            pytest.skip("array of length 0 not supported")
        # struct array0 { int len; short data[0]; };
        p = ffi.new("char[]", ffi.sizeof("struct array0") + 7 * SIZE_OF_SHORT)
        q = ffi.cast("struct array0 *", p)
        assert q.len == 0
        # 'q.data' gets not a 'short[0]', but just a 'short *' instead
        assert repr(q.data).startswith("<cdata 'short *' 0x")
        assert q.data[6] == 0
        q.data[6] = 15
        assert q.data[6] == 15

    def test_new_struct_containing_array_varsize(self):
        pytest.skip("later?")
        ffi.cdef("struct foo_s { int len; short data[]; };")
        p = ffi.new("struct foo_s *", 10)     # a single integer is the length
        assert p.len == 0
        assert p.data[9] == 0
        with pytest.raises(IndexError):
            p.data[10]

    def test_ffi_typeof_getcname(self):
        assert ffi.getctype("int") == "int"
        assert ffi.getctype("int", 'x') == "int x"
        assert ffi.getctype("int*") == "int *"
        assert ffi.getctype("int*", '') == "int *"
        assert ffi.getctype("int*", 'x') == "int * x"
        assert ffi.getctype("int", '*') == "int *"
        assert ffi.getctype("int", ' * x ') == "int * x"
        assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *"
        assert ffi.getctype("int", '[5]') == "int[5]"
        assert ffi.getctype("int[5]", '[6]') == "int[6][5]"
        assert ffi.getctype("int[5]", '(*)') == "int(*)[5]"
        # special-case for convenience: automatically put '()' around '*'
        assert ffi.getctype("int[5]", '*') == "int(*)[5]"
        assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]"
        assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"

    def test_array_of_func_ptr(self):
        f = ffi.cast("int(*)(int)", 42)
        assert f != ffi.NULL
        pytest.raises(ffi.error, ffi.cast, "int(int)", 42)
        pytest.raises(ffi.error, ffi.new, "int([5])(int)")
        a = ffi.new("int(*[5])(int)", [f])
        assert ffi.getctype(ffi.typeof(a)) == "int(*[5])(int)"
        assert len(a) == 5
        assert a[0] == f
        assert a[1] == ffi.NULL
        pytest.raises(TypeError, ffi.cast, "int(*)(int)[5]", 0)
        #
        def cb(n):
            return n + 1
        f = ffi.callback("int(*)(int)", cb)
        a = ffi.new("int(*[5])(int)", [f, f])
        assert a[1](42) == 43

    def test_callback_as_function_argument(self):
        # In C, function arguments can be declared with a function type,
        # which is automatically replaced with the ptr-to-function type.
        def cb(a, b):
            return chr(ord(a) + ord(b)).encode()
        f = ffi.callback("char cb(char, char)", cb)
        assert f(b'A', b'\x01') == b'B'
        def g(callback):
            return callback(b'A', b'\x01')
        g = ffi.callback("char g(char cb(char, char))", g)
        assert g(f) == b'B'

    def test_vararg_callback(self):
        pytest.skip("callback with '...'")
        def cb(i, va_list):
            j = ffi.va_arg(va_list, "int")
            k = ffi.va_arg(va_list, "long long")
            return i * 2 + j * 3 + k * 5
        f = ffi.callback("long long cb(long i, ...)", cb)
        res = f(10, ffi.cast("int", 100), ffi.cast("long long", 1000))
        assert res == 20 + 300 + 5000

    def test_callback_decorator(self):
        #
        @ffi.callback("long(long, long)", error=42)
        def cb(a, b):
            return a - b
        #
        assert cb(-100, -10) == -90
        sz = ffi.sizeof("long")
        assert cb((1 << (sz*8-1)) - 1, -10) == 42

    def test_anonymous_enum(self):
        # typedef enum { Value0 = 0 } e_t, *pe_t;
        assert ffi.getctype("e_t*") == 'e_t *'
        assert ffi.getctype("pe_t") == 'e_t *'
        assert ffi.getctype("foo_e_t*") == 'foo_e_t *'

    def test_new_ctype(self):
        p = ffi.new("int *")
        pytest.raises(TypeError, ffi.new, p)
        p = ffi.new(ffi.typeof("int *"), 42)
        assert p[0] == 42

    def test_enum_with_non_injective_mapping(self):
        # enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 };
        e = ffi.cast("enum e_noninj", 0)
        assert ffi.string(e) == "AA3"     # pick the first one arbitrarily

    def test_enum_refer_previous_enum_value(self):
        # enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 };
        assert ffi.string(ffi.cast("enum e_prev", 2)) == "BB4"
        assert ffi.string(ffi.cast("enum e_prev", 3)) == "EE4"
        assert ffi.sizeof("char[DD4]") == 2
        assert ffi.sizeof("char[EE4]") == 3
        assert ffi.sizeof("char[FF4]") == 4
        assert ffi.sizeof("char[GG4]") == 4

    def test_nested_anonymous_struct(self):
        # struct nested_anon {
        #     struct { int a, b; };
        #     union { int c, d; };
        # };
        assert ffi.sizeof("struct nested_anon") == 3 * SIZE_OF_INT
        p = ffi.new("struct nested_anon *", [1, 2, 3])
        assert p.a == 1
        assert p.b == 2
        assert p.c == 3
        assert p.d == 3
        p.d = 17
        assert p.c == 17
        p.b = 19
        assert p.a == 1
        assert p.b == 19
        assert p.c == 17
        assert p.d == 17
        p = ffi.new("struct nested_anon *", {'b': 12, 'd': 14})
        assert p.a == 0
        assert p.b == 12
        assert p.c == 14
        assert p.d == 14

    def test_nested_field_offset_align(self):
        # struct nested_field_ofs_s {
        #    struct { int a; char b; };
        #    union { char c; };
        # };
        assert ffi.offsetof("struct nested_field_ofs_s", "c") == 2 * SIZE_OF_INT
        assert ffi.sizeof("struct nested_field_ofs_s") == 3 * SIZE_OF_INT

    def test_nested_anonymous_union(self):
        # union nested_anon_u {
        #     struct { int a, b; };
        #     union { int c, d; };
        # };
        assert ffi.sizeof("union nested_anon_u") == 2 * SIZE_OF_INT
        p = ffi.new("union nested_anon_u *", [5])
        assert p.a == 5
        assert p.b == 0
        assert p.c == 5
        assert p.d == 5
        p.d = 17
        assert p.c == 17
        assert p.a == 17
        p.b = 19
        assert p.a == 17
        assert p.b == 19
        assert p.c == 17
        assert p.d == 17
        p = ffi.new("union nested_anon_u *", {'d': 14})
        assert p.a == 14
        assert p.b == 0
        assert p.c == 14
        assert p.d == 14
        p = ffi.new("union nested_anon_u *", {'b': 12})
        assert p.a == 0
        assert p.b == 12
        assert p.c == 0
        assert p.d == 0
        # we cannot specify several items in the dict, even though
        # in theory in this particular case it would make sense
        # to give both 'a' and 'b'

    def test_cast_to_array_type(self):
        p = ffi.new("int[4]", [-5])
        q = ffi.cast("int[3]", p)
        assert q[0] == -5
        assert repr(q).startswith("<cdata 'int[3]' 0x")

    def test_gc(self):
        p = ffi.new("int *", 123)
        seen = []
        def destructor(p1):
            assert p1 is p
            assert p1[0] == 123
            seen.append(1)
        q = ffi.gc(p, destructor=destructor)
        import gc; gc.collect()
        assert seen == []
        del q
        import gc; gc.collect(); gc.collect(); gc.collect()
        assert seen == [1]

    def test_gc_2(self):
        p = ffi.new("int *", 123)
        seen = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        import gc; gc.collect()
        assert seen == []
        del q1, q2
        import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
        assert seen == [2, 1]

    def test_gc_3(self):
        p = ffi.new("int *", 123)
        r = ffi.new("int *", 123)
        seen = []
        seen_r = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        s1 = ffi.gc(r, lambda r: seen_r.append(4))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        s2 = ffi.gc(s1, lambda r: seen_r.append(5))
        q3 = ffi.gc(q2, lambda p: seen.append(3))
        import gc; gc.collect()
        assert seen == []
        assert seen_r == []
        del q1, q2, q3, s2, s1
        import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect()
        assert seen == [3, 2, 1]
        assert seen_r == [5, 4]

    def test_gc_4(self):
        p = ffi.new("int *", 123)
        seen = []
        q1 = ffi.gc(p, lambda p: seen.append(1))
        q2 = ffi.gc(q1, lambda p: seen.append(2))
        q3 = ffi.gc(q2, lambda p: seen.append(3))
        import gc; gc.collect()
        assert seen == []
        del q1, q3     # q2 remains, and has a hard ref to q1
        import gc; gc.collect(); gc.collect(); gc.collect()
        assert seen == [3]

    def test_release(self):
        p = ffi.new("int[]", 123)
        ffi.release(p)
        # here, reading p[0] might give garbage or segfault...
        ffi.release(p)   # no effect

    def test_release_new_allocator(self):
        seen = []
        def myalloc(size):
            seen.append(size)
            return ffi.new("char[]", b"X" * size)
        def myfree(raw):
            seen.append(raw)
        alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree)
        p = alloc2("int[]", 15)
        assert seen == [15 * 4]
        ffi.release(p)
        assert seen == [15 * 4, p]
        ffi.release(p)    # no effect
        assert seen == [15 * 4, p]
        #
        del seen[:]
        p = alloc2("struct ab *")
        assert seen == [2 * 4]
        ffi.release(p)
        assert seen == [2 * 4, p]
        ffi.release(p)    # no effect
        assert seen == [2 * 4, p]

    def test_CData_CType(self):
        assert isinstance(ffi.cast("int", 0), ffi.CData)
        assert isinstance(ffi.new("int *"), ffi.CData)
        assert not isinstance(ffi.typeof("int"), ffi.CData)
        assert not isinstance(ffi.cast("int", 0), ffi.CType)
        assert not isinstance(ffi.new("int *"), ffi.CType)

    def test_CData_CType_2(self):
        assert isinstance(ffi.typeof("int"), ffi.CType)

    def test_bool(self):
        assert int(ffi.cast("_Bool", 0.1)) == 1
        assert int(ffi.cast("_Bool", -0.0)) == 0
        assert int(ffi.cast("_Bool", b'\x02')) == 1
        assert int(ffi.cast("_Bool", b'\x00')) == 0
        assert int(ffi.cast("_Bool", b'\x80')) == 1
        assert ffi.new("_Bool *", False)[0] == 0
        assert ffi.new("_Bool *", 1)[0] == 1
        pytest.raises(OverflowError, ffi.new, "_Bool *", 2)
        pytest.raises(TypeError, ffi.string, ffi.cast("_Bool", 2))

    def test_addressof(self):
        p = ffi.new("struct ab *")
        a = ffi.addressof(p[0])
        assert repr(a).startswith("<cdata 'struct ab *' 0x")
        assert a == p
        pytest.raises(TypeError, ffi.addressof, p)
        pytest.raises((AttributeError, TypeError), ffi.addressof, 5)
        pytest.raises(TypeError, ffi.addressof, ffi.cast("int", 5))

    def test_addressof_field(self):
        p = ffi.new("struct ab *")
        b = ffi.addressof(p[0], 'b')
        assert repr(b).startswith("<cdata 'int *' 0x")
        assert int(ffi.cast("uintptr_t", b)) == (
            int(ffi.cast("uintptr_t", p)) + ffi.sizeof("int"))
        assert b == ffi.addressof(p, 'b')
        assert b != ffi.addressof(p, 'a')

    def test_addressof_field_nested(self):
        # struct nesting { struct abc d, e; };
        p = ffi.new("struct nesting *")
        pytest.raises(KeyError, ffi.addressof, p[0], 'e.b')
        a = ffi.addressof(p[0], 'e', 'b')
        assert int(ffi.cast("uintptr_t", a)) == (
            int(ffi.cast("uintptr_t", p)) +
            ffi.sizeof("struct abc") + ffi.sizeof("int"))

    def test_addressof_anonymous_struct(self):
        # typedef struct { int a; } anon_foo_t;
        p = ffi.new("anon_foo_t *")
        a = ffi.addressof(p[0])
        assert a == p

    def test_addressof_array(self):
        p = ffi.new("int[52]")
        p0 = ffi.addressof(p)
        assert p0 == p
        assert ffi.typeof(p0) is ffi.typeof("int(*)[52]")
        pytest.raises(TypeError, ffi.addressof, p0)
        #
        p1 = ffi.addressof(p, 25)
        assert ffi.typeof(p1) is ffi.typeof("int *")
        assert (p1 - p) == 25
        assert ffi.addressof(p, 0) == p

    def test_addressof_pointer(self):
        array = ffi.new("int[50]")
        p = ffi.cast("int *", array)
        pytest.raises(TypeError, ffi.addressof, p)
        assert ffi.addressof(p, 0) == p
        assert ffi.addressof(p, 25) == p + 25
        assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)
        #
        array = ffi.new("struct ab[50]")
        p = ffi.cast("int *", array)
        pytest.raises(TypeError, ffi.addressof, p)
        assert ffi.addressof(p, 0) == p
        assert ffi.addressof(p, 25) == p + 25
        assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p)

    def test_addressof_array_in_struct(self):
        # struct abc50 { int a, b; int c[50]; };
        p = ffi.new("struct abc50 *")
        p1 = ffi.addressof(p, "c", 25)
        assert ffi.typeof(p1) is ffi.typeof("int *")
        assert p1 == ffi.cast("int *", p) + 27
        assert ffi.addressof(p, "c") == ffi.cast("int *", p) + 2
        assert ffi.addressof(p, "c", 0) == ffi.cast("int *", p) + 2
        p2 = ffi.addressof(p, 1)
        assert ffi.typeof(p2) is ffi.typeof("struct abc50 *")
        assert p2 == p + 1

    def test_multiple_independent_structs(self):
        CDEF2 = "struct ab { int x; };"
        ffi2 = cffi.FFI(); ffi2.cdef(CDEF2)
        outputfilename = recompile(ffi2, "test_multiple_independent_structs",
                                   CDEF2, tmpdir=str(udir))
        module = load_dynamic("test_multiple_independent_structs",
                                  outputfilename)
        ffi1 = module.ffi
        foo1 = ffi1.new("struct ab *", [10])
        foo2 = ffi .new("struct ab *", [20, 30])
        assert foo1.x == 10
        assert foo2.a == 20
        assert foo2.b == 30

    def test_include_struct_union_enum_typedef(self):
        ffi1, CCODE = construction_params
        ffi2 = cffi.FFI()
        ffi2.include(ffi1)
        outputfilename = recompile(ffi2,
                                   "test_include_struct_union_enum_typedef",
                                   CCODE, tmpdir=str(udir))
        module = load_dynamic("test_include_struct_union_enum_typedef",
                                  outputfilename)
        ffi2 = module.ffi
        #
        p = ffi2.new("struct nonpacked *", [b'A', -43141])
        assert p.a == b'A'
        assert p.b == -43141
        #
        p = ffi.new("union simple_u *", [-52525])
        assert p.a == -52525
        #
        p = ffi.cast("enum foq", 2)
        assert ffi.string(p) == "cffiCC0"
        assert ffi2.sizeof("char[cffiCC0]") == 2
        #
        p = ffi.new("anon_foo_t *", [-52526])
        assert p.a == -52526
        p = ffi.new("named_foo_p", [-52527])
        assert p.a == -52527

    def test_struct_packed(self):
        # struct nonpacked { char a; int b; };
        # struct is_packed { char a; int b; } __attribute__((packed));
        assert ffi.sizeof("struct nonpacked") == 8
        assert ffi.sizeof("struct is_packed") == 5
        assert ffi.alignof("struct nonpacked") == 4
        assert ffi.alignof("struct is_packed") == 1
        s = ffi.new("struct is_packed[2]")
        s[0].b = 42623381
        s[0].a = b'X'
        s[1].b = -4892220
        s[1].a = b'Y'
        assert s[0].b == 42623381
        assert s[0].a == b'X'
        assert s[1].b == -4892220
        assert s[1].a == b'Y'

    def test_not_supported_bitfield_in_result(self):
        # struct ints_and_bitfield { int a,b,c,d,e; int x:1; };
        e = pytest.raises(NotImplementedError, ffi.callback,
                           "struct ints_and_bitfield foo(void)", lambda: 42)
        assert str(e.value) == ("struct ints_and_bitfield(*)(): "
            "callback with unsupported argument or return type or with '...'")

    def test_inspecttype(self):
        assert ffi.typeof("long").kind == "primitive"
        assert ffi.typeof("long(*)(long, long**, ...)").cname == (
            "long(*)(long, long * *, ...)")
        assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True

    def test_new_handle(self):
        o = [2, 3, 4]
        p = ffi.new_handle(o)
        assert ffi.typeof(p) == ffi.typeof("void *")
        assert ffi.from_handle(p) is o
        assert ffi.from_handle(ffi.cast("char *", p)) is o
        pytest.raises(RuntimeError, ffi.from_handle, ffi.NULL)

    def test_struct_array_no_length(self):
        # struct array_no_length { int x; int a[]; };
        p = ffi.new("struct array_no_length *", [100, [200, 300, 400]])
        assert p.x == 100
        assert ffi.typeof(p.a) is ffi.typeof("int[]")   # length available
        assert p.a[0] == 200
        assert p.a[1] == 300
        assert p.a[2] == 400
        assert len(p.a) == 3
        assert list(p.a) == [200, 300, 400]
        q = ffi.cast("struct array_no_length *", p)
        assert ffi.typeof(q.a) is ffi.typeof("int *")   # no length available
        assert q.a[0] == 200
        assert q.a[1] == 300
        assert q.a[2] == 400
        pytest.raises(TypeError, len, q.a)
        pytest.raises(TypeError, list, q.a)

    def test_all_primitives(self):
        assert set(PRIMITIVE_TO_INDEX) == set([
            "char",
            "short",
            "int",
            "long",
            "long long",
            "signed char",
            "unsigned char",
            "unsigned short",
            "unsigned int",
            "unsigned long",
            "unsigned long long",
            "float",
            "double",
            "long double",
            "wchar_t",
            "char16_t",
            "char32_t",
            "_Bool",
            "int8_t",
            "uint8_t",
            "int16_t",
            "uint16_t",
            "int32_t",
            "uint32_t",
            "int64_t",
            "uint64_t",
            "int_least8_t",
            "uint_least8_t",
            "int_least16_t",
            "uint_least16_t",
            "int_least32_t",
            "uint_least32_t",
            "int_least64_t",
            "uint_least64_t",
            "int_fast8_t",
            "uint_fast8_t",
            "int_fast16_t",
            "uint_fast16_t",
            "int_fast32_t",
            "uint_fast32_t",
            "int_fast64_t",
            "uint_fast64_t",
            "intptr_t",
            "uintptr_t",
            "intmax_t",
            "uintmax_t",
            "ptrdiff_t",
            "size_t",
            "ssize_t",
            'float _Complex',
            'double _Complex',
            ])
        for name in PRIMITIVE_TO_INDEX:
            x = ffi.sizeof(name)
            assert 1 <= x <= 16

    def test_emit_c_code(self):
        ffi = cffi.FFI()
        ffi.set_source("foobar", "??")
        c_file = str(udir.join('test_emit_c_code'))
        ffi.emit_c_code(c_file)
        assert os.path.isfile(c_file)

    def test_import_from_lib(self):
        ffi2 = cffi.FFI()
        ffi2.cdef("int myfunc(int); extern int myvar;\n#define MYFOO ...\n")
        outputfilename = recompile(ffi2, "_test_import_from_lib",
                                   "int myfunc(int x) { return x + 1; }\n"
                                   "int myvar = -5;\n"
                                   "#define MYFOO 42", tmpdir=str(udir))
        load_dynamic("_test_import_from_lib", outputfilename)
        from _test_import_from_lib.lib import myfunc, myvar, MYFOO
        assert MYFOO == 42
        assert myfunc(43) == 44
        assert myvar == -5     # but can't be changed, so not very useful
        with pytest.raises(ImportError):
            from _test_import_from_lib.lib import bar
        d = {}
        exec("from _test_import_from_lib.lib import *", d)
        assert (set(key for key in d if not key.startswith('_')) ==
                set(['myfunc', 'MYFOO']))
        #
        # also test "import *" on the module itself, which should be
        # equivalent to "import ffi, lib"
        d = {}
        exec("from _test_import_from_lib import *", d)
        assert (sorted([x for x in d.keys() if not x.startswith('__')]) ==
                ['ffi', 'lib'])

    def test_char16_t(self):
        x = ffi.new("char16_t[]", 5)
        assert len(x) == 5 and ffi.sizeof(x) == 10
        x[2] = u+'\u1324'
        assert x[2] == u+'\u1324'
        y = ffi.new("char16_t[]", u+'\u1234\u5678')
        assert len(y) == 3
        assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
        assert ffi.string(y) == u+'\u1234\u5678'
        z = ffi.new("char16_t[]", u+'\U00012345')
        assert len(z) == 3
        assert list(z) == [u+'\ud808', u+'\udf45', u+'\x00']
        assert ffi.string(z) == u+'\U00012345'

    def test_char32_t(self):
        x = ffi.new("char32_t[]", 5)
        assert len(x) == 5 and ffi.sizeof(x) == 20
        x[3] = u+'\U00013245'
        assert x[3] == u+'\U00013245'
        y = ffi.new("char32_t[]", u+'\u1234\u5678')
        assert len(y) == 3
        assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00']
        z = ffi.new("char32_t[]", u+'\U00012345')
        assert len(z) == 2
        assert list(z) == [u+'\U00012345', u+'\x00'] # maybe a 2-unichars strin
        assert ffi.string(z) == u+'\U00012345'

testing/cffi1/test_new_ffi_1.py
python-cffi/cffi
import sys, re, os
import pytest
import cffi
from cffi import cffi_opcode
from pathlib import Path

if '__pypy__' in sys.builtin_module_names:
    try:
        # pytest >= 4.0
        pytest.skip("not available on pypy", allow_module_level=True)
    except TypeError:
        # older pytest
        pytest.skip("not available on pypy")

cffi_dir = str(Path(os.path.dirname(__file__)).parent.parent / "src/cffi")

r_macro = re.compile(r"#define \w+[(][^\n]*|#include [^\n]*")
r_define = re.compile(r"(#define \w+) [^\n]*")
r_ifdefs = re.compile(r"(#ifdef |#endif)[^\n]*")
header = open(os.path.join(cffi_dir, 'parse_c_type.h')).read()
header = r_macro.sub(r"", header)
header = r_define.sub(r"\1 ...", header)
header = r_ifdefs.sub(r"", header)

ffi = cffi.FFI()
ffi.cdef(header)

lib = ffi.verify(
        open(os.path.join(cffi_dir, '..', 'c', 'parse_c_type.c')).read() + """
static const char *get_common_type(const char *search, size_t search_len) {
    return NULL;
}
""",    include_dirs=[cffi_dir])

class ParseError(Exception):
    pass

struct_names = ["bar_s", "foo", "foo_", "foo_s", "foo_s1", "foo_s12"]
assert struct_names == sorted(struct_names)

enum_names = ["ebar_s", "efoo", "efoo_", "efoo_s", "efoo_s1", "efoo_s12"]
assert enum_names == sorted(enum_names)

identifier_names = ["id", "id0", "id05", "id05b", "tail"]
assert identifier_names == sorted(identifier_names)

global_names = ["FIVE", "NEG", "ZERO"]
assert global_names == sorted(global_names)

ctx = ffi.new("struct _cffi_type_context_s *")
c_struct_names = [ffi.new("char[]", _n.encode('ascii')) for _n in struct_names]
ctx_structs = ffi.new("struct _cffi_struct_union_s[]", len(struct_names))
for _i in range(len(struct_names)):
    ctx_structs[_i].name = c_struct_names[_i]
ctx_structs[3].flags = lib._CFFI_F_UNION
ctx.struct_unions = ctx_structs
ctx.num_struct_unions = len(struct_names)

c_enum_names = [ffi.new("char[]", _n.encode('ascii')) for _n in enum_names]
ctx_enums = ffi.new("struct _cffi_enum_s[]", len(enum_names))
for _i in range(len(enum_names)):
    ctx_enums[_i].name = c_enum_names[_i]
ctx.enums = ctx_enums
ctx.num_enums = len(enum_names)

c_identifier_names = [ffi.new("char[]", _n.encode('ascii'))
                      for _n in identifier_names]
ctx_identifiers = ffi.new("struct _cffi_typename_s[]", len(identifier_names))
for _i in range(len(identifier_names)):
    ctx_identifiers[_i].name = c_identifier_names[_i]
    ctx_identifiers[_i].type_index = 100 + _i
ctx.typenames = ctx_identifiers
ctx.num_typenames = len(identifier_names)

@ffi.callback("int(unsigned long long *)")
def fetch_constant_five(p):
    p[0] = 5
    return 0
@ffi.callback("int(unsigned long long *)")
def fetch_constant_zero(p):
    p[0] = 0
    return 1
@ffi.callback("int(unsigned long long *)")
def fetch_constant_neg(p):
    p[0] = 123321
    return 1

ctx_globals = ffi.new("struct _cffi_global_s[]", len(global_names))
c_glob_names = [ffi.new("char[]", _n.encode('ascii')) for _n in global_names]
for _i, _fn in enumerate([fetch_constant_five,
                          fetch_constant_neg,
                          fetch_constant_zero]):
    ctx_globals[_i].name = c_glob_names[_i]
    ctx_globals[_i].address = _fn
    ctx_globals[_i].type_op = ffi.cast("_cffi_opcode_t",
                                       cffi_opcode.OP_CONSTANT_INT if _i != 1
                                       else cffi_opcode.OP_ENUM)
ctx.globals = ctx_globals
ctx.num_globals = len(global_names)


def parse(input):
    out = ffi.new("_cffi_opcode_t[]", 100)
    info = ffi.new("struct _cffi_parse_info_s *")
    info.ctx = ctx
    info.output = out
    info.output_size = len(out)
    for j in range(len(out)):
        out[j] = ffi.cast("void *", -424242)
    res = lib.parse_c_type(info, input.encode('ascii'))
    if res < 0:
        raise ParseError(ffi.string(info.error_message).decode('ascii'),
                         info.error_location)
    assert 0 <= res < len(out)
    result = []
    for j in range(len(out)):
        if out[j] == ffi.cast("void *", -424242):
            assert res < j
            break
        i = int(ffi.cast("intptr_t", out[j]))
        if j == res:
            result.append('->')
        result.append(i)
    return result

def parsex(input):
    result = parse(input)
    def str_if_int(x):
        if isinstance(x, str):
            return x
        return '%d,%d' % (x & 255, x >> 8)
    return '  '.join(map(str_if_int, result))

def parse_error(input, expected_msg, expected_location):
    e = pytest.raises(ParseError, parse, input)
    assert e.value.args[0] == expected_msg
    assert e.value.args[1] == expected_location

def make_getter(name):
    opcode = getattr(lib, '_CFFI_OP_' + name)
    def getter(value):
        return opcode | (value << 8)
    return getter

Prim = make_getter('PRIMITIVE')
Pointer = make_getter('POINTER')
Array = make_getter('ARRAY')
OpenArray = make_getter('OPEN_ARRAY')
NoOp = make_getter('NOOP')
Func = make_getter('FUNCTION')
FuncEnd = make_getter('FUNCTION_END')
Struct = make_getter('STRUCT_UNION')
Enum = make_getter('ENUM')
Typename = make_getter('TYPENAME')


def test_simple():
    for simple_type, expected in [
            ("int", lib._CFFI_PRIM_INT),
            ("signed int", lib._CFFI_PRIM_INT),
            ("  long  ", lib._CFFI_PRIM_LONG),
            ("long int", lib._CFFI_PRIM_LONG),
            ("unsigned short", lib._CFFI_PRIM_USHORT),
            ("long double", lib._CFFI_PRIM_LONGDOUBLE),
            (" float  _Complex", lib._CFFI_PRIM_FLOATCOMPLEX),
            ("double _Complex ", lib._CFFI_PRIM_DOUBLECOMPLEX),
            ]:
        assert parse(simple_type) == ['->', Prim(expected)]

def test_array():
    assert parse("int[5]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5]
    assert parse("int[]") == [Prim(lib._CFFI_PRIM_INT), '->', OpenArray(0)]
    assert parse("int[5][8]") == [Prim(lib._CFFI_PRIM_INT),
                                  '->', Array(3),
                                  5,
                                  Array(0),
                                  8]
    assert parse("int[][8]") == [Prim(lib._CFFI_PRIM_INT),
                                 '->', OpenArray(2),
                                 Array(0),
                                 8]

def test_pointer():
    assert parse("int*") == [Prim(lib._CFFI_PRIM_INT), '->', Pointer(0)]
    assert parse("int***") == [Prim(lib._CFFI_PRIM_INT),
                               Pointer(0), Pointer(1), '->', Pointer(2)]

def test_grouping():
    assert parse("int*[]") == [Prim(lib._CFFI_PRIM_INT),
                               Pointer(0), '->', OpenArray(1)]
    assert parse("int**[][8]") == [Prim(lib._CFFI_PRIM_INT),
                                   Pointer(0), Pointer(1),
                                   '->', OpenArray(4), Array(2), 8]
    assert parse("int(*)[]") == [Prim(lib._CFFI_PRIM_INT),
                                 NoOp(3), '->', Pointer(1), OpenArray(0)]
    assert parse("int(*)[][8]") == [Prim(lib._CFFI_PRIM_INT),
                                    NoOp(3), '->', Pointer(1),
                                    OpenArray(4), Array(0), 8]
    assert parse("int**(**)") == [Prim(lib._CFFI_PRIM_INT),
                                  Pointer(0), Pointer(1),
                                  NoOp(2), Pointer(3), '->', Pointer(4)]
    assert parse("int**(**)[]") == [Prim(lib._CFFI_PRIM_INT),
                                    Pointer(0), Pointer(1),
                                    NoOp(6), Pointer(3), '->', Pointer(4),
                                    OpenArray(2)]

def test_simple_function():
    assert parse("int()") == [Prim(lib._CFFI_PRIM_INT),
                              '->', Func(0), FuncEnd(0), 0]
    assert parse("int(int)") == [Prim(lib._CFFI_PRIM_INT),
                                 '->', Func(0), NoOp(4), FuncEnd(0),
                                 Prim(lib._CFFI_PRIM_INT)]
    assert parse("int(long, char)") == [
                                 Prim(lib._CFFI_PRIM_INT),
                                 '->', Func(0), NoOp(5), NoOp(6), FuncEnd(0),
                                 Prim(lib._CFFI_PRIM_LONG),
                                 Prim(lib._CFFI_PRIM_CHAR)]
    assert parse("int(int*)") == [Prim(lib._CFFI_PRIM_INT),
                                  '->', Func(0), NoOp(5), FuncEnd(0),
                                  Prim(lib._CFFI_PRIM_INT),
                                  Pointer(4)]
    assert parse("int*(void)") == [Prim(lib._CFFI_PRIM_INT),
                                   Pointer(0),
                                   '->', Func(1), FuncEnd(0), 0]
    assert parse("int(int, ...)") == [Prim(lib._CFFI_PRIM_INT),
                                      '->', Func(0), NoOp(5), FuncEnd(1), 0,
                                      Prim(lib._CFFI_PRIM_INT)]

def test_internal_function():
    assert parse("int(*)()") == [Prim(lib._CFFI_PRIM_INT),
                                 NoOp(3), '->', Pointer(1),
                                 Func(0), FuncEnd(0), 0]
    assert parse("int(*())[]") == [Prim(lib._CFFI_PRIM_INT),
                                   NoOp(6), Pointer(1),
                                   '->', Func(2), FuncEnd(0), 0,
                                   OpenArray(0)]
    assert parse("int(char(*)(long, short))") == [
        Prim(lib._CFFI_PRIM_INT),
        '->', Func(0), NoOp(6), FuncEnd(0),
        Prim(lib._CFFI_PRIM_CHAR),
        NoOp(7), Pointer(5),
        Func(4), NoOp(11), NoOp(12), FuncEnd(0),
        Prim(lib._CFFI_PRIM_LONG),
        Prim(lib._CFFI_PRIM_SHORT)]

def test_fix_arg_types():
    assert parse("int(char(long, short))") == [
        Prim(lib._CFFI_PRIM_INT),
        '->', Func(0), Pointer(5), FuncEnd(0),
        Prim(lib._CFFI_PRIM_CHAR),
        Func(4), NoOp(9), NoOp(10), FuncEnd(0),
        Prim(lib._CFFI_PRIM_LONG),
        Prim(lib._CFFI_PRIM_SHORT)]
    assert parse("int(char[])") == [
        Prim(lib._CFFI_PRIM_INT),
        '->', Func(0), Pointer(4), FuncEnd(0),
        Prim(lib._CFFI_PRIM_CHAR),
        OpenArray(4)]

def test_enum():
    for i in range(len(enum_names)):
        assert parse("enum %s" % (enum_names[i],)) == ['->', Enum(i)]
        assert parse("enum %s*" % (enum_names[i],)) == [Enum(i),
                                                        '->', Pointer(0)]

def test_error():
    parse_error("short short int", "'short' after another 'short' or 'long'", 6)
    parse_error("long long long", "'long long long' is too long", 10)
    parse_error("short long", "'long' after 'short'", 6)
    parse_error("signed unsigned int", "multiple 'signed' or 'unsigned'", 7)
    parse_error("unsigned signed int", "multiple 'signed' or 'unsigned'", 9)
    parse_error("long char", "invalid combination of types", 5)
    parse_error("short char", "invalid combination of types", 6)
    parse_error("signed void", "invalid combination of types", 7)
    parse_error("unsigned struct", "invalid combination of types", 9)
    #
    parse_error("", "identifier expected", 0)
    parse_error("]", "identifier expected", 0)
    parse_error("*", "identifier expected", 0)
    parse_error("int ]**", "unexpected symbol", 4)
    parse_error("char char", "unexpected symbol", 5)
    parse_error("int(int]", "expected ')'", 7)
    parse_error("int(*]", "expected ')'", 5)
    parse_error("int(]", "identifier expected", 4)
    parse_error("int[?]", "expected a positive integer constant", 4)
    parse_error("int[24)", "expected ']'", 6)
    parse_error("struct", "struct or union name expected", 6)
    parse_error("struct 24", "struct or union name expected", 7)
    parse_error("int[5](*)", "unexpected symbol", 6)
    parse_error("int a(*)", "identifier expected", 6)
    parse_error("int[123456789012345678901234567890]", "number too large", 4)
    #
    parse_error("_Complex", "identifier expected", 0)
    parse_error("int _Complex", "_Complex type combination unsupported", 4)
    parse_error("long double _Complex", "_Complex type combination unsupported",
                12)

def test_number_too_large():
    num_max = sys.maxsize
    assert parse("char[%d]" % num_max) == [Prim(lib._CFFI_PRIM_CHAR),
                                          '->', Array(0), num_max]
    parse_error("char[%d]" % (num_max + 1), "number too large", 5)

def test_complexity_limit():
    parse_error("int" + "[]" * 2500, "internal type complexity limit reached",
                202)

def test_struct():
    for i in range(len(struct_names)):
        if i == 3:
            tag = "union"
        else:
            tag = "struct"
        assert parse("%s %s" % (tag, struct_names[i])) == ['->', Struct(i)]
        assert parse("%s %s*" % (tag, struct_names[i])) == [Struct(i),
                                                            '->', Pointer(0)]

def test_exchanging_struct_union():
    parse_error("union %s" % (struct_names[0],),
                "wrong kind of tag: struct vs union", 6)
    parse_error("struct %s" % (struct_names[3],),
                "wrong kind of tag: struct vs union", 7)

def test_identifier():
    for i in range(len(identifier_names)):
        assert parse("%s" % (identifier_names[i])) == ['->', Typename(i)]
        assert parse("%s*" % (identifier_names[i])) == [Typename(i),
                                                        '->', Pointer(0)]

def test_cffi_opcode_sync():
    import cffi.model
    for name in dir(lib):
        if name.startswith('_CFFI_'):
            assert getattr(cffi_opcode, name[6:]) == getattr(lib, name)
    assert sorted(cffi_opcode.PRIMITIVE_TO_INDEX.keys()) == (
        sorted(cffi.model.PrimitiveType.ALL_PRIMITIVE_TYPES.keys()))

def test_array_length_from_constant():
    parse_error("int[UNKNOWN]", "expected a positive integer constant", 4)
    assert parse("int[FIVE]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5]
    assert parse("int[ZERO]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 0]
    parse_error("int[NEG]", "expected a positive integer constant", 4)

def test_various_constant_exprs():
    def array(n):
        return [Prim(lib._CFFI_PRIM_CHAR), '->', Array(0), n]
    assert parse("char[21]") == array(21)
    assert parse("char[0x10]") == array(16)
    assert parse("char[0X21]") == array(33)
    assert parse("char[0Xb]") == array(11)
    assert parse("char[0x1C]") == array(0x1C)
    assert parse("char[0xc6]") == array(0xC6)
    assert parse("char[010]") == array(8)
    assert parse("char[021]") == array(17)
    parse_error("char[08]", "invalid number", 5)
    parse_error("char[1C]", "invalid number", 5)
    parse_error("char[0C]", "invalid number", 5)
    # not supported (really obscure):
    #    "char[+5]"
    #    "char['A']"

def test_stdcall_cdecl():
    assert parse("int __stdcall(int)") == [Prim(lib._CFFI_PRIM_INT),
                                           '->', Func(0), NoOp(4), FuncEnd(2),
                                           Prim(lib._CFFI_PRIM_INT)]
    assert parse("int __stdcall func(int)") == parse("int __stdcall(int)")
    assert parse("int (__stdcall *)()") == [Prim(lib._CFFI_PRIM_INT),
                                            NoOp(3), '->', Pointer(1),
                                            Func(0), FuncEnd(2), 0]
    assert parse("int (__stdcall *p)()") == parse("int (__stdcall*)()")
    parse_error("__stdcall int", "identifier expected", 0)
    parse_error("__cdecl int", "identifier expected", 0)
    parse_error("int __stdcall", "expected '('", 13)
    parse_error("int __cdecl", "expected '('", 11)

testing/cffi1/test_parse_c_type.py
python-cffi/cffi
import sys
import subprocess
import pytest
import cffi.pkgconfig as pkgconfig
from cffi import PkgConfigError


def mock_call(libname, flag):
    assert libname=="foobarbaz"
    flags = {
        "--cflags": "-I/usr/include/python3.6m -DABCD -DCFFI_TEST=1 -O42\n",
        "--libs": "-L/usr/lib64 -lpython3.6 -shared\n",
    }
    return flags[flag]


def test_merge_flags():
    d1 = {"ham": [1, 2, 3], "spam" : ["a", "b", "c"], "foo" : []}
    d2 = {"spam" : ["spam", "spam", "spam"], "bar" : ["b", "a", "z"]}

    pkgconfig.merge_flags(d1, d2)
    assert d1 == {
        "ham": [1, 2, 3],
        "spam" : ["a", "b", "c", "spam", "spam", "spam"],
        "bar" : ["b", "a", "z"],
        "foo" : []}


def test_pkgconfig():
    assert pkgconfig.flags_from_pkgconfig([]) == {}

    saved = pkgconfig.call
    try:
        pkgconfig.call = mock_call
        flags = pkgconfig.flags_from_pkgconfig(["foobarbaz"])
    finally:
        pkgconfig.call = saved
    assert flags == {
        'include_dirs': ['/usr/include/python3.6m'],
        'library_dirs': ['/usr/lib64'],
        'libraries': ['python3.6'],
        'define_macros': [('ABCD', None), ('CFFI_TEST', '1')],
        'extra_compile_args': ['-O42'],
        'extra_link_args': ['-shared']
    }

class mock_subprocess:
    PIPE = Ellipsis
    class Popen:
        def __init__(self, cmd, stdout, stderr):
            if mock_subprocess.RESULT is None:
                raise OSError("oops can't run")
            assert cmd == ['pkg-config', '--print-errors', '--cflags', 'libfoo']
        def communicate(self):
            bout, berr, rc = mock_subprocess.RESULT
            self.returncode = rc
            return bout, berr

def test_call():
    saved = pkgconfig.subprocess
    try:
        pkgconfig.subprocess = mock_subprocess

        mock_subprocess.RESULT = None
        e = pytest.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
        assert str(e.value) == "cannot run pkg-config: oops can't run"

        mock_subprocess.RESULT = b"", "Foo error!\n", 1
        e = pytest.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
        assert str(e.value) == "Foo error!"

        mock_subprocess.RESULT = b"abc\\def\n", "", 0
        e = pytest.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags")
        assert str(e.value).startswith("pkg-config --cflags libfoo returned an "
                                       "unsupported backslash-escaped output:")

        mock_subprocess.RESULT = b"abc def\n", "", 0
        result = pkgconfig.call("libfoo", "--cflags")
        assert result == "abc def\n"

        mock_subprocess.RESULT = b"abc def\n", "", 0
        result = pkgconfig.call("libfoo", "--cflags")
        assert result == "abc def\n"

        if sys.version_info >= (3,):
            mock_subprocess.RESULT = b"\xff\n", "", 0
            e = pytest.raises(PkgConfigError, pkgconfig.call,
                               "libfoo", "--cflags", encoding="utf-8")
            assert str(e.value) == (
                "pkg-config --cflags libfoo returned bytes that cannot be "
                "decoded with encoding 'utf-8':\nb'\\xff\\n'")

    finally:
        pkgconfig.subprocess = saved

testing/cffi1/test_pkgconfig.py
python-cffi/cffi
import sys, os
import pytest
from cffi import FFI
from cffi import recompiler, ffiplatform, VerificationMissing
from testing.udir import udir
from testing.support import u, is_musl


def setup_module(mod):
    SRC = """
    #include <string.h>
    #define FOOBAR (-42)
    static const int FOOBAZ = -43;
    #define BIGPOS 420000000000L
    #define BIGNEG -420000000000L
    int add42(int x) { return x + 42; }
    int add43(int x, ...) { return x; }
    int globalvar42 = 1234;
    const int globalconst42 = 4321;
    const char *const globalconsthello = "hello";
    struct foo_s;
    typedef struct bar_s { int x; signed char a[]; } bar_t;
    enum foo_e { AA, BB, CC };

    void init_test_re_python(void) { }      /* windows hack */
    void PyInit__test_re_python(void) { }   /* windows hack */
    """
    tmpdir = udir.join('test_re_python')
    tmpdir.ensure(dir=1)
    c_file = tmpdir.join('_test_re_python.c')
    c_file.write(SRC)
    ext = ffiplatform.get_extension(
        str(c_file),
        '_test_re_python',
        export_symbols=['add42', 'add43', 'globalvar42',
                        'globalconst42', 'globalconsthello']
    )
    outputfilename = ffiplatform.compile(str(tmpdir), ext)

    # test with a non-ascii char
    ofn, oext = os.path.splitext(outputfilename)
    if sys.platform == "win32":
        unicode_name = ofn + (u+'\u03be') + oext
    else:
        unicode_name = ofn + (u+'\xe9') + oext
        try:
            unicode_name.encode(sys.getfilesystemencoding())
        except UnicodeEncodeError:
            unicode_name = None
    if unicode_name is not None:
        print(repr(outputfilename) + ' ==> ' + repr(unicode_name))
        os.rename(outputfilename, unicode_name)
        outputfilename = unicode_name

    mod.extmod = outputfilename
    mod.tmpdir = tmpdir
    #
    ffi = FFI()
    ffi.cdef("""
    #define FOOBAR -42
    static const int FOOBAZ = -43;
    #define BIGPOS 420000000000L
    #define BIGNEG -420000000000L
    int add42(int);
    int add43(int, ...);
    extern int globalvar42;
    const int globalconst42;
    const char *const globalconsthello;
    int no_such_function(int);
    extern int no_such_globalvar;
    struct foo_s;
    typedef struct bar_s { int x; signed char a[]; } bar_t;
    enum foo_e { AA, BB, CC };
    int strlen(const char *);
    struct with_union { union { int a; char b; }; };
    union with_struct { struct { int a; char b; }; };
    struct with_struct_with_union { struct { union { int x; }; } cp; };
    struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; };
    typedef struct selfref { struct selfref *next; } *selfref_ptr_t;
    """)
    ffi.set_source('re_python_pysrc', None)
    ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
    mod.original_ffi = ffi
    #
    sys.path.insert(0, str(tmpdir))


def test_constant():
    from re_python_pysrc import ffi
    assert ffi.integer_const('FOOBAR') == -42
    assert ffi.integer_const('FOOBAZ') == -43

def test_large_constant():
    from re_python_pysrc import ffi
    assert ffi.integer_const('BIGPOS') == 420000000000
    assert ffi.integer_const('BIGNEG') == -420000000000

def test_function():
    import _cffi_backend
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    assert lib.add42(-10) == 32
    assert type(lib.add42) is _cffi_backend.FFI.CData

def test_function_with_varargs():
    import _cffi_backend
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod, 0)
    assert lib.add43(45, ffi.cast("int", -5)) == 45
    assert type(lib.add43) is _cffi_backend.FFI.CData

def test_dlopen_none():
    import _cffi_backend
    from re_python_pysrc import ffi
    name = None
    if sys.platform == 'win32':
        import ctypes.util
        name = ctypes.util.find_msvcrt()
        if name is None:
            pytest.skip("dlopen(None) cannot work on Windows with Python 3")
    lib = ffi.dlopen(name)
    assert lib.strlen(b"hello") == 5

def test_dlclose():
    import _cffi_backend
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    ffi.dlclose(lib)
    if type(extmod) is not str:   # unicode, on python 2
        str_extmod = extmod.encode('utf-8')
    else:
        str_extmod = extmod
    e = pytest.raises(ffi.error, getattr, lib, 'add42')
    assert str(e.value) == (
        "library '%s' has been closed" % (str_extmod,))
    ffi.dlclose(lib)   # does not raise

def test_constant_via_lib():
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    assert lib.FOOBAR == -42
    assert lib.FOOBAZ == -43

def test_opaque_struct():
    from re_python_pysrc import ffi
    ffi.cast("struct foo_s *", 0)
    pytest.raises(TypeError, ffi.new, "struct foo_s *")

def test_nonopaque_struct():
    from re_python_pysrc import ffi
    for p in [ffi.new("struct bar_s *", [5, b"foobar"]),
              ffi.new("bar_t *", [5, b"foobar"])]:
        assert p.x == 5
        assert p.a[0] == ord('f')
        assert p.a[5] == ord('r')

def test_enum():
    from re_python_pysrc import ffi
    assert ffi.integer_const("BB") == 1
    e = ffi.cast("enum foo_e", 2)
    assert ffi.string(e) == "CC"

def test_include_1():
    sub_ffi = FFI()
    sub_ffi.cdef("static const int k2 = 121212;")
    sub_ffi.include(original_ffi)
    assert 'macro FOOBAR' in original_ffi._parser._declarations
    assert 'macro FOOBAZ' in original_ffi._parser._declarations
    sub_ffi.set_source('re_python_pysrc', None)
    sub_ffi.emit_python_code(str(tmpdir.join('_re_include_1.py')))
    #
    if sys.version_info[:2] >= (3, 3):
        import importlib
        importlib.invalidate_caches()  # issue 197 (but can't reproduce myself)
    #
    from _re_include_1 import ffi
    assert ffi.integer_const('FOOBAR') == -42
    assert ffi.integer_const('FOOBAZ') == -43
    assert ffi.integer_const('k2') == 121212
    lib = ffi.dlopen(extmod)     # <- a random unrelated library would be fine
    assert lib.FOOBAR == -42
    assert lib.FOOBAZ == -43
    assert lib.k2 == 121212
    #
    p = ffi.new("bar_t *", [5, b"foobar"])
    assert p.a[4] == ord('a')

def test_global_var():
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    assert lib.globalvar42 == 1234
    p = ffi.addressof(lib, 'globalvar42')
    lib.globalvar42 += 5
    assert p[0] == 1239
    p[0] -= 1
    assert lib.globalvar42 == 1238

def test_global_const_int():
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    assert lib.globalconst42 == 4321
    pytest.raises(AttributeError, ffi.addressof, lib, 'globalconst42')

def test_global_const_nonint():
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    assert ffi.string(lib.globalconsthello, 8) == b"hello"
    pytest.raises(AttributeError, ffi.addressof, lib, 'globalconsthello')

def test_rtld_constants():
    from re_python_pysrc import ffi
    ffi.RTLD_NOW    # check that we have the attributes
    ffi.RTLD_LAZY
    ffi.RTLD_GLOBAL

def test_no_such_function_or_global_var():
    from re_python_pysrc import ffi
    lib = ffi.dlopen(extmod)
    e = pytest.raises(ffi.error, getattr, lib, 'no_such_function')
    assert str(e.value).startswith(
        "symbol 'no_such_function' not found in library '")
    e = pytest.raises(ffi.error, getattr, lib, 'no_such_globalvar')
    assert str(e.value).startswith(
        "symbol 'no_such_globalvar' not found in library '")

def test_check_version():
    import _cffi_backend
    e = pytest.raises(ImportError, _cffi_backend.FFI,
                       "foobar", _version=0x2594)
    assert str(e.value).startswith(
        "cffi out-of-line Python module 'foobar' has unknown version")

def test_partial_enum():
    ffi = FFI()
    ffi.cdef("enum foo { A, B, ... };")
    ffi.set_source('test_partial_enum', None)
    pytest.raises(VerificationMissing, ffi.emit_python_code,
                   str(tmpdir.join('test_partial_enum.py')))

def test_anonymous_union_inside_struct():
    # based on issue #357
    from re_python_pysrc import ffi
    INT = ffi.sizeof("int")
    assert ffi.offsetof("struct with_union", "a") == 0
    assert ffi.offsetof("struct with_union", "b") == 0
    assert ffi.sizeof("struct with_union") == INT
    #
    assert ffi.offsetof("union with_struct", "a") == 0
    assert ffi.offsetof("union with_struct", "b") == INT
    assert ffi.sizeof("union with_struct") >= INT + 1
    #
    assert ffi.sizeof("struct with_struct_with_union") == INT
    p = ffi.new("struct with_struct_with_union *")
    assert p.cp.x == 0
    #
    FLOAT = ffi.sizeof("float")
    assert ffi.sizeof("struct NVGcolor") == FLOAT * 4
    assert ffi.offsetof("struct NVGcolor", "rgba") == 0
    assert ffi.offsetof("struct NVGcolor", "r") == 0
    assert ffi.offsetof("struct NVGcolor", "g") == FLOAT
    assert ffi.offsetof("struct NVGcolor", "b") == FLOAT * 2
    assert ffi.offsetof("struct NVGcolor", "a") == FLOAT * 3

def test_selfref():
    # based on issue #429
    from re_python_pysrc import ffi
    ffi.new("selfref_ptr_t")

def test_dlopen_handle():
    import _cffi_backend
    from re_python_pysrc import ffi
    if sys.platform == 'win32' or is_musl:
        pytest.skip("uses 'dl' explicitly")
    ffi1 = FFI()
    ffi1.cdef("""void *dlopen(const char *filename, int flags);
                 int dlclose(void *handle);""")
    lib1 = ffi1.dlopen('dl')
    handle = lib1.dlopen(extmod.encode(sys.getfilesystemencoding()),
                         _cffi_backend.RTLD_LAZY)
    assert ffi1.typeof(handle) == ffi1.typeof("void *")
    assert handle

    lib = ffi.dlopen(handle)
    assert lib.add42(-10) == 32
    assert type(lib.add42) is _cffi_backend.FFI.CData

    err = lib1.dlclose(handle)
    assert err == 0

testing/cffi1/test_re_python.py
python-cffi/cffi
import sys
import pytest
from cffi import cffi_opcode


def check(input, expected_output=None, expected_ffi_error=False):
    import _cffi_backend
    ffi = _cffi_backend.FFI()
    if not expected_ffi_error:
        ct = ffi.typeof(input)
        assert isinstance(ct, ffi.CType)
        assert ct.cname == (expected_output or input)
    else:
        e = pytest.raises(ffi.error, ffi.typeof, input)
        if isinstance(expected_ffi_error, str):
            assert str(e.value) == expected_ffi_error

def test_void():
    check("void", "void")
    check("  void  ", "void")

def test_int_star():
    check("int")
    check("int *")
    check("int*", "int *")
    check("long int", "long")
    check("long")

def test_noop():
    check("int(*)", "int *")

def test_array():
    check("int[6]")

def test_funcptr():
    check("int(*)(long)")
    check("int(long)", expected_ffi_error="the type 'int(long)' is a"
          " function type, not a pointer-to-function type")
    check("int(void)", expected_ffi_error="the type 'int()' is a"
          " function type, not a pointer-to-function type")

def test_funcptr_rewrite_args():
    check("int(*)(int(int))", "int(*)(int(*)(int))")
    check("int(*)(long[])", "int(*)(long *)")
    check("int(*)(long[5])", "int(*)(long *)")

def test_all_primitives():
    for name in cffi_opcode.PRIMITIVE_TO_INDEX:
        check(name, name)

def check_func(input, expected_output=None):
    import _cffi_backend
    ffi = _cffi_backend.FFI()
    ct = ffi.typeof(ffi.callback(input, lambda: None))
    assert isinstance(ct, ffi.CType)
    if sys.platform != 'win32' or sys.maxsize > 2**32:
        expected_output = expected_output.replace('__stdcall *', '*')
    assert ct.cname == expected_output

def test_funcptr_stdcall():
    check_func("int(int)", "int(*)(int)")
    check_func("int foobar(int)", "int(*)(int)")
    check_func("int __stdcall(int)", "int(__stdcall *)(int)")
    check_func("int __stdcall foobar(int)", "int(__stdcall *)(int)")
    check_func("void __cdecl(void)", "void(*)()")
    check_func("void __cdecl foobar(void)", "void(*)()")
    check_func("void __stdcall(void)", "void(__stdcall *)()")
    check_func("void __stdcall foobar(long, short)",
                   "void(__stdcall *)(long, short)")
    check_func("void(void __cdecl(void), void __stdcall(void))",
                   "void(*)(void(*)(), void(__stdcall *)())")

def test_variadic_overrides_stdcall():
    check("void (__stdcall*)(int, ...)", "void(*)(int, ...)")

testing/cffi1/test_realize_c_type.py
python-cffi/cffi

import sys, os
import pytest
from cffi import FFI, VerificationError, FFIError, CDefError
from cffi import recompiler
from testing.udir import udir
from testing.support import u, long
from testing.support import FdWriteCapture, StdErrCapture, _verify

try:
    import importlib
except ImportError:
    importlib = None


def check_type_table(input, expected_output, included=None):
    ffi = FFI()
    if included:
        ffi1 = FFI()
        ffi1.cdef(included)
        ffi.include(ffi1)
    ffi.cdef(input)
    recomp = recompiler.Recompiler(ffi, 'testmod')
    recomp.collect_type_table()
    assert ''.join(map(str, recomp.cffi_types)) == expected_output

def verify(ffi, module_name, source, *args, **kwds):
    no_cpp = kwds.pop('no_cpp', False)
    ignore_warnings = kwds.pop('ignore_warnings', False)
    kwds.setdefault('undef_macros', ['NDEBUG'])
    module_name = '_CFFI_' + module_name
    ffi.set_source(module_name, source)
    if not os.environ.get('NO_CPP') and not no_cpp:   # test the .cpp mode too
        kwds.setdefault('source_extension', '.cpp')
        source = 'extern "C" {\n%s\n}' % (source,)
    elif sys.platform != 'win32' and not ignore_warnings:
        # add '-Werror' to the existing 'extra_compile_args' flags
        from testing.support import extra_compile_args
        kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) +
                                      extra_compile_args)
    if sys.platform == 'darwin':
        kwds['extra_link_args'] = (kwds.get('extra_link_args', []) +
                                     ['-stdlib=libc++'])
    return _verify(ffi, module_name, source, *args, **kwds)

def test_set_source_no_slashes():
    ffi = FFI()
    pytest.raises(ValueError, ffi.set_source, "abc/def", None)
    pytest.raises(ValueError, ffi.set_source, "abc/def", "C code")


def test_type_table_func():
    check_type_table("double sin(double);",
                     "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)")
    check_type_table("float sin(double);",
                     "(FUNCTION 3)(PRIMITIVE 14)(FUNCTION_END 0)(PRIMITIVE 13)")
    check_type_table("float sin(void);",
                     "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 13)")
    check_type_table("double sin(float); double cos(float);",
                     "(FUNCTION 3)(PRIMITIVE 13)(FUNCTION_END 0)(PRIMITIVE 14)")
    check_type_table("double sin(float); double cos(double);",
                     "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)"   # cos
                     "(FUNCTION 1)(PRIMITIVE 13)(FUNCTION_END 0)")  # sin
    check_type_table("float sin(double); float cos(float);",
                     "(FUNCTION 4)(PRIMITIVE 14)(FUNCTION_END 0)"   # sin
                     "(FUNCTION 4)(PRIMITIVE 13)(FUNCTION_END 0)")  # cos

def test_type_table_use_noop_for_repeated_args():
    check_type_table("double sin(double *, double *);",
                     "(FUNCTION 4)(POINTER 4)(NOOP 1)(FUNCTION_END 0)"
                     "(PRIMITIVE 14)")
    check_type_table("double sin(double *, double *, double);",
                     "(FUNCTION 3)(POINTER 3)(NOOP 1)(PRIMITIVE 14)"
                     "(FUNCTION_END 0)")

def test_type_table_dont_use_noop_for_primitives():
    check_type_table("double sin(double, double);",
                     "(FUNCTION 1)(PRIMITIVE 14)(PRIMITIVE 14)(FUNCTION_END 0)")

def test_type_table_funcptr_as_argument():
    check_type_table("int sin(double(float));",
                     "(FUNCTION 6)(PRIMITIVE 13)(FUNCTION_END 0)"
                     "(FUNCTION 7)(POINTER 0)(FUNCTION_END 0)"
                     "(PRIMITIVE 14)(PRIMITIVE 7)")

def test_type_table_variadic_function():
    check_type_table("int sin(int, ...);",
                     "(FUNCTION 1)(PRIMITIVE 7)(FUNCTION_END 1)(POINTER 0)")

def test_type_table_array():
    check_type_table("extern int a[100];",
                     "(PRIMITIVE 7)(ARRAY 0)(None 100)")

def test_type_table_typedef():
    check_type_table("typedef int foo_t;",
                     "(PRIMITIVE 7)")

def test_type_table_prebuilt_type():
    check_type_table("int32_t f(void);",
                     "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 21)")

def test_type_table_struct_opaque():
    check_type_table("struct foo_s;",
                     "(STRUCT_UNION 0)")

def test_type_table_struct():
    check_type_table("struct foo_s { int a; long b; };",
                     "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)")

def test_type_table_union():
    check_type_table("union foo_u { int a; long b; };",
                     "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)")

def test_type_table_struct_used():
    check_type_table("struct foo_s { int a; long b; }; int f(struct foo_s*);",
                     "(FUNCTION 3)(POINTER 5)(FUNCTION_END 0)"
                     "(PRIMITIVE 7)(PRIMITIVE 9)"
                     "(STRUCT_UNION 0)")

def test_type_table_anonymous_struct_with_typedef():
    check_type_table("typedef struct { int a; long b; } foo_t;",
                     "(STRUCT_UNION 0)(PRIMITIVE 7)(PRIMITIVE 9)")

def test_type_table_enum():
    check_type_table("enum foo_e { AA, BB, ... };",
                     "(ENUM 0)")

def test_type_table_include_1():
    check_type_table("foo_t sin(foo_t);",
                     "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)",
                     included="typedef double foo_t;")

def test_type_table_include_2():
    check_type_table("struct foo_s *sin(struct foo_s *);",
                     "(FUNCTION 1)(POINTER 3)(FUNCTION_END 0)(STRUCT_UNION 0)",
                     included="struct foo_s { int x, y; };")


def test_math_sin():
    import math
    ffi = FFI()
    ffi.cdef("float sin(double); double cos(double);")
    lib = verify(ffi, 'test_math_sin', '#include <math.h>',
                 ignore_warnings=True)
    assert lib.cos(1.43) == math.cos(1.43)

def test_repr_lib():
    ffi = FFI()
    lib = verify(ffi, 'test_repr_lib', '')
    assert repr(lib) == "<Lib object for '_CFFI_test_repr_lib'>"

def test_funcarg_ptr():
    ffi = FFI()
    ffi.cdef("int foo(int *);")
    lib = verify(ffi, 'test_funcarg_ptr', 'int foo(int *p) { return *p; }')
    assert lib.foo([-12345]) == -12345

def test_funcres_ptr():
    ffi = FFI()
    ffi.cdef("int *foo(void);")
    lib = verify(ffi, 'test_funcres_ptr',
                 'int *foo(void) { static int x=-12345; return &x; }')
    assert lib.foo()[0] == -12345

def test_global_var_array():
    ffi = FFI()
    ffi.cdef("extern int a[100];")
    lib = verify(ffi, 'test_global_var_array', 'int a[100] = { 9999 };')
    lib.a[42] = 123456
    assert lib.a[42] == 123456
    assert lib.a[0] == 9999

def test_verify_typedef():
    ffi = FFI()
    ffi.cdef("typedef int **foo_t;")
    lib = verify(ffi, 'test_verify_typedef', 'typedef int **foo_t;')
    assert ffi.sizeof("foo_t") == ffi.sizeof("void *")

def test_verify_typedef_dotdotdot():
    ffi = FFI()
    ffi.cdef("typedef ... foo_t;")
    verify(ffi, 'test_verify_typedef_dotdotdot', 'typedef int **foo_t;')

def test_verify_typedef_star_dotdotdot():
    ffi = FFI()
    ffi.cdef("typedef ... *foo_t;")
    verify(ffi, 'test_verify_typedef_star_dotdotdot', 'typedef int **foo_t;')

def test_global_var_int():
    ffi = FFI()
    ffi.cdef("extern int a, b, c;")
    lib = verify(ffi, 'test_global_var_int', 'int a = 999, b, c;')
    assert lib.a == 999
    lib.a -= 1001
    assert lib.a == -2
    lib.a = -2147483648
    assert lib.a == -2147483648
    with pytest.raises(OverflowError):
        lib.a = 2147483648
    with pytest.raises(OverflowError):
        lib.a = -2147483649
    lib.b = 525      # try with the first access being in setattr, too
    assert lib.b == 525
    with pytest.raises(AttributeError):
        del lib.a
    with pytest.raises(AttributeError):
        del lib.c
    with pytest.raises(AttributeError):
        del lib.foobarbaz

def test_macro():
    ffi = FFI()
    ffi.cdef("#define FOOBAR ...")
    lib = verify(ffi, 'test_macro', "#define FOOBAR (-6912)")
    assert lib.FOOBAR == -6912
    with pytest.raises(AttributeError):
        lib.FOOBAR = 2

def test_macro_check_value():
    # the value '-0x80000000' in C sources does not have a clear meaning
    # to me; it appears to have a different effect than '-2147483648'...
    # Moreover, on 32-bits, -2147483648 is actually equal to
    # -2147483648U, which in turn is equal to 2147483648U and so positive.
    vals = ['42', '-42', '0x80000000', '-2147483648',
            '0', '9223372036854775809ULL',
            '-9223372036854775807LL']
    if sys.maxsize <= 2**32 or sys.platform == 'win32':
        vals.remove('-2147483648')
    ffi = FFI()
    cdef_lines = ['#define FOO_%d_%d %s' % (i, j, vals[i])
                  for i in range(len(vals))
                  for j in range(len(vals))]
    ffi.cdef('\n'.join(cdef_lines))

    verify_lines = ['#define FOO_%d_%d %s' % (i, j, vals[j])  # [j], not [i]
                    for i in range(len(vals))
                    for j in range(len(vals))]
    lib = verify(ffi, 'test_macro_check_value_ok',
                 '\n'.join(verify_lines))
    #
    for j in range(len(vals)):
        c_got = int(vals[j].replace('U', '').replace('L', ''), 0)
        c_compiler_msg = str(c_got)
        if c_got > 0:
            c_compiler_msg += ' (0x%x)' % (c_got,)
        #
        for i in range(len(vals)):
            attrname = 'FOO_%d_%d' % (i, j)
            if i == j:
                x = getattr(lib, attrname)
                assert x == c_got
            else:
                e = pytest.raises(ffi.error, getattr, lib, attrname)
                assert str(e.value) == (
                    "the C compiler says '%s' is equal to "
                    "%s, but the cdef disagrees" % (attrname, c_compiler_msg))

def test_constant():
    ffi = FFI()
    ffi.cdef("static const int FOOBAR;")
    lib = verify(ffi, 'test_constant', "#define FOOBAR (-6912)")
    assert lib.FOOBAR == -6912
    with pytest.raises(AttributeError):
        lib.FOOBAR = 2

def test_check_value_of_static_const():
    ffi = FFI()
    ffi.cdef("static const int FOOBAR = 042;")
    lib = verify(ffi, 'test_check_value_of_static_const',
                 "#define FOOBAR (-6912)")
    e = pytest.raises(ffi.error, getattr, lib, 'FOOBAR')
    assert str(e.value) == (
       "the C compiler says 'FOOBAR' is equal to -6912, but the cdef disagrees")

def test_constant_nonint():
    ffi = FFI()
    ffi.cdef("static const double FOOBAR;")
    lib = verify(ffi, 'test_constant_nonint', "#define FOOBAR (-6912.5)")
    assert lib.FOOBAR == -6912.5
    with pytest.raises(AttributeError):
        lib.FOOBAR = 2

def test_constant_ptr():
    ffi = FFI()
    ffi.cdef("static double *const FOOBAR;")
    lib = verify(ffi, 'test_constant_ptr', "#define FOOBAR NULL")
    assert lib.FOOBAR == ffi.NULL
    assert ffi.typeof(lib.FOOBAR) == ffi.typeof("double *")

def test_dir():
    ffi = FFI()
    ffi.cdef("int ff(int); extern int aa; static const int my_constant;")
    lib = verify(ffi, 'test_dir', """
        #define my_constant  (-45)
        int aa;
        int ff(int x) { return x+aa; }
    """)
    lib.aa = 5
    assert dir(lib) == ['aa', 'ff', 'my_constant']
    #
    aaobj = lib.__dict__['aa']
    assert not isinstance(aaobj, int)    # some internal object instead
    assert lib.__dict__ == {
        'ff': lib.ff,
        'aa': aaobj,
        'my_constant': -45}
    lib.__dict__['ff'] = "??"
    assert lib.ff(10) == 15

def test_verify_opaque_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s;")
    lib = verify(ffi, 'test_verify_opaque_struct', "struct foo_s;")
    assert ffi.typeof("struct foo_s").cname == "struct foo_s"

def test_verify_opaque_union():
    ffi = FFI()
    ffi.cdef("union foo_s;")
    lib = verify(ffi, 'test_verify_opaque_union', "union foo_s;")
    assert ffi.typeof("union foo_s").cname == "union foo_s"

def test_verify_struct():
    ffi = FFI()
    ffi.cdef("""struct foo_s { int b; short a; ...; };
                struct bar_s { struct foo_s *f; };""")
    lib = verify(ffi, 'test_verify_struct',
                 """struct foo_s { short a; int b; };
                    struct bar_s { struct foo_s *f; };""")
    ffi.typeof("struct bar_s *")
    p = ffi.new("struct foo_s *", {'a': -32768, 'b': -2147483648})
    assert p.a == -32768
    assert p.b == -2147483648
    with pytest.raises(OverflowError):
        p.a -= 1
    with pytest.raises(OverflowError):
        p.b -= 1
    q = ffi.new("struct bar_s *", {'f': p})
    assert q.f == p
    #
    assert ffi.offsetof("struct foo_s", "a") == 0
    assert ffi.offsetof("struct foo_s", "b") == 4
    assert ffi.offsetof(u+"struct foo_s", u+"b") == 4
    #
    pytest.raises(TypeError, ffi.addressof, p)
    assert ffi.addressof(p[0]) == p
    assert ffi.typeof(ffi.addressof(p[0])) is ffi.typeof("struct foo_s *")
    assert ffi.typeof(ffi.addressof(p, "b")) is ffi.typeof("int *")
    assert ffi.addressof(p, "b")[0] == p.b

def test_verify_exact_field_offset():
    ffi = FFI()
    ffi.cdef("""struct foo_s { int b; short a; };""")
    lib = verify(ffi, 'test_verify_exact_field_offset',
                 """struct foo_s { short a; int b; };""")
    e = pytest.raises(ffi.error, ffi.new, "struct foo_s *", [])    # lazily
    assert str(e.value).startswith(
        "struct foo_s: wrong offset for field 'b' (cdef "
        'says 0, but C compiler says 4). fix it or use "...;" ')

def test_type_caching():
    ffi1 = FFI(); ffi1.cdef("struct foo_s;")
    ffi2 = FFI(); ffi2.cdef("struct foo_s;")    # different one!
    lib1 = verify(ffi1, 'test_type_caching_1', 'struct foo_s;')
    lib2 = verify(ffi2, 'test_type_caching_2', 'struct foo_s;')
    # shared types
    assert ffi1.typeof("long") is ffi2.typeof("long")
    assert ffi1.typeof("long**") is ffi2.typeof("long * *")
    assert ffi1.typeof("long(*)(int, ...)") is ffi2.typeof("long(*)(int, ...)")
    # non-shared types
    assert ffi1.typeof("struct foo_s") is not ffi2.typeof("struct foo_s")
    assert ffi1.typeof("struct foo_s *") is not ffi2.typeof("struct foo_s *")
    assert ffi1.typeof("struct foo_s*(*)()") is not (
        ffi2.typeof("struct foo_s*(*)()"))
    assert ffi1.typeof("void(*)(struct foo_s*)") is not (
        ffi2.typeof("void(*)(struct foo_s*)"))

def test_verify_enum():
    ffi = FFI()
    ffi.cdef("""enum e1 { B1, A1, ... }; enum e2 { B2, A2, ... };""")
    lib = verify(ffi, 'test_verify_enum',
                 "enum e1 { A1, B1, C1=%d };" % sys.maxsize +
                 "enum e2 { A2, B2, C2 };")
    ffi.typeof("enum e1")
    ffi.typeof("enum e2")
    assert lib.A1 == 0
    assert lib.B1 == 1
    assert lib.A2 == 0
    assert lib.B2 == 1
    assert ffi.sizeof("enum e1") == ffi.sizeof("long")
    assert ffi.sizeof("enum e2") == ffi.sizeof("int")
    assert repr(ffi.cast("enum e1", 0)) == "<cdata 'enum e1' 0: A1>"

def test_duplicate_enum():
    ffi = FFI()
    ffi.cdef("enum e1 { A1, ... }; enum e2 { A1, ... };")
    pytest.raises(VerificationError, verify, ffi, 'test_duplicate_enum',
                    "enum e1 { A1 }; enum e2 { B1 };")

def test_dotdotdot_length_of_array_field():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[...]; int b[...]; };")
    verify(ffi, 'test_dotdotdot_length_of_array_field',
           "struct foo_s { int a[42]; int b[11]; };")
    assert ffi.sizeof("struct foo_s") == (42 + 11) * 4
    p = ffi.new("struct foo_s *")
    assert p.a[41] == p.b[10] == 0
    with pytest.raises(IndexError):
        p.a[42]
    with pytest.raises(IndexError):
        p.b[11]

def test_dotdotdot_global_array():
    ffi = FFI()
    ffi.cdef("extern int aa[...]; extern int bb[...];")
    lib = verify(ffi, 'test_dotdotdot_global_array',
                 "int aa[41]; int bb[12];")
    assert ffi.sizeof(lib.aa) == 41 * 4
    assert ffi.sizeof(lib.bb) == 12 * 4
    assert lib.aa[40] == lib.bb[11] == 0
    with pytest.raises(IndexError):
        lib.aa[41]
    with pytest.raises(IndexError):
        lib.bb[12]

def test_misdeclared_field_1():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[5]; };")
    try:
        verify(ffi, 'test_misdeclared_field_1',
               "struct foo_s { int a[6]; };")
    except VerificationError:
        pass    # ok, fail during compilation already (e.g. C++)
    else:
        assert ffi.sizeof("struct foo_s") == 24  # found by the actual C code
        try:
            # lazily build the fields and boom:
            p = ffi.new("struct foo_s *")
            p.a
            assert False, "should have raised"
        except ffi.error as e:
            assert str(e).startswith("struct foo_s: wrong size for field 'a' "
                                     "(cdef says 20, but C compiler says 24)")

def test_open_array_in_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { int b; int a[]; };")
    verify(ffi, 'test_open_array_in_struct',
           "struct foo_s { int b; int a[]; };")
    assert ffi.sizeof("struct foo_s") == 4
    p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]])
    assert p.a[2] == 30
    assert ffi.sizeof(p) == ffi.sizeof("void *")
    assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int")

def test_math_sin_type():
    ffi = FFI()
    ffi.cdef("double sin(double); void *xxtestfunc();")
    lib = verify(ffi, 'test_math_sin_type', """
        #include <math.h>
        void *xxtestfunc(void) { return 0; }
    """)
    # 'lib.sin' is typed as a <built-in method> object on lib
    assert ffi.typeof(lib.sin).cname == "double(*)(double)"
    # 'x' is another <built-in method> object on lib, made very indirectly
    x = type(lib).__dir__.__get__(lib)
    pytest.raises(TypeError, ffi.typeof, x)
    #
    # present on built-in functions on CPython; must be emulated on PyPy:
    assert lib.sin.__name__ == 'sin'
    assert lib.sin.__module__ == '_CFFI_test_math_sin_type'
    assert lib.sin.__doc__ == (
        "double sin(double);\n"
        "\n"
        "CFFI C function from _CFFI_test_math_sin_type.lib")

    assert ffi.typeof(lib.xxtestfunc).cname == "void *(*)()"
    assert lib.xxtestfunc.__doc__ == (
        "void *xxtestfunc();\n"
        "\n"
        "CFFI C function from _CFFI_test_math_sin_type.lib")

def test_verify_anonymous_struct_with_typedef():
    ffi = FFI()
    ffi.cdef("typedef struct { int a; long b; ...; } foo_t;")
    verify(ffi, 'test_verify_anonymous_struct_with_typedef',
           "typedef struct { long b; int hidden, a; } foo_t;")
    p = ffi.new("foo_t *", {'b': 42})
    assert p.b == 42
    assert repr(p).startswith("<cdata 'foo_t *' ")

def test_verify_anonymous_struct_with_star_typedef():
    ffi = FFI()
    ffi.cdef("typedef struct { int a; long b; } *foo_t;")
    verify(ffi, 'test_verify_anonymous_struct_with_star_typedef',
           "typedef struct { int a; long b; } *foo_t;")
    p = ffi.new("foo_t", {'b': 42})
    assert p.b == 42

def test_verify_anonymous_enum_with_typedef():
    ffi = FFI()
    ffi.cdef("typedef enum { AA, ... } e1;")
    lib = verify(ffi, 'test_verify_anonymous_enum_with_typedef1',
                 "typedef enum { BB, CC, AA } e1;")
    assert lib.AA == 2
    assert ffi.sizeof("e1") == ffi.sizeof("int")
    assert repr(ffi.cast("e1", 2)) == "<cdata 'e1' 2: AA>"
    #
    ffi = FFI()
    ffi.cdef("typedef enum { AA=%d } e1;" % sys.maxsize)
    lib = verify(ffi, 'test_verify_anonymous_enum_with_typedef2',
                 "typedef enum { AA=%d } e1;" % sys.maxsize)
    assert lib.AA == int(ffi.cast("long", sys.maxsize))
    assert ffi.sizeof("e1") == ffi.sizeof("long")

def test_unique_types():
    CDEF = "struct foo_s; union foo_u; enum foo_e { AA };"
    ffi1 = FFI(); ffi1.cdef(CDEF); verify(ffi1, "test_unique_types_1", CDEF)
    ffi2 = FFI(); ffi2.cdef(CDEF); verify(ffi2, "test_unique_types_2", CDEF)
    #
    assert ffi1.typeof("char") is ffi2.typeof("char ")
    assert ffi1.typeof("long") is ffi2.typeof("signed long int")
    assert ffi1.typeof("double *") is ffi2.typeof("double*")
    assert ffi1.typeof("int ***") is ffi2.typeof(" int * * *")
    assert ffi1.typeof("int[]") is ffi2.typeof("signed int[]")
    assert ffi1.typeof("signed int*[17]") is ffi2.typeof("int *[17]")
    assert ffi1.typeof("void") is ffi2.typeof("void")
    assert ffi1.typeof("int(*)(int,int)") is ffi2.typeof("int(*)(int,int)")
    #
    # these depend on user-defined data, so should not be shared
    for name in ["struct foo_s",
                 "union foo_u *",
                 "enum foo_e",
                 "struct foo_s *(*)()",
                 "void(*)(struct foo_s *)",
                 "struct foo_s *(*[5])[8]",
                 ]:
        assert ffi1.typeof(name) is not ffi2.typeof(name)
    # sanity check: twice 'ffi1'
    assert ffi1.typeof("struct foo_s*") is ffi1.typeof("struct foo_s *")

def test_module_name_in_package():
    ffi = FFI()
    ffi.cdef("int foo(int);")
    recompiler.recompile(ffi, "test_module_name_in_package.mymod",
                         "int foo(int x) { return x + 32; }",
                         tmpdir=str(udir))
    old_sys_path = sys.path[:]
    try:
        package_dir = udir.join('test_module_name_in_package')
        for name in os.listdir(str(udir)):
            assert not name.startswith('test_module_name_in_package.')
        assert os.path.isdir(str(package_dir))
        assert len(os.listdir(str(package_dir))) > 0
        assert os.path.exists(str(package_dir.join('mymod.c')))
        package_dir.join('__init__.py').write('')
        #
        getattr(importlib, 'invalidate_caches', object)()
        #
        sys.path.insert(0, str(udir))
        import test_module_name_in_package.mymod
        assert test_module_name_in_package.mymod.lib.foo(10) == 42
        assert test_module_name_in_package.mymod.__name__ == (
            'test_module_name_in_package.mymod')
    finally:
        sys.path[:] = old_sys_path

def test_bad_size_of_global_1():
    ffi = FFI()
    ffi.cdef("extern short glob;")
    pytest.raises(VerificationError, verify, ffi,
                   "test_bad_size_of_global_1", "long glob;")

def test_bad_size_of_global_2():
    ffi = FFI()
    ffi.cdef("extern int glob[10];")
    pytest.raises(VerificationError, verify, ffi,
                   "test_bad_size_of_global_2", "int glob[9];")

def test_unspecified_size_of_global_1():
    ffi = FFI()
    ffi.cdef("extern int glob[];")
    lib = verify(ffi, "test_unspecified_size_of_global_1", "int glob[10];")
    assert ffi.typeof(lib.glob) == ffi.typeof("int *")

def test_unspecified_size_of_global_2():
    ffi = FFI()
    ffi.cdef("extern int glob[][5];")
    lib = verify(ffi, "test_unspecified_size_of_global_2", "int glob[10][5];")
    assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")

def test_unspecified_size_of_global_3():
    ffi = FFI()
    ffi.cdef("extern int glob[][...];")
    lib = verify(ffi, "test_unspecified_size_of_global_3", "int glob[10][5];")
    assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")

def test_unspecified_size_of_global_4():
    ffi = FFI()
    ffi.cdef("extern int glob[...][...];")
    lib = verify(ffi, "test_unspecified_size_of_global_4", "int glob[10][5];")
    assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]")

def test_include_1():
    ffi1 = FFI()
    ffi1.cdef("typedef double foo_t;")
    verify(ffi1, "test_include_1_parent", "typedef double foo_t;")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("foo_t ff1(foo_t);")
    lib = verify(ffi, "test_include_1", "double ff1(double x) { return 42.5; }")
    assert lib.ff1(0) == 42.5
    assert ffi1.typeof("foo_t") is ffi.typeof("foo_t") is ffi.typeof("double")

def test_include_1b():
    ffi1 = FFI()
    ffi1.cdef("int foo1(int);")
    lib1 = verify(ffi1, "test_include_1b_parent",
                  "int foo1(int x) { return x + 10; }")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("int foo2(int);")
    lib = verify(ffi, "test_include_1b", "int foo2(int x) { return x - 5; }")
    assert lib.foo2(42) == 37
    assert lib.foo1(42) == 52
    assert lib.foo1 is lib1.foo1

def test_include_2():
    ffi1 = FFI()
    ffi1.cdef("struct foo_s { int x, y; };")
    verify(ffi1, "test_include_2_parent", "struct foo_s { int x, y; };")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("struct foo_s *ff2(struct foo_s *);")
    lib = verify(ffi, "test_include_2",
                 "struct foo_s { int x, y; }; //usually from a #include\n"
                 "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }")
    p = ffi.new("struct foo_s *")
    p.y = 41
    q = lib.ff2(p)
    assert q == p
    assert p.y == 42
    assert ffi1.typeof("struct foo_s") is ffi.typeof("struct foo_s")

def test_include_3():
    ffi1 = FFI()
    ffi1.cdef("typedef short sshort_t;")
    verify(ffi1, "test_include_3_parent", "typedef short sshort_t;")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("sshort_t ff3(sshort_t);")
    lib = verify(ffi, "test_include_3",
                 "typedef short sshort_t; //usually from a #include\n"
                 "sshort_t ff3(sshort_t x) { return (sshort_t)(x + 42); }")
    assert lib.ff3(10) == 52
    assert ffi.typeof(ffi.cast("sshort_t", 42)) is ffi.typeof("short")
    assert ffi1.typeof("sshort_t") is ffi.typeof("sshort_t")

def test_include_4():
    ffi1 = FFI()
    ffi1.cdef("typedef struct { int x; } mystruct_t;")
    verify(ffi1, "test_include_4_parent",
           "typedef struct { int x; } mystruct_t;")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("mystruct_t *ff4(mystruct_t *);")
    lib = verify(ffi, "test_include_4",
           "typedef struct {int x; } mystruct_t; //usually from a #include\n"
           "mystruct_t *ff4(mystruct_t *p) { p->x += 42; return p; }")
    p = ffi.new("mystruct_t *", [10])
    q = lib.ff4(p)
    assert q == p
    assert p.x == 52
    assert ffi1.typeof("mystruct_t") is ffi.typeof("mystruct_t")

def test_include_5():
    ffi1 = FFI()
    ffi1.cdef("typedef struct { int x[2]; int y; } *mystruct_p;")
    verify(ffi1, "test_include_5_parent",
           "typedef struct { int x[2]; int y; } *mystruct_p;")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("mystruct_p ff5(mystruct_p);")
    lib = verify(ffi, "test_include_5",
        "typedef struct {int x[2]; int y; } *mystruct_p; //usually #include\n"
        "mystruct_p ff5(mystruct_p p) { p->x[1] += 42; return p; }")
    assert ffi.alignof(ffi.typeof("mystruct_p").item) == 4
    assert ffi1.typeof("mystruct_p") is ffi.typeof("mystruct_p")
    p = ffi.new("mystruct_p", [[5, 10], -17])
    q = lib.ff5(p)
    assert q == p
    assert p.x[0] == 5
    assert p.x[1] == 52
    assert p.y == -17
    assert ffi.alignof(ffi.typeof(p[0])) == 4

def test_include_6():
    ffi1 = FFI()
    ffi1.cdef("typedef ... mystruct_t;")
    verify(ffi1, "test_include_6_parent",
           "typedef struct _mystruct_s mystruct_t;")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("mystruct_t *ff6(void); int ff6b(mystruct_t *);")
    lib = verify(ffi, "test_include_6",
           "typedef struct _mystruct_s mystruct_t; //usually from a #include\n"
           "struct _mystruct_s { int x; };\n"
           "static mystruct_t result_struct = { 42 };\n"
           "mystruct_t *ff6(void) { return &result_struct; }\n"
           "int ff6b(mystruct_t *p) { return p->x; }")
    p = lib.ff6()
    assert ffi.cast("int *", p)[0] == 42
    assert lib.ff6b(p) == 42

def test_include_7():
    ffi1 = FFI()
    ffi1.cdef("typedef ... mystruct_t;\n"
              "int ff7b(mystruct_t *);")
    verify(ffi1, "test_include_7_parent",
           "typedef struct { int x; } mystruct_t;\n"
           "int ff7b(mystruct_t *p) { return p->x; }")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("mystruct_t *ff7(void);")
    lib = verify(ffi, "test_include_7",
           "typedef struct { int x; } mystruct_t; //usually from a #include\n"
           "static mystruct_t result_struct = { 42 };"
           "mystruct_t *ff7(void) { return &result_struct; }")
    p = lib.ff7()
    assert ffi.cast("int *", p)[0] == 42
    assert lib.ff7b(p) == 42

def test_include_8():
    ffi1 = FFI()
    ffi1.cdef("struct foo_s;")
    verify(ffi1, "test_include_8_parent", "struct foo_s;")
    ffi = FFI()
    ffi.include(ffi1)
    ffi.cdef("struct foo_s { int x, y; };")
    verify(ffi, "test_include_8", "struct foo_s { int x, y; };")
    e = pytest.raises(NotImplementedError, ffi.new, "struct foo_s *")
    assert str(e.value) == (
        "'struct foo_s' is opaque in the ffi.include(), but no longer in "
        "the ffi doing the include (workaround: don't use ffi.include() but"
        " duplicate the declarations of everything using struct foo_s)")

def test_unicode_libraries():
    try:
        unicode
    except NameError:
        pytest.skip("for python 2.x")
    #
    import math
    lib_m = "m"
    if sys.platform == 'win32':
        #there is a small chance this fails on Mingw via environ $CC
        import distutils.ccompiler
        if distutils.ccompiler.get_default_compiler() == 'msvc':
            lib_m = 'msvcrt'
    ffi = FFI()
    ffi.cdef(unicode("float sin(double); double cos(double);"))
    lib = verify(ffi, 'test_math_sin_unicode', unicode('#include <math.h>'),
                 libraries=[unicode(lib_m)], ignore_warnings=True)
    assert lib.cos(1.43) == math.cos(1.43)

def test_incomplete_struct_as_arg():
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; ...; }; int f(int, struct foo_s);")
    lib = verify(ffi, "test_incomplete_struct_as_arg",
                 "struct foo_s { int a, x, z; };\n"
                 "int f(int b, struct foo_s s) { return s.x * b; }")
    s = ffi.new("struct foo_s *", [21])
    assert s.x == 21
    assert ffi.sizeof(s[0]) == 12
    assert ffi.offsetof(ffi.typeof(s), 'x') == 4
    assert lib.f(2, s[0]) == 42
    assert ffi.typeof(lib.f) == ffi.typeof("int(*)(int, struct foo_s)")

def test_incomplete_struct_as_result():
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; ...; }; struct foo_s f(int);")
    lib = verify(ffi, "test_incomplete_struct_as_result",
            "struct foo_s { int a, x, z; };\n"
            "struct foo_s f(int x) { struct foo_s r; r.x = x * 2; return r; }")
    s = lib.f(21)
    assert s.x == 42
    assert ffi.typeof(lib.f) == ffi.typeof("struct foo_s(*)(int)")

def test_incomplete_struct_as_both():
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; ...; }; struct bar_s { int y; ...; };\n"
             "struct foo_s f(int, struct bar_s);")
    lib = verify(ffi, "test_incomplete_struct_as_both",
            "struct foo_s { int a, x, z; };\n"
            "struct bar_s { int b, c, y, d; };\n"
            "struct foo_s f(int x, struct bar_s b) {\n"
            "  struct foo_s r; r.x = x * b.y; return r;\n"
            "}")
    b = ffi.new("struct bar_s *", [7])
    s = lib.f(6, b[0])
    assert s.x == 42
    assert ffi.typeof(lib.f) == ffi.typeof(
        "struct foo_s(*)(int, struct bar_s)")
    s = lib.f(14, {'y': -3})
    assert s.x == -42

def test_name_of_unnamed_struct():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; } foo_t;\n"
             "typedef struct { int y; } *bar_p;\n"
             "typedef struct { int y; } **baz_pp;\n")
    verify(ffi, "test_name_of_unnamed_struct",
             "typedef struct { int x; } foo_t;\n"
             "typedef struct { int y; } *bar_p;\n"
             "typedef struct { int y; } **baz_pp;\n")
    assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>"
    assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>"
    assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>"

def test_address_of_global_var():
    ffi = FFI()
    ffi.cdef("""
        extern long bottom, bottoms[2];
        long FetchRectBottom(void);
        long FetchRectBottoms1(void);
        #define FOOBAR 42
    """)
    lib = verify(ffi, "test_address_of_global_var", """
        long bottom, bottoms[2];
        long FetchRectBottom(void) { return bottom; }
        long FetchRectBottoms1(void) { return bottoms[1]; }
        #define FOOBAR 42
    """)
    lib.bottom = 300
    assert lib.FetchRectBottom() == 300
    lib.bottom += 1
    assert lib.FetchRectBottom() == 301
    lib.bottoms[1] = 500
    assert lib.FetchRectBottoms1() == 500
    lib.bottoms[1] += 2
    assert lib.FetchRectBottoms1() == 502
    #
    p = ffi.addressof(lib, 'bottom')
    assert ffi.typeof(p) == ffi.typeof("long *")
    assert p[0] == 301
    p[0] += 1
    assert lib.FetchRectBottom() == 302
    p = ffi.addressof(lib, 'bottoms')
    assert ffi.typeof(p) == ffi.typeof("long(*)[2]")
    assert p[0] == lib.bottoms
    #
    pytest.raises(AttributeError, ffi.addressof, lib, 'unknown_var')
    pytest.raises(AttributeError, ffi.addressof, lib, "FOOBAR")

def test_defines__CFFI_():
    # Check that we define the macro _CFFI_ automatically.
    # It should be done before including Python.h, so that PyPy's Python.h
    # can check for it.
    ffi = FFI()
    ffi.cdef("""
        #define CORRECT 1
    """)
    lib = verify(ffi, "test_defines__CFFI_", """
    #ifdef _CFFI_
    #    define CORRECT 1
    #endif
    """)
    assert lib.CORRECT == 1

def test_unpack_args():
    ffi = FFI()
    ffi.cdef("void foo0(void); void foo1(int); void foo2(int, int);")
    lib = verify(ffi, "test_unpack_args", """
    void foo0(void) { }
    void foo1(int x) { }
    void foo2(int x, int y) { }
    """)
    assert 'foo0' in repr(lib.foo0)
    assert 'foo1' in repr(lib.foo1)
    assert 'foo2' in repr(lib.foo2)
    lib.foo0()
    lib.foo1(42)
    lib.foo2(43, 44)
    e1 = pytest.raises(TypeError, lib.foo0, 42)
    e2 = pytest.raises(TypeError, lib.foo0, 43, 44)
    e3 = pytest.raises(TypeError, lib.foo1)
    e4 = pytest.raises(TypeError, lib.foo1, 43, 44)
    e5 = pytest.raises(TypeError, lib.foo2)
    e6 = pytest.raises(TypeError, lib.foo2, 42)
    e7 = pytest.raises(TypeError, lib.foo2, 45, 46, 47)
    def st1(s):
        s = str(s)
        if s.startswith("_CFFI_test_unpack_args.Lib."):
            s = s[len("_CFFI_test_unpack_args.Lib."):]
        return s
    assert st1(e1.value) == "foo0() takes no arguments (1 given)"
    assert st1(e2.value) == "foo0() takes no arguments (2 given)"
    assert st1(e3.value) == "foo1() takes exactly one argument (0 given)"
    assert st1(e4.value) == "foo1() takes exactly one argument (2 given)"
    assert st1(e5.value) in ["foo2 expected 2 arguments, got 0",
                             "foo2() takes exactly 2 arguments (0 given)"]
    assert st1(e6.value) in ["foo2 expected 2 arguments, got 1",
                             "foo2() takes exactly 2 arguments (1 given)"]
    assert st1(e7.value) in ["foo2 expected 2 arguments, got 3",
                             "foo2() takes exactly 2 arguments (3 given)"]

def test_address_of_function():
    ffi = FFI()
    ffi.cdef("long myfunc(long x);")
    lib = verify(ffi, "test_addressof_function", """
        char myfunc(char x) { return (char)(x + 42); }
    """, ignore_warnings=True)
    assert lib.myfunc(5) == 47
    assert lib.myfunc(0xABC05) == 47
    assert not isinstance(lib.myfunc, ffi.CData)
    assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)")
    addr = ffi.addressof(lib, 'myfunc')
    assert addr(5) == 47
    assert addr(0xABC05) == 47
    assert isinstance(addr, ffi.CData)
    assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")

def test_address_of_function_with_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; }; long myfunc(struct foo_s);")
    lib = verify(ffi, "test_addressof_function_with_struct", """
        struct foo_s { int x; };
        char myfunc(struct foo_s input) { return (char)(input.x + 42); }
    """)
    s = ffi.new("struct foo_s *", [5])[0]
    assert lib.myfunc(s) == 47
    assert not isinstance(lib.myfunc, ffi.CData)
    assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)")
    addr = ffi.addressof(lib, 'myfunc')
    assert addr(s) == 47
    assert isinstance(addr, ffi.CData)
    assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")

def test_issue198():
    ffi = FFI()
    ffi.cdef("""
        typedef struct{...;} opaque_t;
        const opaque_t CONSTANT;
        int toint(opaque_t);
    """)
    lib = verify(ffi, 'test_issue198', """
        typedef int opaque_t;
        #define CONSTANT ((opaque_t)42)
        static int toint(opaque_t o) { return o; }
    """)
    def random_stuff():
        pass
    assert lib.toint(lib.CONSTANT) == 42
    random_stuff()
    assert lib.toint(lib.CONSTANT) == 42

def test_constant_is_not_a_compiler_constant():
    ffi = FFI()
    ffi.cdef("static const float almost_forty_two;")
    lib = verify(ffi, 'test_constant_is_not_a_compiler_constant', """
        static float f(void) { return 42.25; }
        #define almost_forty_two (f())
    """)
    assert lib.almost_forty_two == 42.25

def test_constant_of_unknown_size():
    ffi = FFI()
    ffi.cdef("""
        typedef ... opaque_t;
        const opaque_t CONSTANT;
    """)
    lib = verify(ffi, 'test_constant_of_unknown_size',
                 "typedef int opaque_t;"
                 "const int CONSTANT = 42;")
    e = pytest.raises(ffi.error, getattr, lib, 'CONSTANT')
    assert str(e.value) == ("constant 'CONSTANT' is of "
                            "type 'opaque_t', whose size is not known")

def test_variable_of_unknown_size():
    ffi = FFI()
    ffi.cdef("""
        typedef ... opaque_t;
        extern opaque_t globvar;
    """)
    lib = verify(ffi, 'test_variable_of_unknown_size', """
        typedef char opaque_t[6];
        opaque_t globvar = "hello";
    """)
    # can't read or write it at all
    e = pytest.raises(TypeError, getattr, lib, 'globvar')
    assert str(e.value) in ["cdata 'opaque_t' is opaque",
                            "'opaque_t' is opaque or not completed yet"] #pypy
    e = pytest.raises(TypeError, setattr, lib, 'globvar', [])
    assert str(e.value) in ["'opaque_t' is opaque",
                            "'opaque_t' is opaque or not completed yet"] #pypy
    # but we can get its address
    p = ffi.addressof(lib, 'globvar')
    assert ffi.typeof(p) == ffi.typeof('opaque_t *')
    assert ffi.string(ffi.cast("char *", p), 8) == b"hello"

def test_constant_of_value_unknown_to_the_compiler():
    extra_c_source = udir.join(
        'extra_test_constant_of_value_unknown_to_the_compiler.c')
    extra_c_source.write('const int external_foo = 42;\n')
    ffi = FFI()
    ffi.cdef("const int external_foo;")
    lib = verify(ffi, 'test_constant_of_value_unknown_to_the_compiler', """
        extern const int external_foo;
    """, sources=[str(extra_c_source)])
    assert lib.external_foo == 42

def test_dotdot_in_source_file_names():
    extra_c_source = udir.join(
        'extra_test_dotdot_in_source_file_names.c')
    extra_c_source.write('const int external_foo = 42;\n')
    ffi = FFI()
    ffi.cdef("const int external_foo;")
    lib = verify(ffi, 'test_dotdot_in_source_file_names', """
        extern const int external_foo;
    """, sources=[os.path.join(os.path.dirname(str(extra_c_source)),
                               'foobar', '..',
                               os.path.basename(str(extra_c_source)))])
    assert lib.external_foo == 42

def test_call_with_incomplete_structs():
    ffi = FFI()
    ffi.cdef("typedef struct {...;} foo_t; "
             "extern foo_t myglob; "
             "foo_t increment(foo_t s); "
             "double getx(foo_t s);")
    lib = verify(ffi, 'test_call_with_incomplete_structs', """
        typedef double foo_t;
        double myglob = 42.5;
        double getx(double x) { return x; }
        double increment(double x) { return x + 1; }
    """)
    assert lib.getx(lib.myglob) == 42.5
    assert lib.getx(lib.increment(lib.myglob)) == 43.5

def test_struct_array_guess_length_2():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[...][...]; };")
    lib = verify(ffi, 'test_struct_array_guess_length_2',
                 "struct foo_s { int x; int a[5][8]; int y; };")
    assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
    assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int')
    assert s.a[4][7] == 0
    with pytest.raises(IndexError):
        s.a[4][8]
    with pytest.raises(IndexError):
        s.a[5][0]
    assert ffi.typeof(s.a) == ffi.typeof("int[5][8]")
    assert ffi.typeof(s.a[0]) == ffi.typeof("int[8]")

def test_struct_array_guess_length_3():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[][...]; };")
    lib = verify(ffi, 'test_struct_array_guess_length_3',
                 "struct foo_s { int x; int a[5][7]; int y; };")
    assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
    assert s.a[4][6] == 0
    with pytest.raises(IndexError):
        s.a[4][7]
    assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]")

def test_global_var_array_2():
    ffi = FFI()
    ffi.cdef("extern int a[...][...];")
    lib = verify(ffi, 'test_global_var_array_2', 'int a[10][8];')
    lib.a[9][7] = 123456
    assert lib.a[9][7] == 123456
    with pytest.raises(IndexError):
        lib.a[0][8]
    with pytest.raises(IndexError):
        lib.a[10][0]
    assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]")
    assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")

def test_global_var_array_3():
    ffi = FFI()
    ffi.cdef("extern int a[][...];")
    lib = verify(ffi, 'test_global_var_array_3', 'int a[10][8];')
    lib.a[9][7] = 123456
    assert lib.a[9][7] == 123456
    with pytest.raises(IndexError):
        lib.a[0][8]
    assert ffi.typeof(lib.a) == ffi.typeof("int(*)[8]")
    assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")

def test_global_var_array_4():
    ffi = FFI()
    ffi.cdef("extern int a[10][...];")
    lib = verify(ffi, 'test_global_var_array_4', 'int a[10][8];')
    lib.a[9][7] = 123456
    assert lib.a[9][7] == 123456
    with pytest.raises(IndexError):
        lib.a[0][8]
    with pytest.raises(IndexError):
        lib.a[10][8]
    assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]")
    assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]")

def test_some_integer_type():
    ffi = FFI()
    ffi.cdef("""
        typedef int... foo_t;
        typedef unsigned long... bar_t;
        typedef struct { foo_t a, b; } mystruct_t;
        foo_t foobar(bar_t, mystruct_t);
        static const bar_t mu = -20;
        static const foo_t nu = 20;
    """)
    lib = verify(ffi, 'test_some_integer_type', """
        typedef unsigned long long foo_t;
        typedef short bar_t;
        typedef struct { foo_t a, b; } mystruct_t;
        static foo_t foobar(bar_t x, mystruct_t s) {
            return (foo_t)x + s.a + s.b;
        }
        static const bar_t mu = -20;
        static const foo_t nu = 20;
    """)
    assert ffi.sizeof("foo_t") == ffi.sizeof("unsigned long long")
    assert ffi.sizeof("bar_t") == ffi.sizeof("short")
    maxulonglong = 2 ** 64 - 1
    assert int(ffi.cast("foo_t", -1)) == maxulonglong
    assert int(ffi.cast("bar_t", -1)) == -1
    assert lib.foobar(-1, [0, 0]) == maxulonglong
    assert lib.foobar(2 ** 15 - 1, [0, 0]) == 2 ** 15 - 1
    assert lib.foobar(10, [20, 31]) == 61
    assert lib.foobar(0, [0, maxulonglong]) == maxulonglong
    pytest.raises(OverflowError, lib.foobar, 2 ** 15, [0, 0])
    pytest.raises(OverflowError, lib.foobar, -(2 ** 15) - 1, [0, 0])
    pytest.raises(OverflowError, ffi.new, "mystruct_t *", [0, -1])
    assert lib.mu == -20
    assert lib.nu == 20

def test_some_float_type():
    ffi = FFI()
    ffi.cdef("""
        typedef double... foo_t;
        typedef float... bar_t;
        foo_t sum(foo_t[]);
        bar_t neg(bar_t);
        """)
    lib = verify(ffi, 'test_some_float_type', """
        typedef float foo_t;
        static foo_t sum(foo_t x[]) { return x[0] + x[1]; }
        typedef double bar_t;
        static double neg(double x) { return -x; }
    """)
    assert lib.sum([40.0, 2.25]) == 42.25
    assert lib.sum([12.3, 45.6]) != 12.3 + 45.6     # precision loss
    assert lib.neg(12.3) == -12.3                   # no precision loss
    assert ffi.sizeof("foo_t") == ffi.sizeof("float")
    assert ffi.sizeof("bar_t") == ffi.sizeof("double")

def test_some_float_invalid_1():
    ffi = FFI()
    pytest.raises((FFIError,      # with pycparser <= 2.17
                    CDefError),    # with pycparser >= 2.18
                   ffi.cdef, "typedef long double... foo_t;")

def test_some_float_invalid_2():
    ffi = FFI()
    ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);")
    lib = verify(ffi, 'test_some_float_invalid_2', """
        typedef unsigned long foo_t;
        foo_t neg(foo_t x) { return -x; }
    """)
    e = pytest.raises(ffi.error, getattr, lib, 'neg')
    assert str(e.value) == ("primitive floating-point type with an unexpected "
                            "size (or not a float type at all)")

def test_some_float_invalid_3():
    ffi = FFI()
    ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);")
    lib = verify(ffi, 'test_some_float_invalid_3', """
        typedef long double foo_t;
        foo_t neg(foo_t x) { return -x; }
    """, ignore_warnings=True)
    if ffi.sizeof("long double") == ffi.sizeof("double"):
        assert lib.neg(12.3) == -12.3
    else:
        e = pytest.raises(ffi.error, getattr, lib, 'neg')
        assert str(e.value) == ("primitive floating-point type is "
                                "'long double', not supported for now with "
                                "the syntax 'typedef double... xxx;'")

def test_issue200():
    ffi = FFI()
    ffi.cdef("""
        typedef void (function_t)(void*);
        void function(void *);
    """)
    lib = verify(ffi, 'test_issue200', """
        static void function(void *p) { (void)p; }
    """)
    ffi.typeof('function_t*')
    lib.function(ffi.NULL)
    # assert did not crash

def test_alignment_of_longlong():
    ffi = FFI()
    x1 = ffi.alignof('unsigned long long')
    assert x1 in [4, 8]
    ffi.cdef("struct foo_s { unsigned long long x; };")
    lib = verify(ffi, 'test_alignment_of_longlong',
                 "struct foo_s { unsigned long long x; };")
    assert ffi.alignof('unsigned long long') == x1
    assert ffi.alignof('struct foo_s') == x1

def test_import_from_lib():
    ffi = FFI()
    ffi.cdef("int mybar(int); static int myvar;\n#define MYFOO ...")
    lib = verify(ffi, 'test_import_from_lib',
                 "#define MYFOO 42\n"
                 "static int mybar(int x) { return x + 1; }\n"
                 "static int myvar = -5;")
    assert sys.modules['_CFFI_test_import_from_lib'].lib is lib
    assert sys.modules['_CFFI_test_import_from_lib.lib'] is lib
    from _CFFI_test_import_from_lib.lib import MYFOO
    assert MYFOO == 42
    assert hasattr(lib, '__dict__')
    assert lib.__all__ == ['MYFOO', 'mybar']   # but not 'myvar'
    assert lib.__name__ == '_CFFI_test_import_from_lib.lib'
    assert lib.__class__ is type(sys)   # !! hack for help()

def test_macro_var_callback():
    ffi = FFI()
    ffi.cdef("extern int my_value; extern int *(*get_my_value)(void);")
    lib = verify(ffi, 'test_macro_var_callback',
                 "int *(*get_my_value)(void);\n"
                 "#define my_value (*get_my_value())")
    #
    values = ffi.new("int[50]")
    def it():
        for i in range(50):
            yield i
    it = it()
    #
    @ffi.callback("int *(*)(void)")
    def get_my_value():
        for nextvalue in it:
            return values + nextvalue
    lib.get_my_value = get_my_value
    #
    values[0] = 41
    assert lib.my_value == 41            # [0]
    p = ffi.addressof(lib, 'my_value')   # [1]
    assert p == values + 1
    assert p[-1] == 41
    assert p[+1] == 0
    lib.my_value = 42                    # [2]
    assert values[2] == 42
    assert p[-1] == 41
    assert p[+1] == 42
    #
    # if get_my_value raises or returns nonsense, the exception is printed
    # to stderr like with any callback, but then the C expression 'my_value'
    # expand to '*NULL'.  We assume here that '&my_value' will return NULL
    # without segfaulting, and check for NULL when accessing the variable.
    @ffi.callback("int *(*)(void)")
    def get_my_value():
        raise LookupError
    lib.get_my_value = get_my_value
    pytest.raises(ffi.error, getattr, lib, 'my_value')
    pytest.raises(ffi.error, setattr, lib, 'my_value', 50)
    pytest.raises(ffi.error, ffi.addressof, lib, 'my_value')
    @ffi.callback("int *(*)(void)")
    def get_my_value():
        return "hello"
    lib.get_my_value = get_my_value
    pytest.raises(ffi.error, getattr, lib, 'my_value')
    e = pytest.raises(ffi.error, setattr, lib, 'my_value', 50)
    assert str(e.value) == "global variable 'my_value' is at address NULL"

def test_const_fields():
    ffi = FFI()
    ffi.cdef("""struct foo_s { const int a; void *const b; };""")
    lib = verify(ffi, 'test_const_fields', """
        struct foo_s { const int a; void *const b; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'a'
    assert foo_s.fields[0][1].type is ffi.typeof("int")
    assert foo_s.fields[1][0] == 'b'
    assert foo_s.fields[1][1].type is ffi.typeof("void *")

def test_restrict_fields():
    ffi = FFI()
    ffi.cdef("""struct foo_s { void * restrict b; };""")
    lib = verify(ffi, 'test_restrict_fields', """
        struct foo_s { void * __restrict b; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'b'
    assert foo_s.fields[0][1].type is ffi.typeof("void *")

def test_volatile_fields():
    ffi = FFI()
    ffi.cdef("""struct foo_s { void * volatile b; };""")
    lib = verify(ffi, 'test_volatile_fields', """
        struct foo_s { void * volatile b; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'b'
    assert foo_s.fields[0][1].type is ffi.typeof("void *")

def test_const_array_fields():
    ffi = FFI()
    ffi.cdef("""struct foo_s { const int a[4]; };""")
    lib = verify(ffi, 'test_const_array_fields', """
        struct foo_s { const int a[4]; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'a'
    assert foo_s.fields[0][1].type is ffi.typeof("int[4]")

def test_const_array_fields_varlength():
    ffi = FFI()
    ffi.cdef("""struct foo_s { const int a[]; ...; };""")
    lib = verify(ffi, 'test_const_array_fields_varlength', """
        struct foo_s { const int a[4]; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'a'
    assert foo_s.fields[0][1].type is ffi.typeof("int[]")

def test_const_array_fields_unknownlength():
    ffi = FFI()
    ffi.cdef("""struct foo_s { const int a[...]; ...; };""")
    lib = verify(ffi, 'test_const_array_fields_unknownlength', """
        struct foo_s { const int a[4]; };""")
    foo_s = ffi.typeof("struct foo_s")
    assert foo_s.fields[0][0] == 'a'
    assert foo_s.fields[0][1].type is ffi.typeof("int[4]")

def test_const_function_args():
    ffi = FFI()
    ffi.cdef("""int foobar(const int a, const int *b, const int c[]);""")
    lib = verify(ffi, 'test_const_function_args', """
        int foobar(const int a, const int *b, const int c[]) {
            return a + *b + *c;
        }
    """)
    assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142

def test_const_function_type_args():
    ffi = FFI()
    ffi.cdef("""extern int(*foobar)(const int a,const int*b,const int c[]);""")
    lib = verify(ffi, 'test_const_function_type_args', """
        int (*foobar)(const int a, const int *b, const int c[]);
    """)
    t = ffi.typeof(lib.foobar)
    assert t.args[0] is ffi.typeof("int")
    assert t.args[1] is ffi.typeof("int *")
    assert t.args[2] is ffi.typeof("int *")

def test_const_constant():
    ffi = FFI()
    ffi.cdef("""struct foo_s { int x,y; }; const struct foo_s myfoo;""")
    lib = verify(ffi, 'test_const_constant', """
        struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 };
    """)
    assert lib.myfoo.x == 40
    assert lib.myfoo.y == 2

def test_const_via_typedef():
    ffi = FFI()
    ffi.cdef("""typedef const int const_t; const_t aaa;""")
    lib = verify(ffi, 'test_const_via_typedef', """
        typedef const int const_t;
        #define aaa 42
    """)
    assert lib.aaa == 42
    with pytest.raises(AttributeError):
        lib.aaa = 43

def test_win32_calling_convention_0():
    ffi = FFI()
    ffi.cdef("""
        int call1(int(__cdecl   *cb)(int));
        int (*const call2)(int(__stdcall *cb)(int));
    """)
    lib = verify(ffi, 'test_win32_calling_convention_0', r"""
        #ifndef _MSC_VER
        #  define __stdcall  /* nothing */
        #endif
        int call1(int(*cb)(int)) {
            int i, result = 0;
            //printf("call1: cb = %p\n", cb);
            for (i = 0; i < 1000; i++)
                result += cb(i);
            //printf("result = %d\n", result);
            return result;
        }
        int call2(int(__stdcall *cb)(int)) {
            int i, result = 0;
            //printf("call2: cb = %p\n", cb);
            for (i = 0; i < 1000; i++)
                result += cb(-i);
            //printf("result = %d\n", result);
            return result;
        }
    """)
    @ffi.callback("int(int)")
    def cb1(x):
        return x * 2
    @ffi.callback("int __stdcall(int)")
    def cb2(x):
        return x * 3
    res = lib.call1(cb1)
    assert res == 500*999*2
    assert res == ffi.addressof(lib, 'call1')(cb1)
    res = lib.call2(cb2)
    assert res == -500*999*3
    assert res == ffi.addressof(lib, 'call2')(cb2)
    if sys.platform == 'win32' and not sys.maxsize > 2**32:
        assert '__stdcall' in str(ffi.typeof(cb2))
        assert '__stdcall' not in str(ffi.typeof(cb1))
        pytest.raises(TypeError, lib.call1, cb2)
        pytest.raises(TypeError, lib.call2, cb1)
    else:
        assert '__stdcall' not in str(ffi.typeof(cb2))
        assert ffi.typeof(cb2) is ffi.typeof(cb1)

def test_win32_calling_convention_1():
    ffi = FFI()
    ffi.cdef("""
        int __cdecl   call1(int(__cdecl   *cb)(int));
        int __stdcall call2(int(__stdcall *cb)(int));
        int (__cdecl   *const cb1)(int);
        int (__stdcall *const cb2)(int);
    """)
    lib = verify(ffi, 'test_win32_calling_convention_1', r"""
        #ifndef _MSC_VER
        #  define __cdecl
        #  define __stdcall
        #endif
        int __cdecl   cb1(int x) { return x * 2; }
        int __stdcall cb2(int x) { return x * 3; }

        int __cdecl call1(int(__cdecl *cb)(int)) {
            int i, result = 0;
            //printf("here1\n");
            //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
            for (i = 0; i < 1000; i++)
                result += cb(i);
            //printf("result = %d\n", result);
            return result;
        }
        int __stdcall call2(int(__stdcall *cb)(int)) {
            int i, result = 0;
            //printf("here1\n");
            //printf("cb = %p, cb2 = %p\n", cb, (void *)cb2);
            for (i = 0; i < 1000; i++)
                result += cb(-i);
            //printf("result = %d\n", result);
            return result;
        }
    """)
    #print '<<< cb1 =', ffi.addressof(lib, 'cb1')
    ptr_call1 = ffi.addressof(lib, 'call1')
    assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2
    assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2
    #print '<<< cb2 =', ffi.addressof(lib, 'cb2')
    ptr_call2 = ffi.addressof(lib, 'call2')
    assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3
    assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3
    #print '<<< done'

def test_win32_calling_convention_2():
    # any mistake in the declaration of plain function (including the
    # precise argument types and, here, the calling convention) are
    # automatically corrected.  But this does not apply to the 'cb'
    # function pointer argument.
    ffi = FFI()
    ffi.cdef("""
        int __stdcall call1(int(__cdecl   *cb)(int));
        int __cdecl   call2(int(__stdcall *cb)(int));
        int (__cdecl   *const cb1)(int);
        int (__stdcall *const cb2)(int);
    """)
    lib = verify(ffi, 'test_win32_calling_convention_2', """
        #ifndef _MSC_VER
        #  define __cdecl
        #  define __stdcall
        #endif
        int __cdecl call1(int(__cdecl *cb)(int)) {
            int i, result = 0;
            for (i = 0; i < 1000; i++)
                result += cb(i);
            return result;
        }
        int __stdcall call2(int(__stdcall *cb)(int)) {
            int i, result = 0;
            for (i = 0; i < 1000; i++)
                result += cb(-i);
            return result;
        }
        int __cdecl   cb1(int x) { return x * 2; }
        int __stdcall cb2(int x) { return x * 3; }
    """)
    ptr_call1 = ffi.addressof(lib, 'call1')
    ptr_call2 = ffi.addressof(lib, 'call2')
    if sys.platform == 'win32' and not sys.maxsize > 2**32:
        pytest.raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2'))
        pytest.raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2'))
        pytest.raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1'))
        pytest.raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1'))
    assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2
    assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2
    assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3
    assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3

def test_win32_calling_convention_3():
    ffi = FFI()
    ffi.cdef("""
        struct point { int x, y; };

        int (*const cb1)(struct point);
        int (__stdcall *const cb2)(struct point);

        struct point __stdcall call1(int(*cb)(struct point));
        struct point call2(int(__stdcall *cb)(struct point));
    """)
    lib = verify(ffi, 'test_win32_calling_convention_3', r"""
        #ifndef _MSC_VER
        #  define __cdecl
        #  define __stdcall
        #endif
        struct point { int x, y; };
        int           cb1(struct point pt) { return pt.x + 10 * pt.y; }
        int __stdcall cb2(struct point pt) { return pt.x + 100 * pt.y; }
        struct point __stdcall call1(int(__cdecl *cb)(struct point)) {
            int i;
            struct point result = { 0, 0 };
            //printf("here1\n");
            //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1);
            for (i = 0; i < 1000; i++) {
                struct point p = { i, -i };
                int r = cb(p);
                result.x += r;
                result.y -= r;
            }
            return result;
        }
        struct point __cdecl call2(int(__stdcall *cb)(struct point)) {
            int i;
            struct point result = { 0, 0 };
            for (i = 0; i < 1000; i++) {
                struct point p = { -i, i };
                int r = cb(p);
                result.x += r;
                result.y -= r;
            }
            return result;
        }
    """)
    ptr_call1 = ffi.addressof(lib, 'call1')
    ptr_call2 = ffi.addressof(lib, 'call2')
    if sys.platform == 'win32' and not sys.maxsize > 2**32:
        pytest.raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2'))
        pytest.raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2'))
        pytest.raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1'))
        pytest.raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1'))
    pt = lib.call1(ffi.addressof(lib, 'cb1'))
    assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
    pt = ptr_call1(ffi.addressof(lib, 'cb1'))
    assert (pt.x, pt.y) == (-9*500*999, 9*500*999)
    pt = lib.call2(ffi.addressof(lib, 'cb2'))
    assert (pt.x, pt.y) == (99*500*999, -99*500*999)
    pt = ptr_call2(ffi.addressof(lib, 'cb2'))
    assert (pt.x, pt.y) == (99*500*999, -99*500*999)

def test_extern_python_1():
    import warnings
    ffi = FFI()
    with warnings.catch_warnings(record=True) as log:
        ffi.cdef("""
        extern "Python" {
            int bar(int, int);
            void baz(int, int);
            int bok(void);
            void boz(void);
        }
        """)
    assert len(log) == 0, "got a warning: %r" % (log,)
    lib = verify(ffi, 'test_extern_python_1', """
        static void baz(int, int);   /* forward */
    """)
    assert ffi.typeof(lib.bar) == ffi.typeof("int(*)(int, int)")
    with FdWriteCapture() as f:
        res = lib.bar(4, 5)
    assert res == 0
    assert f.getvalue() == (
        b"extern \"Python\": function _CFFI_test_extern_python_1.bar() called, "
        b"but no code was attached "
        b"to it yet with @ffi.def_extern().  Returning 0.\n")

    @ffi.def_extern("bar")
    def my_bar(x, y):
        seen.append(("Bar", x, y))
        return x * y
    assert my_bar != lib.bar
    seen = []
    res = lib.bar(6, 7)
    assert seen == [("Bar", 6, 7)]
    assert res == 42

    def baz(x, y):
        seen.append(("Baz", x, y))
    baz1 = ffi.def_extern()(baz)
    assert baz1 is baz
    seen = []
    baz(long(40), long(4))
    res = lib.baz(long(50), long(8))
    assert res is None
    assert seen == [("Baz", 40, 4), ("Baz", 50, 8)]
    assert type(seen[0][1]) is type(seen[0][2]) is long
    assert type(seen[1][1]) is type(seen[1][2]) is int

    @ffi.def_extern(name="bok")
    def bokk():
        seen.append("Bok")
        return 42
    seen = []
    assert lib.bok() == 42
    assert seen == ["Bok"]

    @ffi.def_extern()
    def boz():
        seen.append("Boz")
    seen = []
    assert lib.boz() is None
    assert seen == ["Boz"]

def test_extern_python_bogus_name():
    ffi = FFI()
    ffi.cdef("extern int abc;")
    lib = verify(ffi, 'test_extern_python_bogus_name', "int abc;")
    def fn():
        pass
    pytest.raises(ffi.error, ffi.def_extern("unknown_name"), fn)
    pytest.raises(ffi.error, ffi.def_extern("abc"), fn)
    assert lib.abc == 0
    e = pytest.raises(ffi.error, ffi.def_extern("abc"), fn)
    assert str(e.value) == ("ffi.def_extern('abc'): no 'extern \"Python\"' "
                            "function with this name")
    e = pytest.raises(ffi.error, ffi.def_extern(), fn)
    assert str(e.value) == ("ffi.def_extern('fn'): no 'extern \"Python\"' "
                            "function with this name")
    #
    pytest.raises(TypeError, ffi.def_extern(42), fn)
    pytest.raises((TypeError, AttributeError), ffi.def_extern(), "foo")
    class X:
        pass
    x = X()
    x.__name__ = x
    pytest.raises(TypeError, ffi.def_extern(), x)

def test_extern_python_bogus_result_type():
    ffi = FFI()
    ffi.cdef("""extern "Python" void bar(int);""")
    lib = verify(ffi, 'test_extern_python_bogus_result_type', "")
    #
    @ffi.def_extern()
    def bar(n):
        return n * 10
    with StdErrCapture() as f:
        res = lib.bar(321)
    assert res is None
    msg = f.getvalue()
    assert "rom cffi callback %r" % (bar,) in msg
    assert "rying to convert the result back to C:\n" in msg
    assert msg.endswith(
        "TypeError: callback with the return type 'void' must return None\n")

def test_extern_python_redefine():
    ffi = FFI()
    ffi.cdef("""extern "Python" int bar(int);""")
    lib = verify(ffi, 'test_extern_python_redefine', "")
    #
    @ffi.def_extern()
    def bar(n):
        return n * 10
    assert lib.bar(42) == 420
    #
    @ffi.def_extern()
    def bar(n):
        return -n
    assert lib.bar(42) == -42

def test_extern_python_struct():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { int a, b, c; };
        extern "Python" int bar(int, struct foo_s, int);
        extern "Python" { struct foo_s baz(int, int);
                          struct foo_s bok(void); }
    """)
    lib = verify(ffi, 'test_extern_python_struct',
                 "struct foo_s { int a, b, c; };")
    #
    @ffi.def_extern()
    def bar(x, s, z):
        return x + s.a + s.b + s.c + z
    res = lib.bar(1000, [1001, 1002, 1004], 1008)
    assert res == 5015
    #
    @ffi.def_extern()
    def baz(x, y):
        return [x + y, x - y, x * y]
    res = lib.baz(1000, 42)
    assert res.a == 1042
    assert res.b == 958
    assert res.c == 42000
    #
    @ffi.def_extern()
    def bok():
        return [10, 20, 30]
    res = lib.bok()
    assert [res.a, res.b, res.c] == [10, 20, 30]

def test_extern_python_long_double():
    ffi = FFI()
    ffi.cdef("""
        extern "Python" int bar(int, long double, int);
        extern "Python" long double baz(int, int);
        extern "Python" long double bok(void);
    """)
    lib = verify(ffi, 'test_extern_python_long_double', "")
    #
    @ffi.def_extern()
    def bar(x, l, z):
        seen.append((x, l, z))
        return 6
    seen = []
    lib.bar(10, 3.5, 20)
    expected = ffi.cast("long double", 3.5)
    assert repr(seen) == repr([(10, expected, 20)])
    #
    @ffi.def_extern()
    def baz(x, z):
        assert x == 10 and z == 20
        return expected
    res = lib.baz(10, 20)
    assert repr(res) == repr(expected)
    #
    @ffi.def_extern()
    def bok():
        return expected
    res = lib.bok()
    assert repr(res) == repr(expected)

def test_extern_python_signature():
    ffi = FFI()
    lib = verify(ffi, 'test_extern_python_signature', "")
    pytest.raises(TypeError, ffi.def_extern(425), None)
    pytest.raises(TypeError, ffi.def_extern, 'a', 'b', 'c', 'd')

def test_extern_python_errors():
    ffi = FFI()
    ffi.cdef("""
        extern "Python" int bar(int);
    """)
    lib = verify(ffi, 'test_extern_python_errors', "")

    seen = []
    def oops(*args):
        seen.append(args)

    @ffi.def_extern(onerror=oops)
    def bar(x):
        return x + ""
    assert lib.bar(10) == 0

    @ffi.def_extern(name="bar", onerror=oops, error=-66)
    def bar2(x):
        return x + ""
    assert lib.bar(10) == -66

    assert len(seen) == 2
    exc, val, tb = seen[0]
    assert exc is TypeError
    assert isinstance(val, TypeError)
    assert tb.tb_frame.f_code.co_name == "bar"
    exc, val, tb = seen[1]
    assert exc is TypeError
    assert isinstance(val, TypeError)
    assert tb.tb_frame.f_code.co_name == "bar2"
    #
    # a case where 'onerror' is not callable
    pytest.raises(TypeError, ffi.def_extern(name='bar', onerror=42),
                   lambda x: x)

def test_extern_python_stdcall():
    ffi = FFI()
    ffi.cdef("""
        extern "Python" int __stdcall foo(int);
        extern "Python" int WINAPI bar(int);
        static int (__stdcall * mycb1)(int);
        static int indirect_call(int);
    """)
    lib = verify(ffi, 'test_extern_python_stdcall', """
        #ifndef _MSC_VER
        #  define __stdcall
        #endif
        static int (__stdcall * mycb1)(int);
        static int indirect_call(int x) {
            return mycb1(x);
        }
    """)
    #
    @ffi.def_extern()
    def foo(x):
        return x + 42
    @ffi.def_extern()
    def bar(x):
        return x + 43
    assert lib.foo(100) == 142
    assert lib.bar(100) == 143
    lib.mycb1 = lib.foo
    assert lib.mycb1(200) == 242
    assert lib.indirect_call(300) == 342

def test_extern_python_plus_c():
    ffi = FFI()
    ffi.cdef("""
        extern "Python+C" int foo(int);
        extern "C +\tPython" int bar(int);
        int call_me(int);
    """)
    lib = verify(ffi, 'test_extern_python_plus_c', """
        int foo(int);
        #ifdef __GNUC__
        __attribute__((visibility("hidden")))
        #endif
        int bar(int);

        static int call_me(int x) {
            return foo(x) - bar(x);
        }
    """)
    #
    @ffi.def_extern()
    def foo(x):
        return x * 42
    @ffi.def_extern()
    def bar(x):
        return x * 63
    assert lib.foo(100) == 4200
    assert lib.bar(100) == 6300
    assert lib.call_me(100) == -2100

def test_introspect_function():
    ffi = FFI()
    ffi.cdef("float f1(double);")
    lib = verify(ffi, 'test_introspect_function', """
        float f1(double x) { return (float)x; }
    """)
    assert dir(lib) == ['f1']
    FUNC = ffi.typeof(lib.f1)
    assert FUNC.kind == 'function'
    assert FUNC.args[0].cname == 'double'
    assert FUNC.result.cname == 'float'
    assert ffi.typeof(ffi.addressof(lib, 'f1')) is FUNC

def test_introspect_global_var():
    ffi = FFI()
    ffi.cdef("extern float g1;")
    lib = verify(ffi, 'test_introspect_global_var', """
        float g1;
    """)
    assert dir(lib) == ['g1']
    FLOATPTR = ffi.typeof(ffi.addressof(lib, 'g1'))
    assert FLOATPTR.kind == 'pointer'
    assert FLOATPTR.item.cname == 'float'

def test_introspect_global_var_array():
    ffi = FFI()
    ffi.cdef("extern float g1[100];")
    lib = verify(ffi, 'test_introspect_global_var_array', """
        float g1[100];
    """)
    assert dir(lib) == ['g1']
    FLOATARRAYPTR = ffi.typeof(ffi.addressof(lib, 'g1'))
    assert FLOATARRAYPTR.kind == 'pointer'
    assert FLOATARRAYPTR.item.kind == 'array'
    assert FLOATARRAYPTR.item.length == 100
    assert ffi.typeof(lib.g1) is FLOATARRAYPTR.item

def test_introspect_integer_const():
    ffi = FFI()
    ffi.cdef("#define FOO 42")
    lib = verify(ffi, 'test_introspect_integer_const', """
        #define FOO 42
    """)
    assert dir(lib) == ['FOO']
    assert lib.FOO == ffi.integer_const('FOO') == 42

def test_introspect_typedef():
    ffi = FFI()
    ffi.cdef("typedef int foo_t;")
    lib = verify(ffi, 'test_introspect_typedef', """
        typedef int foo_t;
    """)
    assert ffi.list_types() == (['foo_t'], [], [])
    assert ffi.typeof('foo_t').kind == 'primitive'
    assert ffi.typeof('foo_t').cname == 'int'

def test_introspect_typedef_multiple():
    ffi = FFI()
    ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;")
    lib = verify(ffi, 'test_introspect_typedef_multiple', """
        typedef signed char a_t, c_t, g_t, b_t;
    """)
    assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'g_t'], [], [])

def test_introspect_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a; };")
    lib = verify(ffi, 'test_introspect_struct', """
        struct foo_s { int a; };
    """)
    assert ffi.list_types() == ([], ['foo_s'], [])
    assert ffi.typeof('struct foo_s').kind == 'struct'
    assert ffi.typeof('struct foo_s').cname == 'struct foo_s'

def test_introspect_union():
    ffi = FFI()
    ffi.cdef("union foo_s { int a; };")
    lib = verify(ffi, 'test_introspect_union', """
        union foo_s { int a; };
    """)
    assert ffi.list_types() == ([], [], ['foo_s'])
    assert ffi.typeof('union foo_s').kind == 'union'
    assert ffi.typeof('union foo_s').cname == 'union foo_s'

def test_introspect_struct_and_typedef():
    ffi = FFI()
    ffi.cdef("typedef struct { int a; } foo_t;")
    lib = verify(ffi, 'test_introspect_struct_and_typedef', """
        typedef struct { int a; } foo_t;
    """)
    assert ffi.list_types() == (['foo_t'], [], [])
    assert ffi.typeof('foo_t').kind == 'struct'
    assert ffi.typeof('foo_t').cname == 'foo_t'

def test_introspect_included_type():
    SOURCE = """
        typedef signed char schar_t;
        struct sint_t { int x; };
    """
    ffi1 = FFI()
    ffi1.cdef(SOURCE)
    ffi2 = FFI()
    ffi2.include(ffi1)
    verify(ffi1, "test_introspect_included_type_parent", SOURCE)
    verify(ffi2, "test_introspect_included_type", SOURCE)
    assert ffi1.list_types() == ffi2.list_types() == (
            ['schar_t'], ['sint_t'], [])

def test_introspect_order():
    ffi = FFI()
    ffi.cdef("union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;")
    ffi.cdef("union CFFIg   { int a; }; typedef struct CFFIcc  { int a; } CFFIbbb;")
    ffi.cdef("union CFFIaa  { int a; }; typedef struct CFFIa   { int a; } CFFIbb;")
    verify(ffi, "test_introspect_order", """
        union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;
        union CFFIg   { int a; }; typedef struct CFFIcc  { int a; } CFFIbbb;
        union CFFIaa  { int a; }; typedef struct CFFIa   { int a; } CFFIbb;
    """)
    assert ffi.list_types() == (['CFFIb', 'CFFIbb', 'CFFIbbb'],
                                ['CFFIa', 'CFFIcc', 'CFFIccc'],
                                ['CFFIaa', 'CFFIaaa', 'CFFIg'])

def test_bool_in_cpp():
    # this works when compiled as C, but in cffi < 1.7 it fails as C++
    ffi = FFI()
    ffi.cdef("bool f(void);")
    lib = verify(ffi, "test_bool_in_cpp", "char f(void) { return 2; }")
    assert lib.f() is True

def test_bool_in_cpp_2():
    ffi = FFI()
    ffi.cdef('int add(int a, int b);')
    lib = verify(ffi, "test_bool_bug_cpp", '''
        typedef bool _Bool;  /* there is a Windows header with this line */
        int add(int a, int b)
        {
            return a + b;
        }''', source_extension='.cpp')
    c = lib.add(2, 3)
    assert c == 5

def test_struct_field_opaque():
    ffi = FFI()
    ffi.cdef("struct a { struct b b; };")
    e = pytest.raises(TypeError, verify,
                       ffi, "test_struct_field_opaque", "?")
    assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
                            " type (not declared in cdef())")
    ffi = FFI()
    ffi.cdef("struct a { struct b b[2]; };")
    e = pytest.raises(TypeError, verify,
                       ffi, "test_struct_field_opaque", "?")
    assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
                            " type (not declared in cdef())")
    ffi = FFI()
    ffi.cdef("struct a { struct b b[]; };")
    e = pytest.raises(TypeError, verify,
                       ffi, "test_struct_field_opaque", "?")
    assert str(e.value) == ("struct a: field 'a.b' is of an opaque"
                            " type (not declared in cdef())")

def test_function_arg_opaque():
    pytest.skip("can currently declare a function with an opaque struct "
                 "as argument, but AFAICT it's impossible to call it later")

def test_function_returns_opaque():
    ffi = FFI()
    ffi.cdef("struct a foo(int);")
    e = pytest.raises(TypeError, verify,
                       ffi, "test_function_returns_opaque", "?")
    assert str(e.value) == ("function foo: 'struct a' is used as result type,"
                            " but is opaque")

def test_function_returns_union():
    ffi = FFI()
    ffi.cdef("union u1 { int a, b; }; union u1 f1(int);")
    lib = verify(ffi, "test_function_returns_union", """
        union u1 { int a, b; };
        static union u1 f1(int x) { union u1 u; u.b = x; return u; }
    """)
    assert lib.f1(51).a == 51

def test_function_returns_partial_struct():
    ffi = FFI()
    ffi.cdef("struct aaa { int a; ...; }; struct aaa f1(int);")
    lib = verify(ffi, "test_function_returns_partial_struct", """
        struct aaa { int b, a, c; };
        static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; }
    """)
    assert lib.f1(52).a == 52

def test_function_returns_float_complex():
    if sys.platform == 'win32':
        pytest.skip("MSVC may not support _Complex")
    ffi = FFI()
    ffi.cdef("float _Complex f1(float a, float b);");
    lib = verify(ffi, "test_function_returns_float_complex", """
        #include <complex.h>
        static float _Complex f1(float a, float b) { return a + I*2.0f*b; }
    """, no_cpp=True)    # <complex.h> fails on some systems with C++
    result = lib.f1(1.25, 5.1)
    assert type(result) == complex
    assert result.real == 1.25   # exact
    assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact

def test_function_returns_double_complex():
    if sys.platform == 'win32':
        pytest.skip("MSVC may not support _Complex")
    ffi = FFI()
    ffi.cdef("double _Complex f1(double a, double b);");
    lib = verify(ffi, "test_function_returns_double_complex", """
        #include <complex.h>
        static double _Complex f1(double a, double b) { return a + I*2.0*b; }
    """, no_cpp=True)    # <complex.h> fails on some systems with C++
    result = lib.f1(1.25, 5.1)
    assert type(result) == complex
    assert result.real == 1.25   # exact
    assert result.imag == 2*5.1  # exact

def test_function_argument_float_complex():
    if sys.platform == 'win32':
        pytest.skip("MSVC may not support _Complex")
    ffi = FFI()
    ffi.cdef("float f1(float _Complex x);");
    lib = verify(ffi, "test_function_argument_float_complex", """
        #include <complex.h>
        static float f1(float _Complex x) { return cabsf(x); }
    """, no_cpp=True)    # <complex.h> fails on some systems with C++
    x = complex(12.34, 56.78)
    result = lib.f1(x)
    assert abs(result - abs(x)) < 1e-5

def test_function_argument_double_complex():
    if sys.platform == 'win32':
        pytest.skip("MSVC may not support _Complex")
    ffi = FFI()
    ffi.cdef("double f1(double _Complex);");
    lib = verify(ffi, "test_function_argument_double_complex", """
        #include <complex.h>
        static double f1(double _Complex x) { return cabs(x); }
    """, no_cpp=True)    # <complex.h> fails on some systems with C++
    x = complex(12.34, 56.78)
    result = lib.f1(x)
    assert abs(result - abs(x)) < 1e-11

def test_typedef_array_dotdotdot():
    ffi = FFI()
    ffi.cdef("""
        typedef int foo_t[...], bar_t[...];
        extern int gv[...];
        typedef int mat_t[...][...];
        typedef int vmat_t[][...];
        """)
    lib = verify(ffi, "test_typedef_array_dotdotdot", """
        typedef int foo_t[50], bar_t[50];
        int gv[23];
        typedef int mat_t[6][7];
        typedef int vmat_t[][8];
    """)
    assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int")
    assert ffi.sizeof("bar_t") == 50 * ffi.sizeof("int")
    assert len(ffi.new("foo_t")) == 50
    assert len(ffi.new("bar_t")) == 50
    assert ffi.sizeof(lib.gv) == 23 * ffi.sizeof("int")
    assert ffi.sizeof("mat_t") == 6 * 7 * ffi.sizeof("int")
    assert len(ffi.new("mat_t")) == 6
    assert len(ffi.new("mat_t")[3]) == 7
    pytest.raises(ffi.error, ffi.sizeof, "vmat_t")
    p = ffi.new("vmat_t", 4)
    assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int")

def test_typedef_array_dotdotdot_usage():
    ffi = FFI()
    ffi.cdef("""
        typedef int foo_t[...];
        typedef int mat_t[...][...];
        struct s { foo_t a; foo_t *b; foo_t **c; };
        int myfunc(foo_t a, foo_t *b, foo_t **c);
        struct sm { mat_t a; mat_t *b; mat_t **c; };
        int myfuncm(mat_t a, mat_t *b, mat_t **c);
        """)
    lib = verify(ffi, "test_typedef_array_dotdotdot_usage", """
        typedef int foo_t[50];
        typedef int mat_t[6][7];
        struct s { foo_t a; foo_t *b; foo_t **c; };
        static int myfunc(foo_t a, foo_t *b, foo_t **c) { return (**c)[49]; }
        struct sm { mat_t a; mat_t *b; mat_t **c; };
        static int myfuncm(mat_t a, mat_t *b, mat_t **c) { return (**c)[5][6]; }
    """)
    assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int")
    p = ffi.new("struct s *")
    assert ffi.sizeof(p[0]) == 50 * ffi.sizeof("int") + 2 * ffi.sizeof("void *")
    p.a[49] = 321
    p.b = ffi.addressof(p, 'a')
    p.c = ffi.addressof(p, 'b')
    assert lib.myfunc(ffi.NULL, ffi.NULL, p.c) == 321
    #
    assert ffi.sizeof("mat_t") == 42 * ffi.sizeof("int")
    p = ffi.new("struct sm *")
    assert ffi.sizeof(p[0]) == 42 * ffi.sizeof("int") + 2 * ffi.sizeof("void *")
    p.a[5][6] = -321
    p.b = ffi.addressof(p, 'a')
    p.c = ffi.addressof(p, 'b')
    assert lib.myfuncm(ffi.NULL, ffi.NULL, p.c) == -321

def test_call_with_custom_field_pos():
    ffi = FFI()
    ffi.cdef("""
        struct foo { int x; ...; };
        struct foo f(void);
        struct foo g(int, ...);
    """)
    lib = verify(ffi, "test_call_with_custom_field_pos", """
        struct foo { int y, x; };
        struct foo f(void) {
            struct foo s = { 40, 200 };
            return s;
        }
        struct foo g(int a, ...) { return f(); }
    """)
    assert lib.f().x == 200
    e = pytest.raises(NotImplementedError, lib.g, 0)
    assert str(e.value) == (
        'ctype \'struct foo\' not supported as return value.  It is a '
        'struct declared with "...;", but the C calling convention may '
        'depend on the missing fields; or, it contains anonymous '
        'struct/unions.  Such structs are only supported '
        'as return value if the function is \'API mode\' and non-variadic '
        '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
        'and not taking a final \'...\' argument)')

def test_call_with_nested_anonymous_struct():
    if sys.platform == 'win32':
        pytest.skip("needs a GCC extension")
    ffi = FFI()
    ffi.cdef("""
        struct foo { int a; union { int b, c; }; };
        struct foo f(void);
        struct foo g(int, ...);
    """)
    lib = verify(ffi, "test_call_with_nested_anonymous_struct", """
        struct foo { int a; union { int b, c; }; };
        struct foo f(void) {
            struct foo s;
            s.a = 40;
            s.b = 200;
            return s;
        }
        struct foo g(int a, ...) { return f(); }
    """)
    assert lib.f().b == 200
    e = pytest.raises(NotImplementedError, lib.g, 0)
    assert str(e.value) == (
        'ctype \'struct foo\' not supported as return value.  It is a '
        'struct declared with "...;", but the C calling convention may '
        'depend on the missing fields; or, it contains anonymous '
        'struct/unions.  Such structs are only supported '
        'as return value if the function is \'API mode\' and non-variadic '
        '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() '
        'and not taking a final \'...\' argument)')

def test_call_with_bitfield():
    ffi = FFI()
    ffi.cdef("""
        struct foo { int x:5; };
        struct foo f(void);
        struct foo g(int, ...);
    """)
    lib = verify(ffi, "test_call_with_bitfield", """
        struct foo { int x:5; };
        struct foo f(void) {
            struct foo s = { 11 };
            return s;
        }
        struct foo g(int a, ...) { return f(); }
    """)
    assert lib.f().x == 11
    e = pytest.raises(NotImplementedError, lib.g, 0)
    assert str(e.value) == (
        "ctype 'struct foo' not supported as return value.  It is a struct "
        "with bit fields, which libffi does not support.  Such structs are "
        "only supported as return value if the function is 'API mode' and "
        "non-variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
        "set_source() and not taking a final '...' argument)")

def test_call_with_zero_length_field():
    if sys.platform == 'win32':
        pytest.skip("zero-length field not supported by MSVC")
    ffi = FFI()
    ffi.cdef("""
        struct foo { int a; int x[0]; };
        struct foo f(void);
        struct foo g(int, ...);
    """)
    lib = verify(ffi, "test_call_with_zero_length_field", """
        struct foo { int a; int x[0]; };
        struct foo f(void) {
            struct foo s = { 42 };
            return s;
        }
        struct foo g(int a, ...) { return f(); }
    """)
    assert lib.f().a == 42
    e = pytest.raises(NotImplementedError, lib.g, 0)
    assert str(e.value) == (
        "ctype 'struct foo' not supported as return value.  It is a "
        "struct with a zero-length array, which libffi does not support."
        "  Such structs are only supported as return value if the function is "
        "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
        "+ffibuilder.set_source() and not taking a final '...' argument)")

def test_call_with_union():
    ffi = FFI()
    ffi.cdef("""
        union foo { int a; char b; };
        union foo f(void);
        union foo g(int, ...);
    """)
    lib = verify(ffi, "test_call_with_union", """
        union foo { int a; char b; };
        union foo f(void) {
            union foo s = { 42 };
            return s;
        }
        union foo g(int a, ...) { return f(); }
    """)
    assert lib.f().a == 42
    e = pytest.raises(NotImplementedError, lib.g, 0)
    assert str(e.value) == (
        "ctype 'union foo' not supported as return value by libffi.  "
        "Unions are only supported as return value if the function is "
        "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
        "+ffibuilder.set_source() and not taking a final '...' argument)")

def test_call_with_packed_struct():
    if sys.platform == 'win32':
        pytest.skip("needs a GCC extension")
    ffi = FFI()
    ffi.cdef("""
        struct foo { char y; int x; };
        struct foo f(void);
        struct foo g(int, ...);
    """, packed=True)
    lib = verify(ffi, "test_call_with_packed_struct", """
        struct foo { char y; int x; } __attribute__((packed));
        struct foo f(void) {
            struct foo s = { 40, 200 };
            return s;
        }
        struct foo g(int a, ...) {
            struct foo s = { 41, 201 };
            return s;
        }
    """)
    assert ord(lib.f().y) == 40
    assert lib.f().x == 200
    e = pytest.raises(NotImplementedError, lib.g, 0)
    assert str(e.value) == (
        "ctype 'struct foo' not supported as return value.  It is a "
        "'packed' structure, with a different layout than expected by libffi."
        "  Such structs are only supported as return value if the function is "
        "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()"
        "+ffibuilder.set_source() and not taking a final '...' argument)")

def test_pack_not_supported():
    ffi = FFI()
    ffi.cdef("""struct foo { char y; int x; };""", pack=2)
    pytest.raises(NotImplementedError, verify,
                   ffi, "test_pack_not_supported", "")

def test_gcc_visibility_hidden():
    if sys.platform == 'win32':
        pytest.skip("test for gcc/clang")
    ffi = FFI()
    ffi.cdef("""
    int f(int);
    """)
    lib = verify(ffi, "test_gcc_visibility_hidden", """
    int f(int a) { return a + 40; }
    """, extra_compile_args=['-fvisibility=hidden'])
    assert lib.f(2) == 42

def test_override_default_definition():
    ffi = FFI()
    ffi.cdef("typedef long int16_t, char16_t;")
    lib = verify(ffi, "test_override_default_definition", "")
    assert ffi.typeof("int16_t") is ffi.typeof("char16_t") is ffi.typeof("long")

def test_char16_char32_type(no_cpp=False):
    if no_cpp is False and sys.platform == "win32":
        pytest.skip("aaaaaaa why do modern MSVC compilers still define "
                     "a very old __cplusplus value")
    ffi = FFI()
    ffi.cdef("""
        char16_t foo_2bytes(char16_t);
        char32_t foo_4bytes(char32_t);
    """)
    lib = verify(ffi, "test_char16_char32_type" + no_cpp * "_nocpp", """
    #if !defined(__cplusplus) || (!defined(_LIBCPP_VERSION) && __cplusplus < 201103L)
    typedef uint_least16_t char16_t;
    typedef uint_least32_t char32_t;
    #endif

    char16_t foo_2bytes(char16_t a) { return (char16_t)(a + 42); }
    char32_t foo_4bytes(char32_t a) { return (char32_t)(a + 42); }
    """, no_cpp=no_cpp)
    assert lib.foo_2bytes(u+'\u1234') == u+'\u125e'
    assert lib.foo_4bytes(u+'\u1234') == u+'\u125e'
    assert lib.foo_4bytes(u+'\U00012345') == u+'\U0001236f'
    pytest.raises(TypeError, lib.foo_2bytes, u+'\U00012345')
    pytest.raises(TypeError, lib.foo_2bytes, 1234)
    pytest.raises(TypeError, lib.foo_4bytes, 1234)

def test_char16_char32_plain_c():
    test_char16_char32_type(no_cpp=True)

def test_loader_spec():
    ffi = FFI()
    lib = verify(ffi, "test_loader_spec", "")
    if sys.version_info < (3,):
        assert not hasattr(lib, '__loader__')
        assert not hasattr(lib, '__spec__')
    else:
        assert lib.__loader__ is None
        assert lib.__spec__ is None

def test_realize_struct_error():
    ffi = FFI()
    ffi.cdef("""typedef ... foo_t; struct foo_s { void (*x)(foo_t); };""")
    lib = verify(ffi, "test_realize_struct_error", """
        typedef int foo_t; struct foo_s { void (*x)(foo_t); };
    """)
    pytest.raises(TypeError, ffi.new, "struct foo_s *")

def test_from_buffer_struct():
    ffi = FFI()
    ffi.cdef("""struct foo_s { int a, b; };""")
    lib = verify(ffi, "test_from_buffer_struct_p", """
        struct foo_s { int a, b; };
    """)
    p = ffi.new("struct foo_s *", [-219239, 58974983])
    q = ffi.from_buffer("struct foo_s[]", ffi.buffer(p))
    assert ffi.typeof(q) == ffi.typeof("struct foo_s[]")
    assert len(q) == 1
    assert q[0].a == p.a
    assert q[0].b == p.b
    assert q == p
    q = ffi.from_buffer("struct foo_s *", ffi.buffer(p))
    assert ffi.typeof(q) == ffi.typeof("struct foo_s *")
    assert q.a == p.a
    assert q.b == p.b
    assert q[0].a == p.a
    assert q[0].b == p.b
    assert q == p

def test_unnamed_bitfield_1():
    ffi = FFI()
    ffi.cdef("""struct A { char : 1; };""")
    lib = verify(ffi, "test_unnamed_bitfield_1", """
        struct A { char : 1; };
    """)
    p = ffi.new("struct A *")
    assert ffi.sizeof(p[0]) == 1
    # Note: on gcc, the type name is ignored for anonymous bitfields
    # and that's why the result is 1.  On MSVC, the result is
    # sizeof("char") which is also 1.

def test_unnamed_bitfield_2():
    ffi = FFI()
    ffi.cdef("""struct A {
        short c : 1; short : 1; short d : 1; short : 1; };""")
    lib = verify(ffi, "test_unnamed_bitfield_2", """
        struct A {
            short c : 1; short : 1; short d : 1; short : 1;
        };
    """)
    p = ffi.new("struct A *")
    assert ffi.sizeof(p[0]) == ffi.sizeof("short")

def test_unnamed_bitfield_3():
    ffi = FFI()
    ffi.cdef("""struct A { struct { char : 1; char : 1; } b; };""")
    lib = verify(ffi, "test_unnamed_bitfield_3", """
        struct A { struct { char : 1; char : 1; } b; };
    """)
    p = ffi.new("struct A *")
    assert ffi.sizeof(p[0]) == 1
    # Note: on gcc, the type name is ignored for anonymous bitfields
    # and that's why the result is 1.  On MSVC, the result is
    # sizeof("char") which is also 1.

def test_unnamed_bitfield_4():
    ffi = FFI()
    ffi.cdef("""struct A { struct {
        unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a;
        };
        struct B { struct A a; };""")
    lib = verify(ffi, "test_unnamed_bitfield_4", """
        struct A { struct {
            unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a;
        };
        struct B { struct A a; };
    """)
    b = ffi.new("struct B *")
    a = ffi.new("struct A *")
    assert ffi.sizeof(a[0]) == ffi.sizeof("unsigned")
    assert ffi.sizeof(b[0]) == ffi.sizeof(a[0])

def test_struct_with_func_with_struct_pointer_arg():
    ffi = FFI()
    ffi.cdef("""struct BinaryTree {
            int (* CompareKey)(struct BinaryTree *tree);
        };""")
    lib = verify(ffi, "test_struct_with_func_with_struct_pointer_arg", """
        struct BinaryTree {
            int (* CompareKey)(struct BinaryTree *tree);
        };
    """)
    ffi.new("struct BinaryTree *")

def test_struct_with_func_with_struct_arg():
    ffi = FFI()
    ffi.cdef("""struct BinaryTree {
            int (* CompareKey)(struct BinaryTree tree);
        };""")
    lib = verify(ffi, "test_struct_with_func_with_struct_arg", """
        struct BinaryTree {
            int (* CompareKey)(struct BinaryTree tree);
        };
    """)
    pytest.raises(RuntimeError, ffi.new, "struct BinaryTree *")

def test_passing_large_list():
    ffi = FFI()
    ffi.cdef("""void passing_large_list(long[]);""")
    lib = verify(ffi, "test_passing_large_list", """
        static void passing_large_list(long a[]) { }
    """)
    arg = list(range(20000000))
    lib.passing_large_list(arg)
    # assert did not segfault

testing/cffi1/test_recompiler.py
python-cffi/cffi
import os, sys, math
import pytest
from cffi import FFI, FFIError, VerificationError, VerificationMissing, model
from cffi import CDefError
from cffi import recompiler
from testing.support import *
from testing.support import _verify, extra_compile_args, is_musl
import _cffi_backend

lib_m = ['m']
if sys.platform == 'win32':
    #there is a small chance this fails on Mingw via environ $CC
    import distutils.ccompiler
    if distutils.ccompiler.get_default_compiler() == 'msvc':
        lib_m = ['msvcrt']

class FFI(FFI):
    error = _cffi_backend.FFI.error
    _extra_compile_args = extra_compile_args
    _verify_counter = 0

    def verify(self, preamble='', *args, **kwds):
        # HACK to reuse the tests from ../cffi0/test_verify.py
        FFI._verify_counter += 1
        module_name = 'verify%d' % FFI._verify_counter
        try:
            del self._assigned_source
        except AttributeError:
            pass
        self.set_source(module_name, preamble)
        return _verify(self, module_name, preamble, *args,
                       extra_compile_args=self._extra_compile_args, **kwds)

class FFI_warnings_not_error(FFI):
    _extra_compile_args = []


def test_missing_function(ffi=None):
    # uses the FFI hacked above with '-Werror'
    if ffi is None:
        ffi = FFI()
    ffi.cdef("void some_completely_unknown_function();")
    try:
        lib = ffi.verify()
    except (VerificationError, OSError, ImportError):
        pass     # expected case: we get a VerificationError
    else:
        # but depending on compiler and loader details, maybe
        # 'lib' could actually be imported but will fail if we
        # actually try to call the unknown function...  Hard
        # to test anything more.
        pass

def test_missing_function_import_error():
    # uses the original FFI that just gives a warning during compilation
    test_missing_function(ffi=FFI_warnings_not_error())

def test_simple_case():
    ffi = FFI()
    ffi.cdef("double sin(double x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    assert lib.sin(1.23) == math.sin(1.23)

def _Wconversion(cdef, source, **kargs):
    if sys.platform in ('win32', 'darwin'):
        pytest.skip("needs GCC")
    if '-Wno-error=sign-conversion' in extra_compile_args:
        pytest.skip("gcc 9.2.0 compiler bug exposed by Python 3.12+ prevents compilation with sign-conversion warnings-as-errors")
    ffi = FFI()
    ffi.cdef(cdef)
    pytest.raises(VerificationError, ffi.verify, source, **kargs)
    extra_compile_args_orig = extra_compile_args[:]
    extra_compile_args.remove('-Wconversion')
    try:
        lib = ffi.verify(source, **kargs)
    finally:
        extra_compile_args[:] = extra_compile_args_orig
    return lib

def test_Wconversion_unsigned():
    _Wconversion("unsigned foo(void);",
                 "int foo(void) { return -1;}")

def test_Wconversion_integer():
    _Wconversion("short foo(void);",
                 "long long foo(void) { return 1<<sizeof(short);}")

def test_Wconversion_floating():
    lib = _Wconversion("float sin(double);",
                       "#include <math.h>", libraries=lib_m)
    res = lib.sin(1.23)
    assert res != math.sin(1.23)     # not exact, because of double->float
    assert abs(res - math.sin(1.23)) < 1E-5

def test_Wconversion_float2int():
    _Wconversion("int sinf(float);",
                 "#include <math.h>", libraries=lib_m)

def test_Wconversion_double2int():
    _Wconversion("int sin(double);",
                 "#include <math.h>", libraries=lib_m)

def test_rounding_1():
    ffi = FFI()
    ffi.cdef("double sinf(float x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    res = lib.sinf(1.23)
    assert res != math.sin(1.23)     # not exact, because of double->float
    assert abs(res - math.sin(1.23)) < 1E-5

def test_rounding_2():
    ffi = FFI()
    ffi.cdef("double sin(float x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    res = lib.sin(1.23)
    assert res != math.sin(1.23)     # not exact, because of double->float
    assert abs(res - math.sin(1.23)) < 1E-5

def test_strlen_exact():
    ffi = FFI()
    ffi.cdef("size_t strlen(const char *s);")
    lib = ffi.verify("#include <string.h>")
    assert lib.strlen(b"hi there!") == 9

def test_strlen_approximate():
    lib = _Wconversion("int strlen(char *s);",
                       "#include <string.h>")
    assert lib.strlen(b"hi there!") == 9

def test_return_approximate():
    for typename in ['short', 'int', 'long', 'long long']:
        ffi = FFI()
        ffi.cdef("%s foo(signed char x);" % typename)
        lib = ffi.verify("signed char foo(signed char x) { return x;}")
        assert lib.foo(-128) == -128
        assert lib.foo(+127) == +127

def test_strlen_array_of_char():
    ffi = FFI()
    ffi.cdef("size_t strlen(char[]);")
    lib = ffi.verify("#include <string.h>")
    assert lib.strlen(b"hello") == 5

def test_longdouble():
    ffi = FFI()
    ffi.cdef("long double sinl(long double x);")
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    for input in [1.23,
                  ffi.cast("double", 1.23),
                  ffi.cast("long double", 1.23)]:
        x = lib.sinl(input)
        assert repr(x).startswith("<cdata 'long double'")
        assert (float(x) - math.sin(1.23)) < 1E-10

def test_longdouble_precision():
    # Test that we don't loose any precision of 'long double' when
    # passing through Python and CFFI.
    ffi = FFI()
    ffi.cdef("long double step1(long double x);")
    SAME_SIZE = ffi.sizeof("long double") == ffi.sizeof("double")
    lib = ffi.verify("""
        long double step1(long double x)
        {
            return 4*x-x*x;
        }
    """)
    def do(cast_to_double):
        x = 0.9789
        for i in range(10000):
            x = lib.step1(x)
            if cast_to_double:
                x = float(x)
        return float(x)

    more_precise = do(False)
    less_precise = do(True)
    if SAME_SIZE:
        assert more_precise == less_precise
    else:
        assert abs(more_precise - less_precise) > 0.1
        # Check the particular results on Intel
        import platform
        if (platform.machine().startswith('i386') or
            platform.machine().startswith('i486') or
            platform.machine().startswith('i586') or
            platform.machine().startswith('i686') or
            platform.machine().startswith('x86')):
            assert abs(more_precise - 0.656769) < 0.001
            assert abs(less_precise - 3.99091) < 0.001
        else:
            pytest.skip("don't know the very exact precision of 'long double'")


all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
if sys.platform == 'win32':
    all_primitive_types = all_primitive_types.copy()
    del all_primitive_types['ssize_t']
all_integer_types = sorted(tp for tp in all_primitive_types
                           if all_primitive_types[tp] == 'i')
all_float_types = sorted(tp for tp in all_primitive_types
                            if all_primitive_types[tp] == 'f')

def all_signed_integer_types(ffi):
    return [x for x in all_integer_types if int(ffi.cast(x, -1)) < 0]

def all_unsigned_integer_types(ffi):
    return [x for x in all_integer_types if int(ffi.cast(x, -1)) > 0]


def test_primitive_category():
    for typename in all_primitive_types:
        tp = model.PrimitiveType(typename)
        C = tp.is_char_type()
        F = tp.is_float_type()
        X = tp.is_complex_type()
        I = tp.is_integer_type()
        assert C == (typename in ('char', 'wchar_t', 'char16_t', 'char32_t'))
        assert F == (typename in ('float', 'double', 'long double'))
        assert X == (typename in ('float _Complex', 'double _Complex'))
        assert I + F + C + X == 1      # one and only one of them is true

def test_all_integer_and_float_types():
    typenames = []
    for typename in all_primitive_types:
        if (all_primitive_types[typename] == 'c' or
            all_primitive_types[typename] == 'j' or    # complex
            typename == '_Bool' or typename == 'long double'):
            pass
        else:
            typenames.append(typename)
    #
    ffi = FFI()
    ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                       for tp in typenames]))
    lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return (%s)(x+1); }" %
                                (tp, tp.replace(' ', '_'), tp, tp)
                                for tp in typenames]))
    for typename in typenames:
        foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_'))
        assert foo(42) == 43
        if sys.version < '3':
            assert foo(long(44)) == 45
        assert foo(ffi.cast(typename, 46)) == 47
        pytest.raises(TypeError, foo, ffi.NULL)
        #
        # check for overflow cases
        if all_primitive_types[typename] == 'f':
            continue
        for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1,
                      2**5, 2**10, 2**20, 2**40, 2**80]:
            overflows = int(ffi.cast(typename, value)) != value
            if overflows:
                pytest.raises(OverflowError, foo, value)
            else:
                assert foo(value) == value + 1

def test_var_signed_integer_types():
    ffi = FFI()
    lst = all_signed_integer_types(ffi)
    csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
                         for tp in lst])
    ffi.cdef(csource)
    lib = ffi.verify(csource)
    for tp in lst:
        varname = 'somevar_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        max = (1 << (8*sz-1)) - 1
        min = -(1 << (8*sz-1))
        setattr(lib, varname, max)
        assert getattr(lib, varname) == max
        setattr(lib, varname, min)
        assert getattr(lib, varname) == min
        pytest.raises(OverflowError, setattr, lib, varname, max+1)
        pytest.raises(OverflowError, setattr, lib, varname, min-1)

def test_var_unsigned_integer_types():
    ffi = FFI()
    lst = all_unsigned_integer_types(ffi)
    csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
                         for tp in lst])
    ffi.cdef(csource)
    lib = ffi.verify(csource)
    for tp in lst:
        varname = 'somevar_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        if tp != '_Bool':
            max = (1 << (8*sz)) - 1
        else:
            max = 1
        setattr(lib, varname, max)
        assert getattr(lib, varname) == max
        setattr(lib, varname, 0)
        assert getattr(lib, varname) == 0
        pytest.raises(OverflowError, setattr, lib, varname, max+1)
        pytest.raises(OverflowError, setattr, lib, varname, -1)

def test_fn_signed_integer_types():
    ffi = FFI()
    lst = all_signed_integer_types(ffi)
    cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                         for tp in lst])
    ffi.cdef(cdefsrc)
    verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
                           (tp, tp.replace(' ', '_'), tp) for tp in lst])
    lib = ffi.verify(verifysrc)
    for tp in lst:
        fnname = 'somefn_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        max = (1 << (8*sz-1)) - 1
        min = -(1 << (8*sz-1))
        fn = getattr(lib, fnname)
        assert fn(max) == max
        assert fn(min) == min
        pytest.raises(OverflowError, fn, max + 1)
        pytest.raises(OverflowError, fn, min - 1)

def test_fn_unsigned_integer_types():
    ffi = FFI()
    lst = all_unsigned_integer_types(ffi)
    cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
                         for tp in lst])
    ffi.cdef(cdefsrc)
    verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
                           (tp, tp.replace(' ', '_'), tp) for tp in lst])
    lib = ffi.verify(verifysrc)
    for tp in lst:
        fnname = 'somefn_%s' % tp.replace(' ', '_')
        sz = ffi.sizeof(tp)
        if tp != '_Bool':
            max = (1 << (8*sz)) - 1
        else:
            max = 1
        fn = getattr(lib, fnname)
        assert fn(max) == max
        assert fn(0) == 0
        pytest.raises(OverflowError, fn, max + 1)
        pytest.raises(OverflowError, fn, -1)

def test_char_type():
    ffi = FFI()
    ffi.cdef("char foo(char);")
    lib = ffi.verify("char foo(char x) { return ++x; }")
    assert lib.foo(b"A") == b"B"
    pytest.raises(TypeError, lib.foo, b"bar")
    pytest.raises(TypeError, lib.foo, "bar")

def test_wchar_type():
    ffi = FFI()
    if ffi.sizeof('wchar_t') == 2:
        uniexample1 = u+'\u1234'
        uniexample2 = u+'\u1235'
    else:
        uniexample1 = u+'\U00012345'
        uniexample2 = u+'\U00012346'
    #
    ffi.cdef("wchar_t foo(wchar_t);")
    lib = ffi.verify("wchar_t foo(wchar_t x) { return x+1; }")
    assert lib.foo(uniexample1) == uniexample2

def test_no_argument():
    ffi = FFI()
    ffi.cdef("int foo(void);")
    lib = ffi.verify("int foo(void) { return 42; }")
    assert lib.foo() == 42

def test_two_arguments():
    ffi = FFI()
    ffi.cdef("int foo(int, int);")
    lib = ffi.verify("int foo(int a, int b) { return a - b; }")
    assert lib.foo(40, -2) == 42

def test_macro():
    ffi = FFI()
    ffi.cdef("int foo(int, int);")
    lib = ffi.verify("#define foo(a, b) ((a) * (b))")
    assert lib.foo(-6, -7) == 42

def test_ptr():
    ffi = FFI()
    ffi.cdef("int *foo(int *);")
    lib = ffi.verify("int *foo(int *a) { return a; }")
    assert lib.foo(ffi.NULL) == ffi.NULL
    p = ffi.new("int *", 42)
    q = ffi.new("int *", 42)
    assert lib.foo(p) == p
    assert lib.foo(q) != p

def test_bogus_ptr():
    ffi = FFI()
    ffi.cdef("int *foo(int *);")
    lib = ffi.verify("int *foo(int *a) { return a; }")
    pytest.raises(TypeError, lib.foo, ffi.new("short *", 42))


def test_verify_typedefs():
    pytest.skip("ignored so far")
    types = ['signed char', 'unsigned char', 'int', 'long']
    for cdefed in types:
        for real in types:
            ffi = FFI()
            ffi.cdef("typedef %s foo_t;" % cdefed)
            if cdefed == real:
                ffi.verify("typedef %s foo_t;" % real)
            else:
                pytest.raises(VerificationError, ffi.verify,
                               "typedef %s foo_t;" % real)

def test_nondecl_struct():
    ffi = FFI()
    ffi.cdef("typedef struct foo_s foo_t; int bar(foo_t *);")
    lib = ffi.verify("typedef struct foo_s foo_t;\n"
                     "int bar(foo_t *f) { (void)f; return 42; }\n")
    assert lib.bar(ffi.NULL) == 42

def test_ffi_full_struct():
    def check(verified_code):
        ffi = FFI()
        ffi.cdef("struct foo_s { char x; int y; long *z; };")
        ffi.verify(verified_code)
        ffi.new("struct foo_s *", {})

    check("struct foo_s { char x; int y; long *z; };")
    #
    if sys.platform != 'win32':  # XXX fixme: only gives warnings
        pytest.raises(VerificationError, check,
            "struct foo_s { char x; int y; int *z; };")
    #
    pytest.raises(VerificationError, check,
        "struct foo_s { int y; long *z; };")     # cdef'ed field x is missing
    #
    e = pytest.raises(FFI.error, check,
                       "struct foo_s { int y; char x; long *z; };")
    assert str(e.value).startswith(
        "struct foo_s: wrong offset for field 'x'"
        " (cdef says 0, but C compiler says 4)")
    #
    e = pytest.raises(FFI.error, check,
        "struct foo_s { char x; int y; long *z; char extra; };")
    assert str(e.value).startswith(
        "struct foo_s: wrong total size"
        " (cdef says %d, but C compiler says %d)" % (
            8 + FFI().sizeof('long *'),
            8 + FFI().sizeof('long *') * 2))
    #
    # a corner case that we cannot really detect, but where it has no
    # bad consequences: the size is the same, but there is an extra field
    # that replaces what is just padding in our declaration above
    check("struct foo_s { char x, extra; int y; long *z; };")
    #
    e = pytest.raises(FFI.error, check,
        "struct foo_s { char x; short pad; short y; long *z; };")
    assert str(e.value).startswith(
        "struct foo_s: wrong size for field 'y'"
        " (cdef says 4, but C compiler says 2)")

def test_ffi_nonfull_struct():
    ffi = FFI()
    ffi.cdef("""
    struct foo_s {
       int x;
       ...;
    };
    """)
    pytest.raises(VerificationMissing, ffi.sizeof, 'struct foo_s')
    pytest.raises(VerificationMissing, ffi.offsetof, 'struct foo_s', 'x')
    pytest.raises(VerificationMissing, ffi.new, 'struct foo_s *')
    ffi.verify("""
    struct foo_s {
       int a, b, x, c, d, e;
    };
    """)
    assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int')
    assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int')

def test_ffi_nonfull_alignment():
    ffi = FFI()
    ffi.cdef("struct foo_s { char x; ...; };")
    ffi.verify("struct foo_s { int a, b; char x; };")
    assert ffi.sizeof('struct foo_s') == 3 * ffi.sizeof('int')
    assert ffi.alignof('struct foo_s') == ffi.sizeof('int')

def _check_field_match(typename, real, expect_mismatch):
    ffi = FFI()
    testing_by_size = (expect_mismatch == 'by_size')
    if testing_by_size:
        expect_mismatch = ffi.sizeof(typename) != ffi.sizeof(real)
    ffi.cdef("struct foo_s { %s x; ...; };" % typename)
    try:
        ffi.verify("struct foo_s { %s x; };" % real)
        ffi.new("struct foo_s *", [])  # because some mismatches show up lazily
    except (VerificationError, ffi.error):
        if not expect_mismatch:
            if testing_by_size and typename != real:
                print("ignoring mismatch between %s* and %s* even though "
                      "they have the same size" % (typename, real))
                return
            raise AssertionError("unexpected mismatch: %s should be accepted "
                                 "as equal to %s" % (typename, real))
    else:
        if expect_mismatch:
            raise AssertionError("mismatch not detected: "
                                 "%s != %s" % (typename, real))

def test_struct_bad_sized_integer():
    for typename in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
        for real in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
            _check_field_match(typename, real, "by_size")

def test_struct_bad_sized_float():
    for typename in all_float_types:
        for real in all_float_types:
            _check_field_match(typename, real, "by_size")

def test_struct_signedness_ignored():
    _check_field_match("int", "unsigned int", expect_mismatch=False)
    _check_field_match("unsigned short", "signed short", expect_mismatch=False)

def test_struct_float_vs_int():
    if sys.platform == 'win32':
        pytest.skip("XXX fixme: only gives warnings")
    ffi = FFI()
    for typename in all_signed_integer_types(ffi):
        for real in all_float_types:
            _check_field_match(typename, real, expect_mismatch=True)
    for typename in all_float_types:
        for real in all_signed_integer_types(ffi):
            _check_field_match(typename, real, expect_mismatch=True)

def test_struct_array_field():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[17]; ...; };")
    ffi.verify("struct foo_s { int x; int a[17]; int y; };")
    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')

def test_struct_array_no_length():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[]; int y; ...; };\n"
             "int bar(struct foo_s *);\n")
    lib = ffi.verify("struct foo_s { int x; int a[17]; int y; };\n"
                     "int bar(struct foo_s *f) { return f->a[14]; }\n")
    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.typeof(s.a) is ffi.typeof('int[]')   # implicit max length
    assert len(s.a) == 18  # max length, computed from the size and start offset
    s.a[14] = 4242
    assert lib.bar(s) == 4242
    # with no declared length, out-of-bound accesses are not detected
    s.a[17] = -521
    assert s.y == s.a[17] == -521
    #
    s = ffi.new("struct foo_s *", {'a': list(range(17))})
    assert s.a[16] == 16
    # overflows at construction time not detected either
    s = ffi.new("struct foo_s *", {'a': list(range(18))})
    assert s.y == s.a[17] == 17

def test_struct_array_guess_length():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a[...]; };")
    ffi.verify("struct foo_s { int x; int a[17]; int y; };")
    assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int')
    with pytest.raises(IndexError):
        s.a[17]

def test_struct_array_c99_1():
    if sys.platform == 'win32':
        pytest.skip("requires C99")
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; int a[]; };")
    ffi.verify("struct foo_s { int x; int a[]; };")
    assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242, 4])
    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
    # ^^^ explanation: if you write in C: "char x[5];", then
    # "sizeof(x)" will evaluate to 5.  The behavior above is
    # a generalization of that to "struct foo_s[len(a)=5] x;"
    # if you could do that in C.
    assert s.a[3] == 0
    s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
    assert s.a[3] == -10
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242])
    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')

def test_struct_array_c99_2():
    if sys.platform == 'win32':
        pytest.skip("requires C99")
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; int a[]; ...; };")
    ffi.verify("struct foo_s { int x, y; int a[]; };")
    assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242, 4])
    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
    assert s.a[3] == 0
    s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
    assert s.a[3] == -10
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
    s = ffi.new("struct foo_s *", [424242])
    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')

def test_struct_ptr_to_array_field():
    ffi = FFI()
    ffi.cdef("struct foo_s { int (*a)[17]; ...; }; struct bar_s { ...; };")
    ffi.verify("struct foo_s { int x; int (*a)[17]; int y; };\n"
               "struct bar_s { int x; int *a; int y; };")
    assert ffi.sizeof('struct foo_s') == ffi.sizeof("struct bar_s")
    s = ffi.new("struct foo_s *")
    assert ffi.sizeof(s.a) == ffi.sizeof('int(*)[17]') == ffi.sizeof("int *")

def test_struct_with_bitfield_exact():
    ffi = FFI()
    ffi.cdef("struct foo_s { int a:2, b:3; };")
    ffi.verify("struct foo_s { int a:2, b:3; };")
    s = ffi.new("struct foo_s *")
    s.b = 3
    with pytest.raises(OverflowError):
        s.b = 4
    assert s.b == 3

def test_struct_with_bitfield_enum():
    ffi = FFI()
    code = """
        typedef enum { AA, BB, CC } foo_e;
        typedef struct { foo_e f:2; } foo_s;
    """
    ffi.cdef(code)
    ffi.verify(code)
    s = ffi.new("foo_s *")
    s.f = 1
    assert s.f == 1
    if int(ffi.cast("foo_e", -1)) < 0:
        two = -2
    else:
        two = 2
    s.f = two
    assert s.f == two

def test_unsupported_struct_with_bitfield_ellipsis():
    ffi = FFI()
    pytest.raises(NotImplementedError, ffi.cdef,
                   "struct foo_s { int a:2, b:3; ...; };")

def test_global_constants():
    ffi = FFI()
    # use 'static const int', as generally documented, although in this
    # case the 'static' is completely ignored.
    ffi.cdef("static const int AA, BB, CC, DD;")
    lib = ffi.verify("#define AA 42\n"
                     "#define BB (-43)   // blah\n"
                     "#define CC (22*2)  /* foobar */\n"
                     "#define DD ((unsigned int)142)  /* foo\nbar */\n")
    assert lib.AA == 42
    assert lib.BB == -43
    assert lib.CC == 44
    assert lib.DD == 142

def test_global_const_int_size():
    # integer constants: ignore the declared type, always just use the value
    for value in [-2**63, -2**31, -2**15,
                  2**15-1, 2**15, 2**31-1, 2**31, 2**32-1, 2**32,
                  2**63-1, 2**63, 2**64-1]:
        ffi = FFI()
        if value == int(ffi.cast("long long", value)):
            if value < 0:
                vstr = '(-%dLL-1)' % (~value,)
            else:
                vstr = '%dLL' % value
        elif value == int(ffi.cast("unsigned long long", value)):
            vstr = '%dULL' % value
        else:
            raise AssertionError(value)
        ffi.cdef("static const unsigned short AA;")
        lib = ffi.verify("#define AA %s\n" % vstr)
        assert lib.AA == value
        assert type(lib.AA) is type(int(lib.AA))

def test_global_constants_non_int():
    ffi = FFI()
    ffi.cdef("static char *const PP;")
    lib = ffi.verify('static char *const PP = "testing!";\n')
    assert ffi.typeof(lib.PP) == ffi.typeof("char *")
    assert ffi.string(lib.PP) == b"testing!"

def test_nonfull_enum():
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2, EE3, ... \n \t };")
    pytest.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE2')
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == "EE2"
    assert ffi.string(ffi.cast('enum ee', -10)) == "EE3"
    #
    assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3': -10}
    assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'}

def test_full_enum():
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2, EE3 };")
    lib = ffi.verify("enum ee { EE1, EE2, EE3 };")
    assert [lib.EE1, lib.EE2, lib.EE3] == [0, 1, 2]

def test_enum_usage():
    ffi = FFI()
    ffi.cdef("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
    lib = ffi.verify("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;")
    assert lib.EE2 == 1
    s = ffi.new("sp", [lib.EE2])
    assert s.x == 1
    s.x = 17
    assert s.x == 17

def test_anonymous_enum():
    ffi = FFI()
    ffi.cdef("enum { EE1 }; enum { EE2, EE3 };")
    lib = ffi.verify("enum { EE1 }; enum { EE2, EE3 };")
    assert lib.EE1 == 0
    assert lib.EE2 == 0
    assert lib.EE3 == 1

def test_nonfull_anonymous_enum():
    ffi = FFI()
    ffi.cdef("enum { EE1, ... }; enum { EE3, ... };")
    lib = ffi.verify("enum { EE2, EE1 }; enum { EE3 };")
    assert lib.EE1 == 1
    assert lib.EE3 == 0

def test_nonfull_enum_syntax2():
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2=\t..., EE3 };")
    pytest.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
    assert ffi.string(ffi.cast('enum ee', -10)) == 'EE3'
    #
    ffi = FFI()
    ffi.cdef("enum ee { EE1, EE2=\t... };")
    pytest.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1')
    ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };")
    assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2'
    #
    ffi = FFI()
    ffi.cdef("enum ee2 { EE4=..., EE5=..., ... };")
    ffi.verify("enum ee2 { EE4=-1234-5, EE5 }; ")
    assert ffi.string(ffi.cast('enum ee2', -1239)) == 'EE4'
    assert ffi.string(ffi.cast('enum ee2', -1238)) == 'EE5'

def test_get_set_errno():
    ffi = FFI()
    ffi.cdef("int foo(int);")
    lib = ffi.verify("""
        static int foo(int x)
        {
            errno += 1;
            return x * 7;
        }
    """)
    ffi.errno = 15
    assert lib.foo(6) == 42
    assert ffi.errno == 16

def test_define_int():
    ffi = FFI()
    ffi.cdef("#define FOO ...\n"
             "\t#\tdefine\tBAR\t...\t\n"
             "#define BAZ ...\n")
    lib = ffi.verify("#define FOO 42\n"
                     "#define BAR (-44)\n"
                     "#define BAZ 0xffffffffffffffffULL\n")
    assert lib.FOO == 42
    assert lib.BAR == -44
    assert lib.BAZ == 0xffffffffffffffff

def test_access_variable():
    ffi = FFI()
    ffi.cdef("static int foo(void);\n"
             "static int somenumber;")
    lib = ffi.verify("""
        static int somenumber = 2;
        static int foo(void) {
            return somenumber * 7;
        }
    """)
    assert lib.somenumber == 2
    assert lib.foo() == 14
    lib.somenumber = -6
    assert lib.foo() == -42
    assert lib.somenumber == -6
    lib.somenumber = 2   # reset for the next run, if any

def test_access_address_of_variable():
    # access the address of 'somenumber': need a trick
    ffi = FFI()
    ffi.cdef("static int somenumber; static int *const somenumberptr;")
    lib = ffi.verify("""
        static int somenumber = 2;
        #define somenumberptr (&somenumber)
    """)
    assert lib.somenumber == 2
    lib.somenumberptr[0] = 42
    assert lib.somenumber == 42
    lib.somenumber = 2    # reset for the next run, if any

def test_access_array_variable(length=5):
    ffi = FFI()
    ffi.cdef("static int foo(int);\n"
             "static int somenumber[%s];" % (length,))
    lib = ffi.verify("""
        static int somenumber[] = {2, 2, 3, 4, 5};
        static int foo(int i) {
            return somenumber[i] * 7;
        }
    """)
    if length == '':
        # a global variable of an unknown array length is implicitly
        # transformed into a global pointer variable, because we can only
        # work with array instances whose length we know.  using a pointer
        # instead of an array gives the correct effects.
        assert repr(lib.somenumber).startswith("<cdata 'int *' 0x")
        pytest.raises(TypeError, len, lib.somenumber)
    else:
        assert repr(lib.somenumber).startswith("<cdata 'int[%s]' 0x" % length)
        assert len(lib.somenumber) == 5
    assert lib.somenumber[3] == 4
    assert lib.foo(3) == 28
    lib.somenumber[3] = -6
    assert lib.foo(3) == -42
    assert lib.somenumber[3] == -6
    assert lib.somenumber[4] == 5
    lib.somenumber[3] = 4    # reset for the next run, if any

def test_access_array_variable_length_hidden():
    test_access_array_variable(length='')

def test_access_struct_variable():
    ffi = FFI()
    ffi.cdef("struct foo { int x; ...; };\n"
             "static int foo(int);\n"
             "static struct foo stuff;")
    lib = ffi.verify("""
        struct foo { int x, y, z; };
        static struct foo stuff = {2, 5, 8};
        static int foo(int i) {
            switch (i) {
            case 0: return stuff.x * 7;
            case 1: return stuff.y * 7;
            case 2: return stuff.z * 7;
            }
            return -1;
        }
    """)
    assert lib.stuff.x == 2
    assert lib.foo(0) == 14
    assert lib.foo(1) == 35
    assert lib.foo(2) == 56
    lib.stuff.x = -6
    assert lib.foo(0) == -42
    assert lib.foo(1) == 35
    lib.stuff.x = 2      # reset for the next run, if any

def test_access_callback():
    ffi = FFI()
    ffi.cdef("static int (*cb)(int);\n"
             "static int foo(int);\n"
             "static void reset_cb(void);")
    lib = ffi.verify("""
        static int g(int x) { return x * 7; }
        static int (*cb)(int);
        static int foo(int i) { return cb(i) - 1; }
        static void reset_cb(void) { cb = g; }
    """)
    lib.reset_cb()
    assert lib.foo(6) == 41
    my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
    lib.cb = my_callback
    assert lib.foo(4) == 887

def test_access_callback_function_typedef():
    ffi = FFI()
    ffi.cdef("typedef int mycallback_t(int);\n"
             "static mycallback_t *cb;\n"
             "static int foo(int);\n"
             "static void reset_cb(void);")
    lib = ffi.verify("""
        static int g(int x) { return x * 7; }
        static int (*cb)(int);
        static int foo(int i) { return cb(i) - 1; }
        static void reset_cb(void) { cb = g; }
    """)
    lib.reset_cb()
    assert lib.foo(6) == 41
    my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
    lib.cb = my_callback
    assert lib.foo(4) == 887

def test_call_with_struct_ptr():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);")
    lib = ffi.verify("""
        typedef struct { int y, x; } foo_t;
        static int foo(foo_t *f) { return f->x * 7; }
    """)
    f = ffi.new("foo_t *")
    f.x = 6
    assert lib.foo(f) == 42

def test_unknown_type():
    ffi = FFI()
    ffi.cdef("""
        typedef ... token_t;
        int foo(token_t *);
        #define TOKEN_SIZE ...
    """)
    lib = ffi.verify("""
        typedef float token_t;
        static int foo(token_t *tk) {
            if (!tk)
                return -42;
            *tk += 1.601f;
            return (int)*tk;
        }
        #define TOKEN_SIZE sizeof(token_t)
    """)
    # we cannot let ffi.new("token_t *") work, because we don't know ahead of
    # time if it's ok to ask 'sizeof(token_t)' in the C code or not.
    # See test_unknown_type_2.  Workaround.
    tkmem = ffi.new("char[]", lib.TOKEN_SIZE)    # zero-initialized
    tk = ffi.cast("token_t *", tkmem)
    results = [lib.foo(tk) for i in range(6)]
    assert results == [1, 3, 4, 6, 8, 9]
    assert lib.foo(ffi.NULL) == -42

def test_unknown_type_2():
    ffi = FFI()
    ffi.cdef("typedef ... token_t;")
    lib = ffi.verify("typedef struct token_s token_t;")
    # assert did not crash, even though 'sizeof(token_t)' is not valid in C.

def test_unknown_type_3():
    ffi = FFI()
    ffi.cdef("""
        typedef ... *token_p;
        token_p foo(token_p);
    """)
    lib = ffi.verify("""
        typedef struct _token_s *token_p;
        token_p foo(token_p arg) {
            if (arg)
                return (token_p)0x12347;
            else
                return (token_p)0x12345;
        }
    """)
    p = lib.foo(ffi.NULL)
    assert int(ffi.cast("intptr_t", p)) == 0x12345
    q = lib.foo(p)
    assert int(ffi.cast("intptr_t", q)) == 0x12347

def test_varargs():
    ffi = FFI()
    ffi.cdef("int foo(int x, ...);")
    lib = ffi.verify("""
        int foo(int x, ...) {
            va_list vargs;
            va_start(vargs, x);
            x -= va_arg(vargs, int);
            x -= va_arg(vargs, int);
            va_end(vargs);
            return x;
        }
    """)
    assert lib.foo(50, ffi.cast("int", 5), ffi.cast("int", 3)) == 42

def test_varargs_exact():
    if sys.platform == 'win32':
        pytest.skip("XXX fixme: only gives warnings")
    ffi = FFI()
    ffi.cdef("int foo(int x, ...);")
    pytest.raises(VerificationError, ffi.verify, """
        int foo(long long x, ...) {
            return x;
        }
    """)

def test_varargs_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { char a; int b; }; int foo(int x, ...);")
    lib = ffi.verify("""
        struct foo_s {
            char a; int b;
        };
        int foo(int x, ...) {
            va_list vargs;
            struct foo_s s;
            va_start(vargs, x);
            s = va_arg(vargs, struct foo_s);
            va_end(vargs);
            return s.a - s.b;
        }
    """)
    s = ffi.new("struct foo_s *", [b'B', 1])
    assert lib.foo(50, s[0]) == ord('A')

def test_autofilled_struct_as_argument():
    ffi = FFI()
    ffi.cdef("struct foo_s { long a; double b; ...; };\n"
             "int foo(struct foo_s);")
    lib = ffi.verify("""
        struct foo_s {
            double b;
            long a;
        };
        int foo(struct foo_s s) {
            return (int)s.a - (int)s.b;
        }
    """)
    s = ffi.new("struct foo_s *", [100, 1])
    assert lib.foo(s[0]) == 99
    assert lib.foo([100, 1]) == 99

def test_autofilled_struct_as_argument_dynamic():
    ffi = FFI()
    ffi.cdef("struct foo_s { long a; ...; };\n"
             "static int (*foo)(struct foo_s);")
    lib = ffi.verify("""
        struct foo_s {
            double b;
            long a;
        };
        int foo1(struct foo_s s) {
            return (int)s.a - (int)s.b;
        }
        static int (*foo)(struct foo_s s) = &foo1;
    """)
    e = pytest.raises(NotImplementedError, lib.foo, "?")
    msg = ("ctype 'struct foo_s' not supported as argument.  It is a struct "
           'declared with "...;", but the C calling convention may depend on '
           "the missing fields; or, it contains anonymous struct/unions.  "
           "Such structs are only supported as argument "
           "if the function is 'API mode' and non-variadic (i.e. declared "
           "inside ffibuilder.cdef()+ffibuilder.set_source() and not taking "
           "a final '...' argument)")
    assert str(e.value) == msg

def test_func_returns_struct():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { int aa, bb; };
        struct foo_s foo(int a, int b);
    """)
    lib = ffi.verify("""
        struct foo_s { int aa, bb; };
        struct foo_s foo(int a, int b) {
            struct foo_s r;
            r.aa = a*a;
            r.bb = b*b;
            return r;
        }
    """)
    s = lib.foo(6, 7)
    assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>"
    assert s.aa == 36
    assert s.bb == 49

def test_func_as_funcptr():
    ffi = FFI()
    ffi.cdef("int *(*const fooptr)(void);")
    lib = ffi.verify("""
        int *foo(void) {
            return (int*)"foobar";
        }
        int *(*fooptr)(void) = foo;
    """)
    foochar = ffi.cast("char *(*)(void)", lib.fooptr)
    s = foochar()
    assert ffi.string(s) == b"foobar"

def test_funcptr_as_argument():
    ffi = FFI()
    ffi.cdef("""
        void qsort(void *base, size_t nel, size_t width,
            int (*compar)(const void *, const void *));
    """)
    ffi.verify("#include <stdlib.h>")

def test_func_as_argument():
    ffi = FFI()
    ffi.cdef("""
        void qsort(void *base, size_t nel, size_t width,
            int compar(const void *, const void *));
    """)
    ffi.verify("#include <stdlib.h>")

def test_array_as_argument():
    ffi = FFI()
    ffi.cdef("""
        size_t strlen(char string[]);
    """)
    ffi.verify("#include <string.h>")

def test_enum_as_argument():
    ffi = FFI()
    ffi.cdef("""
        enum foo_e { AA, BB, ... };
        int foo_func(enum foo_e);
    """)
    lib = ffi.verify("""
        enum foo_e { AA, CC, BB };
        int foo_func(enum foo_e e) { return (int)e; }
    """)
    assert lib.foo_func(lib.BB) == 2
    pytest.raises(TypeError, lib.foo_func, "BB")

def test_enum_as_function_result():
    ffi = FFI()
    ffi.cdef("""
        enum foo_e { AA, BB, ... };
        enum foo_e foo_func(int x);
    """)
    lib = ffi.verify("""
        enum foo_e { AA, CC, BB };
        enum foo_e foo_func(int x) { return (enum foo_e)x; }
    """)
    assert lib.foo_func(lib.BB) == lib.BB == 2

def test_enum_values():
    ffi = FFI()
    ffi.cdef("enum enum1_e { AA, BB };")
    lib = ffi.verify("enum enum1_e { AA, BB };")
    assert lib.AA == 0
    assert lib.BB == 1
    assert ffi.string(ffi.cast("enum enum1_e", 1)) == 'BB'

def test_typedef_complete_enum():
    ffi = FFI()
    ffi.cdef("typedef enum { AA, BB } enum1_t;")
    lib = ffi.verify("typedef enum { AA, BB } enum1_t;")
    assert ffi.string(ffi.cast("enum1_t", 1)) == 'BB'
    assert lib.AA == 0
    assert lib.BB == 1

def test_typedef_broken_complete_enum():
    # xxx this is broken in old cffis, but works with recompiler.py
    ffi = FFI()
    ffi.cdef("typedef enum { AA, BB } enum1_t;")
    lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
    assert lib.AA == 0
    assert lib.BB == 2

def test_typedef_incomplete_enum():
    ffi = FFI()
    ffi.cdef("typedef enum { AA, BB, ... } enum1_t;")
    lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;")
    assert ffi.string(ffi.cast("enum1_t", 1)) == '1'
    assert ffi.string(ffi.cast("enum1_t", 2)) == 'BB'
    assert lib.AA == 0
    assert lib.BB == 2

def test_typedef_enum_as_argument():
    ffi = FFI()
    ffi.cdef("""
        typedef enum { AA, BB, ... } foo_t;
        int foo_func(foo_t);
    """)
    lib = ffi.verify("""
        typedef enum { AA, CC, BB } foo_t;
        int foo_func(foo_t e) { return (int)e; }
    """)
    assert lib.foo_func(lib.BB) == lib.BB == 2
    pytest.raises(TypeError, lib.foo_func, "BB")

def test_typedef_enum_as_function_result():
    ffi = FFI()
    ffi.cdef("""
        typedef enum { AA, BB, ... } foo_t;
        foo_t foo_func(int x);
    """)
    lib = ffi.verify("""
        typedef enum { AA, CC, BB } foo_t;
        foo_t foo_func(int x) { return (foo_t)x; }
    """)
    assert lib.foo_func(lib.BB) == lib.BB == 2

def test_function_typedef():
    ffi = FFI()
    ffi.cdef("""
        typedef double func_t(double);
        func_t sin;
    """)
    lib = ffi.verify('#include <math.h>', libraries=lib_m)
    assert lib.sin(1.23) == math.sin(1.23)

def test_opaque_integer_as_function_result():
    #import platform
    #if platform.machine().startswith('sparc'):
    #    pytest.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
    #elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
    #    pytest.skip('Segfaults on mips64el')
    # XXX bad abuse of "struct { ...; }".  It only works a bit by chance
    # anyway.  XXX think about something better :-(
    ffi = FFI()
    ffi.cdef("""
        typedef struct { ...; } myhandle_t;
        myhandle_t foo(void);
    """)
    lib = ffi.verify("""
        typedef short myhandle_t;
        myhandle_t foo(void) { return 42; }
    """)
    h = lib.foo()
    assert ffi.sizeof(h) == ffi.sizeof("short")

def test_return_partial_struct():
    ffi = FFI()
    ffi.cdef("""
        typedef struct { int x; ...; } foo_t;
        foo_t foo(void);
    """)
    lib = ffi.verify("""
        typedef struct { int y, x; } foo_t;
        foo_t foo(void) { foo_t r = { 45, 81 }; return r; }
    """)
    h = lib.foo()
    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
    assert h.x == 81

def test_take_and_return_partial_structs():
    ffi = FFI()
    ffi.cdef("""
        typedef struct { int x; ...; } foo_t;
        foo_t foo(foo_t, foo_t);
    """)
    lib = ffi.verify("""
        typedef struct { int y, x; } foo_t;
        foo_t foo(foo_t a, foo_t b) {
            foo_t r = { 100, a.x * 5 + b.x * 7 };
            return r;
        }
    """)
    args = ffi.new("foo_t[3]")
    args[0].x = 1000
    args[2].x = -498
    h = lib.foo(args[0], args[2])
    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
    assert h.x == 1000 * 5 - 498 * 7

def test_cannot_name_struct_type():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; } **sp; void foo(sp);")
    e = pytest.raises(VerificationError, ffi.verify,
                       "typedef struct { int x; } **sp; void foo(sp x) { }")
    assert 'in argument of foo: unknown type name' in str(e.value)

def test_dont_check_unnamable_fields():
    ffi = FFI()
    ffi.cdef("struct foo_s { struct { int x; } someone; };")
    ffi.verify("struct foo_s { struct { int x; } someone; };")
    # assert did not crash

def test_nested_anonymous_struct_exact():
    if sys.platform == 'win32':
        pytest.skip("nested anonymous struct/union")
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { struct { int a; char b; }; union { char c, d; }; };
    """)
    assert ffi.offsetof("struct foo_s", "c") == 2 * ffi.sizeof("int")
    assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")
    ffi.verify("""
        struct foo_s { struct { int a; char b; }; union { char c, d; }; };
    """)
    p = ffi.new("struct foo_s *")
    assert ffi.sizeof(p[0]) == 3 * ffi.sizeof("int")    # with alignment
    p.a = 1234567
    p.b = b'X'
    p.c = b'Y'
    assert p.a == 1234567
    assert p.b == b'X'
    assert p.c == b'Y'
    assert p.d == b'Y'

def test_nested_anonymous_struct_exact_error():
    if sys.platform == 'win32':
        pytest.skip("nested anonymous struct/union")
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { struct { int a; char b; }; union { char c, d; }; };
    """)
    pytest.raises(VerificationError, ffi.verify, """
        struct foo_s { struct { int a; short b; }; union { char c, d; }; };
    """)
    # works fine now
    #pytest.raises(VerificationError, ffi.verify, """
    #    struct foo_s { struct { int a; char e, b; }; union { char c, d; }; };
    #""")

def test_nested_anonymous_struct_inexact_1():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { struct { char b; ...; }; union { char c, d; }; };
    """)
    ffi.verify("""
        struct foo_s { int a, padding; char c, d, b; };
    """)
    assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")

def test_nested_anonymous_struct_inexact_2():
    ffi = FFI()
    ffi.cdef("""
        struct foo_s { union { char c, d; }; struct { int a; char b; }; ...; };
    """)
    ffi.verify("""
        struct foo_s { int a, padding; char c, d, b; };
    """)
    assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int")

def test_ffi_union():
    ffi = FFI()
    ffi.cdef("union foo_u { char x; long *z; };")
    ffi.verify("union foo_u { char x; int y; long *z; };")

def test_ffi_union_partial():
    ffi = FFI()
    ffi.cdef("union foo_u { char x; ...; };")
    ffi.verify("union foo_u { char x; int y; };")
    assert ffi.sizeof("union foo_u") == 4

def test_ffi_union_with_partial_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { int x; ...; }; union foo_u { struct foo_s s; };")
    ffi.verify("struct foo_s { int a; int x; }; "
               "union foo_u { char b[32]; struct foo_s s; };")
    assert ffi.sizeof("struct foo_s") == 8
    assert ffi.sizeof("union foo_u") == 32

def test_ffi_union_partial_2():
    ffi = FFI()
    ffi.cdef("typedef union { char x; ...; } u1;")
    ffi.verify("typedef union { char x; int y; } u1;")
    assert ffi.sizeof("u1") == 4

def test_ffi_union_with_partial_struct_2():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; ...; } s1;"
             "typedef union { s1 s; } u1;")
    ffi.verify("typedef struct { int a; int x; } s1; "
               "typedef union { char b[32]; s1 s; } u1;")
    assert ffi.sizeof("s1") == 8
    assert ffi.sizeof("u1") == 32
    assert ffi.offsetof("u1", "s") == 0

def test_ffi_struct_packed():
    if sys.platform == 'win32':
        pytest.skip("needs a GCC extension")
    ffi = FFI()
    ffi.cdef("struct foo_s { int b; ...; };")
    ffi.verify("""
        struct foo_s {
            char a;
            int b;
        } __attribute__((packed));
    """)

def test_tmpdir():
    import tempfile, os
    from testing.udir import udir
    tmpdir = tempfile.mkdtemp(dir=str(udir))
    ffi = FFI()
    ffi.cdef("int foo(int);")
    lib = ffi.verify("int foo(int a) { return a + 42; }", tmpdir=tmpdir)
    assert os.listdir(tmpdir)
    assert lib.foo(100) == 142

def test_relative_to():
    pytest.skip("not available")
    import tempfile, os
    from testing.udir import udir
    tmpdir = tempfile.mkdtemp(dir=str(udir))
    ffi = FFI()
    ffi.cdef("int foo(int);")
    f = open(os.path.join(tmpdir, 'foo.h'), 'w')
    f.write("int foo(int a) { return a + 42; }\n")
    f.close()
    lib = ffi.verify('#include "foo.h"',
                     include_dirs=['.'],
                     relative_to=os.path.join(tmpdir, 'x'))
    assert lib.foo(100) == 142

def test_bug1():
    ffi = FFI()
    ffi.cdef("""
        typedef struct tdlhandle_s { ...; } *tdl_handle_t;
        typedef struct my_error_code_ {
            tdl_handle_t *rh;
        } my_error_code_t;
    """)
    ffi.verify("""
        typedef struct tdlhandle_s { int foo; } *tdl_handle_t;
        typedef struct my_error_code_ {
            tdl_handle_t *rh;
        } my_error_code_t;
    """)

def test_bool():
    if sys.platform == 'win32':
        pytest.skip("_Bool not in MSVC")
    ffi = FFI()
    ffi.cdef("struct foo_s { _Bool x; };"
             "_Bool foo(_Bool); static _Bool (*foop)(_Bool);")
    lib = ffi.verify("""
        struct foo_s { _Bool x; };
        int foo(int arg) {
            return !arg;
        }
        _Bool _foofunc(_Bool x) {
            return !x;
        }
        static _Bool (*foop)(_Bool) = _foofunc;
    """)
    p = ffi.new("struct foo_s *")
    p.x = 1
    assert p.x is True
    with pytest.raises(OverflowError):
        p.x = -1
    with pytest.raises(TypeError):
        p.x = 0.0
    assert lib.foop(1) is False
    assert lib.foop(True) is False
    assert lib.foop(0) is True
    pytest.raises(OverflowError, lib.foop, 42)
    pytest.raises(TypeError, lib.foop, 0.0)
    assert lib.foo(1) is False
    assert lib.foo(True) is False
    assert lib.foo(0) is True
    pytest.raises(OverflowError, lib.foo, 42)
    pytest.raises(TypeError, lib.foo, 0.0)
    assert int(ffi.cast("_Bool", long(1))) == 1
    assert int(ffi.cast("_Bool", long(0))) == 0
    assert int(ffi.cast("_Bool", long(-1))) == 1
    assert int(ffi.cast("_Bool", 10**200)) == 1
    assert int(ffi.cast("_Bool", 10**40000)) == 1
    #
    class Foo(object):
        def __int__(self):
            self.seen = 1
            return result
    f = Foo()
    f.seen = 0
    result = 42
    assert int(ffi.cast("_Bool", f)) == 1
    assert f.seen
    f.seen = 0
    result = 0
    assert int(ffi.cast("_Bool", f)) == 0
    assert f.seen
    #
    pytest.raises(TypeError, ffi.cast, "_Bool", [])

def test_bool_on_long_double():
    if sys.platform == 'win32':
        pytest.skip("_Bool not in MSVC")
    f = 1E-250
    if f == 0.0 or f*f != 0.0:
        pytest.skip("unexpected precision")
    ffi = FFI()
    ffi.cdef("long double square(long double f); _Bool opposite(_Bool);")
    lib = ffi.verify("long double square(long double f) { return f*f; }\n"
                     "_Bool opposite(_Bool x) { return !x; }")
    f0 = lib.square(0.0)
    f2 = lib.square(f)
    f3 = lib.square(f * 2.0)
    if repr(f2) == repr(f3):
        pytest.skip("long double doesn't have enough precision")
    assert float(f0) == float(f2) == float(f3) == 0.0  # too tiny for 'double'
    assert int(ffi.cast("_Bool", f2)) == 1
    assert int(ffi.cast("_Bool", f3)) == 1
    assert int(ffi.cast("_Bool", f0)) == 0
    pytest.raises(TypeError, lib.opposite, f2)

def test_cannot_pass_float():
    for basetype in ['char', 'short', 'int', 'long', 'long long']:
        for sign in ['signed', 'unsigned']:
            type = '%s %s' % (sign, basetype)
            ffi = FFI()
            ffi.cdef("struct foo_s { %s x; };\n"
                     "int foo(%s);" % (type, type))
            lib = ffi.verify("""
                struct foo_s { %s x; };
                int foo(%s arg) {
                    return !arg;
                }
            """ % (type, type))
            p = ffi.new("struct foo_s *")
            with pytest.raises(TypeError):
                p.x = 0.0
            assert lib.foo(42) == 0
            assert lib.foo(0) == 1
            pytest.raises(TypeError, lib.foo, 0.0)

def test_addressof():
    ffi = FFI()
    ffi.cdef("""
        struct point_s { int x, y; };
        struct foo_s { int z; struct point_s point; };
        struct point_s sum_coord(struct point_s *);
    """)
    lib = ffi.verify("""
        struct point_s { int x, y; };
        struct foo_s { int z; struct point_s point; };
        struct point_s sum_coord(struct point_s *point) {
            struct point_s r;
            r.x = point->x + point->y;
            r.y = point->x - point->y;
            return r;
        }
    """)
    p = ffi.new("struct foo_s *")
    p.point.x = 16
    p.point.y = 9
    pytest.raises(TypeError, lib.sum_coord, p.point)
    res = lib.sum_coord(ffi.addressof(p.point))
    assert res.x == 25
    assert res.y == 7
    res2 = lib.sum_coord(ffi.addressof(res))
    assert res2.x == 32
    assert res2.y == 18
    pytest.raises(TypeError, lib.sum_coord, res2)

def test_callback_in_thread():
    pytest.xfail("adapt or remove")
    if sys.platform == 'win32':
        pytest.skip("pthread only")
    import os, subprocess
    from cffi import _imp_emulation as imp
    arg = os.path.join(os.path.dirname(__file__), 'callback_in_thread.py')
    g = subprocess.Popen([sys.executable, arg,
                          os.path.dirname(imp.find_module('cffi')[1])])
    result = g.wait()
    assert result == 0

def test_keepalive_lib():
    pytest.xfail("adapt or remove")
    ffi = FFI()
    ffi.cdef("int foobar(void);")
    lib = ffi.verify("int foobar(void) { return 42; }")
    func = lib.foobar
    ffi_r = weakref.ref(ffi)
    lib_r = weakref.ref(lib)
    del ffi
    import gc; gc.collect()       # lib stays alive
    assert lib_r() is not None
    assert ffi_r() is not None
    assert func() == 42

def test_keepalive_ffi():
    pytest.xfail("adapt or remove")
    ffi = FFI()
    ffi.cdef("int foobar(void);")
    lib = ffi.verify("int foobar(void) { return 42; }")
    func = lib.foobar
    ffi_r = weakref.ref(ffi)
    lib_r = weakref.ref(lib)
    del lib
    import gc; gc.collect()       # ffi stays alive
    assert ffi_r() is not None
    assert lib_r() is not None
    assert func() == 42

def test_FILE_stored_in_stdout():
    if not sys.platform.startswith('linux') or is_musl:
        pytest.skip("likely, we cannot assign to stdout")
    ffi = FFI()
    ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);")
    lib = ffi.verify("""
        #include <stdio.h>
        FILE *setstdout(FILE *f) {
            FILE *result = stdout;
            stdout = f;
            return result;
        }
    """)
    import os
    fdr, fdw = os.pipe()
    fw1 = os.fdopen(fdw, 'wb', 256)
    old_stdout = lib.setstdout(fw1)
    try:
        #
        fw1.write(b"X")
        r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42))
        fw1.close()
        assert r == len("hello, 42!\n")
        #
    finally:
        lib.setstdout(old_stdout)
    #
    result = os.read(fdr, 256)
    os.close(fdr)
    # the 'X' might remain in the user-level buffer of 'fw1' and
    # end up showing up after the 'hello, 42!\n'
    assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"

def test_FILE_stored_explicitly():
    ffi = FFI()
    ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;")
    lib = ffi.verify("""
        #include <stdio.h>
        FILE *myfile;
        int myprintf11(const char *out, int value) {
            return fprintf(myfile, out, value);
        }
    """)
    import os
    fdr, fdw = os.pipe()
    fw1 = os.fdopen(fdw, 'wb', 256)
    lib.myfile = ffi.cast("FILE *", fw1)
    #
    fw1.write(b"X")
    r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42))
    fw1.close()
    assert r == len("hello, 42!\n")
    #
    result = os.read(fdr, 256)
    os.close(fdr)
    # the 'X' might remain in the user-level buffer of 'fw1' and
    # end up showing up after the 'hello, 42!\n'
    assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX"

def test_global_array_with_missing_length():
    ffi = FFI()
    ffi.cdef("extern int fooarray[];")
    lib = ffi.verify("int fooarray[50];")
    assert repr(lib.fooarray).startswith("<cdata 'int *'")

def test_global_array_with_dotdotdot_length():
    ffi = FFI()
    ffi.cdef("extern int fooarray[...];")
    lib = ffi.verify("int fooarray[50];")
    assert repr(lib.fooarray).startswith("<cdata 'int[50]'")

def test_bad_global_array_with_dotdotdot_length():
    pytest.xfail("was detected only because 23 bytes cannot be divided by 4; "
                  "redo more generally")
    ffi = FFI()
    ffi.cdef("extern int fooarray[...];")
    pytest.raises(VerificationError, ffi.verify, "char fooarray[23];")

def test_struct_containing_struct():
    ffi = FFI()
    ffi.cdef("struct foo_s { ...; }; struct bar_s { struct foo_s f; ...; };")
    ffi.verify("struct foo_s { int x; }; struct bar_s { struct foo_s f; };")
    #
    ffi = FFI()
    ffi.cdef("struct foo_s { struct bar_s f; ...; }; struct bar_s { ...; };")
    ffi.verify("struct bar_s { int x; }; struct foo_s { struct bar_s f; };")

def test_struct_returned_by_func():
    ffi = FFI()
    ffi.cdef("typedef ... foo_t; foo_t myfunc(void);")
    e = pytest.raises(TypeError, ffi.verify,
                       "typedef struct { int x; } foo_t; "
                       "foo_t myfunc(void) { foo_t x = { 42 }; return x; }")
    assert str(e.value) == (
        "function myfunc: 'foo_t' is used as result type, but is opaque")

def test_include():
    ffi1 = FFI()
    ffi1.cdef("typedef struct { int x; ...; } foo_t;")
    ffi1.verify("typedef struct { int y, x; } foo_t;")
    ffi2 = FFI()
    ffi2.include(ffi1)
    ffi2.cdef("int myfunc(foo_t *);")
    lib = ffi2.verify("typedef struct { int y, x; } foo_t;"
                      "int myfunc(foo_t *p) { return 42 * p->x; }")
    res = lib.myfunc(ffi2.new("foo_t *", {'x': 10}))
    assert res == 420
    res = lib.myfunc(ffi1.new("foo_t *", {'x': -10}))
    assert res == -420

def test_include_enum():
    ffi1 = FFI()
    ffi1.cdef("enum foo_e { AA, ... };")
    lib1 = ffi1.verify("enum foo_e { CC, BB, AA };")
    ffi2 = FFI()
    ffi2.include(ffi1)
    ffi2.cdef("int myfunc(enum foo_e);")
    lib2 = ffi2.verify("enum foo_e { CC, BB, AA };"
                       "int myfunc(enum foo_e x) { return (int)x; }")
    res = lib2.myfunc(lib2.AA)
    assert res == 2

def test_named_pointer_as_argument():
    ffi = FFI()
    ffi.cdef("typedef struct { int x; } *mystruct_p;\n"
             "mystruct_p ff5a(mystruct_p);")
    lib = ffi.verify("typedef struct { int x; } *mystruct_p;\n"
                     "mystruct_p ff5a(mystruct_p p) { p->x += 40; return p; }")
    p = ffi.new("mystruct_p", [-2])
    q = lib.ff5a(p)
    assert q == p
    assert p.x == 38

def test_enum_size():
    cases = [('123',           4, 4294967295),
             ('4294967295U',   4, 4294967295),
             ('-123',          4, -1),
             ('-2147483647-1', 4, -1),
             ]
    if FFI().sizeof("long") == 8:
        cases += [('4294967296L',        8, 2**64-1),
                  ('%dUL' % (2**64-1),   8, 2**64-1),
                  ('-2147483649L',       8, -1),
                  ('%dL-1L' % (1-2**63), 8, -1)]
    for hidden_value, expected_size, expected_minus1 in cases:
        if sys.platform == 'win32' and 'U' in hidden_value:
            continue   # skipped on Windows
        ffi = FFI()
        ffi.cdef("enum foo_e { AA, BB, ... };")
        lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
        assert lib.AA == 0
        assert lib.BB == eval(hidden_value.replace('U', '').replace('L', ''))
        assert ffi.sizeof("enum foo_e") == expected_size
        if sys.platform != 'win32':
            assert int(ffi.cast("enum foo_e", -1)) == expected_minus1
    # test with the large value hidden:
    # disabled so far, doesn't work
##    for hidden_value, expected_size, expected_minus1 in cases:
##        ffi = FFI()
##        ffi.cdef("enum foo_e { AA, BB, ... };")
##        lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value)
##        assert lib.AA == 0
##        assert ffi.sizeof("enum foo_e") == expected_size
##        assert int(ffi.cast("enum foo_e", -1)) == expected_minus1

def test_enum_bug118():
    maxulong = 256 ** FFI().sizeof("unsigned long") - 1
    for c2, c2c in [(-1, ''),
                    (-1, ''),
                    (0xffffffff, 'U'),
                    (maxulong, 'UL'),
                    (-int(maxulong / 3), 'L')]:
        if c2c and sys.platform == 'win32':
            continue     # enums may always be signed with MSVC
        ffi = FFI()
        ffi.cdef("enum foo_e { AA };")
        lib = ffi.verify("enum foo_e { AA=%s%s };" % (c2, c2c))
        assert lib.AA == c2

def test_string_to_voidp_arg():
    ffi = FFI()
    ffi.cdef("int myfunc(void *);")
    lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }")
    res = lib.myfunc(b"hi!")
    assert res == ord(b"h")
    p = ffi.new("char[]", b"gah")
    res = lib.myfunc(p)
    assert res == ord(b"g")
    res = lib.myfunc(ffi.cast("void *", p))
    assert res == ord(b"g")
    res = lib.myfunc(ffi.cast("int *", p))
    assert res == ord(b"g")

def test_callback_indirection():
    ffi = FFI()
    ffi.cdef("""
        static int (*python_callback)(int how_many, int *values);
        int (*const c_callback)(int,...);   /* pass this ptr to C routines */
        int some_c_function(int(*cb)(int,...));
    """)
    lib = ffi.verify("""
        #include <stdarg.h>
        #ifdef _WIN32
        #include <malloc.h>
        #define alloca _alloca
        #else
        # ifdef __FreeBSD__
        #  include <stdlib.h>
        # else
        #  include <alloca.h>
        # endif
        #endif
        static int (*python_callback)(int how_many, int *values);
        static int c_callback(int how_many, ...) {
            va_list ap;
            /* collect the "..." arguments into the values[] array */
            int i, *values = alloca((size_t)how_many * sizeof(int));
            va_start(ap, how_many);
            for (i=0; i<how_many; i++)
                values[i] = va_arg(ap, int);
            va_end(ap);
            return python_callback(how_many, values);
        }
        int some_c_function(int(*cb)(int,...)) {
            int result = cb(2, 10, 20);
            result += cb(3, 30, 40, 50);
            return result;
        }
    """)
    seen = []
    @ffi.callback("int(int, int*)")
    def python_callback(how_many, values):
        seen.append([values[i] for i in range(how_many)])
        return 42
    lib.python_callback = python_callback

    res = lib.some_c_function(lib.c_callback)
    assert res == 84
    assert seen == [[10, 20], [30, 40, 50]]

def test_floatstar_argument():
    ffi = FFI()
    ffi.cdef("float sum3floats(float *);")
    lib = ffi.verify("""
        float sum3floats(float *f) {
            return f[0] + f[1] + f[2];
        }
    """)
    assert lib.sum3floats((1.5, 2.5, 3.5)) == 7.5
    p = ffi.new("float[]", (1.5, 2.5, 3.5))
    assert lib.sum3floats(p) == 7.5

def test_charstar_argument():
    ffi = FFI()
    ffi.cdef("char sum3chars(char *);")
    lib = ffi.verify("""
        char sum3chars(char *f) {
            return (char)(f[0] + f[1] + f[2]);
        }
    """)
    assert lib.sum3chars((b'\x10', b'\x20', b'\x30')) == b'\x60'
    p = ffi.new("char[]", b'\x10\x20\x30')
    assert lib.sum3chars(p) == b'\x60'

def test_passing_string_or_NULL():
    ffi = FFI()
    ffi.cdef("int seeme1(char *); int seeme2(int *);")
    lib = ffi.verify("""
        int seeme1(char *x) {
            return (x == NULL);
        }
        int seeme2(int *x) {
            return (x == NULL);
        }
    """)
    assert lib.seeme1(b"foo") == 0
    assert lib.seeme1(ffi.NULL) == 1
    assert lib.seeme2([42, 43]) == 0
    assert lib.seeme2(ffi.NULL) == 1
    pytest.raises(TypeError, lib.seeme1, None)
    pytest.raises(TypeError, lib.seeme2, None)
    pytest.raises(TypeError, lib.seeme1, 0.0)
    pytest.raises(TypeError, lib.seeme2, 0.0)
    pytest.raises(TypeError, lib.seeme1, 0)
    pytest.raises(TypeError, lib.seeme2, 0)
    zeroL  = 99999999999999999999
    zeroL -= 99999999999999999999
    pytest.raises(TypeError, lib.seeme2, zeroL)

def test_typeof_function():
    ffi = FFI()
    ffi.cdef("int foo(int, char);")
    lib = ffi.verify("int foo(int x, char y) { (void)x; (void)y; return 42; }")
    ctype = ffi.typeof(lib.foo)
    assert len(ctype.args) == 2
    assert ctype.result == ffi.typeof("int")

def test_call_with_voidstar_arg():
    ffi = FFI()
    ffi.cdef("int f(void *);")
    lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }")
    assert lib.f(b"foobar") == ord(b"f")

def test_dir():
    ffi = FFI()
    ffi.cdef("""void somefunc(void);
                extern int somevar, somearray[2];
                static char *const sv2;
                enum my_e { AA, BB, ... };
                #define FOO ...""")
    lib = ffi.verify("""void somefunc(void) { }
                        int somevar, somearray[2];
                        #define sv2 "text"
                        enum my_e { AA, BB };
                        #define FOO 42""")
    assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray',
                        'somefunc', 'somevar', 'sv2']

def test_typeof_func_with_struct_argument():
    ffi = FFI()
    ffi.cdef("""struct s { int a; }; int foo(struct s);""")
    lib = ffi.verify("""struct s { int a; };
                        int foo(struct s x) { return x.a; }""")
    s = ffi.new("struct s *", [-1234])
    m = lib.foo(s[0])
    assert m == -1234
    assert repr(ffi.typeof(lib.foo)) == "<ctype 'int(*)(struct s)'>"

def test_bug_const_char_ptr_array_1():
    ffi = FFI()
    ffi.cdef("""extern const char *a[...];""")
    lib = ffi.verify("""const char *a[5];""")
    assert repr(ffi.typeof(lib.a)) == "<ctype 'char *[5]'>"

def test_bug_const_char_ptr_array_2():
    ffi = FFI()
    ffi.cdef("""extern const int a[];""")
    lib = ffi.verify("""const int a[5];""")
    assert repr(ffi.typeof(lib.a)) == "<ctype 'int *'>"

def _test_various_calls(force_libffi):
    cdef_source = """
    extern int xvalue;
    extern long long ivalue, rvalue;
    extern float fvalue;
    extern double dvalue;
    extern long double Dvalue;
    signed char tf_bb(signed char x, signed char c);
    unsigned char tf_bB(signed char x, unsigned char c);
    short tf_bh(signed char x, short c);
    unsigned short tf_bH(signed char x, unsigned short c);
    int tf_bi(signed char x, int c);
    unsigned int tf_bI(signed char x, unsigned int c);
    long tf_bl(signed char x, long c);
    unsigned long tf_bL(signed char x, unsigned long c);
    long long tf_bq(signed char x, long long c);
    unsigned long long tf_bQ(signed char x, unsigned long long c);
    float tf_bf(signed char x, float c);
    double tf_bd(signed char x, double c);
    long double tf_bD(signed char x, long double c);
    """
    if force_libffi:
        cdef_source = (cdef_source
            .replace('tf_', '(*const tf_')
            .replace('(signed char x', ')(signed char x'))
    ffi = FFI()
    ffi.cdef(cdef_source)
    lib = ffi.verify("""
    int xvalue;
    long long ivalue, rvalue;
    float fvalue;
    double dvalue;
    long double Dvalue;

    typedef signed char b_t;
    typedef unsigned char B_t;
    typedef short h_t;
    typedef unsigned short H_t;
    typedef int i_t;
    typedef unsigned int I_t;
    typedef long l_t;
    typedef unsigned long L_t;
    typedef long long q_t;
    typedef unsigned long long Q_t;
    typedef float f_t;
    typedef double d_t;
    typedef long double D_t;
    #define S(letter)  xvalue = (int)x; letter##value = (letter##_t)c;
    #define R(letter)  return (letter##_t)rvalue;

    signed char tf_bb(signed char x, signed char c) { S(i) R(b) }
    unsigned char tf_bB(signed char x, unsigned char c) { S(i) R(B) }
    short tf_bh(signed char x, short c) { S(i) R(h) }
    unsigned short tf_bH(signed char x, unsigned short c) { S(i) R(H) }
    int tf_bi(signed char x, int c) { S(i) R(i) }
    unsigned int tf_bI(signed char x, unsigned int c) { S(i) R(I) }
    long tf_bl(signed char x, long c) { S(i) R(l) }
    unsigned long tf_bL(signed char x, unsigned long c) { S(i) R(L) }
    long long tf_bq(signed char x, long long c) { S(i) R(q) }
    unsigned long long tf_bQ(signed char x, unsigned long long c) { S(i) R(Q) }
    float tf_bf(signed char x, float c) { S(f) R(f) }
    double tf_bd(signed char x, double c) { S(d) R(d) }
    long double tf_bD(signed char x, long double c) { S(D) R(D) }
    """)
    lib.rvalue = 0x7182838485868788
    for kind, cname in [('b', 'signed char'),
                        ('B', 'unsigned char'),
                        ('h', 'short'),
                        ('H', 'unsigned short'),
                        ('i', 'int'),
                        ('I', 'unsigned int'),
                        ('l', 'long'),
                        ('L', 'unsigned long'),
                        ('q', 'long long'),
                        ('Q', 'unsigned long long'),
                        ('f', 'float'),
                        ('d', 'double'),
                        ('D', 'long double')]:
        sign = +1 if 'unsigned' in cname else -1
        lib.xvalue = 0
        lib.ivalue = 0
        lib.fvalue = 0
        lib.dvalue = 0
        lib.Dvalue = 0
        fun = getattr(lib, 'tf_b' + kind)
        res = fun(-42, sign * 99)
        if kind == 'D':
            res = float(res)
        assert res == int(ffi.cast(cname, 0x7182838485868788))
        assert lib.xvalue == -42
        if kind in 'fdD':
            assert float(getattr(lib, kind + 'value')) == -99.0
        else:
            assert lib.ivalue == sign * 99

def test_various_calls_direct():
    _test_various_calls(force_libffi=False)

def test_various_calls_libffi():
    _test_various_calls(force_libffi=True)

def test_ptr_to_opaque():
    ffi = FFI()
    ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);")
    lib = ffi.verify("""
        #include <stdlib.h>
        typedef struct { int x; } foo_t;
        int f1(foo_t* p) {
            int x = p->x;
            free(p);
            return x;
        }
        foo_t *f2(int x) {
            foo_t *p = malloc(sizeof(foo_t));
            p->x = x;
            return p;
        }
    """)
    p = lib.f2(42)
    x = lib.f1(p)
    assert x == 42

def _run_in_multiple_threads(test1):
    test1()
    import sys
    try:
        import thread
    except ImportError:
        import _thread as thread
    errors = []
    def wrapper(lock):
        try:
            test1()
        except:
            errors.append(sys.exc_info())
        lock.release()
    locks = []
    for i in range(10):
        _lock = thread.allocate_lock()
        _lock.acquire()
        thread.start_new_thread(wrapper, (_lock,))
        locks.append(_lock)
    for _lock in locks:
        _lock.acquire()
        if errors:
            raise errors[0][1]

def test_errno_working_even_with_pypys_jit():
    ffi = FFI()
    ffi.cdef("int f(int);")
    lib = ffi.verify("""
        #include <errno.h>
        int f(int x) { return (errno = errno + x); }
    """)
    @_run_in_multiple_threads
    def test1():
        ffi.errno = 0
        for i in range(10000):
            e = lib.f(1)
            assert e == i + 1
            assert ffi.errno == e
        for i in range(10000):
            ffi.errno = i
            e = lib.f(42)
            assert e == i + 42

def test_getlasterror_working_even_with_pypys_jit():
    if sys.platform != 'win32':
        pytest.skip("win32-only test")
    ffi = FFI()
    ffi.cdef("void SetLastError(DWORD);")
    lib = ffi.dlopen("Kernel32.dll")
    @_run_in_multiple_threads
    def test1():
        for i in range(10000):
            n = (1 << 29) + i
            lib.SetLastError(n)
            assert ffi.getwinerror()[0] == n

def test_verify_dlopen_flags():
    if not hasattr(sys, 'setdlopenflags'):
        pytest.skip("requires sys.setdlopenflags()")
    # Careful with RTLD_GLOBAL.  If by chance the FFI is not deleted
    # promptly, like on PyPy, then other tests may see the same
    # exported symbols as well.  So we must not export a simple name
    # like 'foo'!
    old = sys.getdlopenflags()
    try:
        ffi1 = FFI()
        ffi1.cdef("extern int foo_verify_dlopen_flags_1;")
        sys.setdlopenflags(ffi1.RTLD_GLOBAL | ffi1.RTLD_NOW)
        lib1 = ffi1.verify("int foo_verify_dlopen_flags_1;")
    finally:
        sys.setdlopenflags(old)

    ffi2 = FFI()
    ffi2.cdef("int *getptr(void);")
    lib2 = ffi2.verify("""
        extern int foo_verify_dlopen_flags_1;
        static int *getptr(void) { return &foo_verify_dlopen_flags_1; }
    """)
    p = lib2.getptr()
    assert ffi1.addressof(lib1, 'foo_verify_dlopen_flags_1') == p

def test_consider_not_implemented_function_type():
    ffi = FFI()
    ffi.cdef("typedef union { int a; float b; } Data;"
             "typedef struct { int a:2; } MyStr;"
             "typedef void (*foofunc_t)(Data);"
             "typedef Data (*bazfunc_t)(void);"
             "typedef MyStr (*barfunc_t)(void);")
    fooptr = ffi.cast("foofunc_t", 123)
    bazptr = ffi.cast("bazfunc_t", 123)
    barptr = ffi.cast("barfunc_t", 123)
    # assert did not crash so far
    e = pytest.raises(NotImplementedError, fooptr, ffi.new("Data *"))
    assert str(e.value) == (
        "ctype 'Data' not supported as argument by libffi.  Unions are only "
        "supported as argument if the function is 'API mode' and "
        "non-variadic (i.e. declared inside ffibuilder.cdef()+"
        "ffibuilder.set_source() and not taking a final '...' argument)")
    e = pytest.raises(NotImplementedError, bazptr)
    assert str(e.value) == (
        "ctype 'Data' not supported as return value by libffi.  Unions are "
        "only supported as return value if the function is 'API mode' and "
        "non-variadic (i.e. declared inside ffibuilder.cdef()+"
        "ffibuilder.set_source() and not taking a final '...' argument)")
    e = pytest.raises(NotImplementedError, barptr)
    assert str(e.value) == (
        "ctype 'MyStr' not supported as return value.  It is a struct with "
        "bit fields, which libffi does not support.  Such structs are only "
        "supported as return value if the function is 'API mode' and non-"
        "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder."
        "set_source() and not taking a final '...' argument)")

def test_verify_extra_arguments():
    ffi = FFI()
    ffi.cdef("#define ABA ...")
    lib = ffi.verify("", define_macros=[('ABA', '42')])
    assert lib.ABA == 42

def test_implicit_unicode_on_windows():
    from cffi import FFIError
    if sys.platform != 'win32':
        pytest.skip("win32-only test")
    ffi = FFI()
    e = pytest.raises(FFIError, ffi.cdef, "int foo(LPTSTR);")
    assert str(e.value) == ("The Windows type 'LPTSTR' is only available after"
                            " you call ffi.set_unicode()")
    for with_unicode in [True, False]:
        ffi = FFI()
        ffi.set_unicode(with_unicode)
        ffi.cdef("""
            DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename,
                                    DWORD nSize);
        """)
        lib = ffi.verify("""
            #include <windows.h>
        """, libraries=['Kernel32'])
        outbuf = ffi.new("TCHAR[]", 200)
        n = lib.GetModuleFileName(ffi.NULL, outbuf, 500)
        assert 0 < n < 500
        for i in range(n):
            #print repr(outbuf[i])
            assert ord(outbuf[i]) != 0
        assert ord(outbuf[n]) == 0
        assert ord(outbuf[0]) < 128     # should be a letter, or '\'

def test_define_known_value():
    ffi = FFI()
    ffi.cdef("#define FOO 0x123")
    lib = ffi.verify("#define FOO 0x123")
    assert lib.FOO == 0x123

def test_define_wrong_value():
    ffi = FFI()
    ffi.cdef("#define FOO 123")
    lib = ffi.verify("#define FOO 124")     # used to complain
    with pytest.raises(ffi.error) as e:
        lib.FOO
    assert str(e.value) == ("the C compiler says 'FOO' is equal to 124 (0x7c),"
                            " but the cdef disagrees")

def test_some_integer_type_for_issue73():
    ffi = FFI()
    ffi.cdef("""
        typedef int... AnIntegerWith32Bits;
        typedef AnIntegerWith32Bits (*AFunctionReturningInteger) (void);
        AnIntegerWith32Bits InvokeFunction(AFunctionReturningInteger);
    """)
    lib = ffi.verify("""
        #ifdef __LP64__
        typedef int AnIntegerWith32Bits;
        #else
        typedef long AnIntegerWith32Bits;
        #endif
        typedef AnIntegerWith32Bits (*AFunctionReturningInteger) (void);
        AnIntegerWith32Bits InvokeFunction(AFunctionReturningInteger f) {
            return f();
        }
    """)
    @ffi.callback("AFunctionReturningInteger")
    def add():
        return 3 + 4
    x = lib.InvokeFunction(add)
    assert x == 7

def test_unsupported_some_primitive_types():
    ffi = FFI()
    pytest.raises((FFIError,      # with pycparser <= 2.17
                    CDefError),    # with pycparser >= 2.18
                   ffi.cdef, """typedef void... foo_t;""")
    #
    ffi.cdef("typedef int... foo_t;")
    pytest.raises(VerificationError, ffi.verify, "typedef float foo_t;")

def test_windows_dllimport_data():
    if sys.platform != 'win32':
        pytest.skip("Windows only")
    from testing.udir import udir
    tmpfile = udir.join('dllimport_data.c')
    tmpfile.write('int my_value = 42;\n')
    ffi = FFI()
    ffi.cdef("int my_value;")
    lib = ffi.verify("extern __declspec(dllimport) int my_value;",
                     sources = [str(tmpfile)])
    assert lib.my_value == 42

def test_macro_var():
    ffi = FFI()
    ffi.cdef("extern int myarray[50], my_value;")
    lib = ffi.verify("""
        int myarray[50];
        int *get_my_value(void) {
            static int index = 0;
            return &myarray[index++];
        }
        #define my_value (*get_my_value())
    """)
    assert lib.my_value == 0             # [0]
    lib.my_value = 42                    # [1]
    assert lib.myarray[1] == 42
    assert lib.my_value == 0             # [2]
    lib.myarray[3] = 63
    assert lib.my_value == 63            # [3]
    p = ffi.addressof(lib, 'my_value')   # [4]
    assert p[-1] == 63
    assert p[0] == 0
    assert p == lib.myarray + 4
    p[1] = 82
    assert lib.my_value == 82            # [5]

def test_const_pointer_to_pointer():
    ffi = FFI()
    ffi.cdef("struct s { char *const *a; };")
    ffi.verify("struct s { char *const *a; };")

def test_share_FILE():
    ffi1 = FFI()
    ffi1.cdef("void do_stuff(FILE *);")
    lib1 = ffi1.verify("void do_stuff(FILE *f) { (void)f; }")
    ffi2 = FFI()
    ffi2.cdef("FILE *barize(void);")
    lib2 = ffi2.verify("FILE *barize(void) { return NULL; }")
    lib1.do_stuff(lib2.barize())

def test_win_common_types():
    if sys.platform != 'win32':
        pytest.skip("Windows only")
    ffi = FFI()
    ffi.set_unicode(True)
    ffi.verify("")
    assert ffi.typeof("PBYTE") is ffi.typeof("unsigned char *")
    if sys.maxsize > 2**32:
        expected = "unsigned long long"
    else:
        expected = "unsigned int"
    assert ffi.typeof("UINT_PTR") is ffi.typeof(expected)
    assert ffi.typeof("PTSTR") is ffi.typeof("wchar_t *")

def _only_test_on_linux_intel():
    if not sys.platform.startswith('linux'):
        pytest.skip('only running the memory-intensive test on Linux')
    import platform
    machine = platform.machine()
    if 'x86' not in machine and 'x64' not in machine:
        pytest.skip('only running the memory-intensive test on x86/x64')

def test_ffi_gc_size_arg():
    _only_test_on_linux_intel()
    ffi = FFI()
    ffi.cdef("void *malloc(size_t); void free(void *);")
    lib = ffi.verify(r"""
        #include <stdlib.h>
    """)
    for i in range(2000):
        p = lib.malloc(20*1024*1024)    # 20 MB
        p1 = ffi.cast("char *", p)
        for j in range(0, 20*1024*1024, 4096):
            p1[j] = b'!'
        p = ffi.gc(p, lib.free, 20*1024*1024)
        del p
        # with PyPy's GC, the above would rapidly consume 40 GB of RAM
        # without the third argument to ffi.gc()

def test_ffi_gc_size_arg_2():
    # a variant of the above: this "attack" works on cpython's cyclic gc too
    # and I found no obvious way to prevent that.  So for now, this test
    # is skipped on CPython, where it eats all the memory.
    if '__pypy__' not in sys.builtin_module_names:
        pytest.skip("find a way to tweak the cyclic GC of CPython")
    _only_test_on_linux_intel()
    ffi = FFI()
    ffi.cdef("void *malloc(size_t); void free(void *);")
    lib = ffi.verify(r"""
        #include <stdlib.h>
    """)
    class X(object):
        pass
    for i in range(2000):
        p = lib.malloc(50*1024*1024)    # 50 MB
        p1 = ffi.cast("char *", p)
        for j in range(0, 50*1024*1024, 4096):
            p1[j] = b'!'
        p = ffi.gc(p, lib.free, 50*1024*1024)
        x = X()
        x.p = p
        x.cyclic = x
        del p, x

def test_ffi_new_with_cycles():
    # still another variant, with ffi.new()
    if '__pypy__' not in sys.builtin_module_names:
        pytest.skip("find a way to tweak the cyclic GC of CPython")
    ffi = FFI()
    ffi.cdef("")
    lib = ffi.verify("")
    class X(object):
        pass
    for i in range(2000):
        p = ffi.new("char[]", 50*1024*1024)    # 50 MB
        for j in range(0, 50*1024*1024, 4096):
            p[j] = b'!'
        x = X()
        x.p = p
        x.cyclic = x
        del p, x

testing/cffi1/test_verify1.py
python-cffi/cffi
import sys, os
import pytest
import subprocess
import cffi
from testing.udir import udir
from shutil import rmtree
from tempfile import mkdtemp


def chdir_to_tmp(f):
    f.chdir_to_tmp = True
    return f

def from_outside(f):
    f.chdir_to_tmp = False
    return f


class TestDist(object):

    def setup_method(self, meth):
        self.executable = os.path.abspath(sys.executable)
        self.rootdir = os.path.abspath(os.path.dirname(os.path.dirname(
            cffi.__file__)))
        self.udir = udir.join(meth.__name__)
        os.mkdir(str(self.udir))
        if meth.chdir_to_tmp:
            self.saved_cwd = os.getcwd()
            os.chdir(str(self.udir))

    def teardown_method(self, meth):
        if hasattr(self, 'saved_cwd'):
            os.chdir(self.saved_cwd)

    def run(self, args, cwd=None):
        env = os.environ.copy()
        # a horrible hack to prevent distutils from finding ~/.pydistutils.cfg
        # (there is the --no-user-cfg option, but not in Python 2.6...)
        # NOTE: pointing $HOME to a nonexistent directory can break certain things
        # that look there for configuration (like ccache).
        tmp_home = mkdtemp()
        assert tmp_home != None, "cannot create temporary homedir"
        env['HOME'] = tmp_home
        pathlist = sys.path[:]
        if cwd is None:
            pathlist.insert(0, self.rootdir)
        env['PYTHONPATH'] = os.pathsep.join(pathlist)
        try:
            subprocess.check_call([self.executable] + args, cwd=cwd, env=env)
        finally:
            rmtree(tmp_home)

    def _prepare_setuptools(self):
        if hasattr(TestDist, '_setuptools_ready'):
            return
        try:
            import setuptools
        except ImportError:
            pytest.skip("setuptools not found")
        if os.path.exists(os.path.join(self.rootdir, 'setup.py')):
            self.run(['setup.py', 'egg_info'], cwd=self.rootdir)
        TestDist._setuptools_ready = True

    def check_produced_files(self, content, curdir=None):
        if curdir is None:
            curdir = str(self.udir)
        found_so = None
        for name in os.listdir(curdir):
            if (name.endswith('.so') or name.endswith('.pyd') or
                name.endswith('.dylib') or name.endswith('.dll')):
                found_so = os.path.join(curdir, name)
                # foo.so => foo
                parts = name.split('.')
                del parts[-1]
                if len(parts) > 1 and parts[-1] != 'bar':
                    # foo.cpython-34m.so => foo, but foo.bar.so => foo.bar
                    del parts[-1]
                name = '.'.join(parts)
                # foo_d => foo (Python 2 debug builds)
                if name.endswith('_d') and hasattr(sys, 'gettotalrefcount'):
                    name = name[:-2]
                name += '.SO'
            if name.startswith('pycparser') and name.endswith('.egg'):
                continue    # no clue why this shows up sometimes and not others
            if name == '.eggs':
                continue    # seems new in 3.5, ignore it
            assert name in content, "found unexpected file %r" % (
                os.path.join(curdir, name),)
            value = content.pop(name)
            if value is None:
                assert name.endswith('.SO') or (
                    os.path.isfile(os.path.join(curdir, name)))
            else:
                subdir = os.path.join(curdir, name)
                assert os.path.isdir(subdir)
                if value == '?':
                    continue
                found_so = self.check_produced_files(value, subdir) or found_so
        assert content == {}, "files or dirs not produced in %r: %r" % (
            curdir, content.keys())
        return found_so

    @chdir_to_tmp
    def test_empty(self):
        self.check_produced_files({})

    @chdir_to_tmp
    def test_abi_emit_python_code_1(self):
        ffi = cffi.FFI()
        ffi.set_source("package_name_1.mymod", None)
        ffi.emit_python_code('xyz.py')
        self.check_produced_files({'xyz.py': None})

    @chdir_to_tmp
    def test_abi_emit_python_code_2(self):
        ffi = cffi.FFI()
        ffi.set_source("package_name_1.mymod", None)
        pytest.raises(IOError, ffi.emit_python_code, 'unexisting/xyz.py')

    @from_outside
    def test_abi_emit_python_code_3(self):
        ffi = cffi.FFI()
        ffi.set_source("package_name_1.mymod", None)
        ffi.emit_python_code(str(self.udir.join('xyt.py')))
        self.check_produced_files({'xyt.py': None})

    @chdir_to_tmp
    def test_abi_compile_1(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", None)
        x = ffi.compile()
        self.check_produced_files({'mod_name_in_package': {'mymod.py': None}})
        assert x == os.path.join('.', 'mod_name_in_package', 'mymod.py')

    @chdir_to_tmp
    def test_abi_compile_2(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", None)
        x = ffi.compile('build2')
        self.check_produced_files({'build2': {
            'mod_name_in_package': {'mymod.py': None}}})
        assert x == os.path.join('build2', 'mod_name_in_package', 'mymod.py')

    @from_outside
    def test_abi_compile_3(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", None)
        tmpdir = str(self.udir.join('build3'))
        x = ffi.compile(tmpdir)
        self.check_produced_files({'build3': {
            'mod_name_in_package': {'mymod.py': None}}})
        assert x == os.path.join(tmpdir, 'mod_name_in_package', 'mymod.py')

    @chdir_to_tmp
    def test_api_emit_c_code_1(self):
        ffi = cffi.FFI()
        ffi.set_source("package_name_1.mymod", "/*code would be here*/")
        ffi.emit_c_code('xyz.c')
        self.check_produced_files({'xyz.c': None})

    @chdir_to_tmp
    def test_api_emit_c_code_2(self):
        ffi = cffi.FFI()
        ffi.set_source("package_name_1.mymod", "/*code would be here*/")
        pytest.raises(IOError, ffi.emit_c_code, 'unexisting/xyz.c')

    @from_outside
    def test_api_emit_c_code_3(self):
        ffi = cffi.FFI()
        ffi.set_source("package_name_1.mymod", "/*code would be here*/")
        ffi.emit_c_code(str(self.udir.join('xyu.c')))
        self.check_produced_files({'xyu.c': None})

    @chdir_to_tmp
    def test_api_compile_1(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        x = ffi.compile()
        if sys.platform != 'win32':
            sofile = self.check_produced_files({
                'mod_name_in_package': {'mymod.SO': None,
                                        'mymod.c': None,
                                        'mymod.o': None}})
            assert os.path.isabs(x) and os.path.samefile(x, sofile)
        else:
            self.check_produced_files({
                'mod_name_in_package': {'mymod.SO': None,
                                        'mymod.c': None},
                'Release': '?'})

    @chdir_to_tmp
    def test_api_compile_2(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        x = ffi.compile('output')
        if sys.platform != 'win32':
            sofile = self.check_produced_files({
                'output': {'mod_name_in_package': {'mymod.SO': None,
                                                   'mymod.c': None,
                                                   'mymod.o': None}}})
            assert os.path.isabs(x) and os.path.samefile(x, sofile)
        else:
            self.check_produced_files({
                'output': {'mod_name_in_package': {'mymod.SO': None,
                                                   'mymod.c': None},
                           'Release': '?'}})

    @from_outside
    def test_api_compile_3(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        x = ffi.compile(str(self.udir.join('foo')))
        if sys.platform != 'win32':
            sofile = self.check_produced_files({
                'foo': {'mod_name_in_package': {'mymod.SO': None,
                                                'mymod.c': None,
                                                'mymod.o': None}}})
            assert os.path.isabs(x) and os.path.samefile(x, sofile)
        else:
            self.check_produced_files({
                'foo': {'mod_name_in_package': {'mymod.SO': None,
                                                'mymod.c': None},
                        'Release': '?'}})

    @chdir_to_tmp
    def test_api_compile_explicit_target_1(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        x = ffi.compile(target="foo.bar.*")
        if sys.platform != 'win32':
            sofile = self.check_produced_files({
                'mod_name_in_package': {'foo.bar.SO': None,
                                        'mymod.c': None,
                                        'mymod.o': None}})
            assert os.path.isabs(x) and os.path.samefile(x, sofile)
        else:
            self.check_produced_files({
                'mod_name_in_package': {'foo.bar.SO': None,
                                        'mymod.c': None},
                'Release': '?'})

    @chdir_to_tmp
    def test_api_compile_explicit_target_3(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        x = ffi.compile(target="foo.bar.baz")
        if sys.platform != 'win32':
            self.check_produced_files({
                'mod_name_in_package': {'foo.bar.baz': None,
                                        'mymod.c': None,
                                        'mymod.o': None}})
            sofile = os.path.join(str(self.udir),
                                  'mod_name_in_package', 'foo.bar.baz')
            assert os.path.isabs(x) and os.path.samefile(x, sofile)
        else:
            self.check_produced_files({
                'mod_name_in_package': {'foo.bar.baz': None,
                                        'mymod.c': None},
                'Release': '?'})

    @chdir_to_tmp
    def test_api_distutils_extension_1(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        ext = ffi.distutils_extension()
        self.check_produced_files({'build': {
            'mod_name_in_package': {'mymod.c': None}}})
        if hasattr(os.path, 'samefile'):
            assert os.path.samefile(ext.sources[0],
                                    'build/mod_name_in_package/mymod.c')

    @from_outside
    def test_api_distutils_extension_2(self):
        ffi = cffi.FFI()
        ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/")
        ext = ffi.distutils_extension(str(self.udir.join('foo')))
        self.check_produced_files({'foo': {
            'mod_name_in_package': {'mymod.c': None}}})
        if hasattr(os.path, 'samefile'):
            assert os.path.samefile(ext.sources[0],
                str(self.udir.join('foo/mod_name_in_package/mymod.c')))


    def _make_distutils_api(self):
        os.mkdir("src")
        os.mkdir(os.path.join("src", "pack1"))
        with open(os.path.join("src", "pack1", "__init__.py"), "w") as f:
            pass
        with open("setup.py", "w") as f:
            f.write("""if 1:
                # https://bugs.python.org/issue23246
                import setuptools
                import cffi
                ffi = cffi.FFI()
                ffi.set_source("pack1.mymod", "/*code would be here*/")

                from distutils.core import setup
                setup(name='example1',
                      version='0.1',
                      packages=['pack1'],
                      package_dir={'': 'src'},
                      ext_modules=[ffi.distutils_extension()])
            """)

    @chdir_to_tmp
    def test_distutils_api_1(self):
        self._make_distutils_api()
        self.run(["setup.py", "build"])
        self.check_produced_files({'setup.py': None,
                                   'build': '?',
                                   'src': {'pack1': {'__init__.py': None}}})

    @chdir_to_tmp
    def test_distutils_api_2(self):
        self._make_distutils_api()
        self.run(["setup.py", "build_ext", "-i"])
        self.check_produced_files({'setup.py': None,
                                   'build': '?',
                                   'src': {'pack1': {'__init__.py': None,
                                                     'mymod.SO': None}}})

    def _make_setuptools_abi(self):
        self._prepare_setuptools()
        os.mkdir("src0")
        os.mkdir(os.path.join("src0", "pack2"))
        with open(os.path.join("src0", "pack2", "__init__.py"), "w") as f:
            pass
        with open(os.path.join("src0", "pack2", "_build.py"), "w") as f:
            f.write("""if 1:
                import cffi
                ffi = cffi.FFI()
                ffi.set_source("pack2.mymod", None)
            """)
        with open("setup.py", "w") as f:
            f.write("""if 1:
                from setuptools import setup
                setup(name='example1',
                      version='0.1',
                      packages=['pack2'],
                      package_dir={'': 'src0'},
                      cffi_modules=["src0/pack2/_build.py:ffi"])
            """)

    @chdir_to_tmp
    def test_setuptools_abi_1(self):
        self._make_setuptools_abi()
        self.run(["setup.py", "build"])
        self.check_produced_files({'setup.py': None,
                                   'build': '?',
                                   'src0': {'pack2': {'__init__.py': None,
                                                      '_build.py': None}}})

    @chdir_to_tmp
    def test_setuptools_abi_2(self):
        self._make_setuptools_abi()
        self.run(["setup.py", "build_ext", "-i"])
        self.check_produced_files({'setup.py': None,
                                   'src0': {'pack2': {'__init__.py': None,
                                                      '_build.py': None,
                                                      'mymod.py': None}}})

    def _make_setuptools_api(self):
        self._prepare_setuptools()
        os.mkdir("src1")
        os.mkdir(os.path.join("src1", "pack3"))
        with open(os.path.join("src1", "pack3", "__init__.py"), "w") as f:
            pass
        with open(os.path.join("src1", "pack3", "_build.py"), "w") as f:
            f.write("""if 1:
                import cffi
                ffi = cffi.FFI()
                ffi.set_source("pack3.mymod", "/*code would be here*/")
                ffi._hi_there = 42
            """)
        with open("setup.py", "w") as f:
            f.write("from __future__ import print_function\n"
                """if 1:
                from setuptools import setup
                from distutils.command.build_ext import build_ext
                import os

                class TestBuildExt(build_ext):
                    def pre_run(self, ext, ffi):
                        print('_make_setuptools_api: in pre_run:', end=" ")
                        assert ffi._hi_there == 42
                        assert ext.name == "pack3.mymod"
                        fn = os.path.join(os.path.dirname(self.build_lib),
                                          '..', 'see_me')
                        print('creating %r' % (fn,))
                        open(fn, 'w').close()

                setup(name='example1',
                      version='0.1',
                      packages=['pack3'],
                      package_dir={'': 'src1'},
                      cffi_modules=["src1/pack3/_build.py:ffi"],
                      cmdclass={'build_ext': TestBuildExt},
                      )
            """)

    @chdir_to_tmp
    def test_setuptools_api_1(self):
        self._make_setuptools_api()
        self.run(["setup.py", "build"])
        self.check_produced_files({'setup.py': None,
                                   'build': '?',
                                   'see_me': None,
                                   'src1': {'pack3': {'__init__.py': None,
                                                      '_build.py': None}}})

    @chdir_to_tmp
    def test_setuptools_api_2(self):
        self._make_setuptools_api()
        self.run(["setup.py", "build_ext", "-i"])
        self.check_produced_files({'setup.py': None,
                                   'build': '?',
                                   'see_me': None,
                                   'src1': {'pack3': {'__init__.py': None,
                                                      '_build.py': None,
                                                      'mymod.SO': None}}})

testing/cffi1/test_zdist.py
python-cffi/cffi
import pytest
import sys

from ctypes import util

# this problem was supposedly fixed in a newer Python 3.8 release, but after binary installer support expired
# https://github.com/python/cpython/pull/28054
if sys.platform == 'darwin' and sys.version_info[:2] == (3, 8):
    orig_find_library = util.find_library

    def hacked_find_library(*args, **kwargs):
        res = orig_find_library(*args, **kwargs)

        if res is None:
            pytest.xfail("busted find_library on MacOS Python 3.8")

        return res

    util.find_library = hacked_find_library

testing/conftest.py
python-cffi/cffi
import sys, os, re
import shutil, subprocess, time
import pytest
from testing.udir import udir
import cffi


local_dir = os.path.dirname(os.path.abspath(__file__))
_link_error = '?'

def check_lib_python_found(tmpdir):
    global _link_error
    if _link_error == '?':
        ffi = cffi.FFI()
        kwds = {}
        ffi._apply_embedding_fix(kwds)
        ffi.set_source("_test_lib_python_found", "", **kwds)
        try:
            ffi.compile(tmpdir=tmpdir, verbose=True)
        except cffi.VerificationError as e:
            _link_error = e
        else:
            _link_error = None
    if _link_error:
        pytest.skip(str(_link_error))


def prefix_pythonpath():
    cffi_base = os.path.dirname(os.path.dirname(local_dir))
    pythonpath = org_env.get('PYTHONPATH', '').split(os.pathsep)
    if cffi_base not in pythonpath:
        pythonpath.insert(0, cffi_base)
    return os.pathsep.join(pythonpath)

def copy_away_env():
    global org_env
    try:
        org_env
    except NameError:
        org_env = os.environ.copy()


class EmbeddingTests:
    _compiled_modules = {}

    def setup_method(self, meth):
        check_lib_python_found(str(udir.ensure('embedding', dir=1)))
        self._path = udir.join('embedding', meth.__name__)
        if sys.platform == "win32" or sys.platform == "darwin":
            self._compiled_modules.clear()   # workaround

    def get_path(self):
        return str(self._path.ensure(dir=1))

    def _run_base(self, args, **kwds):
        print('RUNNING:', args, kwds)
        return subprocess.Popen(args, **kwds)

    def _run(self, args):
        popen = self._run_base(args, cwd=self.get_path(),
                                 stdout=subprocess.PIPE,
                                 universal_newlines=True)
        output = popen.stdout.read()
        err = popen.wait()
        if err:
            raise OSError(("popen failed with exit code %r: %r\n\n%s" % (
                err, args, output)).rstrip())
        print(output.rstrip())
        return output

    def prepare_module(self, name):
        self.patch_environment()
        if name not in self._compiled_modules:
            path = self.get_path()
            filename = '%s.py' % name
            # NOTE: if you have an .egg globally installed with an older
            # version of cffi, this will not work, because sys.path ends
            # up with the .egg before the PYTHONPATH entries.  I didn't
            # find a solution to that: we could hack sys.path inside the
            # script run here, but we can't hack it in the same way in
            # execute().
            pathname = os.path.join(path, filename)
            with open(pathname, 'w') as g:
                g.write('''
# https://bugs.python.org/issue23246
import sys
if sys.platform == 'win32':
    try:
        import setuptools
    except ImportError:
        pass
''')
                with open(os.path.join(local_dir, filename), 'r') as f:
                    g.write(f.read())

            output = self._run([sys.executable, pathname])
            match = re.compile(r"\bFILENAME: (.+)").search(output)
            assert match
            dynamic_lib_name = match.group(1)
            if sys.platform == 'win32':
                assert dynamic_lib_name.endswith('_cffi.dll')
            elif sys.platform == 'darwin':
                assert dynamic_lib_name.endswith('_cffi.dylib')
            else:
                assert dynamic_lib_name.endswith('_cffi.so')
            self._compiled_modules[name] = dynamic_lib_name
        return self._compiled_modules[name]

    def compile(self, name, modules, opt=False, threads=False, defines={}):
        path = self.get_path()
        filename = '%s.c' % name
        shutil.copy(os.path.join(local_dir, filename), path)
        shutil.copy(os.path.join(local_dir, 'thread-test.h'), path)
        import distutils.ccompiler
        curdir = os.getcwd()
        try:
            os.chdir(self.get_path())
            c = distutils.ccompiler.new_compiler()
            print('compiling %s with %r' % (name, modules))
            extra_preargs = []
            debug = True
            if sys.platform == 'win32':
                libfiles = []
                for m in modules:
                    m = os.path.basename(m)
                    assert m.endswith('.dll')
                    libfiles.append('Release\\%s.lib' % m[:-4])
                modules = libfiles
                extra_preargs.append('/MANIFEST')
                debug = False    # you need to install extra stuff
                                 # for this to work
            elif threads:
                extra_preargs.append('-pthread')
            objects = c.compile([filename], macros=sorted(defines.items()),
                                debug=debug)
            c.link_executable(objects + modules, name, extra_preargs=extra_preargs)
        finally:
            os.chdir(curdir)

    def patch_environment(self):
        copy_away_env()
        path = self.get_path()
        # for libpypy-c.dll or Python27.dll
        path = os.path.split(sys.executable)[0] + os.path.pathsep + path
        env_extra = {'PYTHONPATH': prefix_pythonpath()}
        if sys.platform == 'win32':
            envname = 'PATH'
        else:
            envname = 'LD_LIBRARY_PATH'
        libpath = org_env.get(envname)
        if libpath:
            libpath = path + os.path.pathsep + libpath
        else:
            libpath = path
        env_extra[envname] = libpath
        for key, value in sorted(env_extra.items()):
            if os.environ.get(key) != value:
                print('* setting env var %r to %r' % (key, value))
                os.environ[key] = value

    def execute(self, name):
        path = self.get_path()
        print('running %r in %r' % (name, path))
        executable_name = name
        if sys.platform == 'win32':
            executable_name = os.path.join(path, executable_name + '.exe')
        else:
            executable_name = os.path.join('.', executable_name)
        popen = self._run_base([executable_name], cwd=path,
                               stdout=subprocess.PIPE,
                               universal_newlines=True)
        result = popen.stdout.read()
        err = popen.wait()
        if err:
            raise OSError("%r failed with exit code %r" % (
                os.path.join(path, executable_name), err))
        return result


class TestBasic(EmbeddingTests):
    def test_empty(self):
        empty_cffi = self.prepare_module('empty')
        self.compile('empty-test', [empty_cffi])
        output = self.execute('empty-test')
        assert output == 'OK\n'

    def test_basic(self):
        add1_cffi = self.prepare_module('add1')
        self.compile('add1-test', [add1_cffi])
        output = self.execute('add1-test')
        assert output == ("preparing...\n"
                          "adding 40 and 2\n"
                          "adding 100 and -5\n"
                          "got: 42 95\n")

    def test_two_modules(self):
        add1_cffi = self.prepare_module('add1')
        add2_cffi = self.prepare_module('add2')
        self.compile('add2-test', [add1_cffi, add2_cffi])
        output = self.execute('add2-test')
        assert output == ("preparing...\n"
                          "adding 40 and 2\n"
                          "prepADD2\n"
                          "adding 100 and -5 and -20\n"
                          "got: 42 75\n")

    def test_init_time_error(self):
        initerror_cffi = self.prepare_module('initerror')
        self.compile('add1-test', [initerror_cffi])
        output = self.execute('add1-test')
        assert output == "got: 0 0\n"    # plus lots of info to stderr

    def test_embedding_with_unicode(self):
        withunicode_cffi = self.prepare_module('withunicode')
        self.compile('add1-test', [withunicode_cffi])
        output = self.execute('add1-test')
        assert output == "255\n4660\n65244\ngot: 0 0\n"

testing/embedding/test_basic.py
python-cffi/cffi
import sys, os
from cffi._imp_emulation import load_dynamic

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

    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', 'load_dynamic']
    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):
    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 = 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
    except ImportError:
        pass
    else:
        tagset = frozenset(platform_tags())
        is_musl = any(t.startswith('musllinux') for t in tagset)
        if is_musl and sys.version_info >= (3, 12):
            if any(t.startswith('musllinux_1_1_') for t in tagset) and not any(t.startswith('musllinux_1_2_') for t in tagset):
                # gcc 9.2.0 in the musllinux_1_1 build container has a bug in its sign-conversion warning detection that
                # bombs on the definition of _PyLong_CompactValue under Python 3.12; disable warnings-as-errors for that
                # specific error on musl 1.1
                extra_compile_args.append('-Wno-error=sign-conversion')

        del platform_tags

testing/support.py
python-cffi/cffi
#!/usr/bin/env python
"""A simple script to update the version embedded in the source."""

import argparse
import pathlib
import re

from packaging.version import Version


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('version', type=Version, help='version number to embed in source files')
    args = parser.parse_args()
    version: Version = args.version

    major_minor_version = f'{version.major}.{version.minor}'
    version_info = ', '.join(map(repr, get_version_info(version)))

    updates: list[tuple[str, re.Pattern, str | Version]] = [
        ('doc/source/conf.py', re.compile(r"^(version = ')[^']*(')$", flags=re.MULTILINE), major_minor_version),
        ('doc/source/conf.py', re.compile(r"^(release = ')[^']*(')$", flags=re.MULTILINE), version),
        ('setup.py', re.compile(r"^( +version=')[^']*(',)$", flags=re.MULTILINE), version),
        ('src/c/_cffi_backend.c', re.compile(r'^(#define CFFI_VERSION +")[^"]*(")$', flags=re.MULTILINE), version),
        ('src/c/test_c.py', re.compile(r'^(assert __version__ == ")[^"]*(", .*)$', flags=re.MULTILINE), version),
        ('src/cffi/__init__.py', re.compile(r'^(__version__ = ")[^"]*(")$', flags=re.MULTILINE), version),
        ('src/cffi/__init__.py', re.compile(r'^(__version_info__ = \()[^)]*(\))$', flags=re.MULTILINE), version_info),
        ('src/cffi/_embedding.h', re.compile(r'^( +"\\ncompiled with cffi version: )[^"]*(")$', flags=re.MULTILINE), version),
    ]

    repo_root = pathlib.Path(__file__).parent.parent

    for relative_path, pattern, replacement in updates:
        path = repo_root / relative_path
        original_content = path.read_text()

        if not pattern.search(original_content):
            raise RuntimeError(f'{relative_path}: no match found for pattern: {pattern.pattern}')

        updated_content = pattern.sub(rf'\g<1>{replacement}\g<2>', original_content)

        if updated_content == original_content:
            print(f'{relative_path}: unchanged')
        else:
            path.write_text(updated_content)
            print(f'{relative_path}: updated')


def get_version_info(version: Version) -> tuple:
    """Return a tuple representing the given version."""
    version_info = list(version.release)

    if version.pre is not None:
        version_info.append(''.join(map(str, version.pre)))

    if version.post is not None:
        version_info.append(f'post{version.post}')

    if version.dev is not None:
        version_info.append(f'dev{version.dev}')

    if version.local is not None:
        version_info.append(f'+{version.local}')

    return tuple(version_info)


if __name__ == '__main__':
    main()

tools/version.py
python-cffi/cffi