diff options
Diffstat (limited to 'objectivec')
-rw-r--r-- | objectivec/GPBWellKnownTypes.h | 22 | ||||
-rw-r--r-- | objectivec/GPBWellKnownTypes.m | 49 | ||||
-rw-r--r-- | objectivec/Tests/GPBWellKnownTypesTest.m | 53 | ||||
-rwxr-xr-x | objectivec/generate_descriptors_proto.sh | 1 |
4 files changed, 122 insertions, 3 deletions
diff --git a/objectivec/GPBWellKnownTypes.h b/objectivec/GPBWellKnownTypes.h index c98594a2..050f85f6 100644 --- a/objectivec/GPBWellKnownTypes.h +++ b/objectivec/GPBWellKnownTypes.h @@ -30,8 +30,10 @@ #import <Foundation/Foundation.h> -#import "google/protobuf/Timestamp.pbobjc.h" +#import "google/protobuf/Any.pbobjc.h" #import "google/protobuf/Duration.pbobjc.h" +#import "google/protobuf/Timestamp.pbobjc.h" + NS_ASSUME_NONNULL_BEGIN @@ -49,4 +51,22 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970; @end +// Extension to GPBAny to support packing and unpacking for arbitrary messages. +@interface GPBAny (GPBWellKnownTypes) +// Initialize GPBAny instance with the given message. e.g., for google.protobuf.foo, type +// url will be "type.googleapis.com/google.protobuf.foo" and value will be serialized foo. +- (instancetype)initWithMessage:(GPBMessage*)message; +// Serialize the given message to the value in GPBAny. Type url will also be updated. +- (void)setMessage:(GPBMessage*)message; +// Parse the value in GPBAny to the given message. If messageClass message doesn't match the +// type url in GPBAny, nil is returned. +- (GPBMessage*)messageOfClass:(Class)messageClass; +// True if the given type matches the type url in GPBAny. +- (BOOL)wrapsMessageOfClass:(Class)messageClass; +@end + +// Common prefix of type url in GPBAny, which is @"type.googleapis.com/". All valid +// type urls in any should start with this prefix. +extern NSString *const GPBTypeGoogleApisComPrefix; + NS_ASSUME_NONNULL_END diff --git a/objectivec/GPBWellKnownTypes.m b/objectivec/GPBWellKnownTypes.m index fe02f5de..b48f8a53 100644 --- a/objectivec/GPBWellKnownTypes.m +++ b/objectivec/GPBWellKnownTypes.m @@ -115,3 +115,52 @@ static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time, } @end + +NSString *const GPBTypeGoogleApisComPrefix = @"type.googleapis.com/"; + +@implementation GPBAny (GBPWellKnownTypes) + +- (instancetype)initWithMessage:(GPBMessage*)message { + self = [super init]; + if (self) { + [self setMessage:message]; + } + return self; +} + +- (NSString*)typeName { + NSAssert([self.typeURL hasPrefix:GPBTypeGoogleApisComPrefix], + @"Invalid any type url (%@).", self.typeURL); + if (![self.typeURL hasPrefix:GPBTypeGoogleApisComPrefix]) { + return nil; + } + return [self.typeURL substringFromIndex:[GPBTypeGoogleApisComPrefix length]]; +} + +- (void)setMessage:(GPBMessage*)message { + self.typeURL = [GPBTypeGoogleApisComPrefix stringByAppendingString:message.descriptor.name]; + self.value = message.data; +} + +- (GPBMessage*)messageOfClass:(Class)messageClass { + if ([self wrapsMessageOfClass:messageClass]) { + GPBMessage* message = [messageClass message]; + [message mergeFromData:self.value extensionRegistry:nil]; + return message; + } else { + return nil; + } +} + +- (BOOL)wrapsMessageOfClass:(Class)messageClass { + NSAssert([messageClass isSubclassofClass:[GPBMessage class]], + @"Given class (%@) is not a subclass of GPBMessage", + [messageClass name]); + if (![messageClass isSubclassOfClass:[GPBMessage class]]) { + return NO; + } + return [[self typeName] isEqualToString:messageClass.descriptor.name]; +} + +@end + diff --git a/objectivec/Tests/GPBWellKnownTypesTest.m b/objectivec/Tests/GPBWellKnownTypesTest.m index 78f4e637..48c875aa 100644 --- a/objectivec/Tests/GPBWellKnownTypesTest.m +++ b/objectivec/Tests/GPBWellKnownTypesTest.m @@ -28,7 +28,9 @@ // (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 "google/protobuf/Unittest.pbobjc.h" #import "GPBWellKnownTypes.h" +#import "GPBTestUtilities.h" #import <XCTest/XCTest.h> @@ -38,7 +40,7 @@ static const NSTimeInterval kFutureOffsetInterval = 15000; // Nanosecond time accuracy static const NSTimeInterval kTimeAccuracy = 1e-9; -@interface WellKnownTypesTest : XCTestCase +@interface WellKnownTypesTest : GPBTestCase @end @implementation WellKnownTypesTest @@ -99,4 +101,53 @@ static const NSTimeInterval kTimeAccuracy = 1e-9; [duration2 release]; } +- (void)testAnyPackingAndUnpacking { + TestAllTypes *from = [TestAllTypes message]; + [self setAllFields:from repeatedCount:1]; + NSData *data = from.data; + + // Test initWithMessage + GPBAny *anyInited = [[GPBAny alloc] initWithMessage:from]; + XCTAssertEqualObjects( + [GPBTypeGoogleApisComPrefix stringByAppendingString:from.descriptor.name], + anyInited.typeURL); + XCTAssertEqualObjects(data, anyInited.value); + [anyInited release]; + + // Test setMessage. + GPBAny *any = [GPBAny message]; + [any setMessage:from]; + XCTAssertEqualObjects( + [GPBTypeGoogleApisComPrefix stringByAppendingString:from.descriptor.name], + any.typeURL); + XCTAssertEqualObjects(data, any.value); + + // Test messageOfClass + TestAllTypes *to = (TestAllTypes*)[any messageOfClass:[TestAllTypes class]]; + XCTAssertEqualObjects(from, to); + XCTAssertEqual([any messageOfClass:[ForeignMessage class]], nil); + XCTAssertEqual([[GPBAny message] messageOfClass:[TestAllTypes class]], nil); + + // Test setMessage with another type. + ForeignMessage *from2 = [ForeignMessage message]; + [any setMessage:from2]; + XCTAssertEqualObjects( + [GPBTypeGoogleApisComPrefix stringByAppendingString:from2.descriptor.name], + any.typeURL); + XCTAssertEqual(0UL, [any.value length]); + + // Test wrapsMessageOfClass + XCTAssertTrue([any wrapsMessageOfClass:[from2 class]]); + XCTAssertFalse([any wrapsMessageOfClass:[from class]]); +#if !defined(NS_BLOCK_ASSERTIONS) + // If assert is enabled, throw exception when the passed message class to + // wrapsMessageOfClass is not a child of GPBMessage. + XCTAssertThrows([any wrapsMessageOfClass:[NSString class]]); +#else + // If assert is disabled, return false when the passed message class to + // wrapsMessageOfClass is not a child of GPBMessage. + XCTAssertFalse([any wrapsMessageOfClass:[NSString class]]); +#endif +} + @end diff --git a/objectivec/generate_descriptors_proto.sh b/objectivec/generate_descriptors_proto.sh index f2ed00b7..b3ecf398 100755 --- a/objectivec/generate_descriptors_proto.sh +++ b/objectivec/generate_descriptors_proto.sh @@ -33,7 +33,6 @@ fi # Make sure the compiler is current. cd src -make $@ google/protobuf/stubs/pbconfig.h make $@ protoc declare -a RUNTIME_PROTO_FILES=(\ |