// Protocol Buffers - Google's data interchange format // Copyright 2025 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #import #import "GPBDescriptor_PackagePrivate.h" #import "GPBExtensionRegistry.h" #import "GPBMessage.h" #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBRootObject_PackagePrivate.h" #import "GPBTestUtilities.h" #if GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION > 40311 #error "Time to remove this test." #else @interface Message40311FormatTest : GPBTestCase @end // clang-format off // NOLINTBEGIN // ------------------------------------------------------------------------------------------------- // // This is extracted from generated code with the 40311 format for the following proto: // // syntax = "proto2"; // // enum Enum40311 { // FOO = 0; // BAR = 1; // } // // message Message40311 { // message SubMessage { // optional int32 x = 1; // } // enum SubEnum { // SUB_FOO = 0; // SUB_BAR = 1; // } // optional string name = 1; // optional Enum40311 value = 2; // repeated string names = 11; // repeated Enum40311 values = 12; // optional SubMessage sub_m = 20; // optional SubEnum sub_e = 21; // extensions 100 to max; // } // // extend Message40311 { // optional Message40311 other_m = 100; // optional Enum40311 other_e = 101; // repeated Message40311 other_ms = 110; // repeated Enum40311 other_es = 111; // } // // ------------------------------------------------------------------------------------------------- @class Message40311_SubMessage; NS_ASSUME_NONNULL_BEGIN typedef GPB_ENUM(Enum40311) { Enum40311_Foo = 0, Enum40311_Bar = 1, }; GPBEnumDescriptor *Enum40311_EnumDescriptor(void); BOOL Enum40311_IsValidValue(int32_t value); #pragma mark - Enum Message40311_SubEnum typedef GPB_ENUM(Message40311_SubEnum) { Message40311_SubEnum_SubFoo = 0, Message40311_SubEnum_SubBar = 1, }; GPBEnumDescriptor *Message40311_SubEnum_EnumDescriptor(void); BOOL Message40311_SubEnum_IsValidValue(int32_t value); GPB_FINAL @interface Test40311Root : GPBRootObject @end @interface Test40311Root (DynamicMethods) + (GPBExtensionDescriptor *)otherM; + (GPBExtensionDescriptor *)otherE; + (GPBExtensionDescriptor *)otherMs; + (GPBExtensionDescriptor *)otherEs; @end typedef GPB_ENUM(Message40311_FieldNumber) { Message40311_FieldNumber_Name = 1, Message40311_FieldNumber_Value = 2, Message40311_FieldNumber_NamesArray = 11, Message40311_FieldNumber_ValuesArray = 12, Message40311_FieldNumber_SubM = 20, Message40311_FieldNumber_SubE = 21, }; GPB_FINAL @interface Message40311 : GPBMessage @property(nonatomic, readwrite, copy, null_resettable) NSString *name; @property(nonatomic, readwrite) BOOL hasName; @property(nonatomic, readwrite) Enum40311 value; @property(nonatomic, readwrite) BOOL hasValue; @property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *namesArray; @property(nonatomic, readonly) NSUInteger namesArray_Count; @property(nonatomic, readwrite, strong, null_resettable) GPBEnumArray *valuesArray; @property(nonatomic, readonly) NSUInteger valuesArray_Count; @property(nonatomic, readwrite, strong, null_resettable) Message40311_SubMessage *subM; @property(nonatomic, readwrite) BOOL hasSubM; @property(nonatomic, readwrite) Message40311_SubEnum subE; @property(nonatomic, readwrite) BOOL hasSubE; @end typedef GPB_ENUM(Message40311_SubMessage_FieldNumber) { Message40311_SubMessage_FieldNumber_X = 1, }; GPB_FINAL @interface Message40311_SubMessage : GPBMessage @property(nonatomic, readwrite) int32_t x; @property(nonatomic, readwrite) BOOL hasX; @end NS_ASSUME_NONNULL_END #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" GPBObjCClassDeclaration(Message40311); GPBObjCClassDeclaration(Message40311_SubMessage); @implementation Test40311Root + (GPBExtensionRegistry*)extensionRegistry { // This is called by +initialize so there is no need to worry // about thread safety and initialization of registry. static GPBExtensionRegistry* registry = nil; if (!registry) { registry = [[GPBExtensionRegistry alloc] init]; static GPBExtensionDescription descriptions[] = { { .defaultValue.valueMessage = nil, .singletonName = GPBStringifySymbol(Test40311Root) "_otherM", .extendedClass.clazz = GPBObjCClass(Message40311), .messageOrGroupClass.clazz = GPBObjCClass(Message40311), .enumDescriptorFunc = NULL, .fieldNumber = 100, .dataType = GPBDataTypeMessage, .options = GPBExtensionNone, }, { .defaultValue.valueEnum = Enum40311_Foo, .singletonName = GPBStringifySymbol(Test40311Root) "_otherE", .extendedClass.clazz = GPBObjCClass(Message40311), .messageOrGroupClass.clazz = Nil, .enumDescriptorFunc = Enum40311_EnumDescriptor, .fieldNumber = 101, .dataType = GPBDataTypeEnum, .options = GPBExtensionNone, }, { .defaultValue.valueMessage = nil, .singletonName = GPBStringifySymbol(Test40311Root) "_otherMs", .extendedClass.clazz = GPBObjCClass(Message40311), .messageOrGroupClass.clazz = GPBObjCClass(Message40311), .enumDescriptorFunc = NULL, .fieldNumber = 110, .dataType = GPBDataTypeMessage, .options = GPBExtensionRepeated, }, { .defaultValue.valueMessage = nil, .singletonName = GPBStringifySymbol(Test40311Root) "_otherEs", .extendedClass.clazz = GPBObjCClass(Message40311), .messageOrGroupClass.clazz = Nil, .enumDescriptorFunc = Enum40311_EnumDescriptor, .fieldNumber = 111, .dataType = GPBDataTypeEnum, .options = GPBExtensionRepeated, }, }; for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) { GPBExtensionDescriptor *extension = [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i] runtimeSupport:&GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311]; [registry addExtension:extension]; [self globallyRegisterExtension:extension]; [extension release]; } // None of the imports (direct or indirect) defined extensions, so no need to add // them to this registry. } return registry; } @end static GPBFilePackageAndPrefix Test40311Root_FileDescription = { .package = NULL, .prefix = NULL }; GPBEnumDescriptor *Enum40311_EnumDescriptor(void) { static _Atomic(GPBEnumDescriptor*) descriptor = nil; if (!descriptor) { static const char *valueNames = "Foo\000Bar\000"; static const int32_t values[] = { Enum40311_Foo, Enum40311_Bar, }; GPBEnumDescriptor *worker = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(Enum40311) runtimeSupport:&GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311 valueNames:valueNames values:values count:(uint32_t)(sizeof(values) / sizeof(int32_t)) enumVerifier:Enum40311_IsValidValue flags:GPBEnumDescriptorInitializationFlag_IsClosed]; GPBEnumDescriptor *expected = nil; if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) { [worker release]; } } return descriptor; } BOOL Enum40311_IsValidValue(int32_t value__) { switch (value__) { case Enum40311_Foo: case Enum40311_Bar: return YES; default: return NO; } } GPBEnumDescriptor *Message40311_SubEnum_EnumDescriptor(void) { static _Atomic(GPBEnumDescriptor*) descriptor = nil; if (!descriptor) { static const char *valueNames = "SubFoo\000SubBar\000"; static const int32_t values[] = { Message40311_SubEnum_SubFoo, Message40311_SubEnum_SubBar, }; GPBEnumDescriptor *worker = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(Message40311_SubEnum) runtimeSupport:&GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311 valueNames:valueNames values:values count:(uint32_t)(sizeof(values) / sizeof(int32_t)) enumVerifier:Message40311_SubEnum_IsValidValue flags:GPBEnumDescriptorInitializationFlag_IsClosed]; GPBEnumDescriptor *expected = nil; if (!atomic_compare_exchange_strong(&descriptor, &expected, worker)) { [worker release]; } } return descriptor; } BOOL Message40311_SubEnum_IsValidValue(int32_t value__) { switch (value__) { case Message40311_SubEnum_SubFoo: case Message40311_SubEnum_SubBar: return YES; default: return NO; } } @implementation Message40311 @dynamic hasName, name; @dynamic hasValue, value; @dynamic namesArray, namesArray_Count; @dynamic valuesArray, valuesArray_Count; @dynamic hasSubM, subM; @dynamic hasSubE, subE; typedef struct Message40311__storage_ { uint32_t _has_storage_[1]; Enum40311 value; Message40311_SubEnum subE; NSString *name; NSMutableArray *namesArray; GPBEnumArray *valuesArray; Message40311_SubMessage *subM; } Message40311__storage_; + (GPBDescriptor *)descriptor { static GPBDescriptor *descriptor = nil; if (!descriptor) { static GPBMessageFieldDescription fields[] = { { .name = "name", .dataTypeSpecific.clazz = Nil, .number = Message40311_FieldNumber_Name, .hasIndex = 0, .offset = (uint32_t)offsetof(Message40311__storage_, name), .flags = GPBFieldNone, .dataType = GPBDataTypeString, }, { .name = "value", .dataTypeSpecific.enumDescFunc = Enum40311_EnumDescriptor, .number = Message40311_FieldNumber_Value, .hasIndex = 1, .offset = (uint32_t)offsetof(Message40311__storage_, value), .flags = GPBFieldNone, .dataType = GPBDataTypeEnum, }, { .name = "namesArray", .dataTypeSpecific.clazz = Nil, .number = Message40311_FieldNumber_NamesArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(Message40311__storage_, namesArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeString, }, { .name = "valuesArray", .dataTypeSpecific.enumDescFunc = Enum40311_EnumDescriptor, .number = Message40311_FieldNumber_ValuesArray, .hasIndex = GPBNoHasBit, .offset = (uint32_t)offsetof(Message40311__storage_, valuesArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeEnum, }, { .name = "subM", .dataTypeSpecific.clazz = GPBObjCClass(Message40311_SubMessage), .number = Message40311_FieldNumber_SubM, .hasIndex = 2, .offset = (uint32_t)offsetof(Message40311__storage_, subM), .flags = GPBFieldNone, .dataType = GPBDataTypeMessage, }, { .name = "subE", .dataTypeSpecific.enumDescFunc = Message40311_SubEnum_EnumDescriptor, .number = Message40311_FieldNumber_SubE, .hasIndex = 3, .offset = (uint32_t)offsetof(Message40311__storage_, subE), .flags = GPBFieldNone, .dataType = GPBDataTypeEnum, }, }; GPBDescriptor *localDescriptor = [GPBDescriptor allocDescriptorForClass:GPBObjCClass(Message40311) messageName:@"Message40311" runtimeSupport:&GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311 fileDescription:&Test40311Root_FileDescription fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(Message40311__storage_) flags:GPBDescriptorInitializationFlag_None]; static const GPBExtensionRange ranges[] = { { .start = 100, .end = 536870912 }, }; [localDescriptor setupExtensionRanges:ranges count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG descriptor = localDescriptor; } return descriptor; } @end @implementation Message40311_SubMessage @dynamic hasX, x; typedef struct Message40311_SubMessage__storage_ { uint32_t _has_storage_[1]; int32_t x; } Message40311_SubMessage__storage_; // This method is threadsafe because it is initially called // in +initialize for each subclass. + (GPBDescriptor *)descriptor { static GPBDescriptor *descriptor = nil; if (!descriptor) { static GPBMessageFieldDescription fields[] = { { .name = "x", .dataTypeSpecific.clazz = Nil, .number = Message40311_SubMessage_FieldNumber_X, .hasIndex = 0, .offset = (uint32_t)offsetof(Message40311_SubMessage__storage_, x), .flags = GPBFieldNone, .dataType = GPBDataTypeInt32, }, }; GPBDescriptor *localDescriptor = [GPBDescriptor allocDescriptorForClass:GPBObjCClass(Message40311_SubMessage) messageName:@"SubMessage" runtimeSupport:&GOOGLE_PROTOBUF_OBJC_EXPECTED_GENCODE_VERSION_40311 fileDescription:&Test40311Root_FileDescription fields:fields fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(Message40311_SubMessage__storage_) flags:GPBDescriptorInitializationFlag_None]; [localDescriptor setupContainingMessageClass:GPBObjCClass(Message40311)]; #if defined(DEBUG) && DEBUG NSAssert(descriptor == nil, @"Startup recursed!"); #endif // DEBUG descriptor = localDescriptor; } return descriptor; } @end #pragma clang diagnostic pop // NOLINTEND // clang-format on // ------------------------------------------------------------------------------------------------- @implementation Message40311FormatTest - (void)test40311MessageFormat { // This doesn't test everything, just exists to ensure the code compiles/links and seems // to work. Message40311 *message = [Message40311 message]; message.name = @"foo"; message.subM.x = 123; } @end #endif // GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION > 40311