ClientCodeTranslatorSnippetBasedTests.swift 26 KB

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