[ObjC] Add tests for proto3 optional behaviors.
diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh index dc1d6d2..d04c5c5 100755 --- a/objectivec/DevTools/compile_testing_protos.sh +++ b/objectivec/DevTools/compile_testing_protos.sh
@@ -158,6 +158,7 @@ --objc_out="${OUTPUT_DIR}/google/protobuf" \ --proto_path=src/google/protobuf/ \ --proto_path=src \ + --experimental_allow_proto3_optional \ "$@" }
diff --git a/objectivec/Tests/GPBMessageTests+Runtime.m b/objectivec/Tests/GPBMessageTests+Runtime.m index aa5b0db..1dac797 100644 --- a/objectivec/Tests/GPBMessageTests+Runtime.m +++ b/objectivec/Tests/GPBMessageTests+Runtime.m
@@ -270,6 +270,23 @@ @"field: %@", name); } + // Single Optional fields + // - has*/setHas* thanks to the optional keyword in proto3, they exist + // for primitive types. + // - has*/setHas* valid for Message. + + for (NSString *name in names) { + // build the selector, i.e. - hasOptionalInt32/setHasOptionalInt32: + SEL hasSel = NSSelectorFromString( + [NSString stringWithFormat:@"hasOptional%@", name]); + SEL setHasSel = NSSelectorFromString( + [NSString stringWithFormat:@"setHasOptional%@:", name]); + XCTAssertTrue([Message3Optional instancesRespondToSelector:hasSel], @"field: %@", + name); + XCTAssertTrue([Message3Optional instancesRespondToSelector:setHasSel], + @"field: %@", name); + } + // map<> fields // - no has*/setHas* // - *Count @@ -1002,6 +1019,249 @@ //%PDDM-EXPAND-END PROTO3_TEST_HAS_FIELDS() } +- (void)testProto3SingleOptionalFieldHasBehavior { + // + // Setting to any value including the default (0) should result in true. + // + +//%PDDM-DEFINE PROTO3_TEST_OPTIONAL_HAS_FIELD(FIELD, NON_ZERO_VALUE, ZERO_VALUE) +//% { // optional##FIELD +//% Message3Optional *msg = [[Message3Optional alloc] init]; +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = NON_ZERO_VALUE; +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_Optional##FIELD)); +//% msg.hasOptional##FIELD = NO; +//% XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_Optional##FIELD)); +//% msg.optional##FIELD = ZERO_VALUE; +//% XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_Optional##FIELD)); +//% [msg release]; +//% } +//% +//%PDDM-DEFINE PROTO3_TEST_OPTIONAL_HAS_FIELDS() +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Int32, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Int64, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Uint32, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Uint64, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Sint32, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Sint64, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Fixed32, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Fixed64, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Sfixed32, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Sfixed64, 1, 0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Float, 1.0f, 0.0f) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Double, 1.0, 0.0) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Bool, YES, NO) +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(String, @"foo", @"") +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Bytes, [@"foo" dataUsingEncoding:NSUTF8StringEncoding], [NSData data]) +//% // +//% // Test doesn't apply to optionalMessage (no groups in proto3). +//% // +//% +//%PROTO3_TEST_OPTIONAL_HAS_FIELD(Enum, Message3Optional_Enum_Bar, Message3Optional_Enum_Foo) +//%PDDM-EXPAND PROTO3_TEST_OPTIONAL_HAS_FIELDS() +// This block of code is generated, do not edit it directly. +// clang-format off + + { // optionalInt32 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt32)); + msg.hasOptionalInt32 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt32)); + msg.optionalInt32 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt32)); + [msg release]; + } + + { // optionalInt64 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt64)); + msg.hasOptionalInt64 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt64)); + msg.optionalInt64 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalInt64)); + [msg release]; + } + + { // optionalUint32 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint32)); + msg.hasOptionalUint32 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint32)); + msg.optionalUint32 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint32)); + [msg release]; + } + + { // optionalUint64 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint64)); + msg.hasOptionalUint64 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint64)); + msg.optionalUint64 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalUint64)); + [msg release]; + } + + { // optionalSint32 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint32)); + msg.hasOptionalSint32 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint32)); + msg.optionalSint32 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint32)); + [msg release]; + } + + { // optionalSint64 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint64)); + msg.hasOptionalSint64 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint64)); + msg.optionalSint64 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSint64)); + [msg release]; + } + + { // optionalFixed32 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed32)); + msg.hasOptionalFixed32 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed32)); + msg.optionalFixed32 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed32)); + [msg release]; + } + + { // optionalFixed64 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed64)); + msg.hasOptionalFixed64 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed64)); + msg.optionalFixed64 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFixed64)); + [msg release]; + } + + { // optionalSfixed32 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed32)); + msg.hasOptionalSfixed32 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed32)); + msg.optionalSfixed32 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed32)); + [msg release]; + } + + { // optionalSfixed64 + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 1; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed64)); + msg.hasOptionalSfixed64 = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed64)); + msg.optionalSfixed64 = 0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalSfixed64)); + [msg release]; + } + + { // optionalFloat + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFloat)); + msg.optionalFloat = 1.0f; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFloat)); + msg.hasOptionalFloat = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFloat)); + msg.optionalFloat = 0.0f; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalFloat)); + [msg release]; + } + + { // optionalDouble + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalDouble)); + msg.optionalDouble = 1.0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalDouble)); + msg.hasOptionalDouble = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalDouble)); + msg.optionalDouble = 0.0; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalDouble)); + [msg release]; + } + + { // optionalBool + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBool)); + msg.optionalBool = YES; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBool)); + msg.hasOptionalBool = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBool)); + msg.optionalBool = NO; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBool)); + [msg release]; + } + + { // optionalString + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalString)); + msg.optionalString = @"foo"; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalString)); + msg.hasOptionalString = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalString)); + msg.optionalString = @""; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalString)); + [msg release]; + } + + { // optionalBytes + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBytes)); + msg.optionalBytes = [@"foo" dataUsingEncoding:NSUTF8StringEncoding]; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBytes)); + msg.hasOptionalBytes = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBytes)); + msg.optionalBytes = [NSData data]; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalBytes)); + [msg release]; + } + + // + // Test doesn't apply to optionalMessage (no groups in proto3). + // + + { // optionalEnum + Message3Optional *msg = [[Message3Optional alloc] init]; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message3Optional_Enum_Bar; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalEnum)); + msg.hasOptionalEnum = NO; + XCTAssertFalse(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalEnum)); + msg.optionalEnum = Message3Optional_Enum_Foo; + XCTAssertTrue(GPBMessageHasFieldNumberSet(msg, Message3Optional_FieldNumber_OptionalEnum)); + [msg release]; + } + +// clang-format on +//%PDDM-EXPAND-END PROTO3_TEST_OPTIONAL_HAS_FIELDS() +} + - (void)testAccessingProto2UnknownEnumValues { Message2 *msg = [[Message2 alloc] init];
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m index ef6e589..6f20797 100644 --- a/objectivec/Tests/GPBMessageTests+Serialization.m +++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -109,6 +109,317 @@ [msg release]; } +- (void)testProto3SerializationHandlingOptionals { + // + // Proto3 optionals should be just like proto2, zero values also get serialized. + // + +//%PDDM-DEFINE PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(FIELD, ZERO_VALUE, EXPECTED_LEN) +//% { // optional##FIELD +//% Message3Optional *msg = [[Message3Optional alloc] init]; +//% NSData *data = [msg data]; +//% XCTAssertEqual([data length], 0U); +//% msg.optional##FIELD = ZERO_VALUE; +//% data = [msg data]; +//% XCTAssertEqual(data.length, EXPECTED_LEN); +//% NSError *err = nil; +//% Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; +//% XCTAssertNotNil(msg2); +//% XCTAssertNil(err); +//% XCTAssertTrue(msg2.hasOptional##FIELD); +//% XCTAssertEqualObjects(msg, msg2); +//% [msg release]; +//% } +//% +//%PDDM-DEFINE PROTO3_TEST_SERIALIZE_OPTIONAL_FIELDS() +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Int32, 0, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Int64, 0, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Uint32, 0, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Uint64, 0, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Sint32, 0, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Sint64, 0, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Fixed32, 0, 5) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Fixed64, 0, 9) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Sfixed32, 0, 5) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Sfixed64, 0, 9) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Float, 0.0f, 5) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Double, 0.0, 9) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Bool, NO, 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(String, @"", 2) +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Bytes, [NSData data], 2) +//% // +//% // Test doesn't apply to optionalMessage (no groups in proto3). +//% // +//% +//%PROTO3_TEST_SERIALIZE_OPTIONAL_FIELD(Enum, Message3Optional_Enum_Foo, 3) +//%PDDM-EXPAND PROTO3_TEST_SERIALIZE_OPTIONAL_FIELDS() +// This block of code is generated, do not edit it directly. +// clang-format off + + { // optionalInt32 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalInt32 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalInt32); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalInt64 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalInt64 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalInt64); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalUint32 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalUint32 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalUint32); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalUint64 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalUint64 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalUint64); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalSint32 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalSint32 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalSint32); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalSint64 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalSint64 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalSint64); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalFixed32 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalFixed32 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 5); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalFixed32); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalFixed64 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalFixed64 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 9); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalFixed64); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalSfixed32 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalSfixed32 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 5); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalSfixed32); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalSfixed64 + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalSfixed64 = 0; + data = [msg data]; + XCTAssertEqual(data.length, 9); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalSfixed64); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalFloat + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalFloat = 0.0f; + data = [msg data]; + XCTAssertEqual(data.length, 5); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalFloat); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalDouble + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalDouble = 0.0; + data = [msg data]; + XCTAssertEqual(data.length, 9); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalDouble); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalBool + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalBool = NO; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalBool); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalString + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalString = @""; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalString); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + { // optionalBytes + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalBytes = [NSData data]; + data = [msg data]; + XCTAssertEqual(data.length, 2); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalBytes); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + + // + // Test doesn't apply to optionalMessage (no groups in proto3). + // + + { // optionalEnum + Message3Optional *msg = [[Message3Optional alloc] init]; + NSData *data = [msg data]; + XCTAssertEqual([data length], 0U); + msg.optionalEnum = Message3Optional_Enum_Foo; + data = [msg data]; + XCTAssertEqual(data.length, 3); + NSError *err = nil; + Message3Optional *msg2 = [Message3Optional parseFromData:data error:&err]; + XCTAssertNotNil(msg2); + XCTAssertNil(err); + XCTAssertTrue(msg2.hasOptionalEnum); + XCTAssertEqualObjects(msg, msg2); + [msg release]; + } + +// clang-format on +//%PDDM-EXPAND-END PROTO3_TEST_SERIALIZE_OPTIONAL_FIELDS() +} + - (void)testProto2UnknownEnumToUnknownField { Message3 *orig = [[Message3 alloc] init];
diff --git a/objectivec/Tests/unittest_runtime_proto3.proto b/objectivec/Tests/unittest_runtime_proto3.proto index ad2e362..c2ee5fb 100644 --- a/objectivec/Tests/unittest_runtime_proto3.proto +++ b/objectivec/Tests/unittest_runtime_proto3.proto
@@ -119,3 +119,31 @@ map<int32 , Enum > map_int32_enum = 87; map<int32 , Message3> map_int32_message = 88; } + +message Message3Optional { + enum Enum { + FOO = 0; + BAR = 1; + BAZ = 2; + EXTRA_3 = 30; + } + + optional int32 optional_int32 = 1; + optional int64 optional_int64 = 2; + optional uint32 optional_uint32 = 3; + optional uint64 optional_uint64 = 4; + optional sint32 optional_sint32 = 5; + optional sint64 optional_sint64 = 6; + optional fixed32 optional_fixed32 = 7; + optional fixed64 optional_fixed64 = 8; + optional sfixed32 optional_sfixed32 = 9; + optional sfixed64 optional_sfixed64 = 10; + optional float optional_float = 11; + optional double optional_double = 12; + optional bool optional_bool = 13; + optional string optional_string = 14; + optional bytes optional_bytes = 15; + // No 'group' in proto3. + optional Message3 optional_message = 18; + optional Enum optional_enum = 19; +}