ServerCodeTranslatorSnippetBasedTests.swift 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Testing
  17. @testable import GRPCCodeGen
  18. @Suite
  19. final class ServerCodeTranslatorSnippetBasedTests {
  20. @Test
  21. @available(gRPCSwift 2.0, *)
  22. func translate() {
  23. let method = MethodDescriptor(
  24. documentation: "/// Documentation for unaryMethod",
  25. name: MethodName(identifyingName: "UnaryMethod", typeName: "Unary", functionName: "unary"),
  26. isInputStreaming: false,
  27. isOutputStreaming: false,
  28. inputType: "NamespaceA_ServiceARequest",
  29. outputType: "NamespaceA_ServiceAResponse"
  30. )
  31. let service = ServiceDescriptor(
  32. documentation: "/// Documentation for ServiceA",
  33. name: ServiceName(
  34. identifyingName: "namespaceA.AlongNameForServiceA",
  35. typeName: "NamespaceA_ServiceA",
  36. propertyName: "namespaceA_serviceA"
  37. ),
  38. methods: [method]
  39. )
  40. let expectedSwift = """
  41. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  42. extension NamespaceA_ServiceA {
  43. /// Streaming variant of the service protocol for the "namespaceA.AlongNameForServiceA" service.
  44. ///
  45. /// This protocol is the lowest-level of the service protocols generated for this service
  46. /// giving you the most flexibility over the implementation of your service. This comes at
  47. /// the cost of more verbose and less strict APIs. Each RPC requires you to implement it in
  48. /// terms of a request stream and response stream. Where only a single request or response
  49. /// message is expected, you are responsible for enforcing this invariant is maintained.
  50. ///
  51. /// Where possible, prefer using the stricter, less-verbose ``ServiceProtocol``
  52. /// or ``SimpleServiceProtocol`` instead.
  53. ///
  54. /// > Source IDL Documentation:
  55. /// >
  56. /// > Documentation for ServiceA
  57. public protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  58. /// Handle the "UnaryMethod" method.
  59. ///
  60. /// > Source IDL Documentation:
  61. /// >
  62. /// > Documentation for unaryMethod
  63. ///
  64. /// - Parameters:
  65. /// - request: A streaming request of `NamespaceA_ServiceARequest` messages.
  66. /// - context: Context providing information about the RPC.
  67. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  68. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  69. /// to an internal error.
  70. /// - Returns: A streaming response of `NamespaceA_ServiceAResponse` messages.
  71. func unary(
  72. request: GRPCCore.StreamingServerRequest<NamespaceA_ServiceARequest>,
  73. context: GRPCCore.ServerContext
  74. ) async throws -> GRPCCore.StreamingServerResponse<NamespaceA_ServiceAResponse>
  75. }
  76. /// Service protocol for the "namespaceA.AlongNameForServiceA" service.
  77. ///
  78. /// This protocol is higher level than ``StreamingServiceProtocol`` but lower level than
  79. /// the ``SimpleServiceProtocol``, it provides access to request and response metadata and
  80. /// trailing response metadata. If you don't need these then consider using
  81. /// the ``SimpleServiceProtocol``. If you need fine grained control over your RPCs then
  82. /// use ``StreamingServiceProtocol``.
  83. ///
  84. /// > Source IDL Documentation:
  85. /// >
  86. /// > Documentation for ServiceA
  87. public protocol ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol {
  88. /// Handle the "UnaryMethod" method.
  89. ///
  90. /// > Source IDL Documentation:
  91. /// >
  92. /// > Documentation for unaryMethod
  93. ///
  94. /// - Parameters:
  95. /// - request: A request containing a single `NamespaceA_ServiceARequest` message.
  96. /// - context: Context providing information about the RPC.
  97. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  98. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  99. /// to an internal error.
  100. /// - Returns: A response containing a single `NamespaceA_ServiceAResponse` message.
  101. func unary(
  102. request: GRPCCore.ServerRequest<NamespaceA_ServiceARequest>,
  103. context: GRPCCore.ServerContext
  104. ) async throws -> GRPCCore.ServerResponse<NamespaceA_ServiceAResponse>
  105. }
  106. /// Simple service protocol for the "namespaceA.AlongNameForServiceA" service.
  107. ///
  108. /// This is the highest level protocol for the service. The API is the easiest to use but
  109. /// doesn't provide access to request or response metadata. If you need access to these
  110. /// then use ``ServiceProtocol`` instead.
  111. ///
  112. /// > Source IDL Documentation:
  113. /// >
  114. /// > Documentation for ServiceA
  115. public protocol SimpleServiceProtocol: NamespaceA_ServiceA.ServiceProtocol {
  116. /// Handle the "UnaryMethod" method.
  117. ///
  118. /// > Source IDL Documentation:
  119. /// >
  120. /// > Documentation for unaryMethod
  121. ///
  122. /// - Parameters:
  123. /// - request: A `NamespaceA_ServiceARequest` message.
  124. /// - context: Context providing information about the RPC.
  125. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  126. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  127. /// to an internal error.
  128. /// - Returns: A `NamespaceA_ServiceAResponse` to respond with.
  129. func unary(
  130. request: NamespaceA_ServiceARequest,
  131. context: GRPCCore.ServerContext
  132. ) async throws -> NamespaceA_ServiceAResponse
  133. }
  134. }
  135. // Default implementation of 'registerMethods(with:)'.
  136. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  137. extension NamespaceA_ServiceA.StreamingServiceProtocol {
  138. public func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {
  139. router.registerHandler(
  140. forMethod: NamespaceA_ServiceA.Method.Unary.descriptor,
  141. deserializer: GRPCProtobuf.ProtobufDeserializer<NamespaceA_ServiceARequest>(),
  142. serializer: GRPCProtobuf.ProtobufSerializer<NamespaceA_ServiceAResponse>(),
  143. handler: { request, context in
  144. try await self.unary(
  145. request: request,
  146. context: context
  147. )
  148. }
  149. )
  150. }
  151. }
  152. // Default implementation of streaming methods from 'StreamingServiceProtocol'.
  153. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  154. extension NamespaceA_ServiceA.ServiceProtocol {
  155. public func unary(
  156. request: GRPCCore.StreamingServerRequest<NamespaceA_ServiceARequest>,
  157. context: GRPCCore.ServerContext
  158. ) async throws -> GRPCCore.StreamingServerResponse<NamespaceA_ServiceAResponse> {
  159. let response = try await self.unary(
  160. request: GRPCCore.ServerRequest(stream: request),
  161. context: context
  162. )
  163. return GRPCCore.StreamingServerResponse(single: response)
  164. }
  165. }
  166. // Default implementation of methods from 'ServiceProtocol'.
  167. @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
  168. extension NamespaceA_ServiceA.SimpleServiceProtocol {
  169. public func unary(
  170. request: GRPCCore.ServerRequest<NamespaceA_ServiceARequest>,
  171. context: GRPCCore.ServerContext
  172. ) async throws -> GRPCCore.ServerResponse<NamespaceA_ServiceAResponse> {
  173. return GRPCCore.ServerResponse<NamespaceA_ServiceAResponse>(
  174. message: try await self.unary(
  175. request: request.message,
  176. context: context
  177. ),
  178. metadata: [:]
  179. )
  180. }
  181. }
  182. """
  183. let rendered = self.render(accessLevel: .public, service: service)
  184. #expect(rendered == expectedSwift)
  185. }
  186. @available(gRPCSwift 2.0, *)
  187. private func render(
  188. accessLevel: AccessModifier,
  189. service: ServiceDescriptor
  190. ) -> String {
  191. let translator = ServerCodeTranslator()
  192. let codeBlocks = translator.translate(
  193. accessModifier: accessLevel,
  194. service: service,
  195. availability: .macOS15Aligned
  196. ) {
  197. "GRPCProtobuf.ProtobufSerializer<\($0)>()"
  198. } deserializer: {
  199. "GRPCProtobuf.ProtobufDeserializer<\($0)>()"
  200. }
  201. let renderer = TextBasedRenderer.default
  202. renderer.renderCodeBlocks(codeBlocks)
  203. return renderer.renderedContents()
  204. }
  205. }