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 <objc/runtime.h> 9 10#import "GPBDescriptor.h" 11#import "GPBDescriptor_PackagePrivate.h" 12#import "GPBTestUtilities.h" 13#import "objectivec/Tests/Unittest.pbobjc.h" 14#import "objectivec/Tests/UnittestObjc.pbobjc.h" 15#import "objectivec/Tests/UnittestObjcOptions.pbobjc.h" 16 17@interface DescriptorTests : GPBTestCase 18@end 19 20@implementation DescriptorTests 21 22- (void)testDescriptor_containingType { 23 GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor]; 24 GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor]; 25 XCTAssertNil(testAllTypesDesc.containingType); 26 XCTAssertNotNil(nestedMessageDesc.containingType); 27 XCTAssertEqual(nestedMessageDesc.containingType, testAllTypesDesc); // Ptr comparison 28} 29 30- (void)testDescriptor_fullName { 31 GPBDescriptor *testAllTypesDesc = [TestAllTypes descriptor]; 32 XCTAssertEqualObjects(testAllTypesDesc.fullName, @"objc.protobuf.tests.TestAllTypes"); 33 GPBDescriptor *nestedMessageDesc = [TestAllTypes_NestedMessage descriptor]; 34 XCTAssertEqualObjects(nestedMessageDesc.fullName, 35 @"objc.protobuf.tests.TestAllTypes.NestedMessage"); 36 37 // Prefixes removed. 38 GPBDescriptor *descDesc = [GPBTESTPrefixedParentMessage descriptor]; 39 XCTAssertEqualObjects(descDesc.fullName, @"objc.protobuf.tests.options.PrefixedParentMessage"); 40 GPBDescriptor *descExtRngDesc = [GPBTESTPrefixedParentMessage_Child descriptor]; 41 XCTAssertEqualObjects(descExtRngDesc.fullName, 42 @"objc.protobuf.tests.options.PrefixedParentMessage.Child"); 43 44 // Things that get "_Class" added. 45 GPBDescriptor *pointDesc = [Point_Class descriptor]; 46 XCTAssertEqualObjects(pointDesc.fullName, @"objc.protobuf.tests.Point"); 47 GPBDescriptor *pointRectDesc = [Point_Rect descriptor]; 48 XCTAssertEqualObjects(pointRectDesc.fullName, @"objc.protobuf.tests.Point.Rect"); 49} 50 51- (void)testFieldDescriptor { 52 GPBDescriptor *descriptor = [TestAllTypes descriptor]; 53 54 // Nested Enum 55 GPBFieldDescriptor *fieldDescriptorWithName = [descriptor fieldWithName:@"optionalNestedEnum"]; 56 XCTAssertNotNil(fieldDescriptorWithName); 57 GPBFieldDescriptor *fieldDescriptorWithNumber = [descriptor fieldWithNumber:21]; 58 XCTAssertNotNil(fieldDescriptorWithNumber); 59 XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); 60 XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); 61 XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, @"TestAllTypes_NestedEnum"); 62 XCTAssertEqual(fieldDescriptorWithName.number, fieldDescriptorWithNumber.number); 63 XCTAssertEqual(fieldDescriptorWithName.dataType, GPBDataTypeEnum); 64 65 // Foreign Enum 66 fieldDescriptorWithName = [descriptor fieldWithName:@"optionalForeignEnum"]; 67 XCTAssertNotNil(fieldDescriptorWithName); 68 fieldDescriptorWithNumber = [descriptor fieldWithNumber:22]; 69 XCTAssertNotNil(fieldDescriptorWithNumber); 70 XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); 71 XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); 72 XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, @"ForeignEnum"); 73 XCTAssertEqual(fieldDescriptorWithName.number, fieldDescriptorWithNumber.number); 74 XCTAssertEqual(fieldDescriptorWithName.dataType, GPBDataTypeEnum); 75 76 // Import Enum 77 fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportEnum"]; 78 XCTAssertNotNil(fieldDescriptorWithName); 79 fieldDescriptorWithNumber = [descriptor fieldWithNumber:23]; 80 XCTAssertNotNil(fieldDescriptorWithNumber); 81 XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); 82 XCTAssertNotNil(fieldDescriptorWithNumber.enumDescriptor); 83 XCTAssertEqualObjects(fieldDescriptorWithNumber.enumDescriptor.name, @"ImportEnum"); 84 XCTAssertEqual(fieldDescriptorWithName.number, fieldDescriptorWithNumber.number); 85 XCTAssertEqual(fieldDescriptorWithName.dataType, GPBDataTypeEnum); 86 87 // Nested Message 88 fieldDescriptorWithName = [descriptor fieldWithName:@"optionalNestedMessage"]; 89 XCTAssertNotNil(fieldDescriptorWithName); 90 fieldDescriptorWithNumber = [descriptor fieldWithNumber:18]; 91 XCTAssertNotNil(fieldDescriptorWithNumber); 92 XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); 93 XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); 94 XCTAssertEqual(fieldDescriptorWithName.number, fieldDescriptorWithNumber.number); 95 XCTAssertEqual(fieldDescriptorWithName.dataType, GPBDataTypeMessage); 96 97 // Foreign Message 98 fieldDescriptorWithName = [descriptor fieldWithName:@"optionalForeignMessage"]; 99 XCTAssertNotNil(fieldDescriptorWithName); 100 fieldDescriptorWithNumber = [descriptor fieldWithNumber:19]; 101 XCTAssertNotNil(fieldDescriptorWithNumber); 102 XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); 103 XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); 104 XCTAssertEqual(fieldDescriptorWithName.number, fieldDescriptorWithNumber.number); 105 XCTAssertEqual(fieldDescriptorWithName.dataType, GPBDataTypeMessage); 106 107 // Import Message 108 fieldDescriptorWithName = [descriptor fieldWithName:@"optionalImportMessage"]; 109 XCTAssertNotNil(fieldDescriptorWithName); 110 fieldDescriptorWithNumber = [descriptor fieldWithNumber:20]; 111 XCTAssertNotNil(fieldDescriptorWithNumber); 112 XCTAssertEqual(fieldDescriptorWithName, fieldDescriptorWithNumber); 113 XCTAssertNil(fieldDescriptorWithNumber.enumDescriptor); 114 XCTAssertEqual(fieldDescriptorWithName.number, fieldDescriptorWithNumber.number); 115 XCTAssertEqual(fieldDescriptorWithName.dataType, GPBDataTypeMessage); 116 117 // Some failed lookups. 118 XCTAssertNil([descriptor fieldWithName:@"NOT THERE"]); 119 XCTAssertNil([descriptor fieldWithNumber:9876543]); 120} 121 122- (void)testEnumDescriptor { 123 GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor(); 124 125 NSString *enumName = [descriptor enumNameForValue:1]; 126 XCTAssertNotNil(enumName); 127 int32_t value; 128 XCTAssertTrue([descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Foo"]); 129 XCTAssertTrue([descriptor getValue:NULL forEnumName:@"TestAllTypes_NestedEnum_Foo"]); 130 XCTAssertEqual(value, TestAllTypes_NestedEnum_Foo); 131 132 enumName = [descriptor enumNameForValue:2]; 133 XCTAssertNotNil(enumName); 134 XCTAssertTrue([descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Bar"]); 135 XCTAssertEqual(value, TestAllTypes_NestedEnum_Bar); 136 137 enumName = [descriptor enumNameForValue:3]; 138 XCTAssertNotNil(enumName); 139 XCTAssertTrue([descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Baz"]); 140 XCTAssertEqual(value, TestAllTypes_NestedEnum_Baz); 141 142 // TextFormat 143 enumName = [descriptor textFormatNameForValue:1]; 144 XCTAssertNotNil(enumName); 145 XCTAssertTrue([descriptor getValue:&value forEnumTextFormatName:@"FOO"]); 146 XCTAssertEqual(value, TestAllTypes_NestedEnum_Foo); 147 XCTAssertNil([descriptor textFormatNameForValue:99999]); 148 149 // Bad values 150 enumName = [descriptor enumNameForValue:0]; 151 XCTAssertNil(enumName); 152 XCTAssertFalse([descriptor getValue:&value forEnumName:@"Unknown"]); 153 XCTAssertFalse([descriptor getValue:NULL forEnumName:@"Unknown"]); 154 XCTAssertFalse([descriptor getValue:&value forEnumName:@"TestAllTypes_NestedEnum_Unknown"]); 155 XCTAssertFalse([descriptor getValue:NULL forEnumName:@"TestAllTypes_NestedEnum_Unknown"]); 156 XCTAssertFalse([descriptor getValue:NULL forEnumTextFormatName:@"Unknown"]); 157 XCTAssertFalse([descriptor getValue:&value forEnumTextFormatName:@"Unknown"]); 158} 159 160- (void)testEnumDescriptorIntrospection { 161 GPBEnumDescriptor *descriptor = TestAllTypes_NestedEnum_EnumDescriptor(); 162 163 XCTAssertEqual(descriptor.enumNameCount, 4U); 164 XCTAssertEqualObjects([descriptor getEnumNameForIndex:0], @"TestAllTypes_NestedEnum_Foo"); 165 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:0], @"FOO"); 166 XCTAssertEqualObjects([descriptor getEnumNameForIndex:1], @"TestAllTypes_NestedEnum_Bar"); 167 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:1], @"BAR"); 168 XCTAssertEqualObjects([descriptor getEnumNameForIndex:2], @"TestAllTypes_NestedEnum_Baz"); 169 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:2], @"BAZ"); 170 XCTAssertEqualObjects([descriptor getEnumNameForIndex:3], @"TestAllTypes_NestedEnum_Neg"); 171 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:3], @"NEG"); 172} 173 174- (void)testEnumDescriptorIntrospectionWithAlias { 175 GPBEnumDescriptor *descriptor = TestEnumWithDupValue_EnumDescriptor(); 176 NSString *enumName; 177 int32_t value; 178 179 XCTAssertEqual(descriptor.enumNameCount, 5U); 180 181 enumName = [descriptor getEnumNameForIndex:0]; 182 XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Foo1"); 183 XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]); 184 XCTAssertEqual(value, 1); 185 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:0], @"FOO1"); 186 187 enumName = [descriptor getEnumNameForIndex:1]; 188 XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Bar1"); 189 XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]); 190 XCTAssertEqual(value, 2); 191 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:1], @"BAR1"); 192 193 enumName = [descriptor getEnumNameForIndex:2]; 194 XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Baz"); 195 XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]); 196 XCTAssertEqual(value, 3); 197 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:2], @"BAZ"); 198 199 enumName = [descriptor getEnumNameForIndex:3]; 200 XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Foo2"); 201 XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]); 202 XCTAssertEqual(value, 1); 203 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:3], @"FOO2"); 204 205 enumName = [descriptor getEnumNameForIndex:4]; 206 XCTAssertEqualObjects(enumName, @"TestEnumWithDupValue_Bar2"); 207 XCTAssertTrue([descriptor getValue:&value forEnumName:enumName]); 208 XCTAssertEqual(value, 2); 209 XCTAssertEqualObjects([descriptor getEnumTextFormatNameForIndex:4], @"BAR2"); 210} 211 212- (void)testEnumAliasNameCollisions { 213 GPBEnumDescriptor *descriptor = TestEnumObjCNameCollision_EnumDescriptor(); 214 NSString *textFormatName; 215 int32_t value; 216 217 XCTAssertEqual(descriptor.enumNameCount, 5U); 218 219 XCTAssertEqualObjects([descriptor getEnumNameForIndex:0], @"TestEnumObjCNameCollision_Foo"); 220 textFormatName = [descriptor getEnumTextFormatNameForIndex:0]; 221 XCTAssertEqualObjects(textFormatName, @"FOO"); 222 XCTAssertTrue([descriptor getValue:&value forEnumTextFormatName:textFormatName]); 223 XCTAssertEqual(value, 1); 224 225 XCTAssertEqualObjects([descriptor getEnumNameForIndex:1], @"TestEnumObjCNameCollision_Foo"); 226 textFormatName = [descriptor getEnumTextFormatNameForIndex:1]; 227 XCTAssertEqualObjects(textFormatName, @"foo"); 228 XCTAssertTrue([descriptor getValue:&value forEnumTextFormatName:textFormatName]); 229 XCTAssertEqual(value, 1); 230 231 XCTAssertEqualObjects([descriptor getEnumNameForIndex:2], @"TestEnumObjCNameCollision_Bar"); 232 textFormatName = [descriptor getEnumTextFormatNameForIndex:2]; 233 XCTAssertEqualObjects(textFormatName, @"BAR"); 234 XCTAssertTrue([descriptor getValue:&value forEnumTextFormatName:textFormatName]); 235 XCTAssertEqual(value, 2); 236 237 XCTAssertEqualObjects([descriptor getEnumNameForIndex:3], @"TestEnumObjCNameCollision_Mumble"); 238 textFormatName = [descriptor getEnumTextFormatNameForIndex:3]; 239 XCTAssertEqualObjects(textFormatName, @"mumble"); 240 XCTAssertTrue([descriptor getValue:&value forEnumTextFormatName:textFormatName]); 241 XCTAssertEqual(value, 2); 242 243 XCTAssertEqualObjects([descriptor getEnumNameForIndex:4], @"TestEnumObjCNameCollision_Mumble"); 244 textFormatName = [descriptor getEnumTextFormatNameForIndex:4]; 245 XCTAssertEqualObjects(textFormatName, @"MUMBLE"); 246 XCTAssertTrue([descriptor getValue:&value forEnumTextFormatName:textFormatName]); 247 XCTAssertEqual(value, 2); 248} 249 250- (void)testEnumValueValidator { 251 GPBDescriptor *descriptor = [TestAllTypes descriptor]; 252 GPBFieldDescriptor *fieldDescriptor = [descriptor fieldWithName:@"optionalNestedEnum"]; 253 254 // Valid values 255 XCTAssertTrue([fieldDescriptor isValidEnumValue:1]); 256 XCTAssertTrue([fieldDescriptor isValidEnumValue:2]); 257 XCTAssertTrue([fieldDescriptor isValidEnumValue:3]); 258 XCTAssertTrue([fieldDescriptor isValidEnumValue:-1]); 259 260 // Invalid values 261 XCTAssertFalse([fieldDescriptor isValidEnumValue:4]); 262 XCTAssertFalse([fieldDescriptor isValidEnumValue:0]); 263 XCTAssertFalse([fieldDescriptor isValidEnumValue:-2]); 264} 265 266- (void)testOneofDescriptor { 267 GPBDescriptor *descriptor = [TestOneof2 descriptor]; 268 269 GPBFieldDescriptor *fooStringField = 270 [descriptor fieldWithNumber:TestOneof2_FieldNumber_FooString]; 271 XCTAssertNotNil(fooStringField); 272 GPBFieldDescriptor *barStringField = 273 [descriptor fieldWithNumber:TestOneof2_FieldNumber_BarString]; 274 XCTAssertNotNil(barStringField); 275 276 // Check the oneofs to have what is expected but not other onesofs 277 278 GPBOneofDescriptor *oneofFoo = [descriptor oneofWithName:@"foo"]; 279 XCTAssertNotNil(oneofFoo); 280 XCTAssertNotNil([oneofFoo fieldWithName:@"fooString"]); 281 XCTAssertNil([oneofFoo fieldWithName:@"barString"]); 282 283 GPBOneofDescriptor *oneofBar = [descriptor oneofWithName:@"bar"]; 284 XCTAssertNotNil(oneofBar); 285 XCTAssertNil([oneofBar fieldWithName:@"fooString"]); 286 XCTAssertNotNil([oneofBar fieldWithName:@"barString"]); 287 288 // Pointer comparisons against lookups from message. 289 290 XCTAssertEqual([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_FooString], fooStringField); 291 XCTAssertEqual([oneofFoo fieldWithName:@"fooString"], fooStringField); 292 293 XCTAssertEqual([oneofBar fieldWithNumber:TestOneof2_FieldNumber_BarString], barStringField); 294 XCTAssertEqual([oneofBar fieldWithName:@"barString"], barStringField); 295 296 // Unknown oneof not found. 297 298 XCTAssertNil([descriptor oneofWithName:@"mumble"]); 299 XCTAssertNil([descriptor oneofWithName:@"Foo"]); 300 301 // Unknown oneof item. 302 303 XCTAssertNil([oneofFoo fieldWithName:@"mumble"]); 304 XCTAssertNil([oneofFoo fieldWithNumber:666]); 305 306 // Field exists, but not in this oneof. 307 308 XCTAssertNil([oneofFoo fieldWithName:@"barString"]); 309 XCTAssertNil([oneofFoo fieldWithNumber:TestOneof2_FieldNumber_BarString]); 310 XCTAssertNil([oneofBar fieldWithName:@"fooString"]); 311 XCTAssertNil([oneofBar fieldWithNumber:TestOneof2_FieldNumber_FooString]); 312 313 // Check pointers back to the enclosing oneofs. 314 // (pointer comparisons) 315 XCTAssertEqual(fooStringField.containingOneof, oneofFoo); 316 XCTAssertEqual(barStringField.containingOneof, oneofBar); 317 GPBFieldDescriptor *bazString = [descriptor fieldWithNumber:TestOneof2_FieldNumber_BazString]; 318 XCTAssertNotNil(bazString); 319 XCTAssertNil(bazString.containingOneof); 320} 321 322- (void)testExtensiondDescriptor { 323 Class msgClass = [TestAllExtensions class]; 324 Class packedMsgClass = [TestPackedExtensions class]; 325 326 // Int 327 328 GPBExtensionDescriptor *descriptor = [UnittestRoot optionalInt32Extension]; 329 XCTAssertNotNil(descriptor); 330 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 331 XCTAssertFalse(descriptor.isPackable); 332 XCTAssertEqualObjects(descriptor.defaultValue, @0); 333 XCTAssertNil(descriptor.enumDescriptor); 334 335 descriptor = [UnittestRoot defaultInt32Extension]; 336 XCTAssertNotNil(descriptor); 337 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 338 XCTAssertFalse(descriptor.isPackable); 339 XCTAssertEqualObjects(descriptor.defaultValue, @41); 340 XCTAssertNil(descriptor.enumDescriptor); 341 342 // Enum 343 344 descriptor = [UnittestRoot optionalNestedEnumExtension]; 345 XCTAssertNotNil(descriptor); 346 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 347 XCTAssertFalse(descriptor.isPackable); 348 XCTAssertEqual(descriptor.defaultValue, @1); 349 XCTAssertEqualObjects(descriptor.enumDescriptor.name, @"TestAllTypes_NestedEnum"); 350 351 descriptor = [UnittestRoot defaultNestedEnumExtension]; 352 XCTAssertNotNil(descriptor); 353 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 354 XCTAssertFalse(descriptor.isPackable); 355 XCTAssertEqual(descriptor.defaultValue, @2); 356 XCTAssertEqualObjects(descriptor.enumDescriptor.name, @"TestAllTypes_NestedEnum"); 357 358 // Message 359 360 descriptor = [UnittestRoot optionalNestedMessageExtension]; 361 XCTAssertNotNil(descriptor); 362 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 363 XCTAssertFalse(descriptor.isPackable); 364 XCTAssertNil(descriptor.defaultValue); 365 XCTAssertNil(descriptor.enumDescriptor); 366 367 // Repeated Int 368 369 descriptor = [UnittestRoot repeatedInt32Extension]; 370 XCTAssertNotNil(descriptor); 371 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 372 XCTAssertFalse(descriptor.isPackable); 373 XCTAssertNil(descriptor.defaultValue); 374 XCTAssertNil(descriptor.enumDescriptor); 375 376 descriptor = [UnittestRoot packedInt32Extension]; 377 XCTAssertNotNil(descriptor); 378 XCTAssertEqual(descriptor.containingMessageClass, packedMsgClass); // ptr equality 379 XCTAssertTrue(descriptor.isPackable); 380 XCTAssertNil(descriptor.defaultValue); 381 XCTAssertNil(descriptor.enumDescriptor); 382 383 // Repeated Enum 384 385 descriptor = [UnittestRoot repeatedNestedEnumExtension]; 386 XCTAssertNotNil(descriptor); 387 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 388 XCTAssertFalse(descriptor.isPackable); 389 XCTAssertNil(descriptor.defaultValue); 390 XCTAssertEqualObjects(descriptor.enumDescriptor.name, @"TestAllTypes_NestedEnum"); 391 392 descriptor = [UnittestRoot packedEnumExtension]; 393 XCTAssertNotNil(descriptor); 394 XCTAssertEqual(descriptor.containingMessageClass, packedMsgClass); // ptr equality 395 XCTAssertTrue(descriptor.isPackable); 396 XCTAssertNil(descriptor.defaultValue); 397 XCTAssertEqualObjects(descriptor.enumDescriptor.name, @"ForeignEnum"); 398 399 // Repeated Message 400 401 descriptor = [UnittestRoot repeatedNestedMessageExtension]; 402 XCTAssertNotNil(descriptor); 403 XCTAssertEqual(descriptor.containingMessageClass, msgClass); // ptr equality 404 XCTAssertFalse(descriptor.isPackable); 405 XCTAssertNil(descriptor.defaultValue); 406 XCTAssertNil(descriptor.enumDescriptor); 407 408 // Compare (used internally for serialization). 409 410 GPBExtensionDescriptor *ext1 = [UnittestRoot optionalInt32Extension]; 411 XCTAssertEqual(ext1.fieldNumber, 1u); 412 GPBExtensionDescriptor *ext2 = [UnittestRoot optionalInt64Extension]; 413 XCTAssertEqual(ext2.fieldNumber, 2u); 414 415 XCTAssertEqual([ext1 compareByFieldNumber:ext2], NSOrderedAscending); 416 XCTAssertEqual([ext2 compareByFieldNumber:ext1], NSOrderedDescending); 417 XCTAssertEqual([ext1 compareByFieldNumber:ext1], NSOrderedSame); 418} 419 420@end 421