ServerCodeTranslatorSnippetBasedTests.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  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 XCTest
  17. @testable import GRPCCodeGen
  18. final class ServerCodeTranslatorSnippetBasedTests: XCTestCase {
  19. typealias MethodDescriptor = GRPCCodeGen.CodeGenerationRequest.ServiceDescriptor.MethodDescriptor
  20. typealias ServiceDescriptor = GRPCCodeGen.CodeGenerationRequest.ServiceDescriptor
  21. func testServerCodeTranslatorUnaryMethod() throws {
  22. let method = MethodDescriptor(
  23. documentation: "Documentation for unaryMethod",
  24. name: "unaryMethod",
  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: "ServiceA",
  33. namespace: "namespaceA",
  34. methods: [method]
  35. )
  36. let expectedSwift =
  37. """
  38. /// Documentation for ServiceA
  39. protocol namespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  40. /// Documentation for unaryMethod
  41. func unaryMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.unaryMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.unaryMethod.Output>
  42. }
  43. /// Conformance to `GRPCCore.RegistrableRPCService`.
  44. public extension namespaceA.ServiceA.StreamingServiceProtocol {
  45. func registerRPCs(with router: inout GRPCCore.RPCRouter) {
  46. router.registerHandler(
  47. for: namespaceA.ServiceA.Methods.unaryMethod.descriptor,
  48. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.unaryMethod.Input>(),
  49. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.unaryMethod.Output>(),
  50. handler: { request in
  51. try await self.unaryMethod(request: request)
  52. }
  53. )
  54. }
  55. }
  56. /// Documentation for ServiceA
  57. protocol namespaceA_ServiceAServiceProtocol: namespaceA.ServiceA.StreamingServiceProtocol {
  58. /// Documentation for unaryMethod
  59. func unaryMethod(request: ServerRequest.Single<namespaceA.ServiceA.Methods.unaryMethod.Input>) async throws -> ServerResponse.Single<namespaceA.ServiceA.Methods.unaryMethod.Output>
  60. }
  61. /// Partial conformance to `namespaceA_ServiceAStreamingServiceProtocol`.
  62. public extension namespaceA.ServiceA.ServiceProtocol {
  63. func unaryMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.unaryMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.unaryMethod.Output> {
  64. let response = try await self.unaryMethod(request: ServerRequest.Single(stream: request))
  65. return ServerResponse.Stream(single: response)
  66. }
  67. }
  68. """
  69. try self.assertServerCodeTranslation(
  70. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  71. expectedSwift: expectedSwift
  72. )
  73. }
  74. func testServerCodeTranslatorInputStreamingMethod() throws {
  75. let method = MethodDescriptor(
  76. documentation: "Documentation for inputStreamingMethod",
  77. name: "inputStreamingMethod",
  78. isInputStreaming: true,
  79. isOutputStreaming: false,
  80. inputType: "NamespaceA_ServiceARequest",
  81. outputType: "NamespaceA_ServiceAResponse"
  82. )
  83. let service = ServiceDescriptor(
  84. documentation: "Documentation for ServiceA",
  85. name: "ServiceA",
  86. namespace: "namespaceA",
  87. methods: [method]
  88. )
  89. let expectedSwift =
  90. """
  91. /// Documentation for ServiceA
  92. protocol namespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  93. /// Documentation for inputStreamingMethod
  94. func inputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Output>
  95. }
  96. /// Conformance to `GRPCCore.RegistrableRPCService`.
  97. public extension namespaceA.ServiceA.StreamingServiceProtocol {
  98. func registerRPCs(with router: inout GRPCCore.RPCRouter) {
  99. router.registerHandler(
  100. for: namespaceA.ServiceA.Methods.inputStreamingMethod.descriptor,
  101. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>(),
  102. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.inputStreamingMethod.Output>(),
  103. handler: { request in
  104. try await self.inputStreamingMethod(request: request)
  105. }
  106. )
  107. }
  108. }
  109. /// Documentation for ServiceA
  110. protocol namespaceA_ServiceAServiceProtocol: namespaceA.ServiceA.StreamingServiceProtocol {
  111. /// Documentation for inputStreamingMethod
  112. func inputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>) async throws -> ServerResponse.Single<namespaceA.ServiceA.Methods.inputStreamingMethod.Output>
  113. }
  114. /// Partial conformance to `namespaceA_ServiceAStreamingServiceProtocol`.
  115. public extension namespaceA.ServiceA.ServiceProtocol {
  116. func inputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Output> {
  117. let response = try await self.inputStreamingMethod(request: request)
  118. return ServerResponse.Stream(single: response)
  119. }
  120. }
  121. """
  122. try self.assertServerCodeTranslation(
  123. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  124. expectedSwift: expectedSwift
  125. )
  126. }
  127. func testServerCodeTranslatorOutputStreamingMethod() throws {
  128. let method = MethodDescriptor(
  129. documentation: "Documentation for outputStreamingMethod",
  130. name: "outputStreamingMethod",
  131. isInputStreaming: false,
  132. isOutputStreaming: true,
  133. inputType: "NamespaceA_ServiceARequest",
  134. outputType: "NamespaceA_ServiceAResponse"
  135. )
  136. let service = ServiceDescriptor(
  137. documentation: "Documentation for ServiceA",
  138. name: "ServiceA",
  139. namespace: "namespaceA",
  140. methods: [method]
  141. )
  142. let expectedSwift =
  143. """
  144. /// Documentation for ServiceA
  145. protocol namespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  146. /// Documentation for outputStreamingMethod
  147. func outputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Output>
  148. }
  149. /// Conformance to `GRPCCore.RegistrableRPCService`.
  150. public extension namespaceA.ServiceA.StreamingServiceProtocol {
  151. func registerRPCs(with router: inout GRPCCore.RPCRouter) {
  152. router.registerHandler(
  153. for: namespaceA.ServiceA.Methods.outputStreamingMethod.descriptor,
  154. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>(),
  155. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.outputStreamingMethod.Output>(),
  156. handler: { request in
  157. try await self.outputStreamingMethod(request: request)
  158. }
  159. )
  160. }
  161. }
  162. /// Documentation for ServiceA
  163. protocol namespaceA_ServiceAServiceProtocol: namespaceA.ServiceA.StreamingServiceProtocol {
  164. /// Documentation for outputStreamingMethod
  165. func outputStreamingMethod(request: ServerRequest.Single<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Output>
  166. }
  167. /// Partial conformance to `namespaceA_ServiceAStreamingServiceProtocol`.
  168. public extension namespaceA.ServiceA.ServiceProtocol {
  169. func outputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Output> {
  170. let response = try await self.outputStreamingMethod(request: ServerRequest.Single(stream: request))
  171. return response
  172. }
  173. }
  174. """
  175. try self.assertServerCodeTranslation(
  176. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  177. expectedSwift: expectedSwift
  178. )
  179. }
  180. func testServerCodeTranslatorBidirectionalStreamingMethod() throws {
  181. let method = MethodDescriptor(
  182. documentation: "Documentation for bidirectionalStreamingMethod",
  183. name: "bidirectionalStreamingMethod",
  184. isInputStreaming: true,
  185. isOutputStreaming: true,
  186. inputType: "NamespaceA_ServiceARequest",
  187. outputType: "NamespaceA_ServiceAResponse"
  188. )
  189. let service = ServiceDescriptor(
  190. documentation: "Documentation for ServiceA",
  191. name: "ServiceA",
  192. namespace: "namespaceA",
  193. methods: [method]
  194. )
  195. let expectedSwift =
  196. """
  197. /// Documentation for ServiceA
  198. protocol namespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  199. /// Documentation for bidirectionalStreamingMethod
  200. func bidirectionalStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.Output>
  201. }
  202. /// Conformance to `GRPCCore.RegistrableRPCService`.
  203. public extension namespaceA.ServiceA.StreamingServiceProtocol {
  204. func registerRPCs(with router: inout GRPCCore.RPCRouter) {
  205. router.registerHandler(
  206. for: namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.descriptor,
  207. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.Input>(),
  208. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.Output>(),
  209. handler: { request in
  210. try await self.bidirectionalStreamingMethod(request: request)
  211. }
  212. )
  213. }
  214. }
  215. /// Documentation for ServiceA
  216. protocol namespaceA_ServiceAServiceProtocol: namespaceA.ServiceA.StreamingServiceProtocol {
  217. /// Documentation for bidirectionalStreamingMethod
  218. func bidirectionalStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.bidirectionalStreamingMethod.Output>
  219. }
  220. /// Partial conformance to `namespaceA_ServiceAStreamingServiceProtocol`.
  221. public extension namespaceA.ServiceA.ServiceProtocol {
  222. }
  223. """
  224. try self.assertServerCodeTranslation(
  225. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  226. expectedSwift: expectedSwift
  227. )
  228. }
  229. func testServerCodeTranslatorMultipleMethods() throws {
  230. let inputStreamingMethod = MethodDescriptor(
  231. documentation: "Documentation for inputStreamingMethod",
  232. name: "inputStreamingMethod",
  233. isInputStreaming: true,
  234. isOutputStreaming: false,
  235. inputType: "NamespaceA_ServiceARequest",
  236. outputType: "NamespaceA_ServiceAResponse"
  237. )
  238. let outputStreamingMethod = MethodDescriptor(
  239. documentation: "Documentation for outputStreamingMethod",
  240. name: "outputStreamingMethod",
  241. isInputStreaming: false,
  242. isOutputStreaming: true,
  243. inputType: "NamespaceA_ServiceARequest",
  244. outputType: "NamespaceA_ServiceAResponse"
  245. )
  246. let service = ServiceDescriptor(
  247. documentation: "Documentation for ServiceA",
  248. name: "ServiceA",
  249. namespace: "namespaceA",
  250. methods: [inputStreamingMethod, outputStreamingMethod]
  251. )
  252. let expectedSwift =
  253. """
  254. /// Documentation for ServiceA
  255. protocol namespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  256. /// Documentation for inputStreamingMethod
  257. func inputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Output>
  258. /// Documentation for outputStreamingMethod
  259. func outputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Output>
  260. }
  261. /// Conformance to `GRPCCore.RegistrableRPCService`.
  262. public extension namespaceA.ServiceA.StreamingServiceProtocol {
  263. func registerRPCs(with router: inout GRPCCore.RPCRouter) {
  264. router.registerHandler(
  265. for: namespaceA.ServiceA.Methods.inputStreamingMethod.descriptor,
  266. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>(),
  267. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.inputStreamingMethod.Output>(),
  268. handler: { request in
  269. try await self.inputStreamingMethod(request: request)
  270. }
  271. )
  272. router.registerHandler(
  273. for: namespaceA.ServiceA.Methods.outputStreamingMethod.descriptor,
  274. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>(),
  275. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.outputStreamingMethod.Output>(),
  276. handler: { request in
  277. try await self.outputStreamingMethod(request: request)
  278. }
  279. )
  280. }
  281. }
  282. /// Documentation for ServiceA
  283. protocol namespaceA_ServiceAServiceProtocol: namespaceA.ServiceA.StreamingServiceProtocol {
  284. /// Documentation for inputStreamingMethod
  285. func inputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>) async throws -> ServerResponse.Single<namespaceA.ServiceA.Methods.inputStreamingMethod.Output>
  286. /// Documentation for outputStreamingMethod
  287. func outputStreamingMethod(request: ServerRequest.Single<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Output>
  288. }
  289. /// Partial conformance to `namespaceA_ServiceAStreamingServiceProtocol`.
  290. public extension namespaceA.ServiceA.ServiceProtocol {
  291. func inputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.inputStreamingMethod.Output> {
  292. let response = try await self.inputStreamingMethod(request: request)
  293. return ServerResponse.Stream(single: response)
  294. }
  295. func outputStreamingMethod(request: ServerRequest.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Input>) async throws -> ServerResponse.Stream<namespaceA.ServiceA.Methods.outputStreamingMethod.Output> {
  296. let response = try await self.outputStreamingMethod(request: ServerRequest.Single(stream: request))
  297. return response
  298. }
  299. }
  300. """
  301. try assertServerCodeTranslation(
  302. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  303. expectedSwift: expectedSwift
  304. )
  305. }
  306. func testServerCodeTranslatorNoNamespaceService() throws {
  307. let method = MethodDescriptor(
  308. documentation: "Documentation for MethodA",
  309. name: "methodA",
  310. isInputStreaming: false,
  311. isOutputStreaming: false,
  312. inputType: "NamespaceA_ServiceARequest",
  313. outputType: "NamespaceA_ServiceAResponse"
  314. )
  315. let service = ServiceDescriptor(
  316. documentation: "Documentation for ServiceA",
  317. name: "ServiceA",
  318. namespace: "",
  319. methods: [method]
  320. )
  321. let expectedSwift =
  322. """
  323. /// Documentation for ServiceA
  324. protocol ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {
  325. /// Documentation for MethodA
  326. func methodA(request: ServerRequest.Stream<ServiceA.Methods.methodA.Input>) async throws -> ServerResponse.Stream<ServiceA.Methods.methodA.Output>
  327. }
  328. /// Conformance to `GRPCCore.RegistrableRPCService`.
  329. public extension ServiceA.StreamingServiceProtocol {
  330. func registerRPCs(with router: inout GRPCCore.RPCRouter) {
  331. router.registerHandler(
  332. for: ServiceA.Methods.methodA.descriptor,
  333. deserializer: ProtobufDeserializer<ServiceA.Methods.methodA.Input>(),
  334. serializer: ProtobufSerializer<ServiceA.Methods.methodA.Output>(),
  335. handler: { request in
  336. try await self.methodA(request: request)
  337. }
  338. )
  339. }
  340. }
  341. /// Documentation for ServiceA
  342. protocol ServiceAServiceProtocol: ServiceA.StreamingServiceProtocol {
  343. /// Documentation for MethodA
  344. func methodA(request: ServerRequest.Single<ServiceA.Methods.methodA.Input>) async throws -> ServerResponse.Single<ServiceA.Methods.methodA.Output>
  345. }
  346. /// Partial conformance to `ServiceAStreamingServiceProtocol`.
  347. public extension ServiceA.ServiceProtocol {
  348. func methodA(request: ServerRequest.Stream<ServiceA.Methods.methodA.Input>) async throws -> ServerResponse.Stream<ServiceA.Methods.methodA.Output> {
  349. let response = try await self.methodA(request: ServerRequest.Single(stream: request))
  350. return ServerResponse.Stream(single: response)
  351. }
  352. }
  353. """
  354. try self.assertServerCodeTranslation(
  355. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  356. expectedSwift: expectedSwift
  357. )
  358. }
  359. func testServerCodeTranslatorMoreServicesOrder() throws {
  360. let serviceA = ServiceDescriptor(
  361. documentation: "Documentation for ServiceA",
  362. name: "ServiceA",
  363. namespace: "namespaceA",
  364. methods: []
  365. )
  366. let serviceB = ServiceDescriptor(
  367. documentation: "Documentation for ServiceB",
  368. name: "ServiceB",
  369. namespace: "namespaceA",
  370. methods: []
  371. )
  372. let expectedSwift =
  373. """
  374. /// Documentation for ServiceA
  375. protocol namespaceA_ServiceAStreamingServiceProtocol: GRPCCore.RegistrableRPCService {}
  376. /// Conformance to `GRPCCore.RegistrableRPCService`.
  377. public extension namespaceA.ServiceA.StreamingServiceProtocol {
  378. func registerRPCs(with router: inout GRPCCore.RPCRouter) {}
  379. }
  380. /// Documentation for ServiceA
  381. protocol namespaceA_ServiceAServiceProtocol: namespaceA.ServiceA.StreamingServiceProtocol {}
  382. /// Partial conformance to `namespaceA_ServiceAStreamingServiceProtocol`.
  383. public extension namespaceA.ServiceA.ServiceProtocol {
  384. }
  385. /// Documentation for ServiceB
  386. protocol namespaceA_ServiceBStreamingServiceProtocol: GRPCCore.RegistrableRPCService {}
  387. /// Conformance to `GRPCCore.RegistrableRPCService`.
  388. public extension namespaceA.ServiceB.StreamingServiceProtocol {
  389. func registerRPCs(with router: inout GRPCCore.RPCRouter) {}
  390. }
  391. /// Documentation for ServiceB
  392. protocol namespaceA_ServiceBServiceProtocol: namespaceA.ServiceB.StreamingServiceProtocol {}
  393. /// Partial conformance to `namespaceA_ServiceBStreamingServiceProtocol`.
  394. public extension namespaceA.ServiceB.ServiceProtocol {
  395. }
  396. """
  397. try self.assertServerCodeTranslation(
  398. codeGenerationRequest: makeCodeGenerationRequest(services: [serviceA, serviceB]),
  399. expectedSwift: expectedSwift
  400. )
  401. }
  402. private func assertServerCodeTranslation(
  403. codeGenerationRequest: CodeGenerationRequest,
  404. expectedSwift: String
  405. ) throws {
  406. let translator = ServerCodeTranslator()
  407. let codeBlocks = try translator.translate(from: codeGenerationRequest)
  408. let renderer = TextBasedRenderer.default
  409. renderer.renderCodeBlocks(codeBlocks)
  410. let contents = renderer.renderedContents()
  411. try XCTAssertEqualWithDiff(contents, expectedSwift)
  412. }
  413. }