Skip to content

Commit

Permalink
Merge branch 'main' into fix-generate-test-clients
Browse files Browse the repository at this point in the history
  • Loading branch information
glbrntt authored Jan 22, 2024
2 parents f030f5a + 1e36bdc commit cf254bd
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 1 deletion.
23 changes: 22 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ extension Target.Dependency {
static let protocGenGRPCSwift: Self = .target(name: "protoc-gen-grpc-swift")
static let reflectionService: Self = .target(name: "GRPCReflectionService")
static let grpcCodeGen: Self = .target(name: "GRPCCodeGen")
static let grpcProtobuf: Self = .target(name: "GRPCProtobuf")

// Target dependencies; internal
static let grpcSampleData: Self = .target(name: "GRPCSampleData")
Expand Down Expand Up @@ -330,6 +331,15 @@ extension Target {
]
)

static let grpcProtobufTests: Target = .testTarget(
name: "GRPCProtobufTests",
dependencies: [
.grpcCore,
.grpcProtobuf,
.protobuf
]
)

static let interopTestModels: Target = .target(
name: "GRPCInteroperabilityTestModels",
dependencies: [
Expand Down Expand Up @@ -579,6 +589,15 @@ extension Target {
name: "GRPCCodeGen",
path: "Sources/GRPCCodeGen"
)

static let grpcProtobuf: Target = .target(
name: "GRPCProtobuf",
dependencies: [
.grpcCore,
.protobuf
],
path: "Sources/GRPCProtobuf"
)
}

// MARK: - Products
Expand Down Expand Up @@ -666,6 +685,7 @@ let package = Package(
.grpcHTTP2Core,
.grpcHTTP2TransportNIOPosix,
.grpcHTTP2TransportNIOTransportServices,
.grpcProtobuf,

// v2 tests
.grpcCoreTests,
Expand All @@ -674,7 +694,8 @@ let package = Package(
.grpcInterceptorsTests,
.grpcHTTP2CoreTests,
.grpcHTTP2TransportNIOPosixTests,
.grpcHTTP2TransportNIOTransportServicesTests
.grpcHTTP2TransportNIOTransportServicesTests,
.grpcProtobufTests
]
)

Expand Down
63 changes: 63 additions & 0 deletions Sources/GRPCProtobuf/Coding.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2024, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Foundation
import GRPCCore
import SwiftProtobuf

/// Serializes a Protobuf message into a sequence of bytes.
public struct ProtobufSerializer<Message: SwiftProtobuf.Message>: GRPCCore.MessageSerializer {
public init() {}

/// Serializes a ``Message`` into a sequence of bytes.
///
/// - Parameter message: The message to serialize.
/// - Returns: An array of serialized bytes representing the message.
public func serialize(_ message: Message) throws -> [UInt8] {
do {
let data = try message.serializedData()
return Array(data)
} catch let error {
throw RPCError(
code: .invalidArgument,
message: "Can't serialize message of type \(type(of: message)).",
cause: error
)
}
}
}

/// Deserializes a sequence of bytes into a Protobuf message.
public struct ProtobufDeserializer<Message: SwiftProtobuf.Message>: GRPCCore.MessageDeserializer {
public init() {}

/// Deserializes a sequence of bytes into a ``Message``.
///
/// - Parameter serializedMessageBytes: The array of bytes to deserialize.
/// - Returns: The deserialized message.
public func deserialize(_ serializedMessageBytes: [UInt8]) throws -> Message {
do {
let message = try Message(contiguousBytes: serializedMessageBytes)
return message
} catch let error {
throw RPCError(
code: .invalidArgument,
message: "Can't deserialize to message of type \(Message.self)",
cause: error
)
}
}
}
98 changes: 98 additions & 0 deletions Tests/GRPCProtobufTests/ProtobufCodingTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2024, gRPC Authors All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import GRPCCore
import GRPCProtobuf
import SwiftProtobuf
import XCTest

final class ProtobufCodingTests: XCTestCase {
func testSerializeDeserializeRoundtrip() throws {
let message = Google_Protobuf_Timestamp.with {
$0.seconds = 4
}

let serializer = ProtobufSerializer<Google_Protobuf_Timestamp>()
let deserializer = ProtobufDeserializer<Google_Protobuf_Timestamp>()

let bytes = try serializer.serialize(message)
let roundTrip = try deserializer.deserialize(bytes)
XCTAssertEqual(roundTrip, message)
}

func testSerializerError() throws {
let message = TestMessage()
let serializer = ProtobufSerializer<TestMessage>()

XCTAssertThrowsError(
try serializer.serialize(message)
) { error in
XCTAssertEqual(
error as? RPCError,
RPCError(
code: .invalidArgument,
message:
"""
Can't serialize message of type TestMessage.
"""
)
)
}
}

func testDeserializerError() throws {
let bytes = Array("%%%%%££££".utf8)
let deserializer = ProtobufDeserializer<TestMessage>()
XCTAssertThrowsError(
try deserializer.deserialize(bytes)
) { error in
XCTAssertEqual(
error as? RPCError,
RPCError(
code: .invalidArgument,
message:
"""
Can't deserialize to message of type TestMessage
"""
)
)
}
}
}

struct TestMessage: SwiftProtobuf.Message {
var text: String = ""
var unknownFields = SwiftProtobuf.UnknownStorage()
static var protoMessageName: String = "Test" + ".ServiceRequest"
init() {}

mutating func decodeMessage<D>(decoder: inout D) throws where D: SwiftProtobuf.Decoder {
throw RPCError(code: .internalError, message: "Decoding error")
}

func traverse<V>(visitor: inout V) throws where V: SwiftProtobuf.Visitor {
throw RPCError(code: .internalError, message: "Traversing error")
}

public var isInitialized: Bool {
if self.text.isEmpty { return false }
return true
}

func isEqualTo(message: SwiftProtobuf.Message) -> Bool {
return false
}
}

0 comments on commit cf254bd

Please sign in to comment.