ClientCodeTranslatorSnippetBasedTests.swift 25 KB

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