ClientCodeTranslatorSnippetBasedTests.swift 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  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 ClientCodeTranslatorSnippetBasedTests: XCTestCase {
  19. typealias MethodDescriptor = GRPCCodeGen.CodeGenerationRequest.ServiceDescriptor.MethodDescriptor
  20. typealias ServiceDescriptor = GRPCCodeGen.CodeGenerationRequest.ServiceDescriptor
  21. func testClientCodeTranslatorUnaryMethod() throws {
  22. let method = MethodDescriptor(
  23. documentation: "Documentation for MethodA",
  24. name: "methodA",
  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_ServiceAClientProtocol: Sendable {
  40. /// Documentation for MethodA
  41. func methodA<R>(
  42. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodA.Input>,
  43. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  44. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  45. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  46. ) async throws -> R where R: Sendable
  47. }
  48. extension namespaceA.ServiceA.ClientProtocol {
  49. func methodA<R>(
  50. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodA.Input>,
  51. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  52. ) async throws -> R where R: Sendable {
  53. try await self.methodA(
  54. request: request,
  55. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.methodA.Input>(),
  56. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.methodA.Output>(),
  57. body
  58. )
  59. }
  60. }
  61. /// Documentation for ServiceA
  62. struct namespaceA_ServiceAClient: namespaceA.ServiceA.ClientProtocol {
  63. let client: GRPCCore.GRPCClient
  64. init(client: GRPCCore.GRPCClient) {
  65. self.client = client
  66. }
  67. /// Documentation for MethodA
  68. func methodA<R>(
  69. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodA.Input>,
  70. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  71. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  72. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  73. ) async throws -> R where R: Sendable {
  74. try await self.client.unary(
  75. request: request,
  76. descriptor: namespaceA.ServiceA.Methods.methodA.descriptor,
  77. serializer: serializer,
  78. deserializer: deserializer,
  79. handler: body
  80. )
  81. }
  82. }
  83. """
  84. try self.assertClientCodeTranslation(
  85. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  86. expectedSwift: expectedSwift
  87. )
  88. }
  89. func testClientCodeTranslatorClientStreamingMethod() throws {
  90. let method = MethodDescriptor(
  91. documentation: "Documentation for MethodA",
  92. name: "methodA",
  93. isInputStreaming: true,
  94. isOutputStreaming: false,
  95. inputType: "NamespaceA_ServiceARequest",
  96. outputType: "NamespaceA_ServiceAResponse"
  97. )
  98. let service = ServiceDescriptor(
  99. documentation: "Documentation for ServiceA",
  100. name: "ServiceA",
  101. namespace: "namespaceA",
  102. methods: [method]
  103. )
  104. let expectedSwift =
  105. """
  106. /// Documentation for ServiceA
  107. protocol namespaceA_ServiceAClientProtocol: Sendable {
  108. /// Documentation for MethodA
  109. func methodA<R>(
  110. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  111. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  112. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  113. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  114. ) async throws -> R where R: Sendable
  115. }
  116. extension namespaceA.ServiceA.ClientProtocol {
  117. func methodA<R>(
  118. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  119. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  120. ) async throws -> R where R: Sendable {
  121. try await self.methodA(
  122. request: request,
  123. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.methodA.Input>(),
  124. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.methodA.Output>(),
  125. body
  126. )
  127. }
  128. }
  129. /// Documentation for ServiceA
  130. struct namespaceA_ServiceAClient: namespaceA.ServiceA.ClientProtocol {
  131. let client: GRPCCore.GRPCClient
  132. init(client: GRPCCore.GRPCClient) {
  133. self.client = client
  134. }
  135. /// Documentation for MethodA
  136. func methodA<R>(
  137. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  138. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  139. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  140. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  141. ) async throws -> R where R: Sendable {
  142. try await self.client.clientStreaming(
  143. request: request,
  144. descriptor: namespaceA.ServiceA.Methods.methodA.descriptor,
  145. serializer: serializer,
  146. deserializer: deserializer,
  147. handler: body
  148. )
  149. }
  150. }
  151. """
  152. try self.assertClientCodeTranslation(
  153. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  154. expectedSwift: expectedSwift
  155. )
  156. }
  157. func testClientCodeTranslatorServerStreamingMethod() throws {
  158. let method = MethodDescriptor(
  159. documentation: "Documentation for MethodA",
  160. name: "methodA",
  161. isInputStreaming: false,
  162. isOutputStreaming: true,
  163. inputType: "NamespaceA_ServiceARequest",
  164. outputType: "NamespaceA_ServiceAResponse"
  165. )
  166. let service = ServiceDescriptor(
  167. documentation: "Documentation for ServiceA",
  168. name: "ServiceA",
  169. namespace: "namespaceA",
  170. methods: [method]
  171. )
  172. let expectedSwift =
  173. """
  174. /// Documentation for ServiceA
  175. protocol namespaceA_ServiceAClientProtocol: Sendable {
  176. /// Documentation for MethodA
  177. func methodA<R>(
  178. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodA.Input>,
  179. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  180. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  181. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  182. ) async throws -> R where R: Sendable
  183. }
  184. extension namespaceA.ServiceA.ClientProtocol {
  185. func methodA<R>(
  186. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodA.Input>,
  187. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  188. ) async throws -> R where R: Sendable {
  189. try await self.methodA(
  190. request: request,
  191. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.methodA.Input>(),
  192. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.methodA.Output>(),
  193. body
  194. )
  195. }
  196. }
  197. /// Documentation for ServiceA
  198. struct namespaceA_ServiceAClient: namespaceA.ServiceA.ClientProtocol {
  199. let client: GRPCCore.GRPCClient
  200. init(client: GRPCCore.GRPCClient) {
  201. self.client = client
  202. }
  203. /// Documentation for MethodA
  204. func methodA<R>(
  205. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodA.Input>,
  206. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  207. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  208. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  209. ) async throws -> R where R: Sendable {
  210. try await self.client.serverStreaming(
  211. request: request,
  212. descriptor: namespaceA.ServiceA.Methods.methodA.descriptor,
  213. serializer: serializer,
  214. deserializer: deserializer,
  215. handler: body
  216. )
  217. }
  218. }
  219. """
  220. try self.assertClientCodeTranslation(
  221. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  222. expectedSwift: expectedSwift
  223. )
  224. }
  225. func testClientCodeTranslatorBidirectionalStreamingMethod() throws {
  226. let method = MethodDescriptor(
  227. documentation: "Documentation for MethodA",
  228. name: "methodA",
  229. isInputStreaming: true,
  230. isOutputStreaming: true,
  231. inputType: "NamespaceA_ServiceARequest",
  232. outputType: "NamespaceA_ServiceAResponse"
  233. )
  234. let service = ServiceDescriptor(
  235. documentation: "Documentation for ServiceA",
  236. name: "ServiceA",
  237. namespace: "namespaceA",
  238. methods: [method]
  239. )
  240. let expectedSwift =
  241. """
  242. /// Documentation for ServiceA
  243. protocol namespaceA_ServiceAClientProtocol: Sendable {
  244. /// Documentation for MethodA
  245. func methodA<R>(
  246. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  247. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  248. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  249. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  250. ) async throws -> R where R: Sendable
  251. }
  252. extension namespaceA.ServiceA.ClientProtocol {
  253. func methodA<R>(
  254. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  255. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  256. ) async throws -> R where R: Sendable {
  257. try await self.methodA(
  258. request: request,
  259. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.methodA.Input>(),
  260. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.methodA.Output>(),
  261. body
  262. )
  263. }
  264. }
  265. /// Documentation for ServiceA
  266. struct namespaceA_ServiceAClient: namespaceA.ServiceA.ClientProtocol {
  267. let client: GRPCCore.GRPCClient
  268. init(client: GRPCCore.GRPCClient) {
  269. self.client = client
  270. }
  271. /// Documentation for MethodA
  272. func methodA<R>(
  273. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  274. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  275. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  276. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  277. ) async throws -> R where R: Sendable {
  278. try await self.client.bidirectionalStreaming(
  279. request: request,
  280. descriptor: namespaceA.ServiceA.Methods.methodA.descriptor,
  281. serializer: serializer,
  282. deserializer: deserializer,
  283. handler: body
  284. )
  285. }
  286. }
  287. """
  288. try self.assertClientCodeTranslation(
  289. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  290. expectedSwift: expectedSwift
  291. )
  292. }
  293. func testClientCodeTranslatorMultipleMethods() throws {
  294. let methodA = MethodDescriptor(
  295. documentation: "Documentation for MethodA",
  296. name: "methodA",
  297. isInputStreaming: true,
  298. isOutputStreaming: false,
  299. inputType: "NamespaceA_ServiceARequest",
  300. outputType: "NamespaceA_ServiceAResponse"
  301. )
  302. let methodB = MethodDescriptor(
  303. documentation: "Documentation for MethodB",
  304. name: "methodB",
  305. isInputStreaming: false,
  306. isOutputStreaming: true,
  307. inputType: "NamespaceA_ServiceARequest",
  308. outputType: "NamespaceA_ServiceAResponse"
  309. )
  310. let service = ServiceDescriptor(
  311. documentation: "Documentation for ServiceA",
  312. name: "ServiceA",
  313. namespace: "namespaceA",
  314. methods: [methodA, methodB]
  315. )
  316. let expectedSwift =
  317. """
  318. /// Documentation for ServiceA
  319. protocol namespaceA_ServiceAClientProtocol: Sendable {
  320. /// Documentation for MethodA
  321. func methodA<R>(
  322. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  323. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  324. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  325. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  326. ) async throws -> R where R: Sendable
  327. /// Documentation for MethodB
  328. func methodB<R>(
  329. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodB.Input>,
  330. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodB.Input>,
  331. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodB.Output>,
  332. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodB.Output>) async throws -> R
  333. ) async throws -> R where R: Sendable
  334. }
  335. extension namespaceA.ServiceA.ClientProtocol {
  336. func methodA<R>(
  337. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  338. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  339. ) async throws -> R where R: Sendable {
  340. try await self.methodA(
  341. request: request,
  342. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.methodA.Input>(),
  343. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.methodA.Output>(),
  344. body
  345. )
  346. }
  347. func methodB<R>(
  348. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodB.Input>,
  349. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodB.Output>) async throws -> R
  350. ) async throws -> R where R: Sendable {
  351. try await self.methodB(
  352. request: request,
  353. serializer: ProtobufSerializer<namespaceA.ServiceA.Methods.methodB.Input>(),
  354. deserializer: ProtobufDeserializer<namespaceA.ServiceA.Methods.methodB.Output>(),
  355. body
  356. )
  357. }
  358. }
  359. /// Documentation for ServiceA
  360. struct namespaceA_ServiceAClient: namespaceA.ServiceA.ClientProtocol {
  361. let client: GRPCCore.GRPCClient
  362. init(client: GRPCCore.GRPCClient) {
  363. self.client = client
  364. }
  365. /// Documentation for MethodA
  366. func methodA<R>(
  367. request: ClientRequest.Stream<namespaceA.ServiceA.Methods.methodA.Input>,
  368. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodA.Input>,
  369. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodA.Output>,
  370. _ body: @Sendable @escaping (ClientResponse.Single<namespaceA.ServiceA.Methods.methodA.Output>) async throws -> R
  371. ) async throws -> R where R: Sendable {
  372. try await self.client.clientStreaming(
  373. request: request,
  374. descriptor: namespaceA.ServiceA.Methods.methodA.descriptor,
  375. serializer: serializer,
  376. deserializer: deserializer,
  377. handler: body
  378. )
  379. }
  380. /// Documentation for MethodB
  381. func methodB<R>(
  382. request: ClientRequest.Single<namespaceA.ServiceA.Methods.methodB.Input>,
  383. serializer: some MessageSerializer<namespaceA.ServiceA.Methods.methodB.Input>,
  384. deserializer: some MessageDeserializer<namespaceA.ServiceA.Methods.methodB.Output>,
  385. _ body: @Sendable @escaping (ClientResponse.Stream<namespaceA.ServiceA.Methods.methodB.Output>) async throws -> R
  386. ) async throws -> R where R: Sendable {
  387. try await self.client.serverStreaming(
  388. request: request,
  389. descriptor: namespaceA.ServiceA.Methods.methodB.descriptor,
  390. serializer: serializer,
  391. deserializer: deserializer,
  392. handler: body
  393. )
  394. }
  395. }
  396. """
  397. try self.assertClientCodeTranslation(
  398. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  399. expectedSwift: expectedSwift
  400. )
  401. }
  402. func testClientCodeTranslatorNoNamespaceService() throws {
  403. let method = MethodDescriptor(
  404. documentation: "Documentation for MethodA",
  405. name: "methodA",
  406. isInputStreaming: false,
  407. isOutputStreaming: false,
  408. inputType: "ServiceARequest",
  409. outputType: "ServiceAResponse"
  410. )
  411. let service = ServiceDescriptor(
  412. documentation: "Documentation for ServiceA",
  413. name: "ServiceA",
  414. namespace: "",
  415. methods: [method]
  416. )
  417. let expectedSwift =
  418. """
  419. /// Documentation for ServiceA
  420. protocol ServiceAClientProtocol: Sendable {
  421. /// Documentation for MethodA
  422. func methodA<R>(
  423. request: ClientRequest.Single<ServiceA.Methods.methodA.Input>,
  424. serializer: some MessageSerializer<ServiceA.Methods.methodA.Input>,
  425. deserializer: some MessageDeserializer<ServiceA.Methods.methodA.Output>,
  426. _ body: @Sendable @escaping (ClientResponse.Single<ServiceA.Methods.methodA.Output>) async throws -> R
  427. ) async throws -> R where R: Sendable
  428. }
  429. extension ServiceA.ClientProtocol {
  430. func methodA<R>(
  431. request: ClientRequest.Single<ServiceA.Methods.methodA.Input>,
  432. _ body: @Sendable @escaping (ClientResponse.Single<ServiceA.Methods.methodA.Output>) async throws -> R
  433. ) async throws -> R where R: Sendable {
  434. try await self.methodA(
  435. request: request,
  436. serializer: ProtobufSerializer<ServiceA.Methods.methodA.Input>(),
  437. deserializer: ProtobufDeserializer<ServiceA.Methods.methodA.Output>(),
  438. body
  439. )
  440. }
  441. }
  442. /// Documentation for ServiceA
  443. struct ServiceAClient: ServiceA.ClientProtocol {
  444. let client: GRPCCore.GRPCClient
  445. init(client: GRPCCore.GRPCClient) {
  446. self.client = client
  447. }
  448. /// Documentation for MethodA
  449. func methodA<R>(
  450. request: ClientRequest.Single<ServiceA.Methods.methodA.Input>,
  451. serializer: some MessageSerializer<ServiceA.Methods.methodA.Input>,
  452. deserializer: some MessageDeserializer<ServiceA.Methods.methodA.Output>,
  453. _ body: @Sendable @escaping (ClientResponse.Single<ServiceA.Methods.methodA.Output>) async throws -> R
  454. ) async throws -> R where R: Sendable {
  455. try await self.client.unary(
  456. request: request,
  457. descriptor: ServiceA.Methods.methodA.descriptor,
  458. serializer: serializer,
  459. deserializer: deserializer,
  460. handler: body
  461. )
  462. }
  463. }
  464. """
  465. try self.assertClientCodeTranslation(
  466. codeGenerationRequest: makeCodeGenerationRequest(services: [service]),
  467. expectedSwift: expectedSwift
  468. )
  469. }
  470. func testClientCodeTranslatorMultipleServices() throws {
  471. let serviceA = ServiceDescriptor(
  472. documentation: "Documentation for ServiceA",
  473. name: "ServiceA",
  474. namespace: "namespaceA",
  475. methods: []
  476. )
  477. let serviceB = ServiceDescriptor(
  478. documentation: "Documentation for ServiceB",
  479. name: "ServiceB",
  480. namespace: "",
  481. methods: []
  482. )
  483. let expectedSwift =
  484. """
  485. /// Documentation for ServiceA
  486. protocol namespaceA_ServiceAClientProtocol: Sendable {}
  487. extension namespaceA.ServiceA.ClientProtocol {
  488. }
  489. /// Documentation for ServiceA
  490. struct namespaceA_ServiceAClient: namespaceA.ServiceA.ClientProtocol {
  491. let client: GRPCCore.GRPCClient
  492. init(client: GRPCCore.GRPCClient) {
  493. self.client = client
  494. }
  495. }
  496. /// Documentation for ServiceB
  497. protocol ServiceBClientProtocol: Sendable {}
  498. extension ServiceB.ClientProtocol {
  499. }
  500. /// Documentation for ServiceB
  501. struct ServiceBClient: ServiceB.ClientProtocol {
  502. let client: GRPCCore.GRPCClient
  503. init(client: GRPCCore.GRPCClient) {
  504. self.client = client
  505. }
  506. }
  507. """
  508. try self.assertClientCodeTranslation(
  509. codeGenerationRequest: makeCodeGenerationRequest(services: [serviceA, serviceB]),
  510. expectedSwift: expectedSwift
  511. )
  512. }
  513. private func assertClientCodeTranslation(
  514. codeGenerationRequest: CodeGenerationRequest,
  515. expectedSwift: String
  516. ) throws {
  517. let translator = ClientCodeTranslator()
  518. let codeBlocks = try translator.translate(from: codeGenerationRequest)
  519. let renderer = TextBasedRenderer.default
  520. renderer.renderCodeBlocks(codeBlocks)
  521. let contents = renderer.renderedContents()
  522. try XCTAssertEqualWithDiff(contents, expectedSwift)
  523. }
  524. }