GPBUtilitiesTests.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. #import <XCTest/XCTest.h>
  31. #import "GPBUtilities_PackagePrivate.h"
  32. #import <objc/runtime.h>
  33. #import "GPBTestUtilities.h"
  34. #import "GPBDescriptor.h"
  35. #import "GPBDescriptor_PackagePrivate.h"
  36. #import "GPBMessage.h"
  37. #import "google/protobuf/MapUnittest.pbobjc.h"
  38. #import "google/protobuf/Unittest.pbobjc.h"
  39. #import "google/protobuf/UnittestObjc.pbobjc.h"
  40. @interface UtilitiesTests : GPBTestCase
  41. @end
  42. // Support code for testing
  43. typedef struct {
  44. uint32_t _has_storage_[1];
  45. BOOL aBool;
  46. int32_t aInt32;
  47. uint32_t aUInt32;
  48. int64_t aInt64;
  49. uint64_t aUInt64;
  50. float aFloat;
  51. double aDouble;
  52. id aObject;
  53. BOOL _hasTest;
  54. BOOL stopper;
  55. BOOL shouldNotBeCounted;
  56. GPBInt32Array *anArray;
  57. } ApplyFunctionsTest_Storage;
  58. @interface ApplyFunctionsTest : GPBMessage
  59. @property(nonatomic, readwrite) BOOL aBool;
  60. @property(nonatomic, readwrite) int32_t aInt32;
  61. @property(nonatomic, readwrite) uint32_t aUInt32;
  62. @property(nonatomic, readwrite) int64_t aInt64;
  63. @property(nonatomic, readwrite) uint64_t aUInt64;
  64. @property(nonatomic, readwrite) float aFloat;
  65. @property(nonatomic, readwrite) double aDouble;
  66. @property(nonatomic, readwrite, retain) id aObject;
  67. @property(nonatomic, readwrite) BOOL _hasTest;
  68. @property(nonatomic, readwrite) BOOL stopper;
  69. @property(nonatomic, readwrite) BOOL shouldNotBeCounted;
  70. @property(nonatomic, readwrite, retain) GPBInt32Array *anArray;
  71. @end
  72. @implementation ApplyFunctionsTest
  73. @dynamic aBool, aInt32, aUInt32, aInt64, aUInt64, aFloat, aDouble, aObject;
  74. @dynamic _hasTest, stopper, shouldNotBeCounted, anArray;
  75. + (GPBDescriptor *)descriptor {
  76. static GPBDescriptor *descriptor = NULL;
  77. if (!descriptor) {
  78. static GPBMessageFieldDescription fields[] = {
  79. #define FIELD_ENTRY(NAME, INDEX) \
  80. { \
  81. .name = "a" #NAME, .hasIndex = INDEX, .type = GPBType##NAME, \
  82. .offset = offsetof(ApplyFunctionsTest_Storage, a##NAME), \
  83. }
  84. FIELD_ENTRY(Bool, 1),
  85. FIELD_ENTRY(Int32, 2),
  86. FIELD_ENTRY(UInt32, 3),
  87. FIELD_ENTRY(Int64, 4),
  88. FIELD_ENTRY(UInt64, 5),
  89. FIELD_ENTRY(Float, 6),
  90. FIELD_ENTRY(Double, 7),
  91. #undef FIELD_ENTRY
  92. {
  93. .name = "aObject",
  94. .type = GPBTypeString,
  95. .hasIndex = 8,
  96. .offset = offsetof(ApplyFunctionsTest_Storage, aObject),
  97. },
  98. {
  99. .name = "stopper",
  100. .type = GPBTypeBool,
  101. .hasIndex = 9,
  102. .offset = offsetof(ApplyFunctionsTest_Storage, stopper),
  103. },
  104. {
  105. .name = "shouldNotBeCounted",
  106. .type = GPBTypeBool,
  107. .hasIndex = 10,
  108. .offset = offsetof(ApplyFunctionsTest_Storage, shouldNotBeCounted),
  109. },
  110. {
  111. .name = "anArray",
  112. .type = GPBTypeInt32,
  113. .hasIndex = 11,
  114. .flags = GPBFieldRepeated,
  115. .offset = offsetof(ApplyFunctionsTest_Storage, anArray),
  116. },
  117. };
  118. descriptor = [GPBDescriptor
  119. allocDescriptorForClass:[self class]
  120. rootClass:Nil
  121. file:nil
  122. fields:fields
  123. fieldCount:sizeof(fields) /
  124. sizeof(GPBMessageFieldDescription)
  125. oneofs:NULL
  126. oneofCount:0
  127. enums:NULL
  128. enumCount:0
  129. ranges:NULL
  130. rangeCount:0
  131. storageSize:sizeof(ApplyFunctionsTest_Storage)
  132. wireFormat:NO];
  133. }
  134. return descriptor;
  135. }
  136. @end
  137. typedef struct {
  138. int calledBool;
  139. int calledInt32;
  140. int calledUInt32;
  141. int calledInt64;
  142. int calledUInt64;
  143. int calledFloat;
  144. int calledDouble;
  145. int calledObject;
  146. int hitCount;
  147. } TestApplyFunctionsContext;
  148. // Really, who needs templates?
  149. // Macro for testing apply functions. Declares a variety of different functions
  150. // base on |NAME|.
  151. #define TEST_APPLY_FUNCTIONS_FUNC(NAME) \
  152. static BOOL TestApplyFunction##NAME(GPBFieldDescriptor *field, \
  153. void *voidContext) { \
  154. TestApplyFunctionsContext *context = voidContext; \
  155. if (field->getSel_ == sel_getUid("stopper")) return NO; \
  156. context->called##NAME += 1; \
  157. context->hitCount += 1; \
  158. return YES; \
  159. }
  160. TEST_APPLY_FUNCTIONS_FUNC(Bool)
  161. TEST_APPLY_FUNCTIONS_FUNC(Int32)
  162. TEST_APPLY_FUNCTIONS_FUNC(UInt32)
  163. TEST_APPLY_FUNCTIONS_FUNC(Int64)
  164. TEST_APPLY_FUNCTIONS_FUNC(UInt64)
  165. TEST_APPLY_FUNCTIONS_FUNC(Float)
  166. TEST_APPLY_FUNCTIONS_FUNC(Double)
  167. TEST_APPLY_FUNCTIONS_FUNC(Object)
  168. @implementation UtilitiesTests
  169. - (void)testRightShiftFunctions {
  170. XCTAssertEqual((1UL << 31) >> 31, 1UL);
  171. XCTAssertEqual((1 << 31) >> 31, -1);
  172. XCTAssertEqual((1ULL << 63) >> 63, 1ULL);
  173. XCTAssertEqual((1LL << 63) >> 63, -1LL);
  174. XCTAssertEqual(GPBLogicalRightShift32((1 << 31), 31), 1);
  175. XCTAssertEqual(GPBLogicalRightShift64((1LL << 63), 63), 1LL);
  176. }
  177. - (void)testMutability {
  178. ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message];
  179. XCTAssertEqual(0, [foo_message aInt32]);
  180. [foo_message setAInt32:100];
  181. XCTAssertEqual(100, [foo_message aInt32]);
  182. }
  183. - (void)testSerializedSize {
  184. ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message];
  185. [foo_message setAInt32:100];
  186. size_t size1 = [foo_message serializedSize];
  187. [foo_message setAInt64:100];
  188. size_t size2 = [foo_message serializedSize];
  189. // Intentionally doing a pointer comparison.
  190. XCTAssertNotEqual(size1, size2);
  191. }
  192. - (void)testCopying {
  193. ApplyFunctionsTest *foo_message = [ApplyFunctionsTest message];
  194. [foo_message setAInt32:100];
  195. [foo_message setAObject:@"Happy"];
  196. ApplyFunctionsTest *foo = [[foo_message copy] autorelease];
  197. XCTAssertNotEqual(foo, foo_message); // Pointer comparision
  198. XCTAssertEqualObjects(foo, foo_message);
  199. }
  200. - (void)testApplyFunctions {
  201. // Covers ApplyFunctionsToProtoVariables and
  202. // ApplyFunctionsBasedOnEncodingType.
  203. // This test depends on the layout of the ivars to be in the order
  204. // declared in the interface. If this is not true, it will fail and will
  205. // need to be rewritten to accomodate.
  206. TestApplyFunctionsContext context;
  207. memset(&context, 0, sizeof(context));
  208. GPBApplyFunctions foo = GPBAPPLY_FUNCTIONS_INIT(TestApplyFunction);
  209. ApplyFunctionsTest *msg = [ApplyFunctionsTest message];
  210. GPBApplyFunctionsToMessageFields(&foo, msg, &context);
  211. // Only eight vars should be set.
  212. // "stopper" should cause the loop to quit so it and shouldNotBeCounted should
  213. // not be counted.
  214. // "_hasTest" should be skipped over.
  215. // Each of the vars should only be set once.
  216. XCTAssertEqual(context.hitCount, 8);
  217. XCTAssertEqual(context.calledBool, 1);
  218. XCTAssertEqual(context.calledInt32, 1);
  219. XCTAssertEqual(context.calledUInt32, 1);
  220. XCTAssertEqual(context.calledInt64, 1);
  221. XCTAssertEqual(context.calledUInt64, 1);
  222. XCTAssertEqual(context.calledFloat, 1);
  223. XCTAssertEqual(context.calledDouble, 1);
  224. XCTAssertEqual(context.calledObject, 1);
  225. }
  226. - (void)testGPBDecodeTextFormatName {
  227. uint8_t decodeData[] = {
  228. 0x6,
  229. // An inlined string (first to make sure the leading null is handled
  230. // correctly, and with a key of zero to check that).
  231. 0x0, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0,
  232. // All as is (00 op)
  233. 0x1, 0x0A, 0x0,
  234. // Underscore, upper + 9 (10 op)
  235. 0x3, 0xCA, 0x0,
  236. // Upper + 3 (10 op), underscore, upper + 5 (10 op)
  237. 0x2, 0x44, 0xC6, 0x0,
  238. // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op),
  239. // underscore, lower + 0 (01 op)
  240. 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0,
  241. // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op),
  242. // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op),
  243. // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 op),
  244. // underscore, as is + 3 (00 op)
  245. 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0,
  246. };
  247. NSString *inputStr = @"abcdefghIJ";
  248. // Empty inputs
  249. XCTAssertNil(GPBDecodeTextFormatName(nil, 1, NULL));
  250. XCTAssertNil(GPBDecodeTextFormatName(decodeData, 1, NULL));
  251. XCTAssertNil(GPBDecodeTextFormatName(nil, 1, inputStr));
  252. // Keys not found.
  253. XCTAssertNil(GPBDecodeTextFormatName(decodeData, 5, inputStr));
  254. XCTAssertNil(GPBDecodeTextFormatName(decodeData, -1, inputStr));
  255. // Some name decodes.
  256. XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1, inputStr), @"abcdefghIJ");
  257. XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 2, inputStr), @"Abcd_EfghIJ");
  258. XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 3, inputStr), @"_AbcdefghIJ");
  259. XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 4, inputStr), @"ABCD__EfghI_j");
  260. // An inlined string (and key of zero).
  261. XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 0, inputStr), @"zbcdefghIJ");
  262. // Long name so multiple decode ops are needed.
  263. inputStr = @"longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000";
  264. XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1000, inputStr),
  265. @"long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000");
  266. }
  267. - (void)testTextFormat {
  268. TestAllTypes *message = [TestAllTypes message];
  269. // Not kGPBDefaultRepeatCount because we are comparing to golden master file
  270. // which was generated with 2.
  271. [self setAllFields:message repeatedCount:2];
  272. NSString *result = GPBTextFormatForMessage(message, nil);
  273. NSString *fileName = @"text_format_unittest_data.txt";
  274. NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
  275. NSData *expectedData =
  276. [self getDataFileNamed:fileName dataToWrite:resultData];
  277. NSString *expected = [[NSString alloc] initWithData:expectedData
  278. encoding:NSUTF8StringEncoding];
  279. XCTAssertEqualObjects(expected, result);
  280. [expected release];
  281. }
  282. - (void)testTextFormatExtra {
  283. // -testTextFormat uses all protos with fields that don't require special
  284. // handing for figuring out the names. The ObjC proto has a bunch of oddball
  285. // field and enum names that require the decode info to get right, so this
  286. // confirms they generated and decoded correctly.
  287. self_Class *message = [self_Class message];
  288. message.cmd = YES;
  289. message.isProxy_p = YES;
  290. message.subEnum = self_autorelease_RetainCount;
  291. message.new_p.copy_p = @"foo";
  292. NSString *expected = @"_cmd: true\n"
  293. @"isProxy: true\n"
  294. @"SubEnum: retainCount\n"
  295. @"New {\n"
  296. @" copy: \"foo\"\n"
  297. @"}\n";
  298. NSString *result = GPBTextFormatForMessage(message, nil);
  299. XCTAssertEqualObjects(expected, result);
  300. }
  301. - (void)testTextFormatMaps {
  302. TestMap *message = [TestMap message];
  303. // Map iteration order doesn't have to be stable, so use only one entry.
  304. [self setAllMapFields:message numEntries:1];
  305. NSString *result = GPBTextFormatForMessage(message, nil);
  306. NSString *fileName = @"text_format_map_unittest_data.txt";
  307. NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding];
  308. NSData *expectedData =
  309. [self getDataFileNamed:fileName dataToWrite:resultData];
  310. NSString *expected = [[NSString alloc] initWithData:expectedData
  311. encoding:NSUTF8StringEncoding];
  312. XCTAssertEqualObjects(expected, result);
  313. [expected release];
  314. }
  315. // TODO(thomasvl): add test with extensions once those format with correct names.
  316. @end