1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file or at 6// https://developers.google.com/open-source/licenses/bsd 7 8#import <XCTest/XCTest.h> 9#import <objc/runtime.h> 10 11#import "GPBDescriptor.h" 12#import "GPBDescriptor_PackagePrivate.h" 13#import "GPBMessage.h" 14#import "GPBTestUtilities.h" 15#import "GPBUnknownField.h" 16#import "GPBUnknownField_PackagePrivate.h" 17#import "GPBUtilities.h" 18#import "GPBUtilities_PackagePrivate.h" 19#import "objectivec/Tests/MapUnittest.pbobjc.h" 20#import "objectivec/Tests/Unittest.pbobjc.h" 21#import "objectivec/Tests/UnittestObjc.pbobjc.h" 22 23@interface UtilitiesTests : GPBTestCase 24@end 25 26@implementation UtilitiesTests 27 28- (void)testRightShiftFunctions { 29 XCTAssertEqual((1UL << 31) >> 31, 1UL); 30 XCTAssertEqual((int32_t)(1U << 31) >> 31, -1); 31 XCTAssertEqual((1ULL << 63) >> 63, 1ULL); 32 XCTAssertEqual((int64_t)(1ULL << 63) >> 63, -1LL); 33 34 XCTAssertEqual(GPBLogicalRightShift32((1U << 31), 31), 1); 35 XCTAssertEqual(GPBLogicalRightShift64((1ULL << 63), 63), 1LL); 36} 37 38- (void)testGPBDecodeTextFormatName { 39 uint8_t decodeData[] = { 40 // clang-format off 41 0x6, 42 // An inlined string (first to make sure the leading null is handled 43 // correctly, and with a key of zero to check that). 44 0x0, 0x0, 'z', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'I', 'J', 0x0, 45 // All as is (00 op) 46 0x1, 0x0A, 0x0, 47 // Underscore, upper + 9 (10 op) 48 0x3, 0xCA, 0x0, 49 // Upper + 3 (10 op), underscore, upper + 5 (10 op) 50 0x2, 0x44, 0xC6, 0x0, 51 // All Upper for 4 (11 op), underscore, underscore, upper + 5 (10 op), 52 // underscore, lower + 0 (01 op) 53 0x4, 0x64, 0x80, 0xC5, 0xA1, 0x0, 54 // 2 byte key: as is + 3 (00 op), underscore, lower + 4 (01 op), 55 // underscore, lower + 3 (01 op), underscore, lower + 1 (01 op), 56 // underscore, lower + 30 (01 op), as is + 30 (00 op), as is + 13 (00 op), 57 // underscore, as is + 3 (00 op) 58 0xE8, 0x07, 0x04, 0xA5, 0xA4, 0xA2, 0xBF, 0x1F, 0x0E, 0x84, 0x0, 59 // clang-format on 60 }; 61 NSString *inputStr = @"abcdefghIJ"; 62 63 // Empty inputs 64 65 XCTAssertNil(GPBDecodeTextFormatName(nil, 1, NULL)); 66 XCTAssertNil(GPBDecodeTextFormatName(decodeData, 1, NULL)); 67 XCTAssertNil(GPBDecodeTextFormatName(nil, 1, inputStr)); 68 69 // Keys not found. 70 71 XCTAssertNil(GPBDecodeTextFormatName(decodeData, 5, inputStr)); 72 XCTAssertNil(GPBDecodeTextFormatName(decodeData, -1, inputStr)); 73 74 // Some name decodes. 75 76 XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1, inputStr), @"abcdefghIJ"); 77 XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 2, inputStr), @"Abcd_EfghIJ"); 78 XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 3, inputStr), @"_AbcdefghIJ"); 79 XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 4, inputStr), @"ABCD__EfghI_j"); 80 81 // An inlined string (and key of zero). 82 XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 0, inputStr), @"zbcdefghIJ"); 83 84 // clang-format off 85 // Long name so multiple decode ops are needed. 86 inputStr = @"longFieldNameIsLooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong1000"; 87 XCTAssertEqualObjects(GPBDecodeTextFormatName(decodeData, 1000, inputStr), 88 @"long_field_name_is_looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong_1000"); 89 // clang-format on 90} 91 92- (void)testTextFormat { 93 TestAllTypes *message = [TestAllTypes message]; 94 95 // Not kGPBDefaultRepeatCount because we are comparing to golden master file 96 // which was generated with 2. 97 [self setAllFields:message repeatedCount:2]; 98 99 NSString *result = GPBTextFormatForMessage(message, nil); 100 101 NSString *fileName = @"text_format_unittest_data.txt"; 102 NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; 103 NSData *expectedData = [self getDataFileNamed:fileName dataToWrite:resultData]; 104 NSString *expected = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding]; 105 XCTAssertEqualObjects(expected, result); 106 [expected release]; 107} 108 109- (void)testTextFormatExtra { 110 // -testTextFormat uses all protos with fields that don't require special 111 // handing for figuring out the names. The ObjC proto has a bunch of oddball 112 // field and enum names that require the decode info to get right, so this 113 // confirms they generated and decoded correctly. 114 115 self_Class *message = [self_Class message]; 116 message.cmd = YES; 117 message.isProxy_p = YES; 118 message.subEnum = self_autorelease_RetainCount; 119 message.new_p.copy_p = @"foo"; 120 121 // clang-format off 122 NSString *expected = @"_cmd: true\n" 123 @"isProxy: true\n" 124 @"SubEnum: retainCount\n" 125 @"New {\n" 126 @" copy: \"foo\"\n" 127 @"}\n"; 128 // clang-format on 129 NSString *result = GPBTextFormatForMessage(message, nil); 130 XCTAssertEqualObjects(expected, result); 131} 132 133- (void)testTextFormatMaps { 134 TestMap *message = [TestMap message]; 135 136 // Map iteration order doesn't have to be stable, so use only one entry. 137 [self setAllMapFields:message numEntries:1]; 138 139 NSString *result = GPBTextFormatForMessage(message, nil); 140 141 NSString *fileName = @"text_format_map_unittest_data.txt"; 142 NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; 143 NSData *expectedData = [self getDataFileNamed:fileName dataToWrite:resultData]; 144 NSString *expected = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding]; 145 XCTAssertEqualObjects(expected, result); 146 [expected release]; 147} 148 149- (void)testTextFormatExtensions { 150 TestAllExtensions *message = [TestAllExtensions message]; 151 152 // Not kGPBDefaultRepeatCount because we are comparing to golden master file 153 // which was generated with 2. 154 [self setAllExtensions:message repeatedCount:2]; 155 156 NSString *result = GPBTextFormatForMessage(message, nil); 157 158 // NOTE: ObjC TextFormat doesn't have the proper extension names so it 159 // uses comments for the ObjC name and raw numbers for the fields instead 160 // of the bracketed extension name. 161 NSString *fileName = @"text_format_extensions_unittest_data.txt"; 162 NSData *resultData = [result dataUsingEncoding:NSUTF8StringEncoding]; 163 NSData *expectedData = [self getDataFileNamed:fileName dataToWrite:resultData]; 164 NSString *expected = [[NSString alloc] initWithData:expectedData encoding:NSUTF8StringEncoding]; 165 XCTAssertEqualObjects(expected, result); 166 [expected release]; 167} 168 169- (void)testTextFormatUnknownFields { 170 GPBUnknownFields *ufs = [[[GPBUnknownFields alloc] init] autorelease]; 171 [ufs addFieldNumber:100 varint:5]; 172 [ufs addFieldNumber:100 varint:4]; 173 [ufs addFieldNumber:10 varint:1]; 174 [ufs addFieldNumber:300 fixed32:0x50]; 175 [ufs addFieldNumber:300 fixed32:0x40]; 176 [ufs addFieldNumber:10 fixed32:0x10]; 177 [ufs addFieldNumber:200 fixed64:0x5000]; 178 [ufs addFieldNumber:200 fixed64:0x4000]; 179 [ufs addFieldNumber:10 fixed64:0x1000]; 180 [ufs addFieldNumber:10 lengthDelimited:DataFromCStr("foo")]; 181 [ufs addFieldNumber:10 lengthDelimited:DataFromCStr("bar")]; 182 GPBUnknownFields *group = [ufs addGroupWithFieldNumber:150]; 183 [group addFieldNumber:2 varint:2]; 184 [group addFieldNumber:1 varint:1]; 185 group = [ufs addGroupWithFieldNumber:150]; 186 [group addFieldNumber:1 varint:1]; 187 [group addFieldNumber:3 fixed32:0x3]; 188 [group addFieldNumber:2 fixed64:0x2]; 189 TestEmptyMessage *message = [TestEmptyMessage message]; 190 XCTAssertTrue([message mergeUnknownFields:ufs extensionRegistry:nil error:NULL]); 191 192 NSString *expected = @"# --- Unknown fields ---\n" 193 @"10: 1\n" 194 @"10: 0x10\n" 195 @"10: 0x1000\n" 196 @"10: \"foo\"\n" 197 @"10: \"bar\"\n" 198 @"100: 5\n" 199 @"100: 4\n" 200 @"150: {\n" 201 @" 1: 1\n" 202 @" 2: 2\n" 203 @"}\n" 204 @"150: {\n" 205 @" 1: 1\n" 206 @" 2: 0x2\n" 207 @" 3: 0x3\n" 208 @"}\n" 209 @"200: 0x5000\n" 210 @"200: 0x4000\n" 211 @"300: 0x50\n" 212 @"300: 0x40\n"; 213 NSString *result = GPBTextFormatForMessage(message, nil); 214 XCTAssertEqualObjects(expected, result); 215} 216 217- (void)testSetRepeatedFields { 218 TestAllTypes *message = [TestAllTypes message]; 219 220 NSDictionary *repeatedFieldValues = @{ 221 @"repeatedStringArray" : [@[ @"foo", @"bar" ] mutableCopy], 222 @"repeatedBoolArray" : [GPBBoolArray arrayWithValue:YES], 223 @"repeatedInt32Array" : [GPBInt32Array arrayWithValue:14], 224 @"repeatedInt64Array" : [GPBInt64Array arrayWithValue:15], 225 @"repeatedUint32Array" : [GPBUInt32Array arrayWithValue:16], 226 @"repeatedUint64Array" : [GPBUInt64Array arrayWithValue:16], 227 @"repeatedFloatArray" : [GPBFloatArray arrayWithValue:16], 228 @"repeatedDoubleArray" : [GPBDoubleArray arrayWithValue:16], 229 @"repeatedNestedEnumArray" : 230 [GPBEnumArray arrayWithValidationFunction:TestAllTypes_NestedEnum_IsValidValue 231 rawValue:TestAllTypes_NestedEnum_Foo], 232 }; 233 for (NSString *fieldName in repeatedFieldValues) { 234 GPBFieldDescriptor *field = [message.descriptor fieldWithName:fieldName]; 235 XCTAssertNotNil(field, @"No field with name: %@", fieldName); 236 id expectedValues = repeatedFieldValues[fieldName]; 237 GPBSetMessageRepeatedField(message, field, expectedValues); 238 XCTAssertEqualObjects(expectedValues, [message valueForKeyPath:fieldName]); 239 } 240} 241 242#pragma clang diagnostic push 243#pragma clang diagnostic ignored "-Wdeprecated-declarations" 244// Helper to make an unknown field set with something in it. 245static GPBUnknownFieldSet *UnknownFieldsSetHelper(int num) { 246 GPBUnknownFieldSet *result = [[[GPBUnknownFieldSet alloc] init] autorelease]; 247 248 GPBUnknownField *field = [[[GPBUnknownField alloc] initWithNumber:num] autorelease]; 249 [field addVarint:num]; 250 [result addField:field]; 251 252 return result; 253} 254#pragma clang diagnostic pop 255 256// Helper to add an unknown field data to messages. 257static void AddUnknownFields(GPBMessage *message, int num) { 258 GPBUnknownFields *ufs = [[GPBUnknownFields alloc] init]; 259 [ufs addFieldNumber:num varint:num]; 260 // Can't fail since it is a varint. 261 [message mergeUnknownFields:ufs extensionRegistry:nil error:NULL]; 262 [ufs release]; 263} 264 265static BOOL HasUnknownFields(GPBMessage *message) { 266 GPBUnknownFields *ufs = [[GPBUnknownFields alloc] initFromMessage:message]; 267 BOOL result = !ufs.empty; 268 [ufs release]; 269 return result; 270} 271 272- (void)testDropMessageUnknownFieldsRecursively { 273 TestAllExtensions *message = [TestAllExtensions message]; 274 275#pragma clang diagnostic push 276#pragma clang diagnostic ignored "-Wdeprecated-declarations" 277 278 // Give it unknownFields. 279 message.unknownFields = UnknownFieldsSetHelper(777); 280 AddUnknownFields(message, 1777); 281 282 // Given it extensions that include a message with unknown fields of its own. 283 { 284 // Int 285 [message setExtension:[UnittestRoot optionalInt32Extension] value:@5]; 286 287 // Group 288 OptionalGroup_extension *optionalGroup = [OptionalGroup_extension message]; 289 optionalGroup.a = 123; 290 optionalGroup.unknownFields = UnknownFieldsSetHelper(779); 291 AddUnknownFields(optionalGroup, 1779); 292 [message setExtension:[UnittestRoot optionalGroupExtension] value:optionalGroup]; 293 294 // Message 295 TestAllTypes_NestedMessage *nestedMessage = [TestAllTypes_NestedMessage message]; 296 nestedMessage.bb = 456; 297 nestedMessage.unknownFields = UnknownFieldsSetHelper(778); 298 AddUnknownFields(nestedMessage, 1778); 299 [message setExtension:[UnittestRoot optionalNestedMessageExtension] value:nestedMessage]; 300 301 // Repeated Group 302 RepeatedGroup_extension *repeatedGroup = [[RepeatedGroup_extension alloc] init]; 303 repeatedGroup.a = 567; 304 repeatedGroup.unknownFields = UnknownFieldsSetHelper(780); 305 AddUnknownFields(repeatedGroup, 1780); 306 [message addExtension:[UnittestRoot repeatedGroupExtension] value:repeatedGroup]; 307 [repeatedGroup release]; 308 309 // Repeated Message 310 nestedMessage = [[TestAllTypes_NestedMessage alloc] init]; 311 nestedMessage.bb = 678; 312 nestedMessage.unknownFields = UnknownFieldsSetHelper(781); 313 AddUnknownFields(nestedMessage, 1781); 314 [message addExtension:[UnittestRoot repeatedNestedMessageExtension] value:nestedMessage]; 315 [nestedMessage release]; 316 } 317 318 // Confirm everything is there. 319 320 XCTAssertNotNil(message); 321 XCTAssertTrue(HasUnknownFields(message)); 322 XCTAssertNotNil(message.unknownFields); 323 XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]); 324 325 { 326 XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]); 327 OptionalGroup_extension *optionalGroup = 328 [message getExtension:[UnittestRoot optionalGroupExtension]]; 329 XCTAssertNotNil(optionalGroup); 330 XCTAssertEqual(optionalGroup.a, 123); 331 XCTAssertTrue(HasUnknownFields(optionalGroup)); 332 XCTAssertNotNil(optionalGroup.unknownFields); 333 } 334 335 { 336 XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); 337 TestAllTypes_NestedMessage *nestedMessage = 338 [message getExtension:[UnittestRoot optionalNestedMessageExtension]]; 339 XCTAssertNotNil(nestedMessage); 340 XCTAssertEqual(nestedMessage.bb, 456); 341 XCTAssertTrue(HasUnknownFields(nestedMessage)); 342 XCTAssertNotNil(nestedMessage.unknownFields); 343 } 344 345 { 346 XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]); 347 NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]]; 348 XCTAssertEqual(repeatedGroups.count, (NSUInteger)1); 349 RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject; 350 XCTAssertNotNil(repeatedGroup); 351 XCTAssertEqual(repeatedGroup.a, 567); 352 XCTAssertTrue(HasUnknownFields(repeatedGroup)); 353 XCTAssertNotNil(repeatedGroup.unknownFields); 354 } 355 356 { 357 XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]); 358 NSArray *repeatedNestedMessages = 359 [message getExtension:[UnittestRoot repeatedNestedMessageExtension]]; 360 XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1); 361 TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject; 362 XCTAssertNotNil(repeatedNestedMessage); 363 XCTAssertEqual(repeatedNestedMessage.bb, 678); 364 XCTAssertTrue(HasUnknownFields(repeatedNestedMessage)); 365 XCTAssertNotNil(repeatedNestedMessage.unknownFields); 366 } 367 368 // Drop them. 369 GPBMessageDropUnknownFieldsRecursively(message); 370 371 // Confirm unknowns are gone from within the messages. 372 373 XCTAssertNotNil(message); 374 XCTAssertFalse(HasUnknownFields(message)); 375 XCTAssertNil(message.unknownFields); 376 XCTAssertTrue([message hasExtension:[UnittestRoot optionalInt32Extension]]); 377 378 { 379 XCTAssertTrue([message hasExtension:[UnittestRoot optionalGroupExtension]]); 380 OptionalGroup_extension *optionalGroup = 381 [message getExtension:[UnittestRoot optionalGroupExtension]]; 382 XCTAssertNotNil(optionalGroup); 383 XCTAssertEqual(optionalGroup.a, 123); 384 XCTAssertFalse(HasUnknownFields(optionalGroup)); 385 XCTAssertNil(optionalGroup.unknownFields); 386 } 387 388 { 389 XCTAssertTrue([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]); 390 TestAllTypes_NestedMessage *nestedMessage = 391 [message getExtension:[UnittestRoot optionalNestedMessageExtension]]; 392 XCTAssertNotNil(nestedMessage); 393 XCTAssertEqual(nestedMessage.bb, 456); 394 XCTAssertFalse(HasUnknownFields(nestedMessage)); 395 XCTAssertNil(nestedMessage.unknownFields); 396 } 397 398 { 399 XCTAssertTrue([message hasExtension:[UnittestRoot repeatedGroupExtension]]); 400 NSArray *repeatedGroups = [message getExtension:[UnittestRoot repeatedGroupExtension]]; 401 XCTAssertEqual(repeatedGroups.count, (NSUInteger)1); 402 RepeatedGroup_extension *repeatedGroup = repeatedGroups.firstObject; 403 XCTAssertNotNil(repeatedGroup); 404 XCTAssertEqual(repeatedGroup.a, 567); 405 XCTAssertFalse(HasUnknownFields(repeatedGroup)); 406 XCTAssertNil(repeatedGroup.unknownFields); 407 } 408 409 { 410 XCTAssertTrue([message hasExtension:[UnittestRoot repeatedNestedMessageExtension]]); 411 NSArray *repeatedNestedMessages = 412 [message getExtension:[UnittestRoot repeatedNestedMessageExtension]]; 413 XCTAssertEqual(repeatedNestedMessages.count, (NSUInteger)1); 414 TestAllTypes_NestedMessage *repeatedNestedMessage = repeatedNestedMessages.firstObject; 415 XCTAssertNotNil(repeatedNestedMessage); 416 XCTAssertEqual(repeatedNestedMessage.bb, 678); 417 XCTAssertFalse(HasUnknownFields(repeatedNestedMessage)); 418 XCTAssertNil(repeatedNestedMessage.unknownFields); 419 } 420 421#pragma clang diagnostic pop 422} 423 424- (void)testDropMessageUnknownFieldsRecursively_Maps { 425 TestMap *message = [TestMap message]; 426 427#pragma clang diagnostic push 428#pragma clang diagnostic ignored "-Wdeprecated-declarations" 429 430 { 431 ForeignMessage *foreignMessage = [ForeignMessage message]; 432 foreignMessage.unknownFields = UnknownFieldsSetHelper(100); 433 AddUnknownFields(foreignMessage, 1000); 434 [message.mapInt32ForeignMessage setObject:foreignMessage forKey:100]; 435 436 foreignMessage = [ForeignMessage message]; 437 foreignMessage.unknownFields = UnknownFieldsSetHelper(101); 438 AddUnknownFields(foreignMessage, 1001); 439 [message.mapStringForeignMessage setObject:foreignMessage forKey:@"101"]; 440 } 441 442 // Confirm everything is there. 443 444 XCTAssertNotNil(message); 445 446 { 447 ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100]; 448 XCTAssertNotNil(foreignMessage); 449 XCTAssertTrue(HasUnknownFields(foreignMessage)); 450 XCTAssertNotNil(foreignMessage.unknownFields); 451 } 452 453 { 454 ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"]; 455 XCTAssertNotNil(foreignMessage); 456 XCTAssertTrue(HasUnknownFields(foreignMessage)); 457 XCTAssertNotNil(foreignMessage.unknownFields); 458 } 459 460 GPBMessageDropUnknownFieldsRecursively(message); 461 462 // Confirm unknowns are gone from within the messages. 463 464 XCTAssertNotNil(message); 465 466 { 467 ForeignMessage *foreignMessage = [message.mapInt32ForeignMessage objectForKey:100]; 468 XCTAssertNotNil(foreignMessage); 469 XCTAssertFalse(HasUnknownFields(foreignMessage)); 470 XCTAssertNil(foreignMessage.unknownFields); 471 } 472 473 { 474 ForeignMessage *foreignMessage = [message.mapStringForeignMessage objectForKey:@"101"]; 475 XCTAssertNotNil(foreignMessage); 476 XCTAssertFalse(HasUnknownFields(foreignMessage)); 477 XCTAssertNil(foreignMessage.unknownFields); 478 } 479 480#pragma clang diagnostic pop 481} 482 483@end 484