Skip to content

Commit 290a537

Browse files
[ObjC] Add DEBUG-only validations to extension values in GPBMessage, along with tests.
PiperOrigin-RevId: 902869088
1 parent ead8d4b commit 290a537

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

objectivec/GPBMessage.m

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,57 @@ static void CheckExtension(GPBMessage *self, GPBExtensionDescriptor *extension)
306306
}
307307
}
308308

309+
#if defined(DEBUG) && DEBUG
310+
static void CheckExtensionValue(GPBExtensionDescriptor *extension, id value) {
311+
// If asserts are stripped, value is unused.
312+
(void)value;
313+
switch (extension.dataType) {
314+
case GPBDataTypeBool:
315+
case GPBDataTypeFixed32:
316+
case GPBDataTypeSFixed32:
317+
case GPBDataTypeFloat:
318+
case GPBDataTypeFixed64:
319+
case GPBDataTypeSFixed64:
320+
case GPBDataTypeDouble:
321+
case GPBDataTypeInt32:
322+
case GPBDataTypeInt64:
323+
case GPBDataTypeSInt32:
324+
case GPBDataTypeSInt64:
325+
case GPBDataTypeUInt32:
326+
case GPBDataTypeUInt64:
327+
NSCAssert([value isKindOfClass:[NSNumber class]],
328+
@"Extension %@ value must be an NSNumber (was %@)", extension.singletonName,
329+
[value class]);
330+
break;
331+
case GPBDataTypeEnum:
332+
NSCAssert([value isKindOfClass:[NSNumber class]],
333+
@"Extension %@ value must be an NSNumber (was %@)", extension.singletonName,
334+
[value class]);
335+
NSCAssert(!extension.enumDescriptor.isClosed ||
336+
extension.enumDescriptor.enumVerifier([value intValue]),
337+
@"Extension %@ has value %d which is not a valid %@", extension.singletonName,
338+
[value intValue], extension.enumDescriptor.name);
339+
break;
340+
case GPBDataTypeBytes:
341+
NSCAssert([value isKindOfClass:[NSData class]],
342+
@"Extension %@ value must be of type NSData (was %@)", extension.singletonName,
343+
[value class]);
344+
break;
345+
case GPBDataTypeString:
346+
NSCAssert([value isKindOfClass:[NSString class]],
347+
@"Extension %@ value must be of type NSString (was %@)", extension.singletonName,
348+
[value class]);
349+
break;
350+
case GPBDataTypeMessage:
351+
case GPBDataTypeGroup:
352+
NSCAssert([value isKindOfClass:extension.msgClass],
353+
@"Extension %@ value must be of type %@ (was %@)", extension.singletonName,
354+
extension.msgClass, [value class]);
355+
break;
356+
}
357+
}
358+
#endif
359+
309360
static NSMutableDictionary *CloneExtensionMap(NSDictionary *extensionMap, NSZone *zone) {
310361
if (extensionMap.count == 0) {
311362
return nil;
@@ -2151,6 +2202,9 @@ - (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
21512202
}
21522203

21532204
CheckExtension(self, extension);
2205+
#if defined(DEBUG) && DEBUG
2206+
CheckExtensionValue(extension, value);
2207+
#endif
21542208

21552209
if (extension.repeated) {
21562210
[NSException raise:NSInvalidArgumentException
@@ -2184,6 +2238,9 @@ - (void)setExtension:(GPBExtensionDescriptor *)extension value:(id)value {
21842238

21852239
- (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value {
21862240
CheckExtension(self, extension);
2241+
#if defined(DEBUG) && DEBUG
2242+
CheckExtensionValue(extension, value);
2243+
#endif
21872244

21882245
if (!extension.repeated) {
21892246
[NSException raise:NSInvalidArgumentException
@@ -2205,6 +2262,9 @@ - (void)addExtension:(GPBExtensionDescriptor *)extension value:(id)value {
22052262

22062263
- (void)setExtension:(GPBExtensionDescriptor *)extension index:(NSUInteger)idx value:(id)value {
22072264
CheckExtension(self, extension);
2265+
#if defined(DEBUG) && DEBUG
2266+
CheckExtensionValue(extension, value);
2267+
#endif
22082268

22092269
if (!extension.repeated) {
22102270
[NSException raise:NSInvalidArgumentException

objectivec/Tests/GPBMessageTests.m

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2754,4 +2754,94 @@ - (void)testWriteToFullOutputStreamShouldThrow {
27542754
GPBCodedOutputStreamException_WriteFailed);
27552755
}
27562756

2757+
- (void)testExtensionValueValidation {
2758+
#if defined(DEBUG) && DEBUG
2759+
TestAllExtensions *message = [TestAllExtensions message];
2760+
2761+
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
2762+
GPBExtensionDescriptor *msgExt = Objc_Protobuf_Tests_extension_OptionalNestedMessageExtension();
2763+
GPBExtensionDescriptor *enumExt = Objc_Protobuf_Tests_extension_OptionalNestedEnumExtension();
2764+
GPBExtensionDescriptor *repeatedEnumExt =
2765+
Objc_Protobuf_Tests_extension_RepeatedNestedEnumExtension();
2766+
#else
2767+
GPBExtensionDescriptor *msgExt = [UnittestRoot optionalNestedMessageExtension];
2768+
GPBExtensionDescriptor *enumExt = [UnittestRoot optionalNestedEnumExtension];
2769+
GPBExtensionDescriptor *repeatedEnumExt = [UnittestRoot repeatedNestedEnumExtension];
2770+
#endif
2771+
2772+
#if defined(GPB_UNITTEST_USE_C_FUNCTION_FOR_EXTENSIONS)
2773+
GPBExtensionDescriptor *int32Ext = Objc_Protobuf_Tests_extension_OptionalInt32Extension();
2774+
GPBExtensionDescriptor *stringExt = Objc_Protobuf_Tests_extension_OptionalStringExtension();
2775+
GPBExtensionDescriptor *bytesExt = Objc_Protobuf_Tests_extension_OptionalBytesExtension();
2776+
#else
2777+
GPBExtensionDescriptor *int32Ext = [UnittestRoot optionalInt32Extension];
2778+
GPBExtensionDescriptor *stringExt = [UnittestRoot optionalStringExtension];
2779+
GPBExtensionDescriptor *bytesExt = [UnittestRoot optionalBytesExtension];
2780+
#endif
2781+
2782+
// Message extension with wrong type
2783+
XCTAssertThrowsSpecificNamed(
2784+
^{
2785+
[message setExtension:msgExt value:@5];
2786+
}(),
2787+
NSException, NSInternalInconsistencyException);
2788+
2789+
// Enum extension with wrong type
2790+
XCTAssertThrowsSpecificNamed(
2791+
^{
2792+
[message setExtension:enumExt value:@"Not a number"];
2793+
}(),
2794+
NSException, NSInternalInconsistencyException);
2795+
2796+
// Enum extension with invalid enum value (999 is not a valid enum value for the closed
2797+
// TestAllTypes_NestedEnum)
2798+
XCTAssertThrowsSpecificNamed(
2799+
^{
2800+
[message setExtension:enumExt value:@999];
2801+
}(),
2802+
NSException, NSInternalInconsistencyException);
2803+
2804+
// Repeated enum extension with invalid value
2805+
XCTAssertThrowsSpecificNamed(
2806+
^{
2807+
[message addExtension:repeatedEnumExt value:@999];
2808+
}(),
2809+
NSException, NSInternalInconsistencyException);
2810+
2811+
// Setting invalid value by index in repeated enum extension
2812+
[message addExtension:repeatedEnumExt value:@(TestAllTypes_NestedEnum_Foo)];
2813+
XCTAssertThrowsSpecificNamed(
2814+
^{
2815+
[message setExtension:repeatedEnumExt index:0 value:@999];
2816+
}(),
2817+
NSException, NSInternalInconsistencyException);
2818+
2819+
// Primitive extension with wrong type
2820+
XCTAssertThrowsSpecificNamed(
2821+
^{
2822+
[message setExtension:int32Ext value:@"Not a number"];
2823+
}(),
2824+
NSException, NSInternalInconsistencyException);
2825+
2826+
XCTAssertThrowsSpecificNamed(
2827+
^{
2828+
[message setExtension:stringExt value:@5];
2829+
}(),
2830+
NSException, NSInternalInconsistencyException);
2831+
2832+
XCTAssertThrowsSpecificNamed(
2833+
^{
2834+
[message setExtension:bytesExt value:@"Not NSData"];
2835+
}(),
2836+
NSException, NSInternalInconsistencyException);
2837+
2838+
// Valid values should not throw
2839+
XCTAssertNoThrow([message setExtension:msgExt value:[TestAllTypes_NestedMessage message]]);
2840+
XCTAssertNoThrow([message setExtension:enumExt value:@(TestAllTypes_NestedEnum_Foo)]);
2841+
XCTAssertNoThrow([message setExtension:int32Ext value:@5]);
2842+
XCTAssertNoThrow([message setExtension:stringExt value:@"foo"]);
2843+
XCTAssertNoThrow([message setExtension:bytesExt value:[NSData data]]);
2844+
#endif
2845+
}
2846+
27572847
@end

0 commit comments

Comments
 (0)