diff options
Diffstat (limited to 'objectivec/Tests/GPBArrayTests.m')
-rw-r--r-- | objectivec/Tests/GPBArrayTests.m | 331 |
1 files changed, 304 insertions, 27 deletions
diff --git a/objectivec/Tests/GPBArrayTests.m b/objectivec/Tests/GPBArrayTests.m index 0fb15e40..e414d90a 100644 --- a/objectivec/Tests/GPBArrayTests.m +++ b/objectivec/Tests/GPBArrayTests.m @@ -32,12 +32,14 @@ #import <XCTest/XCTest.h> #import "GPBArray.h" +#import "GPBArray_PackagePrivate.h" #import "GPBTestUtilities.h" // To let the testing macros work, add some extra methods to simplify things. @interface GPBEnumArray (TestingTweak) + (instancetype)arrayWithValue:(int32_t)value; ++ (instancetype)arrayWithCapacity:(NSUInteger)count; - (instancetype)initWithValues:(const int32_t [])values count:(NSUInteger)count; @end @@ -71,6 +73,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { rawValues:&value count:1] autorelease]; } ++ (instancetype)arrayWithCapacity:(NSUInteger)count { + return [[[self alloc] initWithValidationFunction:TestingEnum_IsValidValue + capacity:count] autorelease]; +} - (instancetype)initWithValues:(const int32_t [])values count:(NSUInteger)count { return [self initWithValidationFunction:TestingEnum_IsValidValue @@ -176,6 +182,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { //% XCTAssertNotEqual(idx, 0U); //% ++idx2; //% }]; +//% // Ensure description doesn't choke. +//% XCTAssertTrue(array.description.length > 10); //% [array release]; //%} //% @@ -200,6 +208,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { //% NAME$S count:GPBARRAYSIZE(kValues3)]; //% XCTAssertNotNil(array3); //% +//% // Identity +//% XCTAssertTrue([array1 isEqual:array1]); +//% // Wrong type doesn't blow up. +//% XCTAssertFalse([array1 isEqual:@"bogus"]); //% // 1/1Prime should be different objects, but equal. //% XCTAssertNotEqual(array1, array1prime); //% XCTAssertEqualObjects(array1, array1prime); @@ -270,6 +282,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { //% [array add##HELPER##ValuesFromArray:array2]; //% XCTAssertEqual(array.count, 5U); //% +//% // Zero/nil inputs do nothing. +//% [array addValues:kValues1 count:0]; +//% XCTAssertEqual(array.count, 5U); +//% [array addValues:NULL count:5]; +//% XCTAssertEqual(array.count, 5U); +//% //% XCTAssertEqual([array valueAtIndex:0], VAL1); //% XCTAssertEqual([array valueAtIndex:1], VAL2); //% XCTAssertEqual([array valueAtIndex:2], VAL3); @@ -390,9 +408,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { //%- (void)testInternalResizing { //% const TYPE kValues[] = { VAL1, VAL2, VAL3, VAL4 }; //% GPB##NAME##Array *array = -//% [[GPB##NAME##Array alloc] initWithValues:kValues -//% NAME$S count:GPBARRAYSIZE(kValues)]; +//% [GPB##NAME##Array arrayWithCapacity:GPBARRAYSIZE(kValues)]; //% XCTAssertNotNil(array); +//% [array addValues:kValues count:GPBARRAYSIZE(kValues)]; //% //% // Add/remove to trigger the intneral buffer to grow/shrink. //% for (int i = 0; i < 100; ++i) { @@ -409,7 +427,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { //% XCTAssertEqual(array.count, 404U); //% [array removeAll]; //% XCTAssertEqual(array.count, 0U); -//% [array release]; //%} //% //%@end @@ -509,6 +526,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -533,6 +552,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -603,6 +626,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 1); XCTAssertEqual([array valueAtIndex:1], 2); XCTAssertEqual([array valueAtIndex:2], 3); @@ -723,9 +752,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const int32_t kValues[] = { 1, 2, 3, 4 }; GPBInt32Array *array = - [[GPBInt32Array alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBInt32Array arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -742,7 +771,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -842,6 +870,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -866,6 +896,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -936,6 +970,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 11U); XCTAssertEqual([array valueAtIndex:1], 12U); XCTAssertEqual([array valueAtIndex:2], 13U); @@ -1056,9 +1096,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const uint32_t kValues[] = { 11U, 12U, 13U, 14U }; GPBUInt32Array *array = - [[GPBUInt32Array alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBUInt32Array arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -1075,7 +1115,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -1175,6 +1214,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -1199,6 +1240,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -1269,6 +1314,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 31LL); XCTAssertEqual([array valueAtIndex:1], 32LL); XCTAssertEqual([array valueAtIndex:2], 33LL); @@ -1389,9 +1440,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const int64_t kValues[] = { 31LL, 32LL, 33LL, 34LL }; GPBInt64Array *array = - [[GPBInt64Array alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBInt64Array arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -1408,7 +1459,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -1508,6 +1558,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -1532,6 +1584,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -1602,6 +1658,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 41ULL); XCTAssertEqual([array valueAtIndex:1], 42ULL); XCTAssertEqual([array valueAtIndex:2], 43ULL); @@ -1722,9 +1784,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const uint64_t kValues[] = { 41ULL, 42ULL, 43ULL, 44ULL }; GPBUInt64Array *array = - [[GPBUInt64Array alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBUInt64Array arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -1741,7 +1803,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -1841,6 +1902,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -1865,6 +1928,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -1935,6 +2002,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 51.f); XCTAssertEqual([array valueAtIndex:1], 52.f); XCTAssertEqual([array valueAtIndex:2], 53.f); @@ -2055,9 +2128,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const float kValues[] = { 51.f, 52.f, 53.f, 54.f }; GPBFloatArray *array = - [[GPBFloatArray alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBFloatArray arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -2074,7 +2147,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -2174,6 +2246,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -2198,6 +2272,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -2268,6 +2346,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 61.); XCTAssertEqual([array valueAtIndex:1], 62.); XCTAssertEqual([array valueAtIndex:2], 63.); @@ -2388,9 +2472,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const double kValues[] = { 61., 62., 63., 64. }; GPBDoubleArray *array = - [[GPBDoubleArray alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBDoubleArray arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -2407,7 +2491,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -2507,6 +2590,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -2531,6 +2616,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -2601,6 +2690,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], TRUE); XCTAssertEqual([array valueAtIndex:1], TRUE); XCTAssertEqual([array valueAtIndex:2], FALSE); @@ -2721,9 +2816,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const BOOL kValues[] = { TRUE, TRUE, FALSE, FALSE }; GPBBoolArray *array = - [[GPBBoolArray alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBBoolArray arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -2740,7 +2835,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -2840,6 +2934,8 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertNotEqual(idx, 0U); ++idx2; }]; + // Ensure description doesn't choke. + XCTAssertTrue(array.description.length > 10); [array release]; } @@ -2864,6 +2960,10 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { count:GPBARRAYSIZE(kValues3)]; XCTAssertNotNil(array3); + // Identity + XCTAssertTrue([array1 isEqual:array1]); + // Wrong type doesn't blow up. + XCTAssertFalse([array1 isEqual:@"bogus"]); // 1/1Prime should be different objects, but equal. XCTAssertNotEqual(array1, array1prime); XCTAssertEqualObjects(array1, array1prime); @@ -2934,6 +3034,12 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { [array addRawValuesFromArray:array2]; XCTAssertEqual(array.count, 5U); + // Zero/nil inputs do nothing. + [array addValues:kValues1 count:0]; + XCTAssertEqual(array.count, 5U); + [array addValues:NULL count:5]; + XCTAssertEqual(array.count, 5U); + XCTAssertEqual([array valueAtIndex:0], 71); XCTAssertEqual([array valueAtIndex:1], 72); XCTAssertEqual([array valueAtIndex:2], 73); @@ -3054,9 +3160,9 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { - (void)testInternalResizing { const int32_t kValues[] = { 71, 72, 73, 74 }; GPBEnumArray *array = - [[GPBEnumArray alloc] initWithValues:kValues - count:GPBARRAYSIZE(kValues)]; + [GPBEnumArray arrayWithCapacity:GPBARRAYSIZE(kValues)]; XCTAssertNotNil(array); + [array addValues:kValues count:GPBARRAYSIZE(kValues)]; // Add/remove to trigger the intneral buffer to grow/shrink. for (int i = 0; i < 100; ++i) { @@ -3073,7 +3179,6 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { XCTAssertEqual(array.count, 404U); [array removeAll]; XCTAssertEqual(array.count, 0U); - [array release]; } @end @@ -3436,3 +3541,175 @@ static BOOL TestingEnum_IsValidValue2(int32_t value) { } @end + +#pragma mark - GPBAutocreatedArray Tests + +// These are hand written tests to double check some behaviors of the +// GPBAutocreatedArray. + +// NOTE: GPBAutocreatedArray is private to the library, users of the library +// should never have to directly deal with this class. + +@interface GPBAutocreatedArrayTests : XCTestCase +@end + +@implementation GPBAutocreatedArrayTests + +- (void)testEquality { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + XCTAssertTrue([array isEqual:@[]]); + XCTAssertTrue([array isEqualToArray:@[]]); + + XCTAssertFalse([array isEqual:@[ @"foo" ]]); + XCTAssertFalse([array isEqualToArray:@[ @"foo" ]]); + + [array addObject:@"foo"]; + + XCTAssertFalse([array isEqual:@[]]); + XCTAssertFalse([array isEqualToArray:@[]]); + XCTAssertTrue([array isEqual:@[ @"foo" ]]); + XCTAssertTrue([array isEqualToArray:@[ @"foo" ]]); + XCTAssertFalse([array isEqual:@[ @"bar" ]]); + XCTAssertFalse([array isEqualToArray:@[ @"bar" ]]); + + GPBAutocreatedArray *array2 = [[GPBAutocreatedArray alloc] init]; + + XCTAssertFalse([array isEqual:array2]); + XCTAssertFalse([array isEqualToArray:array2]); + + [array2 addObject:@"bar"]; + XCTAssertFalse([array isEqual:array2]); + XCTAssertFalse([array isEqualToArray:array2]); + + [array2 replaceObjectAtIndex:0 withObject:@"foo"]; + XCTAssertTrue([array isEqual:array2]); + XCTAssertTrue([array isEqualToArray:array2]); + + [array2 release]; + [array release]; +} + +- (void)testCopy { + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + NSArray *cpy = [array copy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)0); + + NSArray *cpy2 = [array copy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + // Can't compare cpy and cpy2 because NSArray has a singleton empty + // array it uses, so the ptrs are the same. + XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)0); + + [cpy2 release]; + [cpy release]; + [array release]; + } + + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + NSMutableArray *cpy = [array mutableCopy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSMutableArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)0); + + NSMutableArray *cpy2 = [array mutableCopy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSMutableArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)0); + + [cpy2 release]; + [cpy release]; + [array release]; + } + + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + [array addObject:@"foo"]; + [array addObject:@"bar"]; + + NSArray *cpy = [array copy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy[0], @"foo"); + XCTAssertEqualObjects(cpy[1], @"bar"); + + NSArray *cpy2 = [array copy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy2[0], @"foo"); + XCTAssertEqualObjects(cpy2[1], @"bar"); + + [cpy2 release]; + [cpy release]; + [array release]; + } + + { + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + [array addObject:@"foo"]; + [array addObject:@"bar"]; + + NSMutableArray *cpy = [array mutableCopy]; + XCTAssertTrue(cpy != array); // Ptr compare + XCTAssertTrue([cpy isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy[0], @"foo"); + XCTAssertEqualObjects(cpy[1], @"bar"); + + NSMutableArray *cpy2 = [array mutableCopy]; + XCTAssertTrue(cpy2 != array); // Ptr compare + XCTAssertTrue(cpy2 != cpy); // Ptr compare + XCTAssertTrue([cpy2 isKindOfClass:[NSArray class]]); + XCTAssertFalse([cpy2 isKindOfClass:[GPBAutocreatedArray class]]); + XCTAssertEqual(cpy2.count, (NSUInteger)2); + XCTAssertEqualObjects(cpy2[0], @"foo"); + XCTAssertEqualObjects(cpy2[1], @"bar"); + + [cpy2 release]; + [cpy release]; + [array release]; + } +} + +- (void)testIndexedSubscriptSupport { + // The base NSArray/NSMutableArray behaviors for *IndexedSubscript methods + // should still work via the methods that one has to override to make an + // NSMutableArray subclass. i.e. - this should "just work" and if these + // crash/fail, then something is wrong in how NSMutableArray is subclassed. + + GPBAutocreatedArray *array = [[GPBAutocreatedArray alloc] init]; + + [array addObject:@"foo"]; + [array addObject:@"bar"]; + XCTAssertEqual(array.count, (NSUInteger)2); + XCTAssertEqualObjects(array[0], @"foo"); + XCTAssertEqualObjects(array[1], @"bar"); + array[0] = @"foo2"; + array[2] = @"baz"; + XCTAssertEqual(array.count, (NSUInteger)3); + XCTAssertEqualObjects(array[0], @"foo2"); + XCTAssertEqualObjects(array[1], @"bar"); + XCTAssertEqualObjects(array[2], @"baz"); + + [array release]; +} + +@end |