ServerCodeTranslatorSnippetBasedTests.swift 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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. func translate() {
  22. let method = MethodDescriptor(
  23. documentation: "/// Documentation for unaryMethod",
  24. name: MethodName(identifyingName: "UnaryMethod", typeName: "Unary", functionName: "unary"),
  25. isInputStreaming: false,
  26. isOutputStreaming: false,
  27. inputType: "NamespaceA_ServiceARequest",
  28. outputType: "NamespaceA_ServiceAResponse"
  29. )
  30. let service = ServiceDescriptor(
  31. documentation: "/// Documentation for ServiceA",
  32. name: ServiceName(
  33. identifyingName: "namespaceA.AlongNameForServiceA",
  34. typeName: "NamespaceA_ServiceA",
  35. propertyName: "namespaceA_serviceA"
  36. ),
  37. methods: [method]
  38. )
  39. let expectedSwift = """
  40. extension NamespaceA_ServiceA {
  41. /// Streaming variant of the service protocol for the "namespaceA.AlongNameForServiceA" service.
  42. ///
  43. /// This protocol is the lowest-level of the service protocols generated for this service
  44. /// giving you the most flexibility over the implementation of your service. This comes at
  45. /// the cost of more verbose and less strict APIs. Each RPC requires you to implement it in
  46. /// terms of a request stream and response stream. Where only a single request or response
  47. /// message is expected, you are responsible for enforcing this invariant is maintained.
  48. ///
  49. /// Where possible, prefer using the stricter, less-verbose ``ServiceProtocol``
  50. /// or ``SimpleServiceProtocol`` instead.
  51. ///
  52. /// > Source IDL Documentation:
  53. /// >
  54. /// > Documentation for ServiceA
  55. public protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  56. /// Handle the "UnaryMethod" method.
  57. ///
  58. /// > Source IDL Documentation:
  59. /// >
  60. /// > Documentation for unaryMethod
  61. ///
  62. /// - Parameters:
  63. /// - request: A streaming request of `NamespaceA_ServiceARequest` messages.
  64. /// - context: Context providing information about the RPC.
  65. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  66. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  67. /// to an internal error.
  68. /// - Returns: A streaming response of `NamespaceA_ServiceAResponse` messages.
  69. func unary(
  70. request: GRPCCore.StreamingServerRequest<NamespaceA_ServiceARequest>,
  71. context: GRPCCore.ServerContext
  72. ) async throws -> GRPCCore.StreamingServerResponse<NamespaceA_ServiceAResponse>
  73. }
  74. /// Service protocol for the "namespaceA.AlongNameForServiceA" service.
  75. ///
  76. /// This protocol is higher level than ``StreamingServiceProtocol`` but lower level than
  77. /// the ``SimpleServiceProtocol``, it provides access to request and response metadata and
  78. /// trailing response metadata. If you don't need these then consider using
  79. /// the ``SimpleServiceProtocol``. If you need fine grained control over your RPCs then
  80. /// use ``StreamingServiceProtocol``.
  81. ///
  82. /// > Source IDL Documentation:
  83. /// >
  84. /// > Documentation for ServiceA
  85. public protocol ServiceProtocol: NamespaceA_ServiceA.StreamingServiceProtocol {
  86. /// Handle the "UnaryMethod" method.
  87. ///
  88. /// > Source IDL Documentation:
  89. /// >
  90. /// > Documentation for unaryMethod
  91. ///
  92. /// - Parameters:
  93. /// - request: A request containing a single `NamespaceA_ServiceARequest` message.
  94. /// - context: Context providing information about the RPC.
  95. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  96. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  97. /// to an internal error.
  98. /// - Returns: A response containing a single `NamespaceA_ServiceAResponse` message.
  99. func unary(
  100. request: GRPCCore.ServerRequest<NamespaceA_ServiceARequest>,
  101. context: GRPCCore.ServerContext
  102. ) async throws -> GRPCCore.ServerResponse<NamespaceA_ServiceAResponse>
  103. }
  104. /// Simple service protocol for the "namespaceA.AlongNameForServiceA" service.
  105. ///
  106. /// This is the highest level protocol for the service. The API is the easiest to use but
  107. /// doesn't provide access to request or response metadata. If you need access to these
  108. /// then use ``ServiceProtocol`` instead.
  109. ///
  110. /// > Source IDL Documentation:
  111. /// >
  112. /// > Documentation for ServiceA
  113. public protocol SimpleServiceProtocol: NamespaceA_ServiceA.ServiceProtocol {
  114. /// Handle the "UnaryMethod" method.
  115. ///
  116. /// > Source IDL Documentation:
  117. /// >
  118. /// > Documentation for unaryMethod
  119. ///
  120. /// - Parameters:
  121. /// - request: A `NamespaceA_ServiceARequest` message.
  122. /// - context: Context providing information about the RPC.
  123. /// - Throws: Any error which occurred during the processing of the request. Thrown errors
  124. /// of type `RPCError` are mapped to appropriate statuses. All other errors are converted
  125. /// to an internal error.
  126. /// - Returns: A `NamespaceA_ServiceAResponse` to respond with.
  127. func unary(
  128. request: NamespaceA_ServiceARequest,
  129. context: GRPCCore.ServerContext
  130. ) async throws -> NamespaceA_ServiceAResponse
  131. }
  132. }
  133. // Default implementation of 'registerMethods(with:)'.
  134. extension NamespaceA_ServiceA.StreamingServiceProtocol {
  135. public func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {
  136. router.registerHandler(
  137. forMethod: NamespaceA_ServiceA.Method.Unary.descriptor,
  138. deserializer: GRPCProtobuf.ProtobufDeserializer<NamespaceA_ServiceARequest>(),
  139. serializer: GRPCProtobuf.ProtobufSerializer<NamespaceA_ServiceAResponse>(),
  140. handler: { request, context in
  141. try await self.unary(
  142. request: request,
  143. context: context
  144. )
  145. }
  146. )
  147. }
  148. }
  149. // Default implementation of streaming methods from 'StreamingServiceProtocol'.
  150. extension NamespaceA_ServiceA.ServiceProtocol {
  151. public func unary(
  152. request: GRPCCore.StreamingServerRequest<NamespaceA_ServiceARequest>,
  153. context: GRPCCore.ServerContext
  154. ) async throws -> GRPCCore.StreamingServerResponse<NamespaceA_ServiceAResponse> {
  155. let response = try await self.unary(
  156. request: GRPCCore.ServerRequest(stream: request),
  157. context: context
  158. )
  159. return GRPCCore.StreamingServerResponse(single: response)
  160. }
  161. }
  162. // Default implementation of methods from 'ServiceProtocol'.
  163. extension NamespaceA_ServiceA.SimpleServiceProtocol {
  164. public func unary(
  165. request: GRPCCore.ServerRequest<NamespaceA_ServiceARequest>,
  166. context: GRPCCore.ServerContext
  167. ) async throws -> GRPCCore.ServerResponse<NamespaceA_ServiceAResponse> {
  168. return GRPCCore.ServerResponse<NamespaceA_ServiceAResponse>(
  169. message: try await self.unary(
  170. request: request.message,
  171. context: context
  172. ),
  173. metadata: [:]
  174. )
  175. }
  176. }
  177. """
  178. let rendered = self.render(accessLevel: .public, service: service)
  179. #expect(rendered == expectedSwift)
  180. }
  181. private func render(
  182. accessLevel: AccessModifier,
  183. service: ServiceDescriptor
  184. ) -> String {
  185. let translator = ServerCodeTranslator()
  186. let codeBlocks = translator.translate(accessModifier: accessLevel, service: service) {
  187. "GRPCProtobuf.ProtobufSerializer<\($0)>()"
  188. } deserializer: {
  189. "GRPCProtobuf.ProtobufDeserializer<\($0)>()"
  190. }
  191. let renderer = TextBasedRenderer.default
  192. renderer.renderCodeBlocks(codeBlocks)
  193. return renderer.renderedContents()
  194. }
  195. }