aboutsummaryrefslogtreecommitdiff
path: root/objectivec/Tests/GPBArrayTests.m
diff options
context:
space:
mode:
Diffstat (limited to 'objectivec/Tests/GPBArrayTests.m')
-rw-r--r--objectivec/Tests/GPBArrayTests.m331
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