Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 1 | import unittest |
| 2 | from ctypes import * |
| 3 | import re, struct, sys |
| 4 | |
| 5 | if sys.byteorder == "little": |
| 6 | THIS_ENDIAN = "<" |
| 7 | OTHER_ENDIAN = ">" |
| 8 | else: |
| 9 | THIS_ENDIAN = ">" |
| 10 | OTHER_ENDIAN = "<" |
| 11 | |
| 12 | def normalize(format): |
| 13 | # Remove current endian specifier and white space from a format |
| 14 | # string |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 15 | if format is None: |
| 16 | return "" |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 17 | format = format.replace(OTHER_ENDIAN, THIS_ENDIAN) |
| 18 | return re.sub(r"\s", "", format) |
| 19 | |
| 20 | class Test(unittest.TestCase): |
| 21 | |
| 22 | def test_native_types(self): |
| 23 | for tp, fmt, shape, itemtp in native_types: |
| 24 | ob = tp() |
| 25 | v = memoryview(ob) |
| 26 | try: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 27 | self.assertEqual(normalize(v.format), normalize(fmt)) |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 28 | if shape: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 29 | self.assertEqual(len(v), shape[0]) |
Antoine Pitrou | c3b3924 | 2009-01-03 16:59:18 +0000 | [diff] [blame] | 30 | else: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 31 | self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob)) |
| 32 | self.assertEqual(v.itemsize, sizeof(itemtp)) |
| 33 | self.assertEqual(v.shape, shape) |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 34 | # XXX Issue #12851: PyCData_NewGetBuffer() must provide strides |
| 35 | # if requested. memoryview currently reconstructs missing |
| 36 | # stride information, so this assert will fail. |
| 37 | # self.assertEqual(v.strides, ()) |
| 38 | |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 39 | # they are always read/write |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 40 | self.assertFalse(v.readonly) |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 41 | |
| 42 | if v.shape: |
| 43 | n = 1 |
| 44 | for dim in v.shape: |
| 45 | n = n * dim |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 46 | self.assertEqual(n * v.itemsize, len(v.tobytes())) |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 47 | except: |
| 48 | # so that we can see the failing type |
| 49 | print(tp) |
| 50 | raise |
| 51 | |
| 52 | def test_endian_types(self): |
| 53 | for tp, fmt, shape, itemtp in endian_types: |
| 54 | ob = tp() |
| 55 | v = memoryview(ob) |
| 56 | try: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 57 | self.assertEqual(v.format, fmt) |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 58 | if shape: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 59 | self.assertEqual(len(v), shape[0]) |
Antoine Pitrou | c3b3924 | 2009-01-03 16:59:18 +0000 | [diff] [blame] | 60 | else: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 61 | self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob)) |
| 62 | self.assertEqual(v.itemsize, sizeof(itemtp)) |
| 63 | self.assertEqual(v.shape, shape) |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 64 | # XXX Issue #12851 |
| 65 | # self.assertEqual(v.strides, ()) |
| 66 | |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 67 | # they are always read/write |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 68 | self.assertFalse(v.readonly) |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 69 | |
| 70 | if v.shape: |
| 71 | n = 1 |
| 72 | for dim in v.shape: |
| 73 | n = n * dim |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 74 | self.assertEqual(n, len(v)) |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 75 | except: |
| 76 | # so that we can see the failing type |
| 77 | print(tp) |
| 78 | raise |
| 79 | |
| 80 | # define some structure classes |
| 81 | |
| 82 | class Point(Structure): |
| 83 | _fields_ = [("x", c_long), ("y", c_long)] |
| 84 | |
| 85 | class PackedPoint(Structure): |
| 86 | _pack_ = 2 |
| 87 | _fields_ = [("x", c_long), ("y", c_long)] |
| 88 | |
| 89 | class Point2(Structure): |
| 90 | pass |
| 91 | Point2._fields_ = [("x", c_long), ("y", c_long)] |
| 92 | |
| 93 | class EmptyStruct(Structure): |
| 94 | _fields_ = [] |
| 95 | |
| 96 | class aUnion(Union): |
| 97 | _fields_ = [("a", c_int)] |
| 98 | |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 99 | class Incomplete(Structure): |
| 100 | pass |
| 101 | |
| 102 | class Complete(Structure): |
| 103 | pass |
| 104 | PComplete = POINTER(Complete) |
Thomas Heller | f70e195 | 2008-07-15 20:23:33 +0000 | [diff] [blame] | 105 | Complete._fields_ = [("a", c_long)] |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 106 | |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 107 | ################################################################ |
| 108 | # |
| 109 | # This table contains format strings as they look on little endian |
| 110 | # machines. The test replaces '<' with '>' on big endian machines. |
| 111 | # |
| 112 | native_types = [ |
| 113 | # type format shape calc itemsize |
| 114 | |
| 115 | ## simple types |
| 116 | |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 117 | (c_char, "<c", (), c_char), |
| 118 | (c_byte, "<b", (), c_byte), |
| 119 | (c_ubyte, "<B", (), c_ubyte), |
| 120 | (c_short, "<h", (), c_short), |
| 121 | (c_ushort, "<H", (), c_ushort), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 122 | |
| 123 | # c_int and c_uint may be aliases to c_long |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 124 | #(c_int, "<i", (), c_int), |
| 125 | #(c_uint, "<I", (), c_uint), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 126 | |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 127 | (c_long, "<l", (), c_long), |
| 128 | (c_ulong, "<L", (), c_ulong), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 129 | |
| 130 | # c_longlong and c_ulonglong are aliases on 64-bit platforms |
| 131 | #(c_longlong, "<q", None, c_longlong), |
| 132 | #(c_ulonglong, "<Q", None, c_ulonglong), |
| 133 | |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 134 | (c_float, "<f", (), c_float), |
| 135 | (c_double, "<d", (), c_double), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 136 | # c_longdouble may be an alias to c_double |
| 137 | |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 138 | (c_bool, "<?", (), c_bool), |
| 139 | (py_object, "<O", (), py_object), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 140 | |
| 141 | ## pointers |
| 142 | |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 143 | (POINTER(c_byte), "&<b", (), POINTER(c_byte)), |
| 144 | (POINTER(POINTER(c_long)), "&&<l", (), POINTER(POINTER(c_long))), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 145 | |
| 146 | ## arrays and pointers |
| 147 | |
| 148 | (c_double * 4, "(4)<d", (4,), c_double), |
| 149 | (c_float * 4 * 3 * 2, "(2,3,4)<f", (2,3,4), c_float), |
| 150 | (POINTER(c_short) * 2, "(2)&<h", (2,), POINTER(c_short)), |
| 151 | (POINTER(c_short) * 2 * 3, "(3,2)&<h", (3,2,), POINTER(c_short)), |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 152 | (POINTER(c_short * 2), "&(2)<h", (), POINTER(c_short)), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 153 | |
| 154 | ## structures and unions |
| 155 | |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 156 | (Point, "T{<l:x:<l:y:}", (), Point), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 157 | # packed structures do not implement the pep |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 158 | (PackedPoint, "B", (), PackedPoint), |
| 159 | (Point2, "T{<l:x:<l:y:}", (), Point2), |
| 160 | (EmptyStruct, "T{}", (), EmptyStruct), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 161 | # the pep does't support unions |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 162 | (aUnion, "B", (), aUnion), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 163 | |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 164 | ## pointer to incomplete structure |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 165 | (Incomplete, "B", (), Incomplete), |
| 166 | (POINTER(Incomplete), "&B", (), POINTER(Incomplete)), |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 167 | |
| 168 | # 'Complete' is a structure that starts incomplete, but is completed after the |
| 169 | # pointer type to it has been created. |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 170 | (Complete, "T{<l:a:}", (), Complete), |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 171 | # Unfortunately the pointer format string is not fixed... |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 172 | (POINTER(Complete), "&B", (), POINTER(Complete)), |
Thomas Heller | 0261e1e | 2008-07-15 17:25:07 +0000 | [diff] [blame] | 173 | |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 174 | ## other |
| 175 | |
| 176 | # function signatures are not implemented |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 177 | (CFUNCTYPE(None), "X{}", (), CFUNCTYPE(None)), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 178 | |
| 179 | ] |
| 180 | |
| 181 | class BEPoint(BigEndianStructure): |
| 182 | _fields_ = [("x", c_long), ("y", c_long)] |
| 183 | |
| 184 | class LEPoint(LittleEndianStructure): |
| 185 | _fields_ = [("x", c_long), ("y", c_long)] |
| 186 | |
| 187 | ################################################################ |
| 188 | # |
| 189 | # This table contains format strings as they really look, on both big |
| 190 | # and little endian machines. |
| 191 | # |
| 192 | endian_types = [ |
Stefan Krah | 9a2d99e | 2012-02-25 12:24:21 +0100 | [diff] [blame] | 193 | (BEPoint, "T{>l:x:>l:y:}", (), BEPoint), |
| 194 | (LEPoint, "T{<l:x:<l:y:}", (), LEPoint), |
| 195 | (POINTER(BEPoint), "&T{>l:x:>l:y:}", (), POINTER(BEPoint)), |
| 196 | (POINTER(LEPoint), "&T{<l:x:<l:y:}", (), POINTER(LEPoint)), |
Thomas Heller | b041fda | 2008-04-30 17:11:46 +0000 | [diff] [blame] | 197 | ] |
| 198 | |
| 199 | if __name__ == "__main__": |
| 200 | unittest.main() |