|
|
@@ -1,116 +1,134 @@ |
|
|
from ctypes import Structure, c_char, c_uint32, c_ubyte, alignment, sizeof, Union |
|
|
from ctypes import ( |
|
|
c_char, c_uint32, c_ubyte, alignment, sizeof, |
|
|
Structure, BigEndianStructure, LittleEndianStructure, |
|
|
Union, BigEndianUnion, LittleEndianUnion, |
|
|
) |
|
|
import inspect |
|
|
import unittest |
|
|
|
|
|
|
|
|
|
|
|
class TestAlignedStructures(unittest.TestCase): |
|
|
def test_aligned_string(self): |
|
|
data = bytearray( |
|
|
b'\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |
|
|
b'\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21\x00\x00\x00\x00' |
|
|
) |
|
|
|
|
|
class Aligned(Structure): |
|
|
_align_ = 16 |
|
|
_fields_ = [ |
|
|
('value', c_char * 16), |
|
|
] |
|
|
|
|
|
class Main(Structure): |
|
|
_fields_ = [ |
|
|
('first', c_uint32), |
|
|
('string', Aligned), |
|
|
] |
|
|
|
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(main.first, 7) |
|
|
self.assertEqual(main.string.value, b'hello world!') |
|
|
self.assertEqual( |
|
|
bytes(main.string.__buffer__(inspect.BufferFlags.SIMPLE)), |
|
|
b'\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21\x00\x00\x00\x00' |
|
|
) |
|
|
|
|
|
def test_aligned_structures(self): |
|
|
data = bytearray( |
|
|
b'\x01\x00\x01\x00\x07\x00\x00\x00' |
|
|
) |
|
|
|
|
|
class SomeBools(Structure): |
|
|
_align_ = 4 |
|
|
_fields_ = [ |
|
|
("bool1", c_ubyte), |
|
|
("bool2", c_ubyte), |
|
|
("bool3", c_ubyte), |
|
|
] |
|
|
class Main(Structure): |
|
|
_fields_ = [ |
|
|
("x", SomeBools), |
|
|
("y", c_uint32), |
|
|
] |
|
|
|
|
|
class SomeBoolsTooBig(Structure): |
|
|
_align_ = 8 |
|
|
_fields_ = [ |
|
|
("bool1", c_ubyte), |
|
|
("bool2", c_ubyte), |
|
|
("bool3", c_ubyte), |
|
|
] |
|
|
class MainTooBig(Structure): |
|
|
_fields_ = [ |
|
|
("x", SomeBoolsTooBig), |
|
|
("y", c_uint32), |
|
|
] |
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(main.y, 7) |
|
|
self.assertEqual(alignment(SomeBools), 4) |
|
|
self.assertEqual(main.x.bool1, True) |
|
|
self.assertEqual(main.x.bool2, False) |
|
|
self.assertEqual(main.x.bool3, True) |
|
|
|
|
|
with self.assertRaises(ValueError) as ctx: |
|
|
MainTooBig.from_buffer(data) |
|
|
for base, data in ( |
|
|
(LittleEndianStructure, bytearray( |
Comment thread
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also use struct.pack() to generate data. It may be more compact and more readable.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
b'\x07\x00\x00\x00\x00\x00\x00\x00' |
|
|
b'\x00\x00\x00\x00\x00\x00\x00\x00' |
|
|
b'\x68\x65\x6c\x6c\x6f\x20\x77\x6f' |
|
|
b'\x72\x6c\x64\x21\x00\x00\x00\x00' |
|
|
)), |
|
|
(BigEndianStructure, bytearray( |
|
|
b'\x00\x00\x00\x07\x00\x00\x00\x00' |
|
|
b'\x00\x00\x00\x00\x00\x00\x00\x00' |
|
|
b'\x68\x65\x6c\x6c\x6f\x20\x77\x6f' |
|
|
b'\x72\x6c\x64\x21\x00\x00\x00\x00' |
|
|
)), |
|
|
): |
|
|
|
|
|
class Aligned(base): |
|
|
_align_ = 16 |
|
|
_fields_ = [ |
|
|
('value', c_char * 16), |
|
|
] |
|
|
|
|
|
class Main(base): |
|
|
_fields_ = [ |
|
|
('first', c_uint32), |
|
|
('string', Aligned), |
|
|
] |
|
|
|
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(main.first, 7) |
|
|
self.assertEqual(main.string.value, b'hello world!') |
|
|
self.assertEqual( |
|
|
ctx.exception.args[0], |
|
|
'Buffer size too small (4 instead of at least 8 bytes)' |
|
|
bytes(main.string.__buffer__(inspect.BufferFlags.SIMPLE)), |
Comment thread
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe simply bytes(main.string)?
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
b'\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21\x00\x00\x00\x00' |
Comment thread
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
b'hello world!\0\0\0\0' could be more readable.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
) |
|
|
self.assertEqual(Main.string.offset, 16) |
Comment thread
serhiy-storchaka marked this conversation as resolved.
Resolved
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
|
|
|
def test_aligned_subclasses(self): |
|
|
data = bytearray( |
|
|
b"\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00" |
|
|
) |
|
|
|
|
|
class UnalignedSub(Structure): |
|
|
x: c_uint32 |
|
|
_fields_ = [ |
|
|
("x", c_uint32), |
|
|
] |
|
|
|
|
|
class AlignedStruct(UnalignedSub): |
|
|
_align_ = 8 |
|
|
y: c_uint32 |
|
|
_fields_ = [ |
|
|
("y", c_uint32), |
|
|
] |
|
|
|
|
|
class Main(Structure): |
|
|
_fields_ = [ |
|
|
("a", c_uint32), |
|
|
("b", AlignedStruct) |
|
|
] |
|
|
def test_aligned_structures(self): |
Comment thread
serhiy-storchaka marked this conversation as resolved.
Resolved
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
for base, data in ( |
|
|
(LittleEndianStructure, bytearray(b"\1\0\1\0\7\0\0\0")), |
|
|
(BigEndianStructure, bytearray(b"\1\0\1\0\0\0\0\7")), |
|
|
): |
|
|
class SomeBools(base): |
|
|
_align_ = 4 |
|
|
_fields_ = [ |
|
|
("bool1", c_ubyte), |
|
|
("bool2", c_ubyte), |
|
|
("bool3", c_ubyte), |
|
|
] |
|
|
class Main(base): |
|
|
_fields_ = [ |
|
|
("x", SomeBools), |
|
|
("y", c_uint32), |
|
|
] |
|
|
|
|
|
class SomeBoolsTooBig(base): |
|
|
_align_ = 8 |
|
|
_fields_ = [ |
|
|
("bool1", c_ubyte), |
|
|
("bool2", c_ubyte), |
|
|
("bool3", c_ubyte), |
|
|
] |
|
|
class MainTooBig(base): |
|
|
_fields_ = [ |
|
|
("x", SomeBoolsTooBig), |
|
|
("y", c_uint32), |
|
|
] |
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(main.y, 7) |
|
|
self.assertEqual(alignment(SomeBools), 4) |
|
|
self.assertEqual(main.x.bool1, True) |
|
|
self.assertEqual(main.x.bool2, False) |
|
|
self.assertEqual(main.x.bool3, True) |
|
|
|
|
|
with self.assertRaises(ValueError) as ctx: |
Comment thread
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is still not very informative test. If you want to test that the _align_ setting affects the size of Main, you can do this more directly by checking sizeof(Main). If you want to check also content, use the data of size 12.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess with this test I was just wanting to ensure that the appropriate error is raised when you have a Structure/Union with an alignment which will cause the size it expects to be bigger than what it is given. Rather than checking anything about the content itself.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
MainTooBig.from_buffer(data) |
|
|
self.assertEqual( |
|
|
ctx.exception.args[0], |
|
|
'Buffer size too small (4 instead of at least 8 bytes)' |
|
|
) |
|
|
|
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(alignment(main.b), 8) |
|
|
self.assertEqual(alignment(main), 8) |
|
|
self.assertEqual(sizeof(main.b), 8) |
|
|
self.assertEqual(sizeof(main), 16) |
|
|
self.assertEqual(main.a, 1) |
|
|
self.assertEqual(main.b.x, 3) |
|
|
self.assertEqual(main.b.y, 4) |
|
|
def test_aligned_subclasses(self): |
|
|
for base, data in ( |
|
|
(LittleEndianStructure, bytearray( |
|
|
b"\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0" |
|
|
)), |
|
|
(BigEndianStructure, bytearray( |
|
|
b"\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4" |
|
|
)), |
|
|
): |
|
|
class UnalignedSub(base): |
|
|
x: c_uint32 |
|
|
_fields_ = [ |
|
|
("x", c_uint32), |
|
|
] |
|
|
|
|
|
class AlignedStruct(UnalignedSub): |
|
|
_align_ = 8 |
|
|
y: c_uint32 |
|
|
_fields_ = [ |
|
|
("y", c_uint32), |
|
|
] |
|
|
|
|
|
class Main(base): |
|
|
_fields_ = [ |
|
|
("a", c_uint32), |
|
|
("b", AlignedStruct) |
|
|
] |
|
|
|
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(alignment(main.b), 8) |
|
|
self.assertEqual(alignment(main), 8) |
|
|
self.assertEqual(sizeof(main.b), 8) |
|
|
self.assertEqual(sizeof(main), 16) |
|
|
self.assertEqual(main.a, 1) |
|
|
self.assertEqual(main.b.x, 3) |
|
|
self.assertEqual(main.b.y, 4) |
|
|
|
|
|
def test_aligned_union(self): |
|
|
data = bytearray( |
|
|
b"\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00" |
|
|
) |
|
|
data = bytearray(b"\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0") |
|
|
|
|
|
class AlignedUnion(Union): |
|
|
_align_ = 8 |
|
Expand All
|
@@ -126,14 +144,11 @@ class Main(Structure): |
|
|
] |
|
|
|
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(main.first, 1) |
|
|
self.assertEqual(main.union.a, 3) |
|
|
self.assertEqual(bytes(main.union.b), b"\x03\x00\x00\x00\x04\x00\x00\x00") |
|
|
self.assertEqual(Main.union.offset, 8) |
|
|
self.assertEqual(len(bytes(main.union.b)), 8) |
|
|
|
|
|
def test_aligned_struct_in_union(self): |
|
|
data = bytearray( |
|
|
b"\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00" |
|
|
) |
|
|
data = bytearray(b"\1\0\0\0\2\0\0\0\3\0\0\3\4\0\0\4") |
|
|
|
|
|
class Sub(Structure): |
|
|
_align_ = 8 |
|
Expand All
|
@@ -155,10 +170,11 @@ class Main(Structure): |
|
|
] |
|
|
|
|
|
main = Main.from_buffer(data) |
|
|
self.assertEqual(main.first, 1) |
|
|
self.assertEqual(main.union.a, 3) |
|
|
self.assertEqual(main.union.b.x, 3) |
|
|
self.assertEqual(main.union.b.y, 4) |
|
|
self.assertEqual(Main.first.size, 4) |
|
|
self.assertEqual(Main.union.offset, 8) |
|
|
self.assertEqual(main.union.a, 0x03000003) |
|
|
self.assertEqual(main.union.b.x, 0x03000003) |
|
|
self.assertEqual(main.union.b.y, 0x04000004) |
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
Expand Down
|
|