import ctypes import reference_project as r import unittest import sys r.init_lib("../../../../target/debug/interoptopus_reference_project.dll") # https://stackoverflow.com/questions/52475749/maximum-and-minimum-value-of-c-types-integers-from-python def limits(c_int_type): signed = c_int_type(-1).value < c_int_type(0).value bit_size = ctypes.sizeof(c_int_type) * 8 signed_limit = 2 ** (bit_size - 1) return (-signed_limit, signed_limit - 1) if signed else (0, 2 * signed_limit - 1) i8_min = limits(ctypes.c_int8)[0] i16_min = limits(ctypes.c_int16)[0] i32_min = limits(ctypes.c_int32)[0] i64_min = limits(ctypes.c_int64)[0] i8_max = limits(ctypes.c_int8)[1] i16_max = limits(ctypes.c_int16)[1] i32_max = limits(ctypes.c_int32)[1] i64_max = limits(ctypes.c_int64)[1] u8_max = limits(ctypes.c_uint8)[1] u16_max = limits(ctypes.c_uint16)[1] u32_max = limits(ctypes.c_uint32)[1] u64_max = limits(ctypes.c_uint64)[1] class TestFunctions(unittest.TestCase): def test_primitives(self): r.primitive_void() r.primitive_void2() self.assertEqual(True, r.primitive_bool(False)) self.assertEqual(0, r.primitive_u8(u8_max)) self.assertEqual(0, r.primitive_u16(u16_max)) self.assertEqual(0, r.primitive_u32(u32_max)) self.assertEqual(0, r.primitive_u64(u64_max)) self.assertEqual(-i8_max, r.primitive_i8(i8_max)) self.assertEqual(-i16_max, r.primitive_i16(i16_max)) self.assertEqual(-i32_max, r.primitive_i32(i32_max)) self.assertEqual(-i64_max, r.primitive_i64(i64_max)) def test_ptr(self): ptr = (ctypes.c_int64 * 100)(100, 2, 3) ptr_ptr = ctypes.POINTER(ctypes.POINTER(ctypes.c_int64))() r.ptr_ptr(ptr_ptr) # This is unfortunately a bit ugly in ctypes. To compare pointers for equality you must # cast them to `c_void_p` AND compare `.value`. self.assertEqual(ctypes.cast(ptr, ctypes.c_void_p).value, ctypes.cast(r.ptr(ptr), ctypes.c_void_p).value) self.assertEqual(ctypes.cast(ptr_ptr, ctypes.c_void_p).value, ctypes.cast(r.ptr_ptr(ptr_ptr), ctypes.c_void_p).value) self.assertEqual(True, r.ref_option(ptr)) self.assertEqual(True, r.ref_mut_option(ptr)) self.assertEqual(ctypes.cast(ptr, ctypes.c_void_p).value, ctypes.cast(r.ptr_mut(ptr), ctypes.c_void_p).value) self.assertEqual(-100, ptr[0]) def test_tuple(self): tupled = r.Tupled(x0=100) self.assertEqual(200, r.tupled(tupled).x0) def test_complex(self): vec = r.Vec3f32() foreign = r.SomeForeignType() r.complex_args_1(vec, None) self.assertEqual(None, r.complex_args_2(foreign)) def test_callback(self): def my_callback(param): return param * 3 self.assertEqual(9, r.callback(my_callback, 3)) def test_generic(self): uint32 = (ctypes.c_uint32 * 10)(123) genericu32 = r.Genericu32(uint32) phantom = r.Phantomu8() self.assertEqual(123, r.generic_1a(genericu32, phantom)) def test_documented(self): documented = r.StructDocumented() self.assertEqual(r.EnumDocumented.A, r.documented(documented)) def test_ambiguous(self): vec1 = r.Vec1(x=10.0) vec2 = r.Vec2(x=10.0, z=11.0) for i in range(1000): self.assertEqual(10.0, r.ambiguous_1(vec1).x) self.assertEqual(11.0, r.ambiguous_2(vec2).z) self.assertEqual(True, r.ambiguous_3(vec1, vec2)) def test_namespaces(self): vec = r.Vec(x=10) self.assertEqual(10.0, r.namespaced_type(vec).x) def test_panics(self): worked = False try: r.panics() worked = True except: pass self.assertFalse(worked) def test_slice_from_ctypes_array(self): array = (ctypes.c_uint32 * 10)() returned_length = r.pattern_ffi_slice_1(array) self.assertEqual(len(array), returned_length) slice = r.Sliceu32(data=ctypes.cast(array, ctypes.POINTER(ctypes.c_uint32)), len=len(array)) returned_length = r.pattern_ffi_slice_1(slice) self.assertEqual(len(slice), returned_length) def test_slice_from_ctypes_array_callback(self): array = (ctypes.c_uint8 * 10)() def callback(x): self.assertEqual(1, x[0]) self.assertEqual(0, x[1]) r.pattern_ffi_slice_3(array, callback) class TestPatterns(unittest.TestCase): def test_services(self): service = r.SimpleService.new_with(123) slice = service.return_slice_mut() self.assertEqual(10, service.method_value(10)) self.assertEqual(123, slice[0]) def test_service_new_string(self): service = r.SimpleService.new_with_string(b"abc") def test_ascii_pointer(self): self.assertEqual(3, r.pattern_ascii_pointer_1(b"111")) self.assertEqual(b'', r.pattern_ascii_pointer_2()) def test_c_char(self): self.assertEqual(b'X', r.pattern_ffi_cchar(b'X')) def test_slice_callback(self): def callback(x): self.assertEqual(9, x[-1]) self.assertEqual(9, x.last()) self.assertEqual(9, x.bytearray()[-1]) try: i = x[10] self.assertFalse(True, "Index out of error should throw exception") except IndexError: pass return 0 r.pattern_ffi_slice_delegate(callback) if __name__ == '__main__': unittest.main() sys.exit(0)