FLEXTypeEncodingParserTests.m 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. //
  2. // FLEXTypeEncodingParserTests.m
  3. // FLEXTests
  4. //
  5. // Created by Tanner Bennett on 8/25/19.
  6. // Copyright © 2019 Flipboard. All rights reserved.
  7. //
  8. #import <XCTest/XCTest.h>
  9. #import <UIKit/UIKit.h>
  10. #import "FLEXTypeEncodingParser.h"
  11. #define Type(t) @(@encode(t))
  12. #define TypeSizeAlignPair(t) Type(t): @[@(sizeof(t)), @(__alignof__(t))]
  13. @interface FLEXTypeEncodingParserTests : XCTestCase {
  14. struct {
  15. id __unsafe_unretained *bar;
  16. void (*foo[5])(void);
  17. SEL abc;
  18. Class cls;
  19. int baz;
  20. NSString * __unsafe_unretained str;
  21. id<NSCopying, NSCoding> __unsafe_unretained proto;
  22. NSDictionary<NSCopying, NSCoding> * __unsafe_unretained another;
  23. } _yikes;
  24. }
  25. @property (nonatomic, readonly) NSDictionary<NSString *, NSArray<NSNumber *> *> *typesToSizes;
  26. @end
  27. typedef struct Anon {
  28. NSString<NSCopying,NSCoding> *bar;
  29. int baz;
  30. } Anon;
  31. @implementation FLEXTypeEncodingParserTests
  32. - (void)setUp {
  33. memset(&_yikes.bar, 0x55, sizeof(id));
  34. memset(&_yikes.foo, 0xff, sizeof(_yikes.foo));
  35. memset(&_yikes.abc, 0x88, sizeof(SEL));
  36. _typesToSizes = @{
  37. TypeSizeAlignPair(__typeof__(_yikes)),
  38. @"{Anon=\"bar\"@\"NSString<NSCopying><NSCoding>\"\"baz\"i}" : @[@(sizeof(Anon)), @(__alignof__(Anon))],
  39. Type(NSDecimal) : @[@-1, @0], // Real size is 16 on 64 bit machines
  40. TypeSizeAlignPair(char),
  41. TypeSizeAlignPair(short),
  42. TypeSizeAlignPair(int),
  43. TypeSizeAlignPair(long),
  44. TypeSizeAlignPair(long long),
  45. TypeSizeAlignPair(float),
  46. TypeSizeAlignPair(double),
  47. TypeSizeAlignPair(long double),
  48. TypeSizeAlignPair(Class),
  49. TypeSizeAlignPair(id),
  50. TypeSizeAlignPair(CGPoint),
  51. TypeSizeAlignPair(CGRect),
  52. TypeSizeAlignPair(char *),
  53. TypeSizeAlignPair(long *),
  54. TypeSizeAlignPair(Class *),
  55. TypeSizeAlignPair(CGRect *)
  56. };
  57. }
  58. - (void)testTypeEncodingParser {
  59. [self.typesToSizes enumerateKeysAndObjectsUsingBlock:^(NSString *typeString, NSArray<NSNumber *> *sa, BOOL *stop) {
  60. if (sa[0].longLongValue >= 0) {
  61. XCTAssertNoThrow(NSGetSizeAndAlignment(typeString.UTF8String, nil, nil));
  62. } else {
  63. XCTAssertThrows(NSGetSizeAndAlignment(typeString.UTF8String, nil, nil));
  64. }
  65. ssize_t align = 0;
  66. ssize_t size = [FLEXTypeEncodingParser sizeForTypeEncoding:typeString alignment:&align];
  67. XCTAssertEqual(size, sa[0].longValue);
  68. XCTAssertEqual(align, sa[1].longValue);
  69. }];
  70. }
  71. - (void)testExpectedStructureSizes {
  72. typedef struct _FooBytes {
  73. uint8_t x: 3;
  74. struct {
  75. uint8_t a: 1;
  76. uint8_t b: 2;
  77. } y;
  78. uint8_t z: 5;
  79. } FooBytes;
  80. typedef struct _FooInts {
  81. unsigned int x: 3;
  82. struct {
  83. unsigned int a: 1;
  84. unsigned int b: 2;
  85. } y;
  86. unsigned int z: 5;
  87. } FooInts;
  88. typedef struct _Bar {
  89. unsigned int x: 3;
  90. unsigned int z: 5;
  91. struct {
  92. unsigned int a: 1;
  93. unsigned int b: 2;
  94. } y;
  95. } Bar;
  96. typedef struct _ArrayInMiddle {
  97. unsigned int x: 3;
  98. unsigned char c[2];
  99. unsigned int z: 5;
  100. } ArrayInMiddle;
  101. typedef struct _ArrayAtEnd {
  102. unsigned int x: 3;
  103. unsigned int z: 5;
  104. unsigned char c[2];
  105. } ArrayAtEnd;
  106. typedef struct _OneBit {
  107. uint8_t x: 1;
  108. } OneBit;
  109. typedef struct _OneByte {
  110. uint8_t x;
  111. } OneByte;
  112. typedef struct _TwoBytes {
  113. uint8_t x, y;
  114. } TwoBytes;
  115. typedef struct _TwoJoinedBytesAndOneByte {
  116. uint16_t x;
  117. uint8_t y;
  118. } TwoJoinedBytesAndOneByte;
  119. // Structs have the alignment of the size of their smallest member, recursively.
  120. // That is, a struct has the alignment of the greater of the size of its
  121. // largest direct member or the largest alignment of it's nested structs.
  122. XCTAssertEqual(__alignof__(FooBytes), 1);
  123. XCTAssertEqual(__alignof__(FooInts), 4);
  124. XCTAssertEqual(__alignof__(ArrayInMiddle), 4);
  125. XCTAssertEqual(__alignof__(ArrayAtEnd), 4);
  126. XCTAssertEqual(__alignof__(OneBit), 1);
  127. XCTAssertEqual(__alignof__(OneByte), 1);
  128. XCTAssertEqual(__alignof__(TwoBytes), 1);
  129. XCTAssertEqual(__alignof__(TwoJoinedBytesAndOneByte), 2);
  130. // Nested structs are aligned before and after, if between bitfields
  131. XCTAssertEqual(sizeof(FooBytes), 3);
  132. XCTAssertEqual(sizeof(FooInts), 12);
  133. // Bitfields are not aligned at all and they will pack if adjacent to one another
  134. XCTAssertEqual(sizeof(Bar), 8);
  135. // Structs are resized to match their alignment
  136. XCTAssertEqual(sizeof(OneBit), 1);
  137. XCTAssertEqual(sizeof(OneByte), 1);
  138. XCTAssertEqual(sizeof(TwoJoinedBytesAndOneByte), 4);
  139. // Arrays do not affect alignment like nested structs do
  140. XCTAssertEqual(sizeof(ArrayInMiddle), 4);
  141. XCTAssertEqual(sizeof(ArrayAtEnd), 4);
  142. // Test my method of converting calculated sizes to actual sizes
  143. // for FLEXTypeEncodingParser
  144. #define RoundUpToMultipleOf4(num) ((num + 3) & ~0x03)
  145. XCTAssertEqual(RoundUpToMultipleOf4(1), 4);
  146. XCTAssertEqual(RoundUpToMultipleOf4(2), 4);
  147. XCTAssertEqual(RoundUpToMultipleOf4(3), 4);
  148. XCTAssertEqual(RoundUpToMultipleOf4(4), 4);
  149. XCTAssertEqual(RoundUpToMultipleOf4(5), 8);
  150. XCTAssertEqual(RoundUpToMultipleOf4(6), 8);
  151. XCTAssertEqual(RoundUpToMultipleOf4(7), 8);
  152. XCTAssertEqual(RoundUpToMultipleOf4(8), 8);
  153. XCTAssertEqual(RoundUpToMultipleOf4(9), 12);
  154. XCTAssertEqual(RoundUpToMultipleOf4(10), 12);
  155. XCTAssertEqual(RoundUpToMultipleOf4(11), 12);
  156. XCTAssertEqual(RoundUpToMultipleOf4(12), 12);
  157. XCTAssertEqual(RoundUpToMultipleOf4(13), 16);
  158. }
  159. - (void)testMethodSignatures {
  160. NSArray<NSString *> *signatures = @[
  161. @"^{__CFBundle=}16@0:8", @"v24@0:8@16", @"@40@0:8@16{CGSize=dd}24"
  162. ];
  163. for (NSString *signature in signatures) {
  164. XCTAssertTrue([FLEXTypeEncodingParser methodTypeEncodingSupported:signature]);
  165. }
  166. }
  167. @end