Skip to content

Commit

Permalink
pythongh-110190: Fix ctypes structs with array on PPCLE64
Browse files Browse the repository at this point in the history
Fix the same issue of PR python#112604 on PPC64LE platform
Refactor tests to make easier to add more platfroms if needed.
  • Loading branch information
diegorusso committed Dec 11, 2023
1 parent 97cd45b commit b7f949b
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 207 deletions.
232 changes: 84 additions & 148 deletions Lib/test/test_ctypes/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
c_short, c_ushort, c_int, c_uint,
c_long, c_ulong, c_longlong, c_ulonglong, c_float, c_double)
from struct import calcsize
from collections import namedtuple
from test import support


Expand Down Expand Up @@ -474,36 +475,53 @@ class X(Structure):
def test_array_in_struct(self):
# See bpo-22273

# Load the shared library
dll = CDLL(_ctypes_test.__file__)

# These should mirror the structures in Modules/_ctypes/_ctypes_test.c
class Test2(Structure):
_fields_ = [
('data', c_ubyte * 16),
]

class Test3(Structure):
class Test3AParent(Structure):
_fields_ = [
('data', c_float * 2),
]

class Test3A(Test3AParent):
_fields_ = [
('more_data', c_float * 2),
]

class Test3B(Structure):
_fields_ = [
('data', c_double * 2),
]

class Test3A(Structure):
class Test3C(Structure):
_fields_ = [
('data', c_float * 2),
("data", c_double * 4)
]

class Test3B(Test3A):
class Test3D(Structure):
_fields_ = [
('more_data', c_float * 2),
("data", c_double * 8)
]

class Test3E(Structure):
_fields_ = [
("data", c_double * 9)
]

# Load the shared library
dll = CDLL(_ctypes_test.__file__)

# Tests for struct Test2
s = Test2()
expected = 0
for i in range(16):
s.data[i] = i
expected += i
func = dll._testfunc_array_in_struct1
func = dll._testfunc_array_in_struct2
func.restype = c_int
func.argtypes = (Test2,)
result = func(s)
Expand All @@ -512,29 +530,16 @@ class Test3B(Test3A):
for i in range(16):
self.assertEqual(s.data[i], i)

s = Test3()
s.data[0] = 3.14159
s.data[1] = 2.71828
expected = 3.14159 + 2.71828
func = dll._testfunc_array_in_struct2
func.restype = c_double
func.argtypes = (Test3,)
result = func(s)
self.assertEqual(result, expected)
# check the passed-in struct hasn't changed
self.assertEqual(s.data[0], 3.14159)
self.assertEqual(s.data[1], 2.71828)

s = Test3B()
# Tests for struct Test3A
s = Test3A()
s.data[0] = 3.14159
s.data[1] = 2.71828
s.more_data[0] = -3.0
s.more_data[1] = -2.0

expected = 3.14159 + 2.71828 - 5.0
func = dll._testfunc_array_in_struct2a
expected = 3.14159 + 2.71828 - 3.0 - 2.0
func = dll._testfunc_array_in_struct3A
func.restype = c_double
func.argtypes = (Test3B,)
func.argtypes = (Test3A,)
result = func(s)
self.assertAlmostEqual(result, expected, places=6)
# check the passed-in struct hasn't changed
Expand All @@ -543,129 +548,60 @@ class Test3B(Test3A):
self.assertAlmostEqual(s.more_data[0], -3.0, places=6)
self.assertAlmostEqual(s.more_data[1], -2.0, places=6)

@unittest.skipIf(
'ppc64le' in platform.uname().machine,
"gh-110190: currently fails on ppc64le",
)
def test_array_in_struct_registers(self):
dll = CDLL(_ctypes_test.__file__)

class Test3C1(Structure):
_fields_ = [
("data", c_double * 4)
]

class DataType4(Array):
_type_ = c_double
_length_ = 4

class Test3C2(Structure):
_fields_ = [
("data", DataType4)
]

class Test3C3(Structure):
_fields_ = [
("x", c_double),
("y", c_double),
("z", c_double),
("t", c_double)
]

class Test3D1(Structure):
_fields_ = [
("data", c_double * 5)
]

class DataType5(Array):
_type_ = c_double
_length_ = 5

class Test3D2(Structure):
_fields_ = [
("data", DataType5)
]

class Test3D3(Structure):
_fields_ = [
("x", c_double),
("y", c_double),
("z", c_double),
("t", c_double),
("u", c_double)
]

# Tests for struct Test3C
expected = (1.0, 2.0, 3.0, 4.0)
func = dll._testfunc_array_in_struct_set_defaults_3C
func.restype = Test3C1
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3]),
expected
# Test3B, Test3C, Test3D, Test3E have the same logic with different
# sizes hence putting them in a loop.
StructCtype = namedtuple(
"StructCtype",
["cls", "cfunc1", "cfunc2", "items"]
)

func = dll._testfunc_array_in_struct_set_defaults_3C
func.restype = Test3C2
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3]),
expected
)

func = dll._testfunc_array_in_struct_set_defaults_3C
func.restype = Test3C3
result = func()
# check the default values have been set properly
self.assertEqual((result.x, result.y, result.z, result.t), expected)

# Tests for struct Test3D
expected = (1.0, 2.0, 3.0, 4.0, 5.0)
func = dll._testfunc_array_in_struct_set_defaults_3D
func.restype = Test3D1
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3],
result.data[4]),
expected
)

func = dll._testfunc_array_in_struct_set_defaults_3D
func.restype = Test3D2
result = func()
# check the default values have been set properly
self.assertEqual(
(result.data[0],
result.data[1],
result.data[2],
result.data[3],
result.data[4]),
expected
)

func = dll._testfunc_array_in_struct_set_defaults_3D
func.restype = Test3D3
result = func()
# check the default values have been set properly
self.assertEqual(
(result.x,
result.y,
result.z,
result.t,
result.u),
expected)
structs_to_test = [
StructCtype(
Test3B,
dll._testfunc_array_in_struct3B,
dll._testfunc_array_in_struct3B_set_defaults,
2),
StructCtype(
Test3C,
dll._testfunc_array_in_struct3C,
dll._testfunc_array_in_struct3C_set_defaults,
4),
StructCtype(
Test3D,
dll._testfunc_array_in_struct3D,
dll._testfunc_array_in_struct3D_set_defaults,
8),
StructCtype(
Test3E,
dll._testfunc_array_in_struct3E,
dll._testfunc_array_in_struct3E_set_defaults,
9),
]

for sut in structs_to_test:
s = sut.cls()

# Test for cfunc1
expected = 0
for i in range(sut.items):
float_i = float(i)
s.data[i] = float_i
expected += float_i
func = sut.cfunc1
func.restype = c_double
func.argtypes = (sut.cls,)
result = func(s)
self.assertEqual(result, expected)
# check the passed-in struct hasn't changed
for i in range(sut.items):
self.assertEqual(s.data[i], float(i))

# Test for cfunc2
func = sut.cfunc2
func.restype = sut.cls
result = func()
# check if the default values have been set correctly
for i in range(sut.items):
self.assertEqual(result.data[i], float(i+1))

def test_38368(self):
class U(Union):
Expand Down
Loading

0 comments on commit b7f949b

Please sign in to comment.