| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,286 @@ | ||
| from ctypes import ( | ||
| c_char, c_uint32, c_uint16, c_ubyte, c_byte, alignment, sizeof, | ||
| BigEndianStructure, LittleEndianStructure, | ||
| BigEndianUnion, LittleEndianUnion, | ||
| ) | ||
| import struct | ||
| import unittest | ||
|
|
||
|
|
||
| class TestAlignedStructures(unittest.TestCase): | ||
| def test_aligned_string(self): | ||
| for base, e in ( | ||
| (LittleEndianStructure, "<"), | ||
| (BigEndianStructure, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}i12x16s", 7, b"hello world!")) | ||
| class Aligned(base): | ||
| _align_ = 16 | ||
| _fields_ = [ | ||
| ('value', c_char * 12) | ||
| ] | ||
|
|
||
| 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(bytes(main.string), b'hello world!\0\0\0\0') | ||
| self.assertEqual(Main.string.offset, 16) | ||
| self.assertEqual(Main.string.size, 16) | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt is not affected by the _align_ setting, because its size was already 16. Maybe make the value field type c_char * 12? Then the _align_ setting will affect also the size of Aligned.
Sorry, something went wrong.
All reactions
|
||
| self.assertEqual(alignment(main.string), 16) | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityDoes alignment(Main.string) work?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt does not since Main.string is a ctypes.CField which has no alignment info.
Sorry, something went wrong.
All reactions
|
||
| self.assertEqual(alignment(main), 16) | ||
|
|
||
| def test_aligned_structures(self): | ||
|
Comment thread
serhiy-storchaka marked this conversation as resolved.
|
||
| for base, data in ( | ||
| (LittleEndianStructure, bytearray(b"\1\0\0\0\1\0\0\0\7\0\0\0")), | ||
| (BigEndianStructure, bytearray(b"\1\0\0\0\1\0\0\0\7\0\0\0")), | ||
| ): | ||
| class SomeBools(base): | ||
| _align_ = 4 | ||
| _fields_ = [ | ||
| ("bool1", c_ubyte), | ||
| ("bool2", c_ubyte), | ||
| ] | ||
| class Main(base): | ||
| _fields_ = [ | ||
| ("x", c_ubyte), | ||
| ("y", SomeBools), | ||
| ("z", c_ubyte), | ||
| ] | ||
|
|
||
| main = Main.from_buffer(data) | ||
| self.assertEqual(alignment(SomeBools), 4) | ||
| self.assertEqual(alignment(main), 4) | ||
| self.assertEqual(alignment(main.y), 4) | ||
| self.assertEqual(Main.x.size, 1) | ||
| self.assertEqual(Main.y.offset, 4) | ||
| self.assertEqual(Main.y.size, 4) | ||
| self.assertEqual(main.y.bool1, True) | ||
| self.assertEqual(main.y.bool2, False) | ||
| self.assertEqual(Main.z.offset, 8) | ||
| self.assertEqual(main.z, 7) | ||
|
|
||
| def test_oversized_structure(self): | ||
| data = bytearray(b"\0" * 8) | ||
| for base in (LittleEndianStructure, BigEndianStructure): | ||
| class SomeBoolsTooBig(base): | ||
| _align_ = 8 | ||
| _fields_ = [ | ||
| ("bool1", c_ubyte), | ||
| ("bool2", c_ubyte), | ||
| ("bool3", c_ubyte), | ||
| ] | ||
| class Main(base): | ||
| _fields_ = [ | ||
| ("y", SomeBoolsTooBig), | ||
| ("z", c_uint32), | ||
| ] | ||
| with self.assertRaises(ValueError) as ctx: | ||
|
Comment thread
Copy link
Copy Markdown
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt 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.
All reactions
Copy link
Copy Markdown
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityI 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.
All reactions
|
||
| Main.from_buffer(data) | ||
| self.assertEqual( | ||
| ctx.exception.args[0], | ||
| 'Buffer size too small (4 instead of at least 8 bytes)' | ||
| ) | ||
|
|
||
| def test_aligned_subclasses(self): | ||
| for base, e in ( | ||
| (LittleEndianStructure, "<"), | ||
| (BigEndianStructure, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}4i", 1, 2, 3, 4)) | ||
| class UnalignedSub(base): | ||
| x: c_uint32 | ||
| _fields_ = [ | ||
| ("x", c_uint32), | ||
| ] | ||
|
|
||
| class AlignedStruct(UnalignedSub): | ||
| _align_ = 8 | ||
| _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) | ||
| self.assertEqual(Main.b.offset, 8) | ||
| self.assertEqual(Main.b.size, 8) | ||
|
|
||
| def test_aligned_union(self): | ||
| for sbase, ubase, e in ( | ||
| (LittleEndianStructure, LittleEndianUnion, "<"), | ||
| (BigEndianStructure, BigEndianUnion, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}4i", 1, 2, 3, 4)) | ||
| class AlignedUnion(ubase): | ||
| _align_ = 8 | ||
| _fields_ = [ | ||
| ("a", c_uint32), | ||
| ("b", c_ubyte * 7), | ||
| ] | ||
|
|
||
| class Main(sbase): | ||
| _fields_ = [ | ||
| ("first", c_uint32), | ||
| ("union", AlignedUnion), | ||
| ] | ||
|
|
||
| main = Main.from_buffer(data) | ||
| self.assertEqual(main.first, 1) | ||
| self.assertEqual(main.union.a, 3) | ||
| self.assertEqual(bytes(main.union.b), data[8:-1]) | ||
| self.assertEqual(Main.union.offset, 8) | ||
| self.assertEqual(Main.union.size, 8) | ||
| self.assertEqual(alignment(main.union), 8) | ||
| self.assertEqual(alignment(main), 8) | ||
|
|
||
| def test_aligned_struct_in_union(self): | ||
| for sbase, ubase, e in ( | ||
| (LittleEndianStructure, LittleEndianUnion, "<"), | ||
| (BigEndianStructure, BigEndianUnion, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}4i", 1, 2, 3, 4)) | ||
| class Sub(sbase): | ||
| _align_ = 8 | ||
| _fields_ = [ | ||
| ("x", c_uint32), | ||
| ("y", c_uint32), | ||
| ] | ||
|
|
||
| class MainUnion(ubase): | ||
| _fields_ = [ | ||
| ("a", c_uint32), | ||
| ("b", Sub), | ||
| ] | ||
|
|
||
| class Main(sbase): | ||
| _fields_ = [ | ||
| ("first", c_uint32), | ||
| ("union", MainUnion), | ||
| ] | ||
|
|
||
| main = Main.from_buffer(data) | ||
| self.assertEqual(Main.first.size, 4) | ||
| self.assertEqual(alignment(main.union), 8) | ||
| self.assertEqual(alignment(main), 8) | ||
| self.assertEqual(Main.union.offset, 8) | ||
| self.assertEqual(Main.union.size, 8) | ||
| 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) | ||
|
|
||
| def test_smaller_aligned_subclassed_union(self): | ||
| for sbase, ubase, e in ( | ||
| (LittleEndianStructure, LittleEndianUnion, "<"), | ||
| (BigEndianStructure, BigEndianUnion, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}H2xI", 1, 0xD60102D7)) | ||
| class SubUnion(ubase): | ||
| _align_ = 2 | ||
| _fields_ = [ | ||
| ("unsigned", c_ubyte), | ||
| ("signed", c_byte), | ||
| ] | ||
|
|
||
| class MainUnion(SubUnion): | ||
| _fields_ = [ | ||
| ("num", c_uint32) | ||
| ] | ||
|
|
||
| class Main(sbase): | ||
| _fields_ = [ | ||
| ("first", c_uint16), | ||
| ("union", MainUnion), | ||
| ] | ||
|
|
||
| main = Main.from_buffer(data) | ||
| self.assertEqual(main.union.num, 0xD60102D7) | ||
| self.assertEqual(main.union.unsigned, data[4]) | ||
| self.assertEqual(main.union.signed, data[4] - 256) | ||
| self.assertEqual(alignment(main), 4) | ||
| self.assertEqual(alignment(main.union), 4) | ||
| self.assertEqual(Main.union.offset, 4) | ||
| self.assertEqual(Main.union.size, 4) | ||
| self.assertEqual(Main.first.size, 2) | ||
|
|
||
| def test_larger_aligned_subclassed_union(self): | ||
| for ubase, e in ( | ||
| (LittleEndianUnion, "<"), | ||
| (BigEndianUnion, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}I4x", 0xD60102D6)) | ||
| class SubUnion(ubase): | ||
| _align_ = 8 | ||
| _fields_ = [ | ||
| ("unsigned", c_ubyte), | ||
| ("signed", c_byte), | ||
| ] | ||
|
|
||
| class Main(SubUnion): | ||
| _fields_ = [ | ||
| ("num", c_uint32) | ||
| ] | ||
|
|
||
| main = Main.from_buffer(data) | ||
| self.assertEqual(alignment(main), 8) | ||
| self.assertEqual(sizeof(main), 8) | ||
| self.assertEqual(main.num, 0xD60102D6) | ||
| self.assertEqual(main.unsigned, 0xD6) | ||
| self.assertEqual(main.signed, -42) | ||
|
|
||
| def test_aligned_packed_structures(self): | ||
| for sbase, e in ( | ||
| (LittleEndianStructure, "<"), | ||
| (BigEndianStructure, ">"), | ||
| ): | ||
| data = bytearray(struct.pack(f"{e}B2H4xB", 1, 2, 3, 4)) | ||
|
|
||
| class Inner(sbase): | ||
| _align_ = 8 | ||
| _fields_ = [ | ||
| ("x", c_uint16), | ||
| ("y", c_uint16), | ||
| ] | ||
|
|
||
| class Main(sbase): | ||
| _pack_ = 1 | ||
| _fields_ = [ | ||
| ("a", c_ubyte), | ||
| ("b", Inner), | ||
| ("c", c_ubyte), | ||
| ] | ||
|
|
||
| main = Main.from_buffer(data) | ||
| self.assertEqual(sizeof(main), 10) | ||
| self.assertEqual(Main.b.offset, 1) | ||
| # Alignment == 8 because _pack_ wins out. | ||
| self.assertEqual(alignment(main.b), 8) | ||
| # Size is still 8 though since inside this Structure, it will have | ||
| # effect. | ||
| self.assertEqual(sizeof(main.b), 8) | ||
| self.assertEqual(Main.c.offset, 9) | ||
| self.assertEqual(main.a, 1) | ||
| self.assertEqual(main.b.x, 2) | ||
| self.assertEqual(main.b.y, 3) | ||
| self.assertEqual(main.c, 4) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Add ability to force alignment of :mod:`ctypes.Structure` by way of the new ``_align_`` attribute on the class. |
| Back | FazBrowse Home | New Git URL |
Uh oh!
There was an error while loading. Please reload this page.