Commits

Armin Rigo committed 8e7c7f0

Start testing that the backend has the correct kinds of integers.

Comments (0)

Files changed (3)

         self._backend = backend
         self._functions = {}
         self._cached_btypes = {}
+        self._cached_parsed_types = {}
         self.C = FFILibrary(self, self._backend.load_library())
 
     def cdef(self, csource):
         typenode = self._parse_type(cdecl)
         return self._get_btype(typenode)
 
-    def new(self, cdecl):
+    def new(self, cdecl, *args):
         btype = self.typeof(cdecl)
-        return btype()
+        return btype(*args)
 
     def _parse_type(self, cdecl):
-        parser = pycparser.CParser()
-        csource = 'void __dummy(%s);' % cdecl
-        ast = parser.parse(csource)
-        # XXX: insert some sanity check
-        typenode = ast.ext[0].type.args.params[0].type
-        return typenode
+        try:
+            return self._cached_parsed_types[cdecl]
+        except KeyError:
+            parser = pycparser.CParser()
+            csource = 'void __dummy(%s);' % cdecl
+            ast = parser.parse(csource)
+            # XXX: insert some sanity check
+            typenode = ast.ext[0].type.args.params[0].type
+            self._cached_parsed_types[cdecl] = typenode
+            return typenode
 
     def _get_btype(self, typenode):
         if isinstance(typenode, pycparser.c_ast.ArrayDecl):

ffi/backend_ctypes.py

 class CTypesBackend(object):
 
     PRIMITIVE_TYPES = {
+        'short': ctypes.c_short,
         'int': ctypes.c_int,
+        'long': ctypes.c_long,
+        'long int': ctypes.c_long,
+        'long long': ctypes.c_longlong,
+        'long long int': ctypes.c_longlong,
+        'signed char': ctypes.c_byte,
+        'signed short': ctypes.c_short,
+        'signed int': ctypes.c_int,
+        'signed long': ctypes.c_long,
+        'signed long int': ctypes.c_long,
+        'signed long long': ctypes.c_longlong,
+        'signed long long int': ctypes.c_longlong,
+        'unsigned char': ctypes.c_ubyte,
+        'unsigned short': ctypes.c_ushort,
+        'unsigned int': ctypes.c_uint,
+        'unsigned long': ctypes.c_ulong,
+        'unsigned long int': ctypes.c_ulong,
+        'unsigned long long': ctypes.c_ulonglong,
+        'unsigned long long int': ctypes.c_ulonglong,
         'double': ctypes.c_double,
     }
 
         return CTypesLibrary(cdll)
 
     def new_primitive_type(self, name):
-        return self.PRIMITIVE_TYPES[name]
+        # XXX integer types only
+        ctype = self.PRIMITIVE_TYPES[name]
+        #
+        class CTypesInt(object):
+            _ctype = ctype
+            def __init__(self, value=0):
+                if ctype(value).value != value:
+                    raise OverflowError("%r out of range: %d" %
+                                        (name, value))
+                self._value = value
+            def __int__(self):
+                return self._value
+        #
+        return CTypesInt
 
     def new_array_type(self, bitem, length):
-        ctype = bitem * length
+        ctype = bitem._ctype * length
         #
         class CTypesArray(object):
-            def __init__(self):
+            def __init__(self, *args):
+                if len(args) > length:
+                    raise TypeError("too many arguments: expected up to %d, "
+                                    "got %d" % (length, len(args)))
                 self._blob = ctype()
+                for i, value in enumerate(args):
+                    self[i] = value
             def __getitem__(self, index):
                 if not (0 <= index < length):
                     raise IndexError

testing/backend_tests.py

 import py
+import sys
 from ffi import FFI
 
+SIZE_OF_LONG = 4 if sys.maxint == 2147483647 else 8
+
 
 class BackendTests:
 
+    def test_integer_ranges(self):
+        ffi = FFI(backend=self.Backend())
+        for (c_type, size) in [('char', 1),
+                               ('short', 2),
+                               ('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':
+                    continue
+                if unsigned:
+                    min = 0
+                    max = (1 << (8*size)) - 1
+                else:
+                    min = -(1 << (8*size-1))
+                    max = (1 << (8*size-1)) - 1
+                p = ffi.new(c_decl, min)
+                assert int(p) == min
+                p = ffi.new(c_decl, max)
+                assert int(p) == max
+                py.test.raises(OverflowError, ffi.new, c_decl, min - 1)
+                py.test.raises(OverflowError, ffi.new, c_decl, max + 1)
+
     def test_new_array_no_arg(self):
         ffi = FFI(backend=self.Backend())
         p = ffi.new("int[10]")
         py.test.raises(IndexError, "p[10] = 44")
         py.test.raises(IndexError, "p[-1]")
         py.test.raises(IndexError, "p[-1] = 44")
+
+    def test_new_array_args(self):
+        ffi = FFI(backend=self.Backend())
+        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
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.