aboutsummaryrefslogtreecommitdiff
path: root/objectivec/Tests/GPBMessageTests.m
diff options
context:
space:
mode:
authorThomas Van Lenten <thomasvl@google.com>2015-05-01 08:57:16 -0400
committerThomas Van Lenten <thomasvl@google.com>2015-05-06 13:19:14 -0400
commit30650d81d9baa446dbc8deb784ba53794cafda5b (patch)
tree993f42cbfc871dd25d9273606f48d7c3b520df27 /objectivec/Tests/GPBMessageTests.m
parentefa666cf0ad77827ac0b15a159e2c85e9991d77c (diff)
downloadprotobuf-30650d81d9baa446dbc8deb784ba53794cafda5b.tar.gz
protobuf-30650d81d9baa446dbc8deb784ba53794cafda5b.tar.bz2
protobuf-30650d81d9baa446dbc8deb784ba53794cafda5b.zip
Alpha 1 drop of Google's Objective C plugin and runtime support for protobufs.
Diffstat (limited to 'objectivec/Tests/GPBMessageTests.m')
-rw-r--r--objectivec/Tests/GPBMessageTests.m1728
1 files changed, 1728 insertions, 0 deletions
diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m
new file mode 100644
index 00000000..5ec67cd9
--- /dev/null
+++ b/objectivec/Tests/GPBMessageTests.m
@@ -0,0 +1,1728 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#import "GPBTestUtilities.h"
+
+#import <objc/runtime.h>
+
+#import "GPBArray_PackagePrivate.h"
+#import "GPBDescriptor.h"
+#import "GPBField_PackagePrivate.h"
+#import "GPBMessage_PackagePrivate.h"
+#import "GPBUnknownFieldSet_PackagePrivate.h"
+#import "google/protobuf/Unittest.pbobjc.h"
+#import "google/protobuf/UnittestObjc.pbobjc.h"
+#import "google/protobuf/UnittestNameMangling.pbobjc.h"
+
+@interface MessageTests : GPBTestCase
+@end
+
+@implementation MessageTests
+
+// TODO(thomasvl): this should get split into a few files of logic junks, it is
+// a jumble
+// of things at the moment (and the testutils have a bunch of the real
+// assertions).
+
+#ifdef DEBUG
+- (void)assertBlock:(void (^)())block
+ throwsWithMessageInUserInfo:(GPBMessage *)message {
+ @try {
+ block();
+ XCTAssertTrue(NO);
+ }
+ @catch (NSException *e) {
+ XCTAssertEqualObjects([e userInfo][GPBExceptionMessageKey], message);
+ }
+}
+#endif // DEBUG
+
+- (TestAllTypes *)mergeSource {
+ TestAllTypes *message = [TestAllTypes message];
+ [message setOptionalInt32:1];
+ [message setOptionalString:@"foo"];
+ [message setOptionalForeignMessage:[ForeignMessage message]];
+ message.repeatedStringArray = [NSMutableArray array];
+ [message.repeatedStringArray addObject:@"bar"];
+ return message;
+}
+
+- (TestAllTypes *)mergeDestination {
+ TestAllTypes *message = [TestAllTypes message];
+ [message setOptionalInt64:2];
+ [message setOptionalString:@"baz"];
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ [foreignMessage setC:3];
+ [message setOptionalForeignMessage:foreignMessage];
+ message.repeatedStringArray = [NSMutableArray array];
+ [message.repeatedStringArray addObject:@"qux"];
+ return message;
+}
+
+- (TestAllTypes *)mergeDestinationWithoutForeignMessageIvar {
+ TestAllTypes *message = [TestAllTypes message];
+ [message setOptionalInt64:2];
+ [message setOptionalString:@"baz"];
+ message.repeatedStringArray = [NSMutableArray array];
+ [message.repeatedStringArray addObject:@"qux"];
+ return message;
+}
+
+- (TestAllTypes *)mergeResult {
+ TestAllTypes *message = [TestAllTypes message];
+ [message setOptionalInt32:1];
+ [message setOptionalInt64:2];
+ [message setOptionalString:@"foo"];
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ [foreignMessage setC:3];
+ [message setOptionalForeignMessage:foreignMessage];
+ message.repeatedStringArray = [NSMutableArray array];
+ [message.repeatedStringArray addObject:@"qux"];
+ [message.repeatedStringArray addObject:@"bar"];
+ return message;
+}
+
+- (TestAllTypes *)mergeResultForDestinationWithoutForeignMessageIvar {
+ TestAllTypes *message = [TestAllTypes message];
+ [message setOptionalInt32:1];
+ [message setOptionalInt64:2];
+ [message setOptionalString:@"foo"];
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ [message setOptionalForeignMessage:foreignMessage];
+ message.repeatedStringArray = [NSMutableArray array];
+ [message.repeatedStringArray addObject:@"qux"];
+ [message.repeatedStringArray addObject:@"bar"];
+ return message;
+}
+
+- (TestAllExtensions *)mergeExtensionsDestination {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
+ [message setExtension:[UnittestRoot optionalStringExtension] value:@"foo"];
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ foreignMessage.c = 4;
+ [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+ value:foreignMessage];
+ TestAllTypes_NestedMessage *nestedMessage =
+ [TestAllTypes_NestedMessage message];
+ [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+ value:nestedMessage];
+ return message;
+}
+
+- (TestAllExtensions *)mergeExtensionsSource {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [message setExtension:[UnittestRoot optionalInt64Extension] value:@6];
+ [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"];
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+ value:foreignMessage];
+ TestAllTypes_NestedMessage *nestedMessage =
+ [TestAllTypes_NestedMessage message];
+ nestedMessage.bb = 7;
+ [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+ value:nestedMessage];
+ return message;
+}
+
+- (TestAllExtensions *)mergeExtensionsResult {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [message setExtension:[UnittestRoot optionalInt32Extension] value:@5];
+ [message setExtension:[UnittestRoot optionalInt64Extension] value:@6];
+ [message setExtension:[UnittestRoot optionalStringExtension] value:@"bar"];
+ ForeignMessage *foreignMessage = [ForeignMessage message];
+ foreignMessage.c = 4;
+ [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+ value:foreignMessage];
+ TestAllTypes_NestedMessage *nestedMessage =
+ [TestAllTypes_NestedMessage message];
+ nestedMessage.bb = 7;
+ [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+ value:nestedMessage];
+ return message;
+}
+
+- (void)testMergeFrom {
+ TestAllTypes *result = [[self.mergeDestination copy] autorelease];
+ [result mergeFrom:self.mergeSource];
+ NSData *resultData = [result data];
+ NSData *mergeResultData = [self.mergeResult data];
+ XCTAssertEqualObjects(resultData, mergeResultData);
+ XCTAssertEqualObjects(result, self.mergeResult);
+
+ // Test when destination does not have an Ivar (type is an object) but source
+ // has such Ivar.
+ // The result must has the Ivar which is same as the one in source.
+ result = [[self.mergeDestinationWithoutForeignMessageIvar copy] autorelease];
+ [result mergeFrom:self.mergeSource];
+ resultData = [result data];
+ mergeResultData =
+ [self.mergeResultForDestinationWithoutForeignMessageIvar data];
+ XCTAssertEqualObjects(resultData, mergeResultData);
+ XCTAssertEqualObjects(
+ result, self.mergeResultForDestinationWithoutForeignMessageIvar);
+
+ // Test when destination is empty.
+ // The result must is same as the source.
+ result = [TestAllTypes message];
+ [result mergeFrom:self.mergeSource];
+ resultData = [result data];
+ mergeResultData = [self.mergeSource data];
+ XCTAssertEqualObjects(resultData, mergeResultData);
+ XCTAssertEqualObjects(result, self.mergeSource);
+}
+
+- (void)testMergeFromWithExtensions {
+ TestAllExtensions *result = [self mergeExtensionsDestination];
+ [result mergeFrom:[self mergeExtensionsSource]];
+ NSData *resultData = [result data];
+ NSData *mergeResultData = [[self mergeExtensionsResult] data];
+ XCTAssertEqualObjects(resultData, mergeResultData);
+ XCTAssertEqualObjects(result, [self mergeExtensionsResult]);
+
+ // Test merging from data.
+ result = [self mergeExtensionsDestination];
+ [result mergeFromData:[[self mergeExtensionsSource] data]
+ extensionRegistry:[UnittestRoot extensionRegistry]];
+ resultData = [result data];
+ XCTAssertEqualObjects(resultData, mergeResultData);
+ XCTAssertEqualObjects(result, [self mergeExtensionsResult]);
+}
+
+- (void)testIsEquals {
+ TestAllTypes *result = [[self.mergeDestination copy] autorelease];
+ [result mergeFrom:self.mergeSource];
+ XCTAssertEqualObjects(result.data, self.mergeResult.data);
+ XCTAssertEqualObjects(result, self.mergeResult);
+ TestAllTypes *result2 = [[self.mergeDestination copy] autorelease];
+ XCTAssertNotEqualObjects(result2.data, self.mergeResult.data);
+ XCTAssertNotEqualObjects(result2, self.mergeResult);
+}
+
+// =================================================================
+// Required-field-related tests.
+
+- (TestRequired *)testRequiredInitialized {
+ TestRequired *message = [TestRequired message];
+ [message setA:1];
+ [message setB:2];
+ [message setC:3];
+ return message;
+}
+
+- (void)testRequired {
+ TestRequired *message = [TestRequired message];
+
+ XCTAssertFalse(message.initialized);
+ [message setA:1];
+ XCTAssertFalse(message.initialized);
+ [message setB:1];
+ XCTAssertFalse(message.initialized);
+ [message setC:1];
+ XCTAssertTrue(message.initialized);
+}
+
+- (void)testRequiredForeign {
+ TestRequiredForeign *message = [TestRequiredForeign message];
+
+ XCTAssertTrue(message.initialized);
+
+ [message setOptionalMessage:[TestRequired message]];
+ XCTAssertFalse(message.initialized);
+
+ [message setOptionalMessage:self.testRequiredInitialized];
+ XCTAssertTrue(message.initialized);
+
+ message.repeatedMessageArray = [NSMutableArray array];
+ [message.repeatedMessageArray addObject:[TestRequired message]];
+ XCTAssertFalse(message.initialized);
+
+ [message.repeatedMessageArray removeAllObjects];
+ [message.repeatedMessageArray addObject:self.testRequiredInitialized];
+ XCTAssertTrue(message.initialized);
+}
+
+- (void)testRequiredExtension {
+ TestAllExtensions *message = [TestAllExtensions message];
+
+ XCTAssertTrue(message.initialized);
+
+ [message setExtension:[TestRequired single] value:[TestRequired message]];
+ XCTAssertFalse(message.initialized);
+
+ [message setExtension:[TestRequired single]
+ value:self.testRequiredInitialized];
+ XCTAssertTrue(message.initialized);
+
+ [message addExtension:[TestRequired multi] value:[TestRequired message]];
+ XCTAssertFalse(message.initialized);
+
+ [message setExtension:[TestRequired multi]
+ index:0
+ value:self.testRequiredInitialized];
+ XCTAssertTrue(message.initialized);
+}
+
+#ifdef DEBUG
+- (void)testUninitializedException {
+ TestRequired *message = [TestRequired message];
+ [self assertBlock:^{
+ [message data];
+ } throwsWithMessageInUserInfo:message];
+}
+#endif // DEBUG
+
+- (void)testInitialized {
+ // We're mostly testing that no exception is thrown.
+ TestRequired *message = [TestRequired message];
+ XCTAssertFalse(message.initialized);
+}
+
+#ifdef DEBUG
+- (void)testNestedUninitializedException {
+ TestRequiredForeign *message = [TestRequiredForeign message];
+ [message setOptionalMessage:[TestRequired message]];
+ message.repeatedMessageArray = [NSMutableArray array];
+ [message.repeatedMessageArray addObject:[TestRequired message]];
+ [message.repeatedMessageArray addObject:[TestRequired message]];
+ [self assertBlock:^{
+ [message data];
+ } throwsWithMessageInUserInfo:message];
+}
+#endif // DEBUG
+
+- (void)testNestedInitialized {
+ // We're mostly testing that no exception is thrown.
+
+ TestRequiredForeign *message = [TestRequiredForeign message];
+ [message setOptionalMessage:[TestRequired message]];
+ message.repeatedMessageArray = [NSMutableArray array];
+ [message.repeatedMessageArray addObject:[TestRequired message]];
+ [message.repeatedMessageArray addObject:[TestRequired message]];
+
+ XCTAssertFalse(message.initialized);
+}
+
+#ifdef DEBUG
+- (void)testParseUninitialized {
+ [self assertBlock:^{
+ [TestRequired parseFromData:GPBEmptyNSData()];
+ } throwsWithMessageInUserInfo:[TestRequired message]];
+}
+#endif // DEBUG
+
+- (void)testCoding {
+ NSData *data =
+ [NSKeyedArchiver archivedDataWithRootObject:[self mergeResult]];
+ id unarchivedObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];
+
+ XCTAssertEqualObjects(unarchivedObject, [self mergeResult]);
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(unarchivedObject, [self mergeResult]);
+}
+
+- (void)testObjectReset {
+ // Tests a failure where clearing out defaults values caused an over release.
+ TestAllTypes *message = [TestAllTypes message];
+ message.hasOptionalNestedMessage = NO;
+ [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]];
+ message.hasOptionalNestedMessage = NO;
+ [message setOptionalNestedMessage:[TestAllTypes_NestedMessage message]];
+ [message setOptionalNestedMessage:nil];
+ message.hasOptionalNestedMessage = NO;
+}
+
+- (void)testSettingHasToYes {
+ TestAllTypes *message = [TestAllTypes message];
+ XCTAssertThrows([message setHasOptionalNestedMessage:YES]);
+}
+
+- (void)testRoot {
+ XCTAssertNotNil([UnittestRoot extensionRegistry]);
+}
+
+- (void)testGPBMessageSize {
+ // See the note in GPBMessage_PackagePrivate.h about why we want to keep the
+ // base instance size pointer size aligned.
+ size_t messageSize = class_getInstanceSize([GPBMessage class]);
+ XCTAssertEqual((messageSize % sizeof(void *)), (size_t)0,
+ @"Base size isn't pointer size aligned");
+
+ // Since we add storage ourselves (see +allocWithZone: in GPBMessage), confirm
+ // that the size of some generated classes is still the same as the base for
+ // that logic to work as desired.
+ size_t testMessageSize = class_getInstanceSize([TestAllTypes class]);
+ XCTAssertEqual(testMessageSize, messageSize);
+}
+
+- (void)testInit {
+ TestAllTypes *message = [TestAllTypes message];
+ [self assertClear:message];
+}
+
+- (void)testAccessors {
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+ [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testKVC_ValueForKey {
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+ [self assertAllFieldsKVCMatch:message];
+}
+
+- (void)testKVC_SetValue_ForKey {
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFieldsViaKVC:message repeatedCount:kGPBDefaultRepeatCount];
+ [self assertAllFieldsKVCMatch:message];
+ [self assertAllFieldsSet:message repeatedCount:kGPBDefaultRepeatCount];
+ [self assertAllFieldsKVCMatch:message];
+}
+
+- (void)testDescription {
+ // No real test, just exercise code
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+
+ GPBUnknownFieldSet *unknownFields =
+ [[[GPBUnknownFieldSet alloc] init] autorelease];
+ GPBField *field = [[[GPBField alloc] initWithNumber:2] autorelease];
+ [field addVarint:2];
+ [unknownFields addField:field];
+ field = [[[GPBField alloc] initWithNumber:3] autorelease];
+ [field addVarint:4];
+ [unknownFields addField:field];
+
+ [message setUnknownFields:unknownFields];
+
+ NSString *description = [message description];
+ XCTAssertGreaterThan([description length], 0U);
+
+ GPBMessage *message2 = [TestAllExtensions message];
+ [message2 setExtension:[UnittestRoot optionalInt32Extension] value:@1];
+
+ [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@2];
+
+ description = [message2 description];
+ XCTAssertGreaterThan([description length], 0U);
+}
+
+- (void)testSetter {
+ // Test to make sure that if we set a value that has a default value
+ // with the default, that the has is set, and the value gets put into the
+ // message correctly.
+ TestAllTypes *message = [TestAllTypes message];
+ GPBDescriptor *descriptor = [[message class] descriptor];
+ XCTAssertNotNil(descriptor);
+ GPBFieldDescriptor *fieldDescriptor =
+ [descriptor fieldWithName:@"defaultInt32"];
+ XCTAssertNotNil(fieldDescriptor);
+ GPBValue defaultValue = [fieldDescriptor defaultValue];
+ [message setDefaultInt32:defaultValue.valueInt32];
+ XCTAssertTrue(message.hasDefaultInt32);
+ XCTAssertEqual(message.defaultInt32, defaultValue.valueInt32);
+
+ // Do the same thing with an object type.
+ message = [TestAllTypes message];
+ fieldDescriptor = [descriptor fieldWithName:@"defaultString"];
+ XCTAssertNotNil(fieldDescriptor);
+ defaultValue = [fieldDescriptor defaultValue];
+ [message setDefaultString:defaultValue.valueString];
+ XCTAssertTrue(message.hasDefaultString);
+ XCTAssertEqualObjects(message.defaultString, defaultValue.valueString);
+
+ // Test default string type.
+ message = [TestAllTypes message];
+ XCTAssertEqualObjects(message.defaultString, @"hello");
+ XCTAssertFalse(message.hasDefaultString);
+ fieldDescriptor = [descriptor fieldWithName:@"defaultString"];
+ XCTAssertNotNil(fieldDescriptor);
+ defaultValue = [fieldDescriptor defaultValue];
+ [message setDefaultString:defaultValue.valueString];
+ XCTAssertEqualObjects(message.defaultString, @"hello");
+ XCTAssertTrue(message.hasDefaultString);
+ [message setDefaultString:nil];
+ XCTAssertEqualObjects(message.defaultString, @"hello");
+ XCTAssertFalse(message.hasDefaultString);
+ message.hasDefaultString = NO;
+ XCTAssertFalse(message.hasDefaultString);
+ XCTAssertEqualObjects(message.defaultString, @"hello");
+
+ // Test default bytes type.
+ NSData *defaultBytes = [@"world" dataUsingEncoding:NSUTF8StringEncoding];
+ XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+ XCTAssertFalse(message.hasDefaultString);
+ fieldDescriptor = [descriptor fieldWithName:@"defaultBytes"];
+ XCTAssertNotNil(fieldDescriptor);
+ defaultValue = [fieldDescriptor defaultValue];
+ [message setDefaultBytes:defaultValue.valueData];
+ XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+ XCTAssertTrue(message.hasDefaultBytes);
+ [message setDefaultBytes:nil];
+ XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+ XCTAssertFalse(message.hasDefaultBytes);
+ message.hasDefaultBytes = NO;
+ XCTAssertFalse(message.hasDefaultBytes);
+ XCTAssertEqualObjects(message.defaultBytes, defaultBytes);
+
+ // Test optional string.
+ XCTAssertFalse(message.hasOptionalString);
+ XCTAssertEqualObjects(message.optionalString, @"");
+ XCTAssertFalse(message.hasOptionalString);
+ message.optionalString = nil;
+ XCTAssertFalse(message.hasOptionalString);
+ XCTAssertEqualObjects(message.optionalString, @"");
+ NSString *string = @"string";
+ message.optionalString = string;
+ XCTAssertEqualObjects(message.optionalString, string);
+ XCTAssertTrue(message.hasOptionalString);
+ message.optionalString = nil;
+ XCTAssertFalse(message.hasOptionalString);
+ XCTAssertEqualObjects(message.optionalString, @"");
+
+ // Test optional data.
+ XCTAssertFalse(message.hasOptionalBytes);
+ XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+ XCTAssertFalse(message.hasOptionalBytes);
+ message.optionalBytes = nil;
+ XCTAssertFalse(message.hasOptionalBytes);
+ XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+ NSData *data = [@"bytes" dataUsingEncoding:NSUTF8StringEncoding];
+ message.optionalBytes = data;
+ XCTAssertEqualObjects(message.optionalBytes, data);
+ XCTAssertTrue(message.hasOptionalBytes);
+ message.optionalBytes = nil;
+ XCTAssertFalse(message.hasOptionalBytes);
+ XCTAssertEqualObjects(message.optionalBytes, GPBEmptyNSData());
+
+ // Test lazy message setting
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ XCTAssertNotNil(message.optionalLazyMessage);
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ message.hasOptionalLazyMessage = NO;
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ XCTAssertNotNil(message.optionalLazyMessage);
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ message.optionalLazyMessage = nil;
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+
+ // Test nested messages
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ message.optionalLazyMessage.bb = 1;
+ XCTAssertTrue(message.hasOptionalLazyMessage);
+ XCTAssertEqual(message.optionalLazyMessage.bb, 1);
+ XCTAssertNotNil(message.optionalLazyMessage);
+ message.optionalLazyMessage = nil;
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ XCTAssertEqual(message.optionalLazyMessage.bb, 0);
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+ XCTAssertNotNil(message.optionalLazyMessage);
+
+ // -testDefaultSubMessages tests the "defaulting" handling of fields
+ // containing messages.
+}
+
+- (void)testRepeatedSetters {
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+ [self modifyRepeatedFields:message];
+ [self assertRepeatedFieldsModified:message
+ repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testClear {
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+ [self clearAllFields:message];
+ [self assertClear:message];
+ TestAllTypes *message2 = [TestAllTypes message];
+ XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testClearKVC {
+ TestAllTypes *message = [TestAllTypes message];
+ [self setAllFields:message repeatedCount:kGPBDefaultRepeatCount];
+ [self clearAllFields:message];
+ [self assertClear:message];
+ [self assertClearKVC:message];
+}
+
+- (void)testClearExtension {
+ // clearExtension() is not actually used in TestUtil, so try it manually.
+ GPBMessage *message1 = [TestAllExtensions message];
+ [message1 setExtension:[UnittestRoot optionalInt32Extension] value:@1];
+
+ XCTAssertTrue([message1 hasExtension:[UnittestRoot optionalInt32Extension]]);
+ [message1 clearExtension:[UnittestRoot optionalInt32Extension]];
+ XCTAssertFalse([message1 hasExtension:[UnittestRoot optionalInt32Extension]]);
+
+ GPBMessage *message2 = [TestAllExtensions message];
+ [message2 addExtension:[UnittestRoot repeatedInt32Extension] value:@1];
+
+ XCTAssertEqual(
+ [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count],
+ (NSUInteger)1);
+ [message2 clearExtension:[UnittestRoot repeatedInt32Extension]];
+ XCTAssertEqual(
+ [[message2 getExtension:[UnittestRoot repeatedInt32Extension]] count],
+ (NSUInteger)0);
+
+ // Clearing an unset extension field shouldn't make the target message
+ // visible.
+ GPBMessage *message3 = [TestAllExtensions message];
+ GPBMessage *extension_msg =
+ [message3 getExtension:[UnittestObjcRoot recursiveExtension]];
+ XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]);
+ [extension_msg clearExtension:[UnittestRoot optionalInt32Extension]];
+ XCTAssertFalse([message3 hasExtension:[UnittestObjcRoot recursiveExtension]]);
+}
+
+- (void)testDefaultingSubMessages {
+ TestAllTypes *message = [TestAllTypes message];
+
+ // Initially they should all not have values.
+
+ XCTAssertFalse(message.hasOptionalGroup);
+ XCTAssertFalse(message.hasOptionalNestedMessage);
+ XCTAssertFalse(message.hasOptionalForeignMessage);
+ XCTAssertFalse(message.hasOptionalImportMessage);
+ XCTAssertFalse(message.hasOptionalPublicImportMessage);
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+
+ // They should auto create something when fetched.
+
+ TestAllTypes_OptionalGroup *optionalGroup = [message.optionalGroup retain];
+ TestAllTypes_NestedMessage *optionalNestedMessage =
+ [message.optionalNestedMessage retain];
+ ForeignMessage *optionalForeignMessage =
+ [message.optionalForeignMessage retain];
+ ImportMessage *optionalImportMessage = [message.optionalImportMessage retain];
+ PublicImportMessage *optionalPublicImportMessage =
+ [message.optionalPublicImportMessage retain];
+ TestAllTypes_NestedMessage *optionalLazyMessage =
+ [message.optionalLazyMessage retain];
+
+ XCTAssertNotNil(optionalGroup);
+ XCTAssertNotNil(optionalNestedMessage);
+ XCTAssertNotNil(optionalForeignMessage);
+ XCTAssertNotNil(optionalImportMessage);
+ XCTAssertNotNil(optionalPublicImportMessage);
+ XCTAssertNotNil(optionalLazyMessage);
+
+ // Although they were created, they should not respond to hasValue until that
+ // submessage is mutated.
+
+ XCTAssertFalse(message.hasOptionalGroup);
+ XCTAssertFalse(message.hasOptionalNestedMessage);
+ XCTAssertFalse(message.hasOptionalForeignMessage);
+ XCTAssertFalse(message.hasOptionalImportMessage);
+ XCTAssertFalse(message.hasOptionalPublicImportMessage);
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+
+ // And they set that value back in to the message since the value created was
+ // mutable (so a second fetch should give the same object).
+
+ XCTAssertEqual(message.optionalGroup, optionalGroup);
+ XCTAssertEqual(message.optionalNestedMessage, optionalNestedMessage);
+ XCTAssertEqual(message.optionalForeignMessage, optionalForeignMessage);
+ XCTAssertEqual(message.optionalImportMessage, optionalImportMessage);
+ XCTAssertEqual(message.optionalPublicImportMessage,
+ optionalPublicImportMessage);
+ XCTAssertEqual(message.optionalLazyMessage, optionalLazyMessage);
+
+ // And the default objects for a second message should be distinct (again,
+ // since they are mutable, each needs their own copy).
+
+ TestAllTypes *message2 = [TestAllTypes message];
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(message2.optionalGroup, optionalGroup);
+ XCTAssertNotEqual(message2.optionalNestedMessage, optionalNestedMessage);
+ XCTAssertNotEqual(message2.optionalForeignMessage, optionalForeignMessage);
+ XCTAssertNotEqual(message2.optionalImportMessage, optionalImportMessage);
+ XCTAssertNotEqual(message2.optionalPublicImportMessage,
+ optionalPublicImportMessage);
+ XCTAssertNotEqual(message2.optionalLazyMessage, optionalLazyMessage);
+
+ // Setting the values to nil will clear the has flag, and on next access you
+ // get back new submessages.
+
+ message.optionalGroup = nil;
+ message.optionalNestedMessage = nil;
+ message.optionalForeignMessage = nil;
+ message.optionalImportMessage = nil;
+ message.optionalPublicImportMessage = nil;
+ message.optionalLazyMessage = nil;
+
+ XCTAssertFalse(message.hasOptionalGroup);
+ XCTAssertFalse(message.hasOptionalNestedMessage);
+ XCTAssertFalse(message.hasOptionalForeignMessage);
+ XCTAssertFalse(message.hasOptionalImportMessage);
+ XCTAssertFalse(message.hasOptionalPublicImportMessage);
+ XCTAssertFalse(message.hasOptionalLazyMessage);
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(message.optionalGroup, optionalGroup);
+ XCTAssertNotEqual(message.optionalNestedMessage, optionalNestedMessage);
+ XCTAssertNotEqual(message.optionalForeignMessage, optionalForeignMessage);
+ XCTAssertNotEqual(message.optionalImportMessage, optionalImportMessage);
+ XCTAssertNotEqual(message.optionalPublicImportMessage,
+ optionalPublicImportMessage);
+ XCTAssertNotEqual(message.optionalLazyMessage, optionalLazyMessage);
+
+ [optionalGroup release];
+ [optionalNestedMessage release];
+ [optionalForeignMessage release];
+ [optionalImportMessage release];
+ [optionalPublicImportMessage release];
+ [optionalLazyMessage release];
+}
+
+- (void)testMultiplePointersToAutocreatedMessage {
+ // Multiple objects pointing to the same autocreated message.
+ TestAllTypes *message = [TestAllTypes message];
+ TestAllTypes *message2 = [TestAllTypes message];
+ message2.optionalGroup = message.optionalGroup;
+ XCTAssertTrue([message2 hasOptionalGroup]);
+ XCTAssertFalse([message hasOptionalGroup]);
+ message2.optionalGroup.a = 42;
+ XCTAssertTrue([message hasOptionalGroup]);
+ XCTAssertTrue([message2 hasOptionalGroup]);
+}
+
+- (void)testCopyWithAutocreatedMessage {
+ // Mutable copy should not copy autocreated messages.
+ TestAllTypes *message = [TestAllTypes message];
+ message.optionalGroup.a = 42;
+ XCTAssertNotNil(message.optionalNestedMessage);
+ TestAllTypes *message2 = [[message copy] autorelease];
+ XCTAssertTrue([message2 hasOptionalGroup]);
+ XCTAssertFalse([message2 hasOptionalNestedMessage]);
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(message.optionalNestedMessage,
+ message2.optionalNestedMessage);
+}
+
+- (void)testClearAutocreatedSubmessage {
+ // Call clear on an intermediate submessage should cause it to get recreated
+ // on the next call.
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ TestRecursiveMessage *message_inner = [message.a.a.a retain];
+ XCTAssertNotNil(message_inner);
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(message_inner, message.a.a));
+ [message.a.a clear];
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a.a));
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(message.a.a.a, message_inner);
+ [message_inner release];
+}
+
+- (void)testRetainAutocreatedSubmessage {
+ // Should be able to retain autocreated submessage while the creator is
+ // dealloced.
+ TestAllTypes *message = [TestAllTypes message];
+
+ ForeignMessage *subMessage;
+ @autoreleasepool {
+ TestAllTypes *message2 = [TestAllTypes message];
+ subMessage = message2.optionalForeignMessage; // Autocreated
+ message.optionalForeignMessage = subMessage;
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(message.optionalForeignMessage,
+ message2));
+ }
+
+ // Should be the same object, and should still be live.
+ XCTAssertEqual(message.optionalForeignMessage, subMessage);
+ XCTAssertNotNil([subMessage description]);
+}
+
+- (void)testSetNilAutocreatedSubmessage {
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ TestRecursiveMessage *message_inner = [message.a.a retain];
+ XCTAssertFalse([message hasA]);
+ XCTAssertFalse([message.a hasA]);
+ message.a.a = nil;
+
+ // |message.a| has to be made visible, but |message.a.a| was set to nil so
+ // shouldn't be.
+ XCTAssertTrue([message hasA]);
+ XCTAssertFalse([message.a hasA]);
+
+ // Setting submessage to nil should cause it to lose its creator.
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(message_inner, message.a));
+
+ // After setting to nil, getting it again should create a new autocreated
+ // message.
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(message.a.a, message_inner);
+
+ [message_inner release];
+}
+
+- (void)testSetDoesntHaveAutocreatedSubmessage {
+ // Clearing submessage (set has == NO) should NOT cause it to lose its
+ // creator.
+ TestAllTypes *message = [TestAllTypes message];
+ TestAllTypes_NestedMessage *nestedMessage = message.optionalNestedMessage;
+ XCTAssertFalse([message hasOptionalNestedMessage]);
+ [message setHasOptionalNestedMessage:NO];
+ XCTAssertFalse([message hasOptionalNestedMessage]);
+ XCTAssertEqual(message.optionalNestedMessage, nestedMessage);
+}
+
+- (void)testSetAutocreatedMessageBecomesVisible {
+ // Setting a value should cause the submessage to appear to its creator.
+ // Test this several levels deep.
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ message.a.a.a.a.i = 42;
+ XCTAssertTrue([message hasA]);
+ XCTAssertTrue([message.a hasA]);
+ XCTAssertTrue([message.a.a hasA]);
+ XCTAssertTrue([message.a.a.a hasA]);
+ XCTAssertFalse([message.a.a.a.a hasA]);
+ XCTAssertEqual(message.a.a.a.a.i, 42);
+}
+
+- (void)testClearUnsetFieldOfAutocreatedMessage {
+ // Clearing an unset field should not cause the submessage to appear to its
+ // creator.
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ message.a.a.a.a.hasI = NO;
+ XCTAssertFalse([message hasA]);
+ XCTAssertFalse([message.a hasA]);
+ XCTAssertFalse([message.a.a hasA]);
+ XCTAssertFalse([message.a.a.a hasA]);
+}
+
+- (void)testAutocreatedSubmessageAssignSkip {
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ TestRecursiveMessage *messageLevel1 = [message.a retain];
+ TestRecursiveMessage *messageLevel2 = [message.a.a retain];
+ TestRecursiveMessage *messageLevel3 = [message.a.a.a retain];
+ TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain];
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3));
+
+ // Test skipping over an autocreated submessage and ensure it gets unset.
+ message.a = message.a.a;
+ XCTAssertEqual(message.a, messageLevel2);
+ XCTAssertTrue([message hasA]);
+ XCTAssertEqual(message.a.a, messageLevel3);
+ XCTAssertFalse([message.a hasA]);
+ XCTAssertEqual(message.a.a.a, messageLevel4);
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1,
+ message)); // Because it was orphaned.
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2));
+
+ [messageLevel1 release];
+ [messageLevel2 release];
+ [messageLevel3 release];
+ [messageLevel4 release];
+}
+
+- (void)testAutocreatedSubmessageAssignLoop {
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ TestRecursiveMessage *messageLevel1 = [message.a retain];
+ TestRecursiveMessage *messageLevel2 = [message.a.a retain];
+ TestRecursiveMessage *messageLevel3 = [message.a.a.a retain];
+ TestRecursiveMessage *messageLevel4 = [message.a.a.a.a retain];
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel1, message));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel2, messageLevel1));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel3, messageLevel2));
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(messageLevel4, messageLevel3));
+
+ // Test a property with a loop. You'd never do this but at least ensure the
+ // autocreated submessages behave sanely.
+ message.a.a = message.a;
+ XCTAssertTrue([message hasA]);
+ XCTAssertEqual(message.a, messageLevel1);
+ XCTAssertTrue([message.a hasA]);
+ XCTAssertEqual(message.a.a, messageLevel1);
+ XCTAssertTrue([message.a.a hasA]);
+ XCTAssertEqual(message.a.a.a, messageLevel1);
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel1,
+ message)); // Because it was assigned.
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(messageLevel2,
+ messageLevel1)); // Because it was orphaned.
+ XCTAssertFalse([messageLevel2 hasA]);
+
+ // Break the retain loop.
+ message.a.a = nil;
+ XCTAssertTrue([message hasA]);
+ XCTAssertFalse([message.a hasA]);
+
+ [messageLevel1 release];
+ [messageLevel2 release];
+ [messageLevel3 release];
+ [messageLevel4 release];
+}
+
+- (void)testSetAutocreatedSubmessage {
+ // Setting autocreated submessage to another value should cause the old one to
+ // lose its creator.
+ TestAllTypes *message = [TestAllTypes message];
+ TestAllTypes_NestedMessage *nestedMessage =
+ [message.optionalNestedMessage retain];
+
+ message.optionalNestedMessage = [TestAllTypes_NestedMessage message];
+ XCTAssertTrue([message hasOptionalNestedMessage]);
+ XCTAssertTrue(message.optionalNestedMessage != nestedMessage);
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(nestedMessage, message));
+
+ [nestedMessage release];
+}
+
+- (void)testAutocreatedUnknownFields {
+ // Doing anything with (except reading) unknown fields should cause the
+ // submessage to become visible.
+ TestAllTypes *message = [TestAllTypes message];
+ XCTAssertNotNil(message.optionalNestedMessage);
+ XCTAssertFalse([message hasOptionalNestedMessage]);
+ XCTAssertNil(message.optionalNestedMessage.unknownFields);
+ XCTAssertFalse([message hasOptionalNestedMessage]);
+
+ GPBUnknownFieldSet *unknownFields =
+ [[[GPBUnknownFieldSet alloc] init] autorelease];
+ message.optionalNestedMessage.unknownFields = unknownFields;
+ XCTAssertTrue([message hasOptionalNestedMessage]);
+
+ message.optionalNestedMessage = nil;
+ XCTAssertFalse([message hasOptionalNestedMessage]);
+ [message.optionalNestedMessage setUnknownFields:unknownFields];
+ XCTAssertTrue([message hasOptionalNestedMessage]);
+}
+
+- (void)testSetAutocreatedSubmessageToSelf {
+ // Setting submessage to itself should cause it to become visible.
+ TestAllTypes *message = [TestAllTypes message];
+ XCTAssertNotNil(message.optionalNestedMessage);
+ XCTAssertFalse([message hasOptionalNestedMessage]);
+ message.optionalNestedMessage = message.optionalNestedMessage;
+ XCTAssertTrue([message hasOptionalNestedMessage]);
+}
+
+- (void)testAutocreatedSubmessageMemoryLeaks {
+ // Test for memory leaks with autocreated submessages.
+ TestRecursiveMessage *message;
+ TestRecursiveMessage *messageLevel1;
+ TestRecursiveMessage *messageLevel2;
+ TestRecursiveMessage *messageLevel3;
+ TestRecursiveMessage *messageLevel4;
+ @autoreleasepool {
+ message = [[TestRecursiveMessage alloc] init];
+ messageLevel1 = [message.a retain];
+ messageLevel2 = [message.a.a retain];
+ messageLevel3 = [message.a.a.a retain];
+ messageLevel4 = [message.a.a.a.a retain];
+ message.a.i = 1;
+ }
+
+ XCTAssertEqual(message.retainCount, (NSUInteger)1);
+ [message release];
+ XCTAssertEqual(messageLevel1.retainCount, (NSUInteger)1);
+ [messageLevel1 release];
+ XCTAssertEqual(messageLevel2.retainCount, (NSUInteger)1);
+ [messageLevel2 release];
+ XCTAssertEqual(messageLevel3.retainCount, (NSUInteger)1);
+ [messageLevel3 release];
+ XCTAssertEqual(messageLevel4.retainCount, (NSUInteger)1);
+ [messageLevel4 release];
+}
+
+- (void)testDefaultingArrays {
+ // Basic tests for default creation of arrays in a message.
+ TestRecursiveMessageWithRepeatedField *message =
+ [TestRecursiveMessageWithRepeatedField message];
+ TestRecursiveMessageWithRepeatedField *message2 =
+ [TestRecursiveMessageWithRepeatedField message];
+
+ // Simply accessing the array should not make any fields visible.
+ XCTAssertNotNil(message.a.a.iArray);
+ XCTAssertFalse([message hasA]);
+ XCTAssertFalse([message.a hasA]);
+ XCTAssertNotNil(message2.a.a.strArray);
+ XCTAssertFalse([message2 hasA]);
+ XCTAssertFalse([message2.a hasA]);
+
+ // But adding an element to the array should.
+ [message.a.a.iArray addValue:42];
+ XCTAssertTrue([message hasA]);
+ XCTAssertTrue([message.a hasA]);
+ XCTAssertEqual([message.a.a.iArray count], (NSUInteger)1);
+ [message2.a.a.strArray addObject:@"foo"];
+ XCTAssertTrue([message2 hasA]);
+ XCTAssertTrue([message2.a hasA]);
+ XCTAssertEqual([message2.a.a.strArray count], (NSUInteger)1);
+}
+
+- (void)testAutocreatedArrayShared {
+ // Multiple objects pointing to the same array.
+ TestRecursiveMessageWithRepeatedField *message1a =
+ [TestRecursiveMessageWithRepeatedField message];
+ TestRecursiveMessageWithRepeatedField *message1b =
+ [TestRecursiveMessageWithRepeatedField message];
+ message1a.a.iArray = message1b.a.iArray;
+ XCTAssertTrue([message1a hasA]);
+ XCTAssertFalse([message1b hasA]);
+ [message1a.a.iArray addValue:1];
+ XCTAssertTrue([message1a hasA]);
+ XCTAssertTrue([message1b hasA]);
+ XCTAssertEqual(message1a.a.iArray, message1b.a.iArray);
+
+ TestRecursiveMessageWithRepeatedField *message2a =
+ [TestRecursiveMessageWithRepeatedField message];
+ TestRecursiveMessageWithRepeatedField *message2b =
+ [TestRecursiveMessageWithRepeatedField message];
+ message2a.a.strArray = message2b.a.strArray;
+ XCTAssertTrue([message2a hasA]);
+ XCTAssertFalse([message2b hasA]);
+ [message2a.a.strArray addObject:@"bar"];
+ XCTAssertTrue([message2a hasA]);
+ XCTAssertTrue([message2b hasA]);
+ XCTAssertEqual(message2a.a.strArray, message2b.a.strArray);
+}
+
+- (void)testAutocreatedArrayCopy {
+ // Copy should not copy autocreated arrays.
+ TestAllTypes *message = [TestAllTypes message];
+ XCTAssertNotNil(message.repeatedStringArray);
+ XCTAssertNotNil(message.repeatedInt32Array);
+ TestAllTypes *message2 = [[message copy] autorelease];
+ // Pointer conparisions.
+ XCTAssertNotEqual(message.repeatedStringArray, message2.repeatedStringArray);
+ XCTAssertNotEqual(message.repeatedInt32Array, message2.repeatedInt32Array);
+
+ // Mutable copy should copy empty arrays that were explicitly set (end up
+ // with different objects that are equal).
+ TestAllTypes *message3 = [TestAllTypes message];
+ message3.repeatedInt32Array = [GPBInt32Array arrayWithValue:42];
+ message3.repeatedStringArray = [NSMutableArray arrayWithObject:@"wee"];
+ XCTAssertNotNil(message.repeatedInt32Array);
+ XCTAssertNotNil(message.repeatedStringArray);
+ TestAllTypes *message4 = [message3 copy];
+ XCTAssertNotEqual(message3.repeatedInt32Array, message4.repeatedInt32Array);
+ XCTAssertEqualObjects(message3.repeatedInt32Array,
+ message4.repeatedInt32Array);
+ XCTAssertNotEqual(message3.repeatedStringArray, message4.repeatedStringArray);
+ XCTAssertEqualObjects(message3.repeatedStringArray,
+ message4.repeatedStringArray);
+}
+
+- (void)testAutocreatedArrayRetain {
+ // Should be able to retain autocreated array while the creator is dealloced.
+ TestAllTypes *message = [TestAllTypes message];
+
+ @autoreleasepool {
+ TestAllTypes *message2 = [TestAllTypes message];
+ message.repeatedInt32Array = message2.repeatedInt32Array;
+ message.repeatedStringArray = message2.repeatedStringArray;
+ // Pointer conparision
+ XCTAssertEqual(message.repeatedInt32Array->_autocreator, message2);
+ XCTAssertTrue([message.repeatedStringArray
+ isKindOfClass:[GPBAutocreatedArray class]]);
+ XCTAssertEqual(
+ ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator,
+ message2);
+ }
+
+ XCTAssertNil(message.repeatedInt32Array->_autocreator);
+ XCTAssertTrue(
+ [message.repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]);
+ XCTAssertNil(
+ ((GPBAutocreatedArray *)message.repeatedStringArray)->_autocreator);
+}
+
+- (void)testSetNilAutocreatedArray {
+ // Setting array to nil should cause it to lose its delegate.
+ TestAllTypes *message = [TestAllTypes message];
+ GPBInt32Array *repeatedInt32Array = [message.repeatedInt32Array retain];
+ GPBAutocreatedArray *repeatedStringArray =
+ (GPBAutocreatedArray *)[message.repeatedStringArray retain];
+ XCTAssertTrue([repeatedStringArray isKindOfClass:[GPBAutocreatedArray class]]);
+ XCTAssertEqual(repeatedInt32Array->_autocreator, message);
+ XCTAssertEqual(repeatedStringArray->_autocreator, message);
+ message.repeatedInt32Array = nil;
+ message.repeatedStringArray = nil;
+ XCTAssertNil(repeatedInt32Array->_autocreator);
+ XCTAssertNil(repeatedStringArray->_autocreator);
+ [repeatedInt32Array release];
+ [repeatedStringArray release];
+}
+
+- (void)testReplaceAutocreatedArray {
+ // Replacing array should orphan the old one and cause its creator to become
+ // visible.
+ {
+ TestRecursiveMessageWithRepeatedField *message =
+ [TestRecursiveMessageWithRepeatedField message];
+ XCTAssertNotNil(message.a);
+ XCTAssertNotNil(message.a.iArray);
+ XCTAssertFalse([message hasA]);
+ GPBInt32Array *iArray = [message.a.iArray retain];
+ XCTAssertEqual(iArray->_autocreator, message.a); // Pointer comparision
+ message.a.iArray = [GPBInt32Array arrayWithValue:1];
+ XCTAssertTrue([message hasA]);
+ XCTAssertNotEqual(message.a.iArray, iArray); // Pointer comparision
+ XCTAssertNil(iArray->_autocreator);
+ [iArray release];
+ }
+
+ {
+ TestRecursiveMessageWithRepeatedField *message =
+ [TestRecursiveMessageWithRepeatedField message];
+ XCTAssertNotNil(message.a);
+ XCTAssertNotNil(message.a.strArray);
+ XCTAssertFalse([message hasA]);
+ GPBAutocreatedArray *strArray =
+ (GPBAutocreatedArray *)[message.a.strArray retain];
+ XCTAssertTrue([strArray isKindOfClass:[GPBAutocreatedArray class]]);
+ XCTAssertEqual(strArray->_autocreator, message.a); // Pointer comparision
+ message.a.strArray = [NSMutableArray arrayWithObject:@"foo"];
+ XCTAssertTrue([message hasA]);
+ XCTAssertNotEqual(message.a.strArray, strArray); // Pointer comparision
+ XCTAssertNil(strArray->_autocreator);
+ [strArray release];
+ }
+}
+
+- (void)testSetAutocreatedArrayToSelf {
+ // Setting array to itself should cause it to become visible.
+ {
+ TestRecursiveMessageWithRepeatedField *message =
+ [TestRecursiveMessageWithRepeatedField message];
+ XCTAssertNotNil(message.a);
+ XCTAssertNotNil(message.a.iArray);
+ XCTAssertFalse([message hasA]);
+ message.a.iArray = message.a.iArray;
+ XCTAssertTrue([message hasA]);
+ XCTAssertNil(message.a.iArray->_autocreator);
+ }
+
+ {
+ TestRecursiveMessageWithRepeatedField *message =
+ [TestRecursiveMessageWithRepeatedField message];
+ XCTAssertNotNil(message.a);
+ XCTAssertNotNil(message.a.strArray);
+ XCTAssertFalse([message hasA]);
+ message.a.strArray = message.a.strArray;
+ XCTAssertTrue([message hasA]);
+ XCTAssertTrue([message.a.strArray isKindOfClass:[GPBAutocreatedArray class]]);
+ XCTAssertNil(((GPBAutocreatedArray *)message.a.strArray)->_autocreator);
+ }
+}
+
+- (void)testAutocreatedArrayRemoveAllValues {
+ // Calling removeAllValues on autocreated array should not cause it to be
+ // visible.
+ TestRecursiveMessageWithRepeatedField *message =
+ [TestRecursiveMessageWithRepeatedField message];
+ [message.a.iArray removeAll];
+ XCTAssertFalse([message hasA]);
+ [message.a.strArray removeAllObjects];
+ XCTAssertFalse([message hasA]);
+}
+
+- (void)testExtensionAccessors {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+ [self assertAllExtensionsSet:message repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testExtensionRepeatedSetters {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+ [self modifyRepeatedExtensions:message];
+ [self assertRepeatedExtensionsModified:message
+ repeatedCount:kGPBDefaultRepeatCount];
+}
+
+- (void)testExtensionDefaults {
+ [self assertExtensionsClear:[TestAllExtensions message]];
+}
+
+- (void)testExtensionIsEquals {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+ [self modifyRepeatedExtensions:message];
+ TestAllExtensions *message2 = [TestAllExtensions message];
+ [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount];
+ XCTAssertFalse([message isEqual:message2]);
+ message2 = [TestAllExtensions message];
+ [self setAllExtensions:message2 repeatedCount:kGPBDefaultRepeatCount];
+ [self modifyRepeatedExtensions:message2];
+ XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testExtensionsMergeFrom {
+ TestAllExtensions *message = [TestAllExtensions message];
+ [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+ [self modifyRepeatedExtensions:message];
+
+ message = [TestAllExtensions message];
+ [self setAllExtensions:message repeatedCount:kGPBDefaultRepeatCount];
+ TestAllExtensions *message2 = [TestAllExtensions message];
+ [self modifyRepeatedExtensions:message2];
+ [message2 mergeFrom:message];
+
+ XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testDefaultingExtensionMessages {
+ TestAllExtensions *message = [TestAllExtensions message];
+
+ // Initially they should all not have values.
+
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+ XCTAssertFalse([message
+ hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]);
+
+ // They should auto create something when fetched.
+
+ TestAllTypes_OptionalGroup *optionalGroup =
+ [message getExtension:[UnittestRoot optionalGroupExtension]];
+ TestAllTypes_NestedMessage *optionalNestedMessage =
+ [message getExtension:[UnittestRoot optionalNestedMessageExtension]];
+ ForeignMessage *optionalForeignMessage =
+ [message getExtension:[UnittestRoot optionalForeignMessageExtension]];
+ ImportMessage *optionalImportMessage =
+ [message getExtension:[UnittestRoot optionalImportMessageExtension]];
+ PublicImportMessage *optionalPublicImportMessage = [message
+ getExtension:[UnittestRoot optionalPublicImportMessageExtension]];
+ TestAllTypes_NestedMessage *optionalLazyMessage =
+ [message getExtension:[UnittestRoot optionalLazyMessageExtension]];
+
+ XCTAssertNotNil(optionalGroup);
+ XCTAssertNotNil(optionalNestedMessage);
+ XCTAssertNotNil(optionalForeignMessage);
+ XCTAssertNotNil(optionalImportMessage);
+ XCTAssertNotNil(optionalPublicImportMessage);
+ XCTAssertNotNil(optionalLazyMessage);
+
+ // Although it auto-created empty messages, it should not show that it has
+ // them.
+
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalLazyMessageExtension]]);
+
+ // And they set that value back in to the message since the value created was
+ // mutable (so a second fetch should give the same object).
+
+ XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]],
+ optionalGroup);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalNestedMessageExtension]],
+ optionalNestedMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalForeignMessageExtension]],
+ optionalForeignMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalImportMessageExtension]],
+ optionalImportMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalPublicImportMessageExtension]],
+ optionalPublicImportMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalLazyMessageExtension]],
+ optionalLazyMessage);
+
+ // And the default objects for a second message should be distinct (again,
+ // since they are mutable, each needs their own copy).
+
+ TestAllExtensions *message2 = [TestAllExtensions message];
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(
+ [message2 getExtension:[UnittestRoot optionalGroupExtension]],
+ optionalGroup);
+ XCTAssertNotEqual(
+ [message2 getExtension:[UnittestRoot optionalNestedMessageExtension]],
+ optionalNestedMessage);
+ XCTAssertNotEqual(
+ [message2 getExtension:[UnittestRoot optionalForeignMessageExtension]],
+ optionalForeignMessage);
+ XCTAssertNotEqual(
+ [message2 getExtension:[UnittestRoot optionalImportMessageExtension]],
+ optionalImportMessage);
+ XCTAssertNotEqual(
+ [message2 getExtension:[UnittestRoot optionalPublicImportMessageExtension]],
+ optionalPublicImportMessage);
+ XCTAssertNotEqual(
+ [message2 getExtension:[UnittestRoot optionalLazyMessageExtension]],
+ optionalLazyMessage);
+
+ // Clear values, and on next access you get back new submessages.
+
+ [message setExtension:[UnittestRoot optionalGroupExtension] value:nil];
+ [message setExtension:[UnittestRoot optionalGroupExtension] value:nil];
+ [message setExtension:[UnittestRoot optionalNestedMessageExtension]
+ value:nil];
+ [message setExtension:[UnittestRoot optionalForeignMessageExtension]
+ value:nil];
+ [message setExtension:[UnittestRoot optionalImportMessageExtension]
+ value:nil];
+ [message setExtension:[UnittestRoot optionalPublicImportMessageExtension]
+ value:nil];
+ [message setExtension:[UnittestRoot optionalLazyMessageExtension] value:nil];
+
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ XCTAssertFalse([message hasExtension:[UnittestRoot optionalGroupExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalNestedMessageExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalForeignMessageExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalImportMessageExtension]]);
+ XCTAssertFalse([message
+ hasExtension:[UnittestRoot optionalPublicImportMessageExtension]]);
+ XCTAssertFalse(
+ [message hasExtension:[UnittestRoot optionalLazyMessageExtension]]);
+
+ XCTAssertEqual([message getExtension:[UnittestRoot optionalGroupExtension]],
+ optionalGroup);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalNestedMessageExtension]],
+ optionalNestedMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalForeignMessageExtension]],
+ optionalForeignMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalImportMessageExtension]],
+ optionalImportMessage);
+ XCTAssertEqual(
+ [message
+ getExtension:[UnittestRoot optionalPublicImportMessageExtension]],
+ optionalPublicImportMessage);
+ XCTAssertEqual(
+ [message getExtension:[UnittestRoot optionalLazyMessageExtension]],
+ optionalLazyMessage);
+}
+
+- (void)testMultiplePointersToAutocreatedExtension {
+ // 2 objects point to the same auto-created extension. One should "has" it.
+ // The other should not.
+ TestAllExtensions *message = [TestAllExtensions message];
+ TestAllExtensions *message2 = [TestAllExtensions message];
+ GPBExtensionField *extension = [UnittestRoot optionalGroupExtension];
+ [message setExtension:extension value:[message2 getExtension:extension]];
+ XCTAssertEqual([message getExtension:extension],
+ [message2 getExtension:extension]);
+ XCTAssertFalse([message2 hasExtension:extension]);
+ XCTAssertTrue([message hasExtension:extension]);
+
+ TestAllTypes_OptionalGroup *extensionValue =
+ [message2 getExtension:extension];
+ extensionValue.a = 1;
+ XCTAssertTrue([message2 hasExtension:extension]);
+ XCTAssertTrue([message hasExtension:extension]);
+}
+
+- (void)testCopyWithAutocreatedExtension {
+ // Mutable copy shouldn't copy autocreated extensions.
+ TestAllExtensions *message = [TestAllExtensions message];
+ GPBExtensionField *optionalGroupExtension =
+ [UnittestRoot optionalGroupExtension];
+ GPBExtensionField *optionalNestedMessageExtesion =
+ [UnittestRoot optionalNestedMessageExtension];
+ TestAllTypes_OptionalGroup *optionalGroup =
+ [message getExtension:optionalGroupExtension];
+ optionalGroup.a = 42;
+ XCTAssertNotNil(optionalGroup);
+ XCTAssertNotNil([message getExtension:optionalNestedMessageExtesion]);
+ XCTAssertTrue([message hasExtension:optionalGroupExtension]);
+ XCTAssertFalse([message hasExtension:optionalNestedMessageExtesion]);
+
+ TestAllExtensions *message2 = [[message copy] autorelease];
+
+ // message2 should end up with its own copy of the optional group.
+ XCTAssertTrue([message2 hasExtension:optionalGroupExtension]);
+ XCTAssertEqualObjects([message getExtension:optionalGroupExtension],
+ [message2 getExtension:optionalGroupExtension]);
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual([message getExtension:optionalGroupExtension],
+ [message2 getExtension:optionalGroupExtension]);
+
+ XCTAssertFalse([message2 hasExtension:optionalNestedMessageExtesion]);
+ // Intentionally doing a pointer comparison (auto creation should be
+ // different)
+ XCTAssertNotEqual([message getExtension:optionalNestedMessageExtesion],
+ [message2 getExtension:optionalNestedMessageExtesion]);
+}
+
+- (void)testClearMessageAutocreatedExtension {
+ // Call clear should cause it to recreate its autocreated extensions.
+ TestAllExtensions *message = [TestAllExtensions message];
+ GPBExtensionField *optionalGroupExtension =
+ [UnittestRoot optionalGroupExtension];
+ TestAllTypes_OptionalGroup *optionalGroup =
+ [[message getExtension:optionalGroupExtension] retain];
+ [message clear];
+ TestAllTypes_OptionalGroup *optionalGroupNew =
+ [message getExtension:optionalGroupExtension];
+
+ // Intentionally doing a pointer comparison.
+ XCTAssertNotEqual(optionalGroup, optionalGroupNew);
+ [optionalGroup release];
+}
+
+- (void)testRetainAutocreatedExtension {
+ // Should be able to retain autocreated extension while the creator is
+ // dealloced.
+ TestAllExtensions *message = [TestAllExtensions message];
+ GPBExtensionField *optionalGroupExtension =
+ [UnittestRoot optionalGroupExtension];
+
+ @autoreleasepool {
+ TestAllExtensions *message2 = [TestAllExtensions message];
+ [message setExtension:optionalGroupExtension
+ value:[message2 getExtension:optionalGroupExtension]];
+ XCTAssertTrue(GPBWasMessageAutocreatedBy(
+ [message getExtension:optionalGroupExtension], message2));
+ }
+
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(
+ [message getExtension:optionalGroupExtension], message));
+}
+
+- (void)testClearAutocreatedExtension {
+ // Clearing autocreated extension should NOT cause it to lose its creator.
+ TestAllExtensions *message = [TestAllExtensions message];
+ GPBExtensionField *optionalGroupExtension =
+ [UnittestRoot optionalGroupExtension];
+ TestAllTypes_OptionalGroup *optionalGroup =
+ [[message getExtension:optionalGroupExtension] retain];
+ [message clearExtension:optionalGroupExtension];
+ TestAllTypes_OptionalGroup *optionalGroupNew =
+ [message getExtension:optionalGroupExtension];
+ XCTAssertEqual(optionalGroup, optionalGroupNew);
+ XCTAssertFalse([message hasExtension:optionalGroupExtension]);
+ [optionalGroup release];
+
+ // Clearing autocreated extension should not cause its creator to become
+ // visible
+ GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension];
+ TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension];
+ TestAllExtensions *message_lvl3 =
+ [message_lvl2 getExtension:recursiveExtension];
+ [message_lvl3 clearExtension:recursiveExtension];
+ XCTAssertFalse([message hasExtension:recursiveExtension]);
+}
+
+- (void)testSetAutocreatedExtensionBecomesVisible {
+ // Setting an extension should cause the extension to appear to its creator.
+ // Test this several levels deep.
+ TestAllExtensions *message = [TestAllExtensions message];
+ GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension];
+ TestAllExtensions *message_lvl2 = [message getExtension:recursiveExtension];
+ TestAllExtensions *message_lvl3 =
+ [message_lvl2 getExtension:recursiveExtension];
+ TestAllExtensions *message_lvl4 =
+ [message_lvl3 getExtension:recursiveExtension];
+ XCTAssertFalse([message hasExtension:recursiveExtension]);
+ XCTAssertFalse([message_lvl2 hasExtension:recursiveExtension]);
+ XCTAssertFalse([message_lvl3 hasExtension:recursiveExtension]);
+ XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]);
+ [message_lvl4 setExtension:[UnittestRoot optionalInt32Extension] value:@(1)];
+ XCTAssertTrue([message hasExtension:recursiveExtension]);
+ XCTAssertTrue([message_lvl2 hasExtension:recursiveExtension]);
+ XCTAssertTrue([message_lvl3 hasExtension:recursiveExtension]);
+ XCTAssertFalse([message_lvl4 hasExtension:recursiveExtension]);
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl4, message_lvl3));
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl3, message_lvl2));
+ XCTAssertFalse(GPBWasMessageAutocreatedBy(message_lvl2, message));
+}
+
+- (void)testSetAutocreatedExtensionToSelf {
+ // Setting extension to itself should cause it to become visible.
+ TestAllExtensions *message = [TestAllExtensions message];
+ GPBExtensionField *optionalGroupExtension =
+ [UnittestRoot optionalGroupExtension];
+ XCTAssertNotNil([message getExtension:optionalGroupExtension]);
+ XCTAssertFalse([message hasExtension:optionalGroupExtension]);
+ [message setExtension:optionalGroupExtension
+ value:[message getExtension:optionalGroupExtension]];
+ XCTAssertTrue([message hasExtension:optionalGroupExtension]);
+}
+
+- (void)testAutocreatedExtensionMemoryLeaks {
+ GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension];
+
+ // Test for memory leaks with autocreated extensions.
+ TestAllExtensions *message;
+ TestAllExtensions *message_lvl2;
+ TestAllExtensions *message_lvl3;
+ TestAllExtensions *message_lvl4;
+ @autoreleasepool {
+ message = [[TestAllExtensions alloc] init];
+ message_lvl2 = [[message getExtension:recursiveExtension] retain];
+ message_lvl3 = [[message_lvl2 getExtension:recursiveExtension] retain];
+ message_lvl4 = [[message_lvl3 getExtension:recursiveExtension] retain];
+ [message_lvl2 setExtension:[UnittestRoot optionalInt32Extension]
+ value:@(1)];
+ }
+
+ XCTAssertEqual(message.retainCount, (NSUInteger)1);
+ @autoreleasepool {
+ [message release];
+ }
+ XCTAssertEqual(message_lvl2.retainCount, (NSUInteger)1);
+ @autoreleasepool {
+ [message_lvl2 release];
+ }
+ XCTAssertEqual(message_lvl3.retainCount, (NSUInteger)1);
+ @autoreleasepool {
+ [message_lvl3 release];
+ }
+ XCTAssertEqual(message_lvl4.retainCount, (NSUInteger)1);
+ [message_lvl4 release];
+}
+
+- (void)testSetExtensionWithAutocreatedValue {
+ GPBExtensionField *recursiveExtension = [UnittestObjcRoot recursiveExtension];
+
+ TestAllExtensions *message;
+ @autoreleasepool {
+ message = [[TestAllExtensions alloc] init];
+ [message getExtension:recursiveExtension];
+ }
+
+ // This statements checks that the extension value isn't accidentally
+ // dealloced when removing it from the autocreated map.
+ [message setExtension:recursiveExtension
+ value:[message getExtension:recursiveExtension]];
+ XCTAssertTrue([message hasExtension:recursiveExtension]);
+ [message release];
+}
+
+- (void)testRecursion {
+ TestRecursiveMessage *message = [TestRecursiveMessage message];
+ XCTAssertNotNil(message.a);
+ XCTAssertNotNil(message.a.a);
+ XCTAssertEqual(message.a.a.i, 0);
+}
+
+- (void)testGenerateAndParseUnknownMessage {
+ GPBUnknownFieldSet *unknowns =
+ [[[GPBUnknownFieldSet alloc] init] autorelease];
+ [unknowns mergeVarintField:123 value:456];
+ GPBMessage *message = [GPBMessage message];
+ [message setUnknownFields:unknowns];
+ NSData *data = [message data];
+ GPBMessage *message2 = [GPBMessage parseFromData:data extensionRegistry:nil];
+ XCTAssertEqualObjects(message, message2);
+}
+
+- (void)testDelimitedWriteAndParseMultipleMessages {
+ GPBUnknownFieldSet *unknowns1 =
+ [[[GPBUnknownFieldSet alloc] init] autorelease];
+ [unknowns1 mergeVarintField:123 value:456];
+ GPBMessage *message1 = [GPBMessage message];
+ [message1 setUnknownFields:unknowns1];
+
+ GPBUnknownFieldSet *unknowns2 =
+ [[[GPBUnknownFieldSet alloc] init] autorelease];
+ [unknowns2 mergeVarintField:789 value:987];
+ [unknowns2 mergeVarintField:654 value:321];
+ GPBMessage *message2 = [GPBMessage message];
+ [message2 setUnknownFields:unknowns2];
+
+ NSMutableData *delimitedData = [NSMutableData data];
+ [delimitedData appendData:[message1 delimitedData]];
+ [delimitedData appendData:[message2 delimitedData]];
+ GPBCodedInputStream *input =
+ [GPBCodedInputStream streamWithData:delimitedData];
+ GPBMessage *message3 = [GPBMessage parseDelimitedFromCodedInputStream:input
+ extensionRegistry:nil];
+ GPBMessage *message4 = [GPBMessage parseDelimitedFromCodedInputStream:input
+ extensionRegistry:nil];
+ XCTAssertEqualObjects(message1, message3);
+ XCTAssertEqualObjects(message2, message4);
+}
+
+- (void)testDuplicateEnums {
+ XCTAssertEqual(TestEnumWithDupValue_Foo1, TestEnumWithDupValue_Foo2);
+}
+
+- (void)testWeirdDefaults {
+ ObjcWeirdDefaults *message = [ObjcWeirdDefaults message];
+ GPBDescriptor *descriptor = [[message class] descriptor];
+ GPBFieldDescriptor *fieldDesc = [descriptor fieldWithName:@"foo"];
+ XCTAssertNotNil(fieldDesc);
+ XCTAssertTrue(fieldDesc.hasDefaultValue);
+ XCTAssertFalse(message.hasFoo);
+ XCTAssertEqualObjects(message.foo, @"");
+
+ fieldDesc = [descriptor fieldWithName:@"bar"];
+ XCTAssertNotNil(fieldDesc);
+ XCTAssertTrue(fieldDesc.hasDefaultValue);
+ XCTAssertFalse(message.hasBar);
+ XCTAssertEqualObjects(message.bar, GPBEmptyNSData());
+}
+
+- (void)testEnumDescriptorFromExtensionDescriptor {
+ GPBExtensionField *extField = [UnittestRoot optionalForeignEnumExtension];
+ GPBExtensionDescriptor *extDescriptor = extField.descriptor;
+ XCTAssertEqual(extDescriptor.type, GPBTypeEnum);
+ GPBEnumDescriptor *enumDescriptor = extDescriptor.enumDescriptor;
+ GPBEnumDescriptor *expectedDescriptor = ForeignEnum_EnumDescriptor();
+ XCTAssertEqualObjects(enumDescriptor, expectedDescriptor);
+}
+
+- (void)testEnumNaming {
+ // objectivec_helpers.cc has some interesting cases to deal with in
+ // EnumValueName/EnumValueShortName. Confirm that things generated as
+ // expected.
+
+ // This block just has to compile to confirm we got the expected types/names.
+ // The *_IsValidValue() calls are just there to keep the projects warnings
+ // flags happy by providing use of the variables/values.
+
+ Foo aFoo = Foo_SerializedSize;
+ Foo_IsValidValue(aFoo);
+ aFoo = Foo_Size;
+ Foo_IsValidValue(aFoo);
+
+ Category_Enum aCat = Category_Enum_Red;
+ Category_Enum_IsValidValue(aCat);
+
+ Time aTime = Time_Base;
+ Time_IsValidValue(aTime);
+ aTime = Time_SomethingElse;
+ Time_IsValidValue(aTime);
+
+ // This block confirms the names in the decriptors is what we wanted.
+
+ GPBEnumDescriptor *descriptor;
+ NSString *valueName;
+
+ descriptor = Foo_EnumDescriptor();
+ XCTAssertNotNil(descriptor);
+ XCTAssertEqualObjects(@"Foo", descriptor.name);
+ valueName = [descriptor enumNameForValue:Foo_SerializedSize];
+ XCTAssertEqualObjects(@"Foo_SerializedSize", valueName);
+ valueName = [descriptor enumNameForValue:Foo_Size];
+ XCTAssertEqualObjects(@"Foo_Size", valueName);
+
+ descriptor = Category_Enum_EnumDescriptor();
+ XCTAssertNotNil(descriptor);
+ XCTAssertEqualObjects(@"Category_Enum", descriptor.name);
+ valueName = [descriptor enumNameForValue:Category_Enum_Red];
+ XCTAssertEqualObjects(@"Category_Enum_Red", valueName);
+
+ descriptor = Time_EnumDescriptor();
+ XCTAssertNotNil(descriptor);
+ XCTAssertEqualObjects(@"Time", descriptor.name);
+ valueName = [descriptor enumNameForValue:Time_Base];
+ XCTAssertEqualObjects(@"Time_Base", valueName);
+ valueName = [descriptor enumNameForValue:Time_SomethingElse];
+ XCTAssertEqualObjects(@"Time_SomethingElse", valueName);
+}
+
+- (void)testNegativeEnums {
+ EnumTestMsg *msg = [EnumTestMsg message];
+
+ // Defaults
+ XCTAssertEqual(msg.foo, EnumTestMsg_MyEnum_Zero);
+ XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_One);
+ XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegOne);
+ // Bounce to wire and back.
+ EnumTestMsg *msgPrime = [EnumTestMsg parseFromData:[msg data]];
+ XCTAssertEqualObjects(msgPrime, msg);
+ XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
+ XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_One);
+ XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegOne);
+
+ // Other values
+ msg.bar = EnumTestMsg_MyEnum_Two;
+ msg.baz = EnumTestMsg_MyEnum_NegTwo;
+ XCTAssertEqual(msg.bar, EnumTestMsg_MyEnum_Two);
+ XCTAssertEqual(msg.baz, EnumTestMsg_MyEnum_NegTwo);
+ // Bounce to wire and back.
+ msgPrime = [EnumTestMsg parseFromData:[msg data]];
+ XCTAssertEqualObjects(msgPrime, msg);
+ XCTAssertEqual(msgPrime.foo, EnumTestMsg_MyEnum_Zero);
+ XCTAssertEqual(msgPrime.bar, EnumTestMsg_MyEnum_Two);
+ XCTAssertEqual(msgPrime.baz, EnumTestMsg_MyEnum_NegTwo);
+
+ // Repeated field (shouldn't ever be an issue since developer has to use the
+ // right GPBArray methods themselves).
+ msg.mumbleArray = [GPBEnumArray
+ arrayWithValidationFunction:EnumTestMsg_MyEnum_IsValidValue];
+ [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Zero];
+ [msg.mumbleArray addValue:EnumTestMsg_MyEnum_One];
+ [msg.mumbleArray addValue:EnumTestMsg_MyEnum_Two];
+ [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegOne];
+ [msg.mumbleArray addValue:EnumTestMsg_MyEnum_NegTwo];
+ XCTAssertEqual([msg.mumbleArray valueAtIndex:0], EnumTestMsg_MyEnum_Zero);
+ XCTAssertEqual([msg.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One);
+ XCTAssertEqual([msg.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two);
+ XCTAssertEqual([msg.mumbleArray valueAtIndex:3], EnumTestMsg_MyEnum_NegOne);
+ XCTAssertEqual([msg.mumbleArray valueAtIndex:4], EnumTestMsg_MyEnum_NegTwo);
+ // Bounce to wire and back.
+ msgPrime = [EnumTestMsg parseFromData:[msg data]];
+ XCTAssertEqualObjects(msgPrime, msg);
+ XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:0],
+ EnumTestMsg_MyEnum_Zero);
+ XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:1], EnumTestMsg_MyEnum_One);
+ XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:2], EnumTestMsg_MyEnum_Two);
+ XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:3],
+ EnumTestMsg_MyEnum_NegOne);
+ XCTAssertEqual([msgPrime.mumbleArray valueAtIndex:4],
+ EnumTestMsg_MyEnum_NegTwo);
+}
+
+- (void)testMutableNameManagling {
+ // These basically confirm that all the expected name mangling happened by not
+ // having compile errors.
+
+ // TODO(thomasvl): Write these, see unittest_name_mangling.proto.
+}
+
+@end