ServerCodeTranslatorSnippetBasedTests.swift 9.6 KB

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