| // 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 <stdatomic.h> |
| |
| #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<NSString*> *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 |