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